Просмотр исходного кода

add app/pages/charge/Reserve.js

wudebin 6 месяцев назад
Родитель
Сommit
30d416dc08
1 измененных файлов с 518 добавлено и 0 удалено
  1. 518 0
      Strides-SPAPP/app/pages/charge/Reserve.js

+ 518 - 0
Strides-SPAPP/app/pages/charge/Reserve.js

@@ -0,0 +1,518 @@
+/**
+ * Reserve页面
+ * @邠心vbe on 2021/03/24
+ */
+import React, { Component } from 'react'
+import { Image, Pressable, StyleSheet, Text, View } from 'react-native'
+import Button from '../../components/Button';
+import { ChargeStyle, EnterStationDialog, SelectableIcon, TypeImage } from './Charging';
+import Payment from '../wallet/Payment';
+import apiCharge from '../../api/apiCharge';
+import Dialog from '../../components/Dialog';
+import { PageList } from '../Router';
+import { CancelReserveDialog } from './InfoDialog';
+import TextView from '../../components/TextView';
+
+export default class Reserve extends Component {
+
+  constructor(props) {
+    super(props);
+    this.state= {
+      total: 0,
+      leftId: 0,
+      refreshId: 0,
+      checkIndex: -1,
+      available: false,
+      showReserve: false,
+      stationInfo: {},
+      checkConnector: {},
+      userReserve: {},
+      timeLeft: '',
+      showCancelDialog: false,
+      showStationDialog: false
+    }
+  }
+
+  componentDidMount() {
+    this.setState({
+      stationInfo: this.props.stationInfo
+    }, () => this.init());
+  }
+
+  componentDidUpdate() {
+    if (this.props.visible && this.props.refreshId != this.state.refreshId) {
+      this.stopCountdown(true);
+      this.setState({
+        refreshId: this.props.refreshId,
+        stationInfo: this.props.stationInfo
+      }, () => this.init());
+    }
+  }
+
+  init() {
+    if (this.state.stationInfo.rateList && this.state.stationInfo.rateList.length > 0) {
+      for (var i = 0; i < this.state.stationInfo.rateList.length; i++) {
+        const item = this.state.stationInfo.rateList[i]
+        if (item.available) {
+          this.setState({
+            checkIndex: i,
+            checkConnector: item,
+          })
+          break;
+        }
+      }
+      this.setState({
+        total: this.props.stationInfo.rateList.length,
+        showReserve: this.props.stationInfo.enableReservation ? true : false
+      })
+      this.getReserve();
+      //this.refreshAvailable();
+    } else {
+      this.setState({
+        showReserve: false
+      })
+    }
+  }
+
+  //刷新可用充电接口
+  refreshAvailable() {
+    const info = this.state.stationInfo
+    const all = info?.allConnector;
+    /*if (info.siteType == 'Private') {
+      this.setState({
+        isPrivate: true
+      })
+    }*/
+    if (all) {
+      this.setState({
+        available: !all.available > 0
+      });
+    }
+  }
+
+  checkChange(index) {
+    if (this.state.checkIndex !== index) {
+      this.setState({
+        checkIndex: index,
+        checkConnector: this.props.stationInfo.rateList[index],
+      })
+    }
+  }
+
+  getAvailable(type) {
+    let count = type;
+    if (typeof type === 'string') {
+      count = type == "AC" ? this.state.stationInfo.acConnector :  this.state.stationInfo.dcConnector;
+    }
+    if (count) {
+      return count.available + '/' + count.all;
+    } else {
+      return '0/0';
+    }
+  }
+
+  getReserve() {
+    apiCharge.getUserReserve(this.state.stationInfo.id).then(res => {
+      if (res.data.reservePk && res.data.reserveEndTimeTimestamp > 0) {
+        this.setState({
+          userReserve: res.data
+        }, () => this.startCountdown());
+      } else {
+        this.stopCountdown();
+      }
+    }).catch((err) => {
+      this.stopCountdown();
+    });
+  }
+
+  onReserve() {
+    Dialog.showProgressDialog();
+    apiCharge.reserveCharge({
+      sitePk: this.state.stationInfo.id,
+      chargeTypePk: this.state.checkConnector.chargeTypePk
+    }).then(res => {
+      Dialog.dismissLoading();
+      toastShort('Reserved successfully!');
+      this.props.onRefresh();
+      this.getReserve();
+    }).catch((err) => {
+      Dialog.dismissLoading();
+      toastShort(err)
+    });
+  }
+
+  onCancel() {
+    if (this.state.userReserve.reservePk) {
+      Dialog.showProgressDialog();
+      apiCharge.cancelReserve(this.state.userReserve.reservePk).then(res => {
+        Dialog.dismissLoading();
+        this.props.onRefresh();
+        toastShort($t('common.cancelSuccess'));
+        this.getReserve();
+      }).catch((err) => {
+        Dialog.dismissLoading();
+        toastShort(err)
+      });
+    }
+  }
+
+  cancelReserve() {
+    this.setState({
+      showCancelDialog: true
+    });
+    /*Dialog.showDialog({
+      title: 'Cancel Reservation',
+      message: 'Are you sure you want to cancel reservation?',
+      ok: 'CONFIRM',
+      callback: (btn => {
+        if (btn == "ok") {
+          this.onCancel();
+        }
+      })
+    })*/
+  }
+
+  startCountdown() {
+    if (this.state.userReserve.reserveEndTimeTimestamp > 0) {
+      if (!this.props.visible && this.props.onReserve)
+        this.props.onReserve()
+      const leftId = this.state.leftId;
+      this.countdown(leftId);
+    } else {
+      this.stopCountdown(false, true);
+    }
+  }
+
+  countdown(leftId) {
+    if (leftId != this.state.leftId) {
+      console.log(leftId, this.state.leftId);
+      return;
+    }
+    const now = new Date().getTime();
+    let left = this.state.userReserve.reserveEndTimeTimestamp - now;
+    let s = 0, m = 0, h = 0;
+    if (left > 1000) {
+      s = left / 1000;
+      if (s > 60) {
+        m = s / 60;
+        s = s % 60;
+        if (m > 60) {
+          h = m / 60;
+          m = m % 60;
+        }
+      }
+    } else {
+      this.stopCountdown(false, true)
+    }
+    this.setState({
+      timeLeft: this.formatNumber(h) + ' : ' + this.formatNumber(m) + ' : ' + this.formatNumber(s)
+    });
+    setTimeout(() => {
+      this.countdown(leftId);
+    }, 1000);
+  }
+
+  formatNumber(ins) {
+    const num = parseInt(ins)
+    if (num > 0) {
+      if (num < 10) {
+        return '0' + num;
+      } else {
+        return num;
+      }
+    } else {
+      return '00';
+    }
+  }
+
+  stopCountdown(just, refresh) {
+    if (just) {
+      this.setState({
+        leftId: this.state.leftId + 1
+      });
+    } else {
+      this.setState({
+        leftId: this.state.leftId + 1,
+        userReserve: {}
+      });
+    }
+    if (refresh) {
+      this.props.onRefresh();
+    }
+  }
+
+  enterStatioinId() {
+    if (this.props.onEnterStation) {
+      this.props.onEnterStation();
+    }
+  }
+
+  render() {
+    return (
+      <View
+        style={{
+          paddingLeft: 16,
+          paddingRight: 16,
+          ...(this.props.style || {})
+        }}>
+        { this.state.showReserve
+          ? (
+            this.state.userReserve.reservePk
+              ? this.countdownView()
+              : this.reserveView()
+            )
+          : <View style={[{height: $vh(50)}, ui.flexvc]}>
+              <Text style={{color: textPrimary, fontSize: 14}}>Reservation is not available for this site.</Text>
+            </View>
+        }
+        <CancelReserveDialog
+          visible={this.state.showCancelDialog}
+          onClose={confirm => {
+            this.setState({
+              showCancelDialog: false
+            });
+            if (confirm) {
+              this.onCancel();
+            }
+          }}/>
+        <EnterStationDialog
+          visible={this.state.showStationDialog}
+          stationId={this.state.stationInfo.id}
+          onConfirm={() => this.enterStatioinId()}
+          onClose={() => {
+            this.setState({
+              showStationDialog: false
+            });
+          }}
+        />
+      </View>
+    )
+  }
+
+  //预定页面
+  reserveView() {
+    return (
+      <>
+      <Text style={styles.title}>Choose Connector</Text>
+      <View style={styles.listView}>
+        { this.state.total > 0
+          ? this.state.stationInfo.rateList.map((item, index) => {
+            const _type = item.type?.indexOf('AC') >= 0 ? 'AC' : 'DC';
+            return (
+              <Pressable
+                key={index}
+                style={[ChargeStyle.stationInfoView, index > 0 ? ChargeStyle.itemDivide : {}]}
+                onPress={() => {
+                    if (item.available) {
+                      this.checkChange(index)
+                    }
+                  }
+                }>
+                <SelectableIcon selected={index == this.state.checkIndex}>
+                  <Image
+                    style={ChargeStyle.infoIcon}
+                    source={_type == "AC" ? TypeImage.AC : TypeImage.DC}/>
+                </SelectableIcon>
+                <View style={ChargeStyle.infoGroup}>
+                  <Text style={ChargeStyle.infoTitle}>Type</Text>
+                  <Text style={ChargeStyle.infoText}>{item.type}</Text>
+                </View>
+                <View style={ChargeStyle.infoGroup}>
+                  <Text style={ChargeStyle.infoTitle}>Power</Text>
+                  <Text style={ChargeStyle.infoText}>{item.power}</Text>
+                </View>
+                <View style={ChargeStyle.infoGroup}>
+                  <Text style={ChargeStyle.infoTitle}>Available/Total</Text>
+                  <Text style={ChargeStyle.infoBoldNumber}>{this.getAvailable(_type)}</Text>
+                </View>
+                { index == this.state.checkIndex
+                  ? <Text style={[ChargeStyle.infoStatus, ChargeStyle.statusSelected]}>Selected</Text>
+                  : (item.available
+                    ? <TextView style={[ChargeStyle.infoStatus, ChargeStyle.statusAvailable]}>Available</TextView>
+                    : <TextView style={[ChargeStyle.infoStatus, ChargeStyle.statusUnavailable]}>Unavailable</TextView>
+                  )
+                }
+              </Pressable>
+            )
+          }) : null
+        }
+      </View>
+      { this.state.checkConnector.available
+        ? <>
+            <Text style={styles.title}>Choose Rate</Text>
+            <View style={styles.listView}>
+              <View style={ChargeStyle.stationInfoView}>
+                <SelectableIcon selected={true}>
+                  <Image 
+                    style={ChargeStyle.infoIcon}
+                    source={require('../../images/charge/ic-type-rate.png')}/>
+                </SelectableIcon>
+                <Text style={ChargeStyle.rateText}>Rate</Text>
+                <Text style={[ChargeStyle.ratePrice]}>{this.state.checkConnector.rates}</Text>
+                <Text style={[ChargeStyle.infoStatus, ChargeStyle.statusSelected]}>Selected</Text>
+              </View>
+            </View>
+          </>
+        : <View style={{height: 60}}></View>
+      }
+
+      <Text style={styles.title}>Choose Payment Method</Text>
+      <Payment refreshId={this.state.refreshId}/>
+
+      <Button
+        style={styles.buttonView}
+        elevation={1.5}
+        text='Reserve'
+        disabled={this.state.available}
+        onClick={() => this.onReserve()}
+      />
+      </>
+    )
+  }
+
+  //倒计时页面
+  countdownView() {
+    let info = this.state.userReserve.siteRate
+    return (
+      <>
+        <Text style={styles.title}>Your Selection</Text>
+        { info &&
+          <View style={styles.listView}>
+            <View style={ChargeStyle.stationInfoView}>
+              <Image
+                style={ChargeStyle.infoIcon}
+                source={info.type?.indexOf('AC') >= 0 ? TypeImage.AC : TypeImage.DC}/>
+              <View style={ChargeStyle.infoGroup}>
+                <Text style={ChargeStyle.infoTitle}>Type</Text>
+                <Text style={ChargeStyle.infoText}>{info.type}</Text>
+              </View>
+              <View style={ChargeStyle.infoGroup}>
+                <Text style={ChargeStyle.infoTitle}>Power</Text>
+                <Text style={ChargeStyle.infoText}>{info.power}</Text>
+              </View>
+              <View style={ChargeStyle.infoGroup}>
+                <Text style={ChargeStyle.infoTitle}>Available/Total</Text>
+                <Text style={ChargeStyle.infoBoldNumber}>{this.getAvailable(info.connectorCount)}</Text>
+              </View>
+              <SelectableIcon selected={true}/>
+            </View>
+            <View style={[ChargeStyle.stationInfoView, ChargeStyle.itemDivide]}>
+              <Image 
+                style={ChargeStyle.infoIcon}
+                source={require('../../images/charge/ic-type-rate.png')}/>
+              <Text style={ChargeStyle.rateText}>Rate</Text>
+              <Text style={[ChargeStyle.ratePrice]}>{info.rates}</Text>
+              <SelectableIcon selected={true}/>
+            </View>
+          </View>
+        }
+        <Text style={styles.timeleftText}>Reservation time left</Text>
+        <View style={styles.timeleftView}>
+          <Text style={styles.timeleft}>{this.state.timeLeft}</Text>
+        </View>
+        <View style={styles.cancelView}>
+          <Button
+            text='Cancel Reservation'
+            textColor={textButton}
+            style={styles.cancelButton}
+            viewStyle={styles.cancelButtonView}
+            onClick={() => this.cancelReserve()}
+          />
+        </View>
+
+        <Text style={styles.title}>Choose Payment Method</Text>
+        <Payment refreshId={this.state.refreshId}/>
+
+        <View style={styles.buttonGroup}>
+          <Button
+            style={styles.buttonLeft}
+            text='Scan QR'
+            disabled={this.state.available}
+            onClick={() => {
+              startPage(PageList.scanqr, {actionDetail: false, id: this.state.stationInfo.id});
+            }}/>
+          <Button
+            style={styles.buttonRight}
+            text='Enter Station ID'
+            disabled={this.state.available}
+            onClick={() => {
+              this.setState({
+                showStationDialog: true
+              });
+              //startPage(PageList.summary)
+            }
+          }/>
+        </View>
+      </> 
+    )
+  }
+}
+
+const styles = StyleSheet.create({
+  title: {
+    color: '#000',
+    fontSize: 15,
+    fontWeight: 'bold',
+    paddingTop: 16,
+    paddingBottom: 16
+  },
+  listView: {
+    padding: 8,
+    borderRadius: 8,
+    backgroundColor: '#F5F5F5'
+  },
+  buttonView: {
+    marginTop: 32,
+    marginBottom: 32
+  },
+  timeleftText: {
+    color: '#000',
+    fontSize: 16,
+    fontWeight: 'bold',
+    paddingTop: 16,
+    paddingBottom: 8,
+    textAlign: 'center'
+  },
+  timeleftView: {
+    alignItems: 'center',
+    justifyContent: 'center',
+    marginBottom: 16
+  },
+  timeleft: {
+    color: '#FF2E00',
+    fontSize: 18,
+    fontWeight: 'bold'
+  },
+  cancelView: {
+    flexDirection: 'row',
+    justifyContent: 'center',
+    paddingTop: 8,
+    paddingBottom: 8
+  },
+  cancelButton: {
+    borderRadius: 10,
+    backgroundColor: '#ED4A4A'
+  },
+  cancelButtonView: {
+    height: 48,
+    paddingLeft: 16,
+    paddingRight: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  buttonGroup: {
+    marginTop: 16,
+    marginBottom: 24,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  buttonLeft: {
+    flex: 1,
+    elevation: 1.5,
+  },
+  buttonRight: {
+    flex: 1,
+    marginLeft: 16,
+    elevation: 1.5
+  },
+})