|
@@ -0,0 +1,434 @@
|
|
|
|
|
+/**
|
|
|
|
|
+ * 充电桩详情页
|
|
|
|
|
+ * @邠心vbe on 2021/03/24
|
|
|
|
|
+ */
|
|
|
|
|
+import React, { Component } from 'react';
|
|
|
|
|
+import { Image, Pressable, RefreshControl, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
|
|
|
|
+import Modal from 'react-native-modal';
|
|
|
|
|
+import apiStation from '../../api/apiStation';
|
|
|
|
|
+import { ModalProps } from '../../components/BottomModal';
|
|
|
|
|
+import { MyRefreshProps } from '../../components/ThemesConfig';
|
|
|
|
|
+import { StationBack } from '../../components/Toolbar';
|
|
|
|
|
+import utils from '../../utils/utils';
|
|
|
|
|
+import Charge from './Charge';
|
|
|
|
|
+import Explore from './Explore';
|
|
|
|
|
+import { LoginDialog } from './InfoDialog';
|
|
|
|
|
+import Provider from './Provider';
|
|
|
|
|
+import { QRResult } from './QRScan';
|
|
|
|
|
+import Reserve from './Reserve';
|
|
|
|
|
+import SiteInfo from './SiteInfo';
|
|
|
|
|
+
|
|
|
|
|
+export default class Details extends Component {
|
|
|
|
|
+
|
|
|
|
|
+ constructor(props) {
|
|
|
|
|
+ super(props);
|
|
|
|
|
+ this.state = {
|
|
|
|
|
+ showTab: true,
|
|
|
|
|
+ tabIndex: 1,
|
|
|
|
|
+ tabView: [{
|
|
|
|
|
+ title: 'Site Information'
|
|
|
|
|
+ }, {
|
|
|
|
|
+ title: 'Charge'
|
|
|
|
|
+ }, {
|
|
|
|
|
+ title: 'Reserve'
|
|
|
|
|
+ }],
|
|
|
|
|
+ refreshId: 0,
|
|
|
|
|
+ refreshing: false,
|
|
|
|
|
+ showContent: false,
|
|
|
|
|
+ showLoginDialog: false,
|
|
|
|
|
+ stationInfo: {}
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ componentDidMount() {
|
|
|
|
|
+ this.props.navigation.addListener('beforeRemove', (e) => {
|
|
|
|
|
+ this.hideDialog();
|
|
|
|
|
+ });
|
|
|
|
|
+ this.props.navigation.addListener('focus', () => {
|
|
|
|
|
+ if (this.isHide && this.state.showContent) {
|
|
|
|
|
+ this.updateStationInfo();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ //this.canShowLoginDialog();
|
|
|
|
|
+ }
|
|
|
|
|
+ this.isHide = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ this.props.navigation.addListener('blur', () => {
|
|
|
|
|
+ this.isHide = true;
|
|
|
|
|
+ });
|
|
|
|
|
+ const params = this.props.route.params;
|
|
|
|
|
+ if (params.action && params.stationInfo) {
|
|
|
|
|
+ this.action = params.action
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ stationInfo: params.stationInfo
|
|
|
|
|
+ });
|
|
|
|
|
+ this.canShowLoginDialog();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ componentDidUpdate() {
|
|
|
|
|
+ var act = this.props.route.params.action;
|
|
|
|
|
+ if (act !== this.state.action) {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ action: act,
|
|
|
|
|
+ refreshId: this.state.refreshId + 1
|
|
|
|
|
+ });
|
|
|
|
|
+ if (act == 'qr') {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ tabIndex: 1
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ componentWillUnmount() {
|
|
|
|
|
+ QRResult.clearResult();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ canShowLoginDialog() {
|
|
|
|
|
+ if (isLogin()) {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ showContent: true
|
|
|
|
|
+ });
|
|
|
|
|
+ //if (this.action !== 'view')
|
|
|
|
|
+ this.updateStationInfo();
|
|
|
|
|
+ if (this.action == 'qr') {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ tabIndex: 1
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ showLoginDialog: true
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ hideDialog(close) {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ showLoginDialog: false
|
|
|
|
|
+ });
|
|
|
|
|
+ if (close) {
|
|
|
|
|
+ goBack();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ updateStationInfo() {
|
|
|
|
|
+ navigator.geolocation.getCurrentPosition(location => {
|
|
|
|
|
+ let params = {
|
|
|
|
|
+ lat: location.coords.latitude,
|
|
|
|
|
+ lng: location.coords.longitude,
|
|
|
|
|
+ sitePk: this.state.stationInfo.id
|
|
|
|
|
+ }
|
|
|
|
|
+ apiStation.getStationRate(params).then(res => {
|
|
|
|
|
+ if (res.data.sitePk) {
|
|
|
|
|
+ var info = utils.getSiteInfo(res.data);
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ refreshing: false,
|
|
|
|
|
+ stationInfo: info,
|
|
|
|
|
+ refreshId: this.state.refreshId + 1
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch((err) => {
|
|
|
|
|
+ toastLong(err);
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ refreshing: false
|
|
|
|
|
+ })
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ getAvailable(type) {
|
|
|
|
|
+ const all = this.state.stationInfo.allConnector;
|
|
|
|
|
+ if (all) {
|
|
|
|
|
+ if (type == 'box') {
|
|
|
|
|
+ return all.boxAvailable + '/' + all.boxAll;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return all.available + '/' + all.all;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return '0/0';
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ onRefresh() {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ refreshing: true
|
|
|
|
|
+ });
|
|
|
|
|
+ this.updateStationInfo();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ onEnterStation() {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ refreshId: this.state.refreshId + 1
|
|
|
|
|
+ }, () => this.changeTab(1));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ changeTab(index) {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ tabIndex: index
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render() {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <ScrollView
|
|
|
|
|
+ style={styles.container}
|
|
|
|
|
+ keyboardShouldPersistTaps={isIOS ? 'never' : 'handled'}
|
|
|
|
|
+ refreshControl={
|
|
|
|
|
+ <RefreshControl
|
|
|
|
|
+ {...MyRefreshProps()}
|
|
|
|
|
+ refreshing={this.state.refreshing}
|
|
|
|
|
+ onRefresh={() => this.onRefresh()}
|
|
|
|
|
+ />
|
|
|
|
|
+ }>
|
|
|
|
|
+ <View style={styles.headerView}>
|
|
|
|
|
+ <StationBack />
|
|
|
|
|
+ <View style={styles.summaryView}>
|
|
|
|
|
+ <Image
|
|
|
|
|
+ style={{
|
|
|
|
|
+ width: 50,
|
|
|
|
|
+ height: 50,
|
|
|
|
|
+ marginTop: 8
|
|
|
|
|
+ }}
|
|
|
|
|
+ source={require('../../images/charge/icon-station-no.png')}/>
|
|
|
|
|
+ <View style={styles.stationInfo}>
|
|
|
|
|
+ <Text
|
|
|
|
|
+ style={styles.stationName}
|
|
|
|
|
+ ellipsizeMode='tail'
|
|
|
|
|
+ numberOfLines={1}>{this.state.stationInfo?.name}</Text>
|
|
|
|
|
+ {/* <Text style={styles.stationAddress}>{this.state.stationInfo?.address}</Text> */}
|
|
|
|
|
+ <Provider
|
|
|
|
|
+ color={textPrimary}
|
|
|
|
|
+ providers={this.state.stationInfo?.serviceProvider}/>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <TouchableOpacity
|
|
|
|
|
+ style={styles.directView}
|
|
|
|
|
+ onPress={() => {
|
|
|
|
|
+ utils.directMaps(this.state.stationInfo.latitude, this.state.stationInfo.longitude, this.state.stationInfo.address);
|
|
|
|
|
+ }}>
|
|
|
|
|
+ <MaterialIcons
|
|
|
|
|
+ name='directions'
|
|
|
|
|
+ size={32}
|
|
|
|
|
+ color={colorPrimary}/>
|
|
|
|
|
+ <Text style={styles.lengthText}>{this.state.stationInfo.distance}</Text>
|
|
|
|
|
+ </TouchableOpacity>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View style={styles.chargingInfo}>
|
|
|
|
|
+ <View style={styles.available}>
|
|
|
|
|
+ <Image
|
|
|
|
|
+ style={{
|
|
|
|
|
+ width: 16,
|
|
|
|
|
+ height: 16,
|
|
|
|
|
+ marginRight: 8
|
|
|
|
|
+ }}
|
|
|
|
|
+ source={require('../../images/charge/icon-type-stops.png')}/>
|
|
|
|
|
+ <Text style={{
|
|
|
|
|
+ color: textPrimary,
|
|
|
|
|
+ fontSize: 14
|
|
|
|
|
+ }}>Available {this.getAvailable('box')}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <Text style={styles.available2}/>
|
|
|
|
|
+ <View style={styles.available}>
|
|
|
|
|
+ <Image
|
|
|
|
|
+ style={{
|
|
|
|
|
+ width: 17,
|
|
|
|
|
+ height: 17,
|
|
|
|
|
+ marginRight: 8
|
|
|
|
|
+ }}
|
|
|
|
|
+ source={require('../../images/charge/icon-type-interfaces.png')}/>
|
|
|
|
|
+ <Text style={{
|
|
|
|
|
+ color: textPrimary,
|
|
|
|
|
+ fontSize: 14
|
|
|
|
|
+ }}>Available {this.getAvailable('inc')}</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View style={styles.tabContainer}>
|
|
|
|
|
+ { this.state.showContent &&
|
|
|
|
|
+ <>
|
|
|
|
|
+ { this.state.showTab &&
|
|
|
|
|
+ <View style={styles.tabView}>
|
|
|
|
|
+ { this.state.tabView.map((view, index) => {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Pressable
|
|
|
|
|
+ key={index}
|
|
|
|
|
+ style={[
|
|
|
|
|
+ styles.tabPress,
|
|
|
|
|
+ index == 0 && styles.tabPress0,
|
|
|
|
|
+ index == this.state.tabIndex && styles.active
|
|
|
|
|
+ ]}
|
|
|
|
|
+ onPress={() => {
|
|
|
|
|
+ this.changeTab(index)
|
|
|
|
|
+ }}
|
|
|
|
|
+ android_ripple={ripple}>
|
|
|
|
|
+ <Text
|
|
|
|
|
+ style={[
|
|
|
|
|
+ styles.tabText,
|
|
|
|
|
+ index == this.state.tabIndex && styles.active,
|
|
|
|
|
+ { borderLeftWidth: index > 0 ? 1 : 0 }
|
|
|
|
|
+ ]}
|
|
|
|
|
+ numberOfLines={1}>{view.title}</Text>
|
|
|
|
|
+ </Pressable>
|
|
|
|
|
+ );
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ </View>
|
|
|
|
|
+ }
|
|
|
|
|
+ <View style={styles.tabContent}>
|
|
|
|
|
+ <SiteInfo
|
|
|
|
|
+ style={this.state.tabIndex == 0 ? styles.tabActive : styles.tabInactive}
|
|
|
|
|
+ stationInfo={this.state.stationInfo}
|
|
|
|
|
+ refreshId={this.state.refreshId}/>
|
|
|
|
|
+ <Charge
|
|
|
|
|
+ style={this.state.tabIndex == 1 ? styles.tabActive : styles.tabInactive}
|
|
|
|
|
+ visible={this.state.tabIndex == 1}
|
|
|
|
|
+ stationInfo={this.state.stationInfo}
|
|
|
|
|
+ refreshId={this.state.refreshId}
|
|
|
|
|
+ onCharge={() =>
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ tabIndex: 1
|
|
|
|
|
+ })
|
|
|
|
|
+ }/>
|
|
|
|
|
+ { this.state.stationInfo.rateList !== undefined &&
|
|
|
|
|
+ <Reserve
|
|
|
|
|
+ style={this.state.tabIndex == 2 ? styles.tabActive : styles.tabInactive}
|
|
|
|
|
+ visible={this.state.tabIndex == 2}
|
|
|
|
|
+ refreshId={this.state.refreshId}
|
|
|
|
|
+ stationInfo={this.state.stationInfo}
|
|
|
|
|
+ onRefresh={() => this.updateStationInfo()}
|
|
|
|
|
+ onReserve={() => this.changeTab(2)}
|
|
|
|
|
+ onEnterStation={() => this.onEnterStation()}
|
|
|
|
|
+ />
|
|
|
|
|
+ }
|
|
|
|
|
+ {/* <Explore style={this.state.tabIndex == 2 ? styles.tabActive : styles.tabInactive}/> */}
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </>
|
|
|
|
|
+ }
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </ScrollView>
|
|
|
|
|
+ <Modal
|
|
|
|
|
+ isVisible={this.state.showLoginDialog}
|
|
|
|
|
+ onBackButtonPress={() => this.hideDialog(true)}
|
|
|
|
|
+ onBackdropPress={() => this.hideDialog()}
|
|
|
|
|
+ {...ModalProps}>
|
|
|
|
|
+ <LoginDialog
|
|
|
|
|
+ onHide={() => this.hideDialog()}
|
|
|
|
|
+ onClose={() => this.hideDialog(true)} />
|
|
|
|
|
+ </Modal>
|
|
|
|
|
+ </>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const styles = StyleSheet.create({
|
|
|
|
|
+ container: {
|
|
|
|
|
+ ...StyleSheet.absoluteFillObject,
|
|
|
|
|
+ backgroundColor: colorLight
|
|
|
|
|
+ },
|
|
|
|
|
+ headerView: {
|
|
|
|
|
+ paddingTop: 16,
|
|
|
|
|
+ paddingLeft: 16,
|
|
|
|
|
+ paddingRight: 16,
|
|
|
|
|
+ paddingBottom: 32,
|
|
|
|
|
+ backgroundColor: colorThemes
|
|
|
|
|
+ },
|
|
|
|
|
+ summaryView: {
|
|
|
|
|
+ paddingBottom: 16,
|
|
|
|
|
+ flexDirection: 'row',
|
|
|
|
|
+ },
|
|
|
|
|
+ stationInfo: {
|
|
|
|
|
+ flex: 1,
|
|
|
|
|
+ paddingLeft: 16,
|
|
|
|
|
+ paddingRight: 16
|
|
|
|
|
+ },
|
|
|
|
|
+ stationName: {
|
|
|
|
|
+ color: textPrimary,
|
|
|
|
|
+ fontSize: 20,
|
|
|
|
|
+ fontWeight: 'bold',
|
|
|
|
|
+ paddingBottom: 2
|
|
|
|
|
+ },
|
|
|
|
|
+ stationAddress: {
|
|
|
|
|
+ color: textPrimary,
|
|
|
|
|
+ fontSize: 12,
|
|
|
|
|
+ },
|
|
|
|
|
+ directView: {
|
|
|
|
|
+ zIndex: 2,
|
|
|
|
|
+ paddingTop: 4,
|
|
|
|
|
+ alignItems: 'center',
|
|
|
|
|
+ },
|
|
|
|
|
+ lengthText: {
|
|
|
|
|
+ color: textPrimary,
|
|
|
|
|
+ fontSize: 12,
|
|
|
|
|
+ paddingTop: 2
|
|
|
|
|
+ },
|
|
|
|
|
+ chargingInfo: {
|
|
|
|
|
+ zIndex: 2,
|
|
|
|
|
+ alignItems: 'center',
|
|
|
|
|
+ borderColor: colorLight,
|
|
|
|
|
+ borderTopWidth: 1,
|
|
|
|
|
+ flexDirection: 'row'
|
|
|
|
|
+ },
|
|
|
|
|
+ available: {
|
|
|
|
|
+ flex: 1,
|
|
|
|
|
+ padding: 16,
|
|
|
|
|
+ alignItems: 'center',
|
|
|
|
|
+ flexDirection: 'row',
|
|
|
|
|
+ justifyContent: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ available2: {
|
|
|
|
|
+ color: textPrimary,
|
|
|
|
|
+ fontSize: 14,
|
|
|
|
|
+ borderLeftWidth: 1.5,
|
|
|
|
|
+ borderLeftColor: colorLight,
|
|
|
|
|
+ },
|
|
|
|
|
+ tabContainer: {
|
|
|
|
|
+ flex: 1,
|
|
|
|
|
+ paddingTop: 14,
|
|
|
|
|
+ marginTop: -32,
|
|
|
|
|
+ backgroundColor: colorLight,
|
|
|
|
|
+ borderTopLeftRadius: 20,
|
|
|
|
|
+ borderTopRightRadius: 20
|
|
|
|
|
+ },
|
|
|
|
|
+ tabView: {
|
|
|
|
|
+ marginTop: 8,
|
|
|
|
|
+ marginLeft: 16,
|
|
|
|
|
+ marginRight: 16,
|
|
|
|
|
+ borderRadius: 8,
|
|
|
|
|
+ overflow: 'hidden',
|
|
|
|
|
+ alignItems: 'center',
|
|
|
|
|
+ flexDirection: 'row',
|
|
|
|
|
+ borderWidth: 1,
|
|
|
|
|
+ borderColor: '#eee',
|
|
|
|
|
+ borderBottomWidth: 2
|
|
|
|
|
+ },
|
|
|
|
|
+ tabPress: {
|
|
|
|
|
+ flex: 1,
|
|
|
|
|
+ paddingTop: 12,
|
|
|
|
|
+ paddingBottom: 12,
|
|
|
|
|
+ marginRight: 1
|
|
|
|
|
+ },
|
|
|
|
|
+ tabPress0: {
|
|
|
|
|
+ flex: 1.2
|
|
|
|
|
+ },
|
|
|
|
|
+ tabText: {
|
|
|
|
|
+ color: textPrimary,
|
|
|
|
|
+ fontSize: 15,
|
|
|
|
|
+ marginLeft: -1,
|
|
|
|
|
+ textAlign: 'center',
|
|
|
|
|
+ borderLeftColor: '#eee'
|
|
|
|
|
+ },
|
|
|
|
|
+ active: {
|
|
|
|
|
+ color: textLight,
|
|
|
|
|
+ backgroundColor: colorPrimary
|
|
|
|
|
+ },
|
|
|
|
|
+ tabContent: {
|
|
|
|
|
+ flex: 1
|
|
|
|
|
+ },
|
|
|
|
|
+ tabActive: {
|
|
|
|
|
+ display: 'flex'
|
|
|
|
|
+ },
|
|
|
|
|
+ tabInactive: {
|
|
|
|
|
+ display: 'none'
|
|
|
|
|
+ }
|
|
|
|
|
+})
|