Home.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  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.alwaysLocation) {
  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,
  278. /*acConnector: item.acConnector,
  279. allConnector: item.allConnector,
  280. dcConnector: item.dcConnector,
  281. distance: utils.getDistance(item.distance)*/
  282. });
  283. });
  284. this.setState({
  285. stopList: list
  286. });
  287. //this.viewChargeStation(list[0].id) //测试显示站点
  288. if (region && (this.settingInfo.alwaysLocation || first)) {
  289. setTimeout(() => {
  290. this.setState({
  291. region: region
  292. });
  293. }, 500);
  294. }
  295. }
  296. }).catch(err => {
  297. if (!isIOS)
  298. Dialog.dismissLoading();
  299. toastShort(err);
  300. this.setState({
  301. stopList: []
  302. });
  303. })
  304. }
  305. //点击Marker获取StaionInfo
  306. viewChargeStation(id) {
  307. //console.log('info', this.state.stopList[index]);
  308. //const stationInfo = this.state.stopList[index];
  309. if (app.modules.bookmarks) {
  310. for (let i = 0; i < this.state.stopList.length; i++) {
  311. let info = this.state.stopList[i];
  312. if (info.id == id) {
  313. this.viewIndex = i;
  314. break;
  315. }
  316. }
  317. }
  318. if (this.state.hasPermission) {
  319. navigator.geolocation.getCurrentPosition(location => {
  320. let region = {
  321. latitude: location.coords.latitude,
  322. longitude: location.coords.longitude,
  323. latitudeDelta: 0.0922,
  324. longitudeDelta: 0.0421
  325. }
  326. this.getStationInfo(id, region);
  327. /*if (this.settingInfo.alwaysLocation) {
  328. this.setState({
  329. region: region
  330. });
  331. }*/
  332. });
  333. } else {
  334. //无定位权限仍然显示
  335. this.getStationInfo(id, this.state.region);
  336. }
  337. //startPage(PageList.chargeDetail, {...this.state.stopList[index]});
  338. }
  339. getStationInfo(id, location) {
  340. apiStation.getStationRate({
  341. sitePk: id,
  342. lat: location?.latitude,
  343. lng: location?.longitude
  344. }).then(res => {
  345. if (res.data.sitePk) {
  346. var info = utils.getSiteInfo(res.data);
  347. this.setState({
  348. stationInfo: info
  349. });
  350. } else {
  351. this.setState({
  352. stationInfo: {}
  353. });
  354. }
  355. }).catch(err => {
  356. this.setState({
  357. stationInfo: {}
  358. });
  359. toastShort(err);
  360. });
  361. }
  362. favoriteSite() {
  363. if (this.state.stationInfo?.id) {
  364. Dialog.showProgressDialog();
  365. apiStation.bookmarkSite(this.state.stationInfo.id).then(res => {
  366. const info = {...this.state.stationInfo, favorite: !this.state.stationInfo.favorite}
  367. if (this.viewIndex >= 0) {
  368. const list = [...this.state.stopList]
  369. const inf = {...list[this.viewIndex], favorite: info.favorite};
  370. list[this.viewIndex] = inf;
  371. this.setState({
  372. stopList: list,
  373. stationInfo: info
  374. });
  375. } else {
  376. this.setState({
  377. stationInfo: info
  378. });
  379. }
  380. }).catch(err => {
  381. toastShort(err);
  382. console.log(err)
  383. }).finally(() => {
  384. Dialog.dismissLoading();
  385. })
  386. }
  387. }
  388. render() {
  389. return (
  390. <View style={ui.flex1}>
  391. <View style={Styles.toolbar}>
  392. <Pressable
  393. style={Styles.backIcon}
  394. android_ripple = {rippleLess}
  395. onPress={() => {
  396. this.props.navigation.toggleDrawer();
  397. }}>
  398. <EvilIcons name={'navicon'} size={28} color={colorPrimary} />
  399. </Pressable>
  400. <View style={styles.logoView}>
  401. <Image
  402. source={require('../../images/tool-logo.png')}
  403. style={Styles.logo}
  404. resizeMode="contain"
  405. />
  406. </View>
  407. {/* <Text style={ui.flex1}></Text> */}
  408. <Pressable
  409. style={Styles.backIcon}
  410. android_ripple = {rippleLess}
  411. onPress={() => startPage(PageList.scanqr, {actionDetail: true})}>
  412. <MaterialCommunityIcons
  413. name='line-scan'
  414. size={20}
  415. color={colorPrimary}
  416. />
  417. </Pressable>
  418. </View>
  419. <SearchTool
  420. count={this.state.stopList.length}
  421. mapReady={this.state.mapReady}
  422. onFilter={data => this.findFilter(data)}
  423. onLocation={() => this.checkPermission2Geo(true)}
  424. navigation={this.props.navigation}
  425. />
  426. <View style={styles.mapContent}>
  427. {/* this.state.hasPermission &&*/}
  428. <Maps.Maps3
  429. region={this.state.region}
  430. stopList={this.state.stopList}
  431. onMapReady={() => {
  432. this.setState({
  433. mapReady: true
  434. }, () => {
  435. this.checkPermission2Geo();
  436. });
  437. }}
  438. onMarkerPress={id => this.viewChargeStation(id)}
  439. showUserLocation={this.state.hasPermission && this.settingInfo.alwaysLocation}
  440. />
  441. <BottomSiteInfo
  442. stationInfo={this.state.stationInfo}
  443. onFavorite={() => this.favoriteSite()}
  444. />
  445. <LocationPermission.VIEW visible={this.state.permissionDenied}/>
  446. </View>
  447. <View style={styles.drawerLeftTouchView}></View>
  448. </View>
  449. );
  450. }
  451. }
  452. const styles = StyleSheet.create({
  453. logoView: {
  454. /*left: 0,
  455. right: 0,
  456. bottom: 0,
  457. zIndex: 1,
  458. alignItems: 'center',
  459. position: 'absolute',*/
  460. flex: 1,
  461. alignItems: 'center',
  462. justifyContent: 'center'
  463. },
  464. searchView: {
  465. ...$padding(8, 16, 16),
  466. backgroundColor: colorThemes
  467. },
  468. searchInput: {
  469. alignItems: 'center',
  470. borderWidth: 1,
  471. borderStyle: 'solid',
  472. borderRadius: 60,
  473. borderColor: colorAccent,
  474. flexDirection: 'row',
  475. paddingLeft: 16,
  476. paddingRight: 16,
  477. backgroundColor: 'rgba(255, 255, 255, 0.5)'
  478. },
  479. searchText: {
  480. flex: 1,
  481. color: '#444',
  482. padding: 8,
  483. fontSize: 15
  484. },
  485. drawerLeftTouchView: {
  486. top: 0,
  487. left: 0,
  488. bottom: 0,
  489. width: 4,
  490. zIndex: 5,
  491. position: 'absolute',
  492. backgroundColor: 'rgba(0,0,0,0)'
  493. },
  494. mapContent: {
  495. flex: 1,
  496. zIndex: 4,
  497. position: 'relative',
  498. }
  499. })