Home.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. /**
  2. * 首页通用页
  3. * @邠心vbe on 2021/08/13
  4. */
  5. import React, { Component } from 'react';
  6. import { View, StyleSheet, BackHandler, Linking, AppState } from 'react-native';
  7. import app from '../../../app.json'
  8. import { i18nUtil } from '../../i18n';
  9. import apiBase from '../../api/apiBase';
  10. import apiStation from '../../api/apiStation';
  11. import Dialog from '../../components/Dialog';
  12. import utils from '../../utils/utils';
  13. import { SettingUtil } from '../Settings';
  14. import MyStatusBar from '../../components/MyStatusBar';
  15. import LocationPermission from './maps/LocationPermission';
  16. import MapUI from './MapUI';
  17. import MapUILumi from './MapUILumi';
  18. import storage from '../../utils/storage';
  19. const KEY_STORE_LIST = "map_stop_list"
  20. const KEY_STORE_GPS = "map_location_gps"
  21. export default class HomePage extends Component {
  22. constructor(props) {
  23. super(props);
  24. this.state = {
  25. region: {
  26. latitude: 1.3532623163977149,
  27. longitude: 103.87092316860532,
  28. latitudeDelta: 0.0922,
  29. longitudeDelta: 0.0421
  30. },
  31. lastRegion: {},
  32. mapReady: false,
  33. showStation: false,
  34. stationId: "",
  35. stationInfo: {},
  36. stopList: [],
  37. hasPermission: false,
  38. permissionDenied: false,
  39. pinMessage: {
  40. visible: false
  41. }
  42. };
  43. this.isHide = true;
  44. this.denied = true;
  45. this.backSeconds = 0;
  46. this.refreshTime = 0;
  47. this.settingInfo = {}
  48. this.viewIndex = -1;
  49. this.filter = {
  50. parkingFee: 'ALL',
  51. connectorType: ''
  52. };
  53. this.refresh = false;
  54. this.stateListener;
  55. this.forceUpdateDialog = undefined;
  56. this.locationListener = undefined;
  57. }
  58. componentDidMount() {
  59. const navigation = this.props.navigation;
  60. if (this.locationListener) {
  61. this.locationListener.removeListener();
  62. this.locationListener = undefined;
  63. }
  64. if (!isIOS) {
  65. this.locationListener = new LocationPermission.LocationListener();
  66. if (this.locationListener) {
  67. this.locationListener.addListener();
  68. }
  69. }
  70. navigation.addListener('focus', () => {
  71. //console.log('------Home------', "Focus")
  72. this.onCloseInfo();
  73. SettingUtil.getSettings(set => {
  74. //console.log("获取设置信息", set);
  75. this.settingInfo = set;
  76. this.init();
  77. })
  78. this.isHide = false;
  79. /*if (!app.isWhitelabel) {
  80. MyStatusBar.setStatusBarThemes(MyStatusBar.DARK_STYLE, colorLight);
  81. }*/
  82. MyStatusBar.setTranslucentStatusBar();
  83. });
  84. navigation.addListener('blur', () => {
  85. //toastShort('onStop')
  86. this.isHide = true;
  87. /*if (app.isLumiWhitelabel) {
  88. MyStatusBar.setStatusBarThemes(MyStatusBar.DARK_STYLE, colorLight);
  89. } else {
  90. MyStatusBar.setStatusBarThemes(themeStatusBar, colorPrimaryDark);
  91. }*/
  92. setTimeout(() => {
  93. MyStatusBar.setStatusBarTheme(MyStatusBar.DEFAULT_STYLE);
  94. }, 50);
  95. setTimeout(() => {
  96. navigation.closeDrawer();
  97. }, 500);
  98. });
  99. this.stateListener = AppState.addEventListener("change", state => {
  100. if (state == 'active' && this.forceUpdateDialog) {
  101. this.showUpdateDialog(this.forceUpdateDialog);
  102. }
  103. });
  104. BackHandler.addEventListener('hardwareBackPress', this.toExit)
  105. this.isHide = false;
  106. this.checkUpdateVersion();
  107. }
  108. componentWillUnmount() {
  109. /*console.log("componentWillUnmount")
  110. if (this.unsubscribe) {
  111. this.unsubscribe();
  112. }*/
  113. this.backSeconds = 0;
  114. if (this.stateListener) {
  115. this.stateListener.remove();
  116. }
  117. BackHandler.removeEventListener("hardwareBackPress", this.toExit);
  118. }
  119. init() {
  120. if (this.state.stopList.length == 0 && !this.refresh) {
  121. storage.getStorage(KEY_STORE_LIST).then(data => {
  122. //console.log("获取站点缓存", "成功");
  123. if (data) {
  124. const list = JSON.parse(data);
  125. this.setState({
  126. stopList: list
  127. }, () => {
  128. this.checkPermission2Geo(true);
  129. })
  130. } else {
  131. this.checkPermission2Geo(true);
  132. }
  133. }).catch(err => {
  134. console.log("获取站点缓存-err", err);
  135. this.checkPermission2Geo(true);
  136. })
  137. storage.getStorage(KEY_STORE_GPS).then(data => {
  138. //console.log("获取GPS缓存", data);
  139. if (data) {
  140. const location = JSON.parse(data);
  141. if (location.latitude) {
  142. this.setState({
  143. lastRegion: location
  144. });
  145. }
  146. }
  147. }).catch(err => {
  148. console.log("获取GPS缓存-err", err);
  149. })
  150. }
  151. if (isLogin()) {
  152. this.getPinMessage()
  153. } else {
  154. setTimeout(() => {
  155. this.getPinMessage()
  156. }, 5000);
  157. }
  158. }
  159. toExit = () => {
  160. //console.log("beforeRemove", this.isHide);
  161. if (this.state.stationInfo?.id) {
  162. this.setState({
  163. stationInfo: {}
  164. });
  165. return true;
  166. }
  167. if (!this.isHide) {
  168. if (isIOS) {
  169. //e.preventDefault();
  170. } else {
  171. let time = new Date().getTime();
  172. //console.log("beforeRemove2", time, this.backSeconds);
  173. if (time - this.backSeconds < 2000) {
  174. BackHandler.exitApp();
  175. } else {
  176. toastShort($t("home.backAgainTips"));
  177. this.backSeconds = time;
  178. //e.preventDefault();
  179. }
  180. }
  181. return true;
  182. }
  183. }
  184. checkGPS() {
  185. if (this.locationListener) {
  186. this.locationListener.check();
  187. }
  188. }
  189. onMapReady() {
  190. this.setState({
  191. mapReady: true
  192. }, () => {
  193. this.init();
  194. });
  195. }
  196. checkUpdateVersion() {
  197. apiBase.checkUpdate().then(res => {
  198. if (res.data.versionCode > app.versionCode) {
  199. var desc = JSON.parse(res.data?.versionDesc ?? "{}");
  200. if (desc) {
  201. const upLog = i18nUtil.analyzeLocaleData(desc);
  202. if (typeof upLog == "string") {
  203. const prps = {
  204. title: $t("home.versionUpdate"),
  205. message: $t("home.newVersionName") + res.data.versionName + "\n\n" + upLog,
  206. showCancel: !(res.data.force),
  207. ok: $t("home.updateNow"),
  208. cancel: $t("home.later"),
  209. callback: btn => {
  210. if (btn == Dialog.BUTTON_OK) {
  211. //TODO 跳转到应用商店
  212. const uri = isIOS
  213. ? app.storeUrl.ios
  214. : app.storeUrl.android
  215. Linking.openURL(uri);
  216. }
  217. }
  218. }
  219. if (res.data.force) {
  220. prps.onBackPress = () => {
  221. }
  222. this.forceUpdateDialog = prps;
  223. }
  224. this.showUpdateDialog(prps);
  225. }
  226. }
  227. }
  228. }).catch(err => {
  229. })
  230. }
  231. showUpdateDialog(options) {
  232. if (Dialog.isShowing()) {
  233. setTimeout(() => {
  234. this.showUpdateDialog(options)
  235. }, 500);
  236. return;
  237. }
  238. Dialog.showDialog(options)
  239. }
  240. getPermission() {
  241. LocationPermission.requestPermission(hasPermission => {
  242. if (hasPermission) {
  243. this.setState({
  244. hasPermission: true
  245. });
  246. this.checkPermission2Geo();
  247. } else {
  248. this.noPermissionSite();
  249. }
  250. })
  251. }
  252. checkPermission2Geo(refresh, button) {
  253. if (button && this.state.lastRegion.latitude) {
  254. this.setState({
  255. region: {...this.state.lastRegion}
  256. });
  257. }
  258. if (this.refresh == refresh) {
  259. return;
  260. }
  261. if (refresh) {
  262. //避免关闭自动移动地图后无法点击按钮移动地图
  263. this.refresh = true
  264. }
  265. console.log("checkPermission2Geo", refresh, button);
  266. this.checkGPS();
  267. if (this.state.hasPermission) {
  268. this.infoGeoLocation();
  269. } else {
  270. LocationPermission.checkPermission((hasPermission, canRequestPermission) => {
  271. if (hasPermission) {
  272. this.setState({
  273. hasPermission: true
  274. });
  275. this.infoGeoLocation();
  276. } else {
  277. if (canRequestPermission) {
  278. if (this.denied) {
  279. this.denied = false;
  280. this.getPermission();
  281. } else {
  282. //避免多次请求
  283. this.denied = true;
  284. this.noPermissionSite();
  285. }
  286. } else {
  287. this.noPermissionSite();
  288. }
  289. }
  290. })
  291. }
  292. }
  293. noPermissionSite() {
  294. console.log("未获取权限也获取站点列表");
  295. this.setState({
  296. hasPermission: false,
  297. permissionDenied: true
  298. });
  299. let first = this.state.stopList.length == 0;//是否第一次加载
  300. this.getStationList(this.state.region, first);
  301. }
  302. /**
  303. * 获取定位数据
  304. * @param {*} again
  305. */
  306. infoGeoLocation(again) {
  307. if (this.state.mapReady) {
  308. navigator.geolocation.getCurrentPosition(location => {
  309. let region = {
  310. latitude: location.coords.latitude,
  311. longitude: location.coords.longitude,
  312. latitudeDelta: 0.0922,
  313. longitudeDelta: 0.0421
  314. }
  315. this.saveGPSCache(region);
  316. //console.log("getGeoLocation", region);
  317. //if (this.state.stopList.length == 0) { //只加载一次
  318. let time = new Date().getTime();
  319. let interval = this.settingInfo.refreshInterval * 1000;//重复加载时间
  320. let first = this.state.stopList.length == 0;//是否第一次加载
  321. if (first || this.refresh || time - this.refreshTime > interval) { //一分钟(10秒)加载一次
  322. this.getStationList(region, first || this.refresh);
  323. this.refreshTime = time;
  324. } else if (this.settingInfo.moveMyLocation) {
  325. this.setState({
  326. region: region
  327. });
  328. }
  329. }, error => {
  330. console.info("getGeoLocation", error);
  331. if (!again) {
  332. setTimeout(() => {
  333. this.infoGeoLocation(true);
  334. }, 2000);
  335. }
  336. });
  337. } else {
  338. setTimeout(() => {
  339. this.infoGeoLocation(true);
  340. }, 1000);
  341. }
  342. }
  343. findFilter(data) {
  344. this.filter = data;
  345. console.log("筛选站点", data);
  346. this.getStationList();
  347. }
  348. /**
  349. * 获取所有充电桩
  350. * @param {Location} region 当前位置
  351. * @param {boolean} first 是否初始化
  352. */
  353. getStationList(region, first) {
  354. //Dialog.showProgressDialog();
  355. if (getUserId()) {
  356. this.filter.operaUserId = getUserId()
  357. }
  358. if (region && (this.settingInfo.moveMyLocation || first)) {
  359. this.setState({
  360. region: region
  361. });
  362. }
  363. apiStation.getAllStation(this.filter).then(res => {
  364. Dialog.dismissLoading();
  365. if (res.data.sites) {
  366. const list = [];
  367. res.data.sites.forEach(item => {
  368. let available = false
  369. if (item.allConnector && item.allConnector.available) {
  370. available = true
  371. }
  372. list.push({
  373. id: item.sitePk,
  374. name: item.siteName,
  375. //address: item.siteAddress,
  376. available: available,
  377. siteType: item.siteType,
  378. latitude: item.locationLatitude,
  379. longitude: item.locationLongitude,
  380. favorite: item?.favorite ? true : false,
  381. hasLabel: item?.hasLabel,
  382. upcoming: item?.upcoming
  383. /*acConnector: item.acConnector,
  384. allConnector: item.allConnector,
  385. dcConnector: item.dcConnector,
  386. distance: utils.getDistance(item.distance)*/
  387. });
  388. });
  389. this.setState({
  390. stopList: list
  391. });
  392. if (this.filter.connectorType == "" && this.filter.parkingFee == "ALL") {
  393. storage.setStorageJson(KEY_STORE_LIST, list);
  394. }
  395. }
  396. this.refresh = false;
  397. }).catch(err => {
  398. Dialog.dismissLoading();
  399. toastShort(err);
  400. /*this.setState({
  401. stopList: []
  402. });*/
  403. this.refresh = false;
  404. })
  405. }
  406. //点击Marker获取StaionInfo
  407. viewChargeStation(id) {
  408. //console.log('info', this.state.stopList[index]);
  409. //const stationInfo = this.state.stopList[index];
  410. if (this.state.stationId == id) {
  411. return;
  412. }
  413. this.setState({
  414. stationId: id,
  415. stationInfo: {},
  416. showStation: true
  417. });
  418. if (app.modules.bookmarks) {
  419. for (let i = 0; i < this.state.stopList.length; i++) {
  420. let info = this.state.stopList[i];
  421. if (info.id == id) {
  422. this.viewIndex = i;
  423. break;
  424. }
  425. }
  426. }
  427. if (this.state.hasPermission) {
  428. navigator.geolocation.getCurrentPosition(location => {
  429. let region = {
  430. latitude: location.coords.latitude,
  431. longitude: location.coords.longitude,
  432. latitudeDelta: 0.0922,
  433. longitudeDelta: 0.0421
  434. }
  435. setTimeout(() => {
  436. this.getStationInfo(id, region);
  437. }, 500);
  438. /*if (this.settingInfo.alwaysLocation) {
  439. this.setState({
  440. region: region
  441. });
  442. }*/
  443. });
  444. } else {
  445. //无定位权限仍然显示
  446. setTimeout(() => {
  447. this.getStationInfo(id, this.state.region);
  448. }, 500);
  449. }
  450. //startPage(PageList.chargeDetail, {...this.state.stopList[index]});
  451. }
  452. getStationInfo(id, location) {
  453. apiStation.getStationRate({
  454. sitePk: id,
  455. lat: location?.latitude,
  456. lng: location?.longitude
  457. }).then(res => {
  458. if (res.data.sitePk) {
  459. var info = utils.getSiteInfo(res.data);
  460. this.setState({
  461. stationInfo: info
  462. });
  463. } else {
  464. this.setState({
  465. stationInfo: {}
  466. });
  467. }
  468. }).catch(err => {
  469. this.setState({
  470. stationInfo: {}
  471. });
  472. toastShort(err);
  473. });
  474. }
  475. onCloseInfo() {
  476. this.viewIndex = -1;
  477. this.setState({
  478. stationId: "",
  479. stationInfo: {},
  480. showStation: false
  481. });
  482. }
  483. favoriteSite() {
  484. if (this.state.stationInfo?.id) {
  485. Dialog.showProgressDialog();
  486. apiStation.bookmarkSite(this.state.stationInfo.id).then(res => {
  487. const info = {...this.state.stationInfo, favorite: !this.state.stationInfo.favorite}
  488. if (this.viewIndex >= 0) {
  489. const list = [...this.state.stopList]
  490. const inf = {...list[this.viewIndex], favorite: info.favorite};
  491. list[this.viewIndex] = inf;
  492. this.setState({
  493. stopList: list,
  494. stationInfo: info
  495. });
  496. } else {
  497. this.setState({
  498. stationInfo: info
  499. });
  500. }
  501. }).catch(err => {
  502. toastShort(err);
  503. console.log(err)
  504. }).finally(() => {
  505. Dialog.dismissLoading();
  506. })
  507. }
  508. }
  509. getPinMessage() {
  510. if (!isLogin()) return;
  511. apiBase.getPinMessage().then(res => {
  512. if (res.data && res.data.pinTitle) {
  513. const pin = {
  514. visible: true,
  515. title: res.data.pinTitle,
  516. message: res.data.pinContent
  517. }
  518. this.setState({
  519. pinMessage: pin
  520. })
  521. } else {
  522. this.setState({
  523. pinMessage: {
  524. visible: false
  525. }
  526. })
  527. }
  528. }).catch(err => {
  529. this.setState({
  530. pinMessage: {
  531. visible: false
  532. }
  533. })
  534. })
  535. }
  536. hidePermissionPanel() {
  537. this.setState({
  538. permissionDenied: false
  539. })
  540. }
  541. saveGPSCache(location={}) {
  542. if (location.latitude) {
  543. storage.setStorageJson(KEY_STORE_GPS, location);
  544. this.setState({
  545. lastRegion: location
  546. });
  547. }
  548. }
  549. render() {
  550. return (
  551. <View style={ui.flex1}>
  552. { app.isLumiWhitelabel
  553. ? <MapUILumi
  554. state={this.state}
  555. navigation={this.props.navigation}
  556. onFilter={data => this.findFilter(data)}
  557. onMapReady={() => this.onMapReady()}
  558. onFavorite={() => this.favoriteSite()}
  559. onCloseInfo={() => this.onCloseInfo()}
  560. onLocation={() => this.checkPermission2Geo(true, true)}
  561. useApplesMap={this.settingInfo.useApplesMap}
  562. showUserLocation={this.state.hasPermission && this.settingInfo.alwaysLocation}
  563. viewChargeStation={id => this.viewChargeStation(id)}/>
  564. : <MapUI
  565. state={this.state}
  566. navigation={this.props.navigation}
  567. onFilter={data => this.findFilter(data)}
  568. onMapReady={() => this.onMapReady()}
  569. onFavorite={() => this.favoriteSite()}
  570. onCloseInfo={() => this.onCloseInfo()}
  571. onLocation={() => this.checkPermission2Geo(true, true)}
  572. useApplesMap={this.settingInfo.useApplesMap}
  573. showUserLocation={this.state.hasPermission && this.settingInfo.alwaysLocation}
  574. viewChargeStation={id => this.viewChargeStation(id)}
  575. pinMessage={this.state.pinMessage}
  576. />
  577. }
  578. <LocationPermission.VIEW
  579. visible={this.state.permissionDenied}
  580. onView={() => this.hidePermissionPanel()}/>
  581. <View style={styles.drawerLeftTouchView}></View>
  582. </View>
  583. );
  584. }
  585. }
  586. const styles = StyleSheet.create({
  587. drawerLeftTouchView: {
  588. top: 0,
  589. left: 0,
  590. bottom: 0,
  591. width: 4,
  592. zIndex: 5,
  593. position: 'absolute',
  594. backgroundColor: 'rgba(0,0,0,0)'
  595. }
  596. })