Home.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /**
  2. * 首页地图页
  3. * @邠心vbe on 2021/08/13
  4. */
  5. import React, { Component } from 'react';
  6. import { View, Text, Pressable, Image, StyleSheet, BackHandler, Linking } from 'react-native';
  7. import apiBase from '../../api/apiBase';
  8. import apiStation from '../../api/apiStation';
  9. import Dialog from '../../components/Dialog';
  10. import { Styles } from '../../components/Toolbar';
  11. import MyStatusBar from '../../components/MyStatusBar';
  12. import utils from '../../utils/utils';
  13. import { PageList } from '../Router';
  14. import { SettingUtil } from '../Settings';
  15. import BottomSiteInfo from './maps/BottomSiteInfo';
  16. import LocationPermission from './maps/LocationPermission';
  17. import Maps from './maps/Maps';
  18. import SearchTool from './maps/SearchTool';
  19. import app from '../../../app.json'
  20. import { i18nUtil } from '../../i18n';
  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. mapReady: false,
  32. stationInfo: {},
  33. stopList: [],
  34. hasPermission: isIOS,
  35. permissionDenied: false
  36. };
  37. this.isHide = true;
  38. this.denied = true;
  39. this.backSeconds = 0;
  40. this.refreshTime = 0;
  41. this.settingInfo = {}
  42. this.viewIndex = -1;
  43. this.filter = {
  44. parkingFee: 'ALL',
  45. connectorType: ''
  46. };
  47. }
  48. componentDidMount() {
  49. const navigation = this.props.navigation;
  50. navigation.addListener('focus', () => {
  51. //toastShort('onResume')
  52. this.setState({
  53. stationInfo: {}
  54. });
  55. this.viewIndex = -1;
  56. SettingUtil.getSettings(set => {
  57. //console.log("获取设置信息", set);
  58. this.settingInfo = set;
  59. this.checkPermission2Geo();
  60. })
  61. this.isHide = false;
  62. //MyStatusBar.setStatusBarThemes(MyStatusBar.DARK_STYLE, colorLight);
  63. });
  64. navigation.addListener('blur', () => {
  65. //toastShort('onStop')
  66. this.isHide = true;
  67. //MyStatusBar.setStatusBarThemes(MyStatusBar.LIGHT_STYLE, colorPrimaryDark);
  68. setTimeout(() => {
  69. navigation.closeDrawer();
  70. }, 200);
  71. });
  72. /*navigation.addListener('beforeRemove', (e) => {
  73. if (isIOS) {
  74. e.preventDefault();
  75. } else {
  76. let time = new Date().getTime();
  77. if (time - this.backSeconds < 2000) {
  78. BackHandler.exitApp();
  79. } else {
  80. toastShort("Press the back button again to exit the program");
  81. this.backSeconds = time;
  82. e.preventDefault();
  83. }
  84. }
  85. });*/
  86. BackHandler.addEventListener('hardwareBackPress', this.toExit)
  87. this.isHide = false;
  88. //MyStatusBar.setStatusBarThemes(MyStatusBar.DARK_STYLE, colorLight);
  89. this.checkUpdateVersion();
  90. }
  91. componentWillUnmount() {
  92. /*console.log("componentWillUnmount")
  93. if (this.unsubscribe) {
  94. this.unsubscribe();
  95. }*/
  96. this.backSeconds = 0;
  97. BackHandler.removeEventListener("hardwareBackPress", this.toExit)
  98. }
  99. toExit = () => {
  100. //console.log("beforeRemove", this.isHide);
  101. if (!this.isHide) {
  102. if (isIOS) {
  103. //e.preventDefault();
  104. } else {
  105. let time = new Date().getTime();
  106. //console.log("beforeRemove2", time, this.backSeconds);
  107. if (time - this.backSeconds < 2000) {
  108. BackHandler.exitApp();
  109. } else {
  110. toastShort("Press the back button again to exit the program");
  111. this.backSeconds = time;
  112. //e.preventDefault();
  113. }
  114. }
  115. return true;
  116. }
  117. }
  118. checkUpdateVersion() {
  119. apiBase.checkUpdate().then(res => {
  120. if (res.data.versionCode > app.versionCode) {
  121. var desc = JSON.parse(res.data?.versionDesc ?? "{}");
  122. if (desc) {
  123. const upLog = i18nUtil.analyzeLocaleData(desc);
  124. if (typeof upLog == "string") {
  125. this.showUpdateDialog({
  126. title: $t("home.versionUpdate"),
  127. message: $t("home.newVersionName") + res.data.versionName + "\n\n" + upLog,
  128. showCancel: !(res.data.force),
  129. ok: $t("home.updateNow"),
  130. cancel: $t("home.later"),
  131. callback: btn => {
  132. if (btn == Dialog.BUTTON_OK) {
  133. //TODO 跳转到应用商店
  134. const uri = isIOS
  135. ? app.storeUrl.ios
  136. : app.storeUrl.android
  137. Linking.openURL(uri);
  138. }
  139. }
  140. })
  141. }
  142. }
  143. }
  144. }).catch(err => {
  145. })
  146. }
  147. showUpdateDialog(options) {
  148. if (Dialog.isShowing()) {
  149. setTimeout(() => {
  150. this.showUpdateDialog(options)
  151. }, 500);
  152. return;
  153. }
  154. Dialog.showDialog(options)
  155. }
  156. getPermission() {
  157. LocationPermission.requestPermission(hasPermission => {
  158. if (hasPermission) {
  159. this.setState({
  160. hasPermission: true
  161. });
  162. this.checkPermission2Geo();
  163. } else {
  164. this.noPermissionSite();
  165. }
  166. })
  167. }
  168. checkPermission2Geo(refresh) {
  169. if (this.state.hasPermission) {
  170. if (refresh) {
  171. //避免关闭自动移动地图后无法点击按钮移动地图
  172. this.state.stopList = []
  173. }
  174. this.infoGeoLocation();
  175. } else {
  176. LocationPermission.checkPermission((hasPermission, canRequestPermission) => {
  177. if (hasPermission) {
  178. this.setState({
  179. hasPermission: true
  180. });
  181. this.infoGeoLocation();
  182. } else {
  183. if (canRequestPermission) {
  184. if (this.denied) {
  185. this.denied = false;
  186. this.getPermission();
  187. } else {
  188. //避免多次请求
  189. this.denied = true;
  190. this.noPermissionSite();
  191. }
  192. } else {
  193. this.noPermissionSite();
  194. }
  195. }
  196. })
  197. }
  198. }
  199. noPermissionSite() {
  200. console.log("未获取权限也获取站点列表");
  201. this.setState({
  202. hasPermission: false,
  203. permissionDenied: true
  204. });
  205. let first = this.state.stopList.length == 0;//是否第一次加载
  206. this.getStationList(this.state.region, first);
  207. }
  208. /**
  209. * 获取定位数据
  210. * @param {*} again
  211. */
  212. infoGeoLocation(again) {
  213. if (this.state.mapReady) {
  214. navigator.geolocation.getCurrentPosition(location => {
  215. let region = {
  216. latitude: location.coords.latitude,
  217. longitude: location.coords.longitude,
  218. latitudeDelta: 0.0922,
  219. longitudeDelta: 0.0421
  220. }
  221. //console.log("getGeoLocation", region);
  222. //if (this.state.stopList.length == 0) { //只加载一次
  223. let time = new Date().getTime();
  224. let interval = this.settingInfo.refreshInterval * 1000;//重复加载时间
  225. let first = this.state.stopList.length == 0;//是否第一次加载
  226. if (first || time - this.refreshTime > interval) { //一分钟(10秒)加载一次
  227. this.getStationList(region, first);
  228. this.refreshTime = time;
  229. } else if (this.settingInfo.moveMyLocation) {
  230. this.setState({
  231. region: region
  232. });
  233. }
  234. }, error => {
  235. console.info("getGeoLocation", error);
  236. if (!again) {
  237. setTimeout(() => {
  238. this.infoGeoLocation(true);
  239. }, 2000);
  240. }
  241. });
  242. }
  243. }
  244. findFilter(data) {
  245. this.filter = data;
  246. this.getStationList();
  247. }
  248. /**
  249. * 获取所有充电桩
  250. * @param {Location} region 当前位置
  251. * @param {boolean} first 是否初始化
  252. */
  253. getStationList(region, first) {
  254. if (!isIOS)
  255. Dialog.showProgressDialog();
  256. if (getUserId()) {
  257. this.filter.operaUserId = getUserId()
  258. }
  259. apiStation.getAllStation(this.filter).then(res => {
  260. if (!isIOS)
  261. Dialog.dismissLoading();
  262. if (res.data.sites) {
  263. const list = [];
  264. res.data.sites.forEach(item => {
  265. let available = false
  266. if (item.allConnector && item.allConnector.available) {
  267. available = true
  268. }
  269. list.push({
  270. id: item.sitePk,
  271. name: item.siteName,
  272. //address: item.siteAddress,
  273. available: available,
  274. siteType: item.siteType,
  275. latitude: item.locationLatitude,
  276. longitude: item.locationLongitude,
  277. favorite: item?.favorite ? true : false,
  278. upcoming: false
  279. /*acConnector: item.acConnector,
  280. allConnector: item.allConnector,
  281. dcConnector: item.dcConnector,
  282. distance: utils.getDistance(item.distance)*/
  283. });
  284. });
  285. this.setState({
  286. stopList: list
  287. });
  288. //this.viewChargeStation(list[0].id) //测试显示站点
  289. if (region && (this.settingInfo.moveMyLocation || first)) {
  290. setTimeout(() => {
  291. this.setState({
  292. region: region
  293. });
  294. }, 500);
  295. }
  296. }
  297. }).catch(err => {
  298. if (!isIOS)
  299. Dialog.dismissLoading();
  300. toastShort(err);
  301. this.setState({
  302. stopList: []
  303. });
  304. })
  305. }
  306. //点击Marker获取StaionInfo
  307. viewChargeStation(id) {
  308. //console.log('info', this.state.stopList[index]);
  309. //const stationInfo = this.state.stopList[index];
  310. if (app.modules.bookmarks) {
  311. for (let i = 0; i < this.state.stopList.length; i++) {
  312. let info = this.state.stopList[i];
  313. if (info.id == id) {
  314. this.viewIndex = i;
  315. break;
  316. }
  317. }
  318. }
  319. if (this.state.hasPermission) {
  320. navigator.geolocation.getCurrentPosition(location => {
  321. let region = {
  322. latitude: location.coords.latitude,
  323. longitude: location.coords.longitude,
  324. latitudeDelta: 0.0922,
  325. longitudeDelta: 0.0421
  326. }
  327. this.getStationInfo(id, region);
  328. /*if (this.settingInfo.alwaysLocation) {
  329. this.setState({
  330. region: region
  331. });
  332. }*/
  333. });
  334. } else {
  335. //无定位权限仍然显示
  336. this.getStationInfo(id, this.state.region);
  337. }
  338. //startPage(PageList.chargeDetail, {...this.state.stopList[index]});
  339. }
  340. getStationInfo(id, location) {
  341. apiStation.getStationRate({
  342. sitePk: id,
  343. lat: location?.latitude,
  344. lng: location?.longitude
  345. }).then(res => {
  346. if (res.data.sitePk) {
  347. var info = utils.getSiteInfo(res.data);
  348. this.setState({
  349. stationInfo: info
  350. });
  351. } else {
  352. this.setState({
  353. stationInfo: {}
  354. });
  355. }
  356. }).catch(err => {
  357. this.setState({
  358. stationInfo: {}
  359. });
  360. toastShort(err);
  361. });
  362. }
  363. favoriteSite() {
  364. if (this.state.stationInfo?.id) {
  365. Dialog.showProgressDialog();
  366. apiStation.bookmarkSite(this.state.stationInfo.id).then(res => {
  367. const info = {...this.state.stationInfo, favorite: !this.state.stationInfo.favorite}
  368. if (this.viewIndex >= 0) {
  369. const list = [...this.state.stopList]
  370. const inf = {...list[this.viewIndex], favorite: info.favorite};
  371. list[this.viewIndex] = inf;
  372. this.setState({
  373. stopList: list,
  374. stationInfo: info
  375. });
  376. } else {
  377. this.setState({
  378. stationInfo: info
  379. });
  380. }
  381. }).catch(err => {
  382. toastShort(err);
  383. console.log(err)
  384. }).finally(() => {
  385. Dialog.dismissLoading();
  386. })
  387. }
  388. }
  389. render() {
  390. return (
  391. <View style={ui.flex1}>
  392. <View style={Styles.toolbar}>
  393. <Pressable
  394. style={Styles.backIcon}
  395. android_ripple = {rippleLess}
  396. onPress={() => {
  397. this.props.navigation.toggleDrawer();
  398. }}>
  399. <EvilIcons name={'navicon'} size={28} color={colorPrimary} />
  400. </Pressable>
  401. <View style={styles.logoView}>
  402. <Image
  403. source={require('../../images/tool-logo.png')}
  404. style={Styles.logo}
  405. resizeMode="contain"
  406. />
  407. </View>
  408. {/* <Text style={ui.flex1}></Text> */}
  409. <Pressable
  410. style={Styles.backIcon}
  411. android_ripple = {rippleLess}
  412. onPress={() => startPage(PageList.scanqr, {actionDetail: true})}>
  413. <MaterialCommunityIcons
  414. name='line-scan'
  415. size={20}
  416. color={colorPrimary}
  417. />
  418. </Pressable>
  419. </View>
  420. <SearchTool
  421. count={this.state.stopList.length}
  422. mapReady={this.state.mapReady}
  423. onFilter={data => this.findFilter(data)}
  424. onLocation={() => this.checkPermission2Geo(true)}
  425. navigation={this.props.navigation}
  426. />
  427. <View style={styles.mapContent}>
  428. {/* this.state.hasPermission &&*/}
  429. <Maps.Maps3
  430. region={this.state.region}
  431. stopList={this.state.stopList}
  432. onMapReady={() => {
  433. this.setState({
  434. mapReady: true
  435. }, () => {
  436. this.checkPermission2Geo();
  437. });
  438. }}
  439. onMarkerPress={id => this.viewChargeStation(id)}
  440. showUserLocation={this.state.hasPermission && this.settingInfo.alwaysLocation}
  441. />
  442. <BottomSiteInfo
  443. stationInfo={this.state.stationInfo}
  444. onFavorite={() => this.favoriteSite()}
  445. />
  446. <LocationPermission.VIEW visible={this.state.permissionDenied}/>
  447. </View>
  448. <View style={styles.drawerLeftTouchView}></View>
  449. </View>
  450. );
  451. }
  452. }
  453. const styles = StyleSheet.create({
  454. logoView: {
  455. /*left: 0,
  456. right: 0,
  457. bottom: 0,
  458. zIndex: 1,
  459. alignItems: 'center',
  460. position: 'absolute',*/
  461. flex: 1,
  462. alignItems: 'center',
  463. justifyContent: 'center'
  464. },
  465. searchView: {
  466. ...$padding(8, 16, 16),
  467. backgroundColor: colorThemes
  468. },
  469. searchInput: {
  470. alignItems: 'center',
  471. borderWidth: 1,
  472. borderStyle: 'solid',
  473. borderRadius: 60,
  474. borderColor: colorAccent,
  475. flexDirection: 'row',
  476. paddingLeft: 16,
  477. paddingRight: 16,
  478. backgroundColor: 'rgba(255, 255, 255, 0.5)'
  479. },
  480. searchText: {
  481. flex: 1,
  482. color: '#444',
  483. padding: 8,
  484. fontSize: 15
  485. },
  486. drawerLeftTouchView: {
  487. top: 0,
  488. left: 0,
  489. bottom: 0,
  490. width: 4,
  491. zIndex: 5,
  492. position: 'absolute',
  493. backgroundColor: 'rgba(0,0,0,0)'
  494. },
  495. mapContent: {
  496. flex: 1,
  497. zIndex: 4,
  498. position: 'relative',
  499. }
  500. })