Explorar el Código

Add Overview V2 in wallet

vbea hace 2 años
padre
commit
cbeec34521

+ 1 - 0
Strides-APP/app.json

@@ -29,6 +29,7 @@
   "v3": {
     "drawer": true,
     "summary": true,
+    "overview": true,
     "anzPayment": false,
     "paymentMethod": false
   },

+ 378 - 0
Strides-APP/app/pages/wallet/OverviewV2.js

@@ -0,0 +1,378 @@
+/**
+ * 钱包概述页面优化版
+ * @邠心vbe on 2024/03/27
+ */
+import React, { Component } from 'react';
+import { View, StyleSheet, Text, Pressable } from 'react-native';
+import { ElevationObject } from '../../components/Button';
+import apiWallet from '../../api/apiWallet';
+import utils from '../../utils/utils';
+import TextView from '../../components/TextView';
+import Dialog from '../../components/Dialog';
+
+const chartThemes = "#A6EB7C"; //配置柱状图颜色
+
+export default class OverviewV2 extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      skeleton: true,
+      glanceData: {},
+      monthData: [],
+      weekdayData: [],
+      weekIndex: 0,
+      monthIndex: 0,
+      maxWeek: 0,
+      maxMonth: 0
+    };
+    this.nowDataString = new Date().toDateString()
+    this.refreshing = false;
+  }
+
+  componentDidMount() {
+    console.log("概述", this.props);
+    if (!this.props.skeleton) {
+      this.refreshing = true;
+      Dialog.showProgressDialog();
+      this.getOverview();
+    }
+  }
+
+  componentDidUpdate() {
+    if (this.props.shown && !this.props.skeleton) {
+      if (this.props.refresh && !this.refreshing) {
+        this.refreshing = true;
+        this.getOverview();
+      } else if (this.state.skeleton && !this.refreshing) {
+        this.refreshing = true;
+        this.getOverview();
+      }
+    }
+  }
+
+  getOverview() {
+    apiWallet.getOverviewData().then(res => {
+      var glanceData = {}
+      var weekdayData = []
+      var monthData = []
+      var weekIndex = 0
+      var monthIndex = 0
+      let maxWeek = 0;
+      let maxMonth = 0;
+      if (res.data) {
+        if (res.data.atAGlance) {
+          glanceData = res.data.atAGlance
+        }
+        if (res.data.statisticsForThisWeek) {
+          res.data.statisticsForThisWeek.forEach((item, index) => {
+            if (this.nowDataString.indexOf(item.x) >= 0) {
+              weekIndex = index;
+            }
+            if (item.y > maxWeek) {
+              maxWeek = item.y;
+            }
+            //item.y += index + 2;
+            item.label = currency + item.y;
+            item.title = item.dateTimeStr + ' | ' + item.label + ' | ' + item.power + 'kW';
+            weekdayData.push(item);
+          });
+        }
+        if (res.data.pastSixMonths) {
+          res.data.pastSixMonths.forEach((item, index) => {
+            if (this.nowDataString.indexOf(item.x) >= 0) {
+              monthIndex = index;
+            }
+            //item.y += index + 3;
+            if (item.y > maxMonth) {
+              maxMonth = item.y;
+            }
+            item.label = currency + item.y;
+            item.title = item.x + ' | ' + item.label + ' | ' + item.power + 'kW';
+            monthData.push(item);
+          });
+        }
+      }
+      this.setState({
+        glanceData: glanceData,
+        weekIndex: weekIndex,
+        monthIndex: monthIndex,
+        weekdayData: weekdayData,
+        monthData: monthData,
+        maxWeek: maxWeek,
+        maxMonth: maxMonth
+      }, () => {
+        this.setState({
+          skeleton: false
+        }, () => {
+          this.stopRefresh();
+        })
+      });
+      
+    }).catch(err => {
+      toastShort(err);
+      this.stopRefresh();
+    });
+  }
+
+  stopRefresh() {
+    if (this.props.refreshed) {
+      this.props.refreshed();
+    }
+    this.refreshing = false;
+    Dialog.dismissLoading();
+  }
+
+  changeWeek(index) {
+    this.setState({
+      weekIndex: index
+    });
+  }
+
+  changeMonth(index) {
+    this.setState({
+      monthIndex: index
+    });
+  }
+
+  getWeekHeight(y) {
+    if (y) {
+      let r = y / this.state.maxWeek * 100;
+      return Math.ceil(r);
+    } else {
+      return 1;
+    }
+  }
+  
+  getMonthHeight(y) {
+    if (y) {
+      let r = y / this.state.maxMonth * 100;
+      return Math.ceil(r);
+    } else {
+      return 1;
+    }
+  }
+
+  render() {
+    return (
+      <View style={this.props.shown ? ui.flex1 : styles.hide}>
+        { this.props.atAglance &&
+          <View style={styles.glanceView}>
+            <TextView style={styles.glanceTitle}>{$t('wallet.atAglance')}</TextView>
+            <View style={styles.overviewRow}>
+              <View style={ui.flex1}>
+                <TextView style={styles.valueText}>{this.state.glanceData.averageCharge ?? 0}</TextView>
+                <TextView style={styles.titleText}>kWh/{$t('wallet.perWeek')}</TextView>
+                <TextView style={styles.subTitleText}>{$t('wallet.averageCharge')}</TextView>
+              </View>
+              <View style={ui.flex1}>
+                <TextView style={styles.valueText}>{this.state.glanceData.averageSpend ?? 0}</TextView>
+                <TextView style={styles.titleText}>{currency}/{$t('wallet.perWeek')}</TextView>
+                <TextView style={styles.subTitleText}>{$t('wallet.averageSpend')}</TextView>
+              </View>
+              <View style={ui.flex1}>
+                <TextView style={styles.valueText}>{utils.hour2HHmm(this.state.glanceData.averageTime)}</TextView>
+                <TextView style={styles.titleText}>{$t('wallet.perHrWeek')}</TextView>
+                <TextView style={styles.subTitleText}>{$t('wallet.averageTime')}</TextView>
+              </View>
+            </View>
+          </View>
+        }
+        <View style={styles.statisticView}>
+          <View style={ui.flexcw}>
+            <TextView style={styles.sectionTitle}>{$t('wallet.forWeekOf')}</TextView>
+            {/* <Text style={styles.linkText}>1st Jan to 8th Jan </Text> */}
+          </View>
+          <View style={styles.overviewRow}>
+            <View style={ui.flex1}>
+              {/* <Text style={styles.valueText}>{this.state.glanceData.averageCharge ?? 0}</Text> */}
+              <TextView style={styles.titleText}>{this.state.glanceData.averageCharge ?? 0} kWh{/*$t('wallet.perWeek')*/}</TextView>
+              <TextView style={styles.subTitleText}>{$t('wallet.averageCharge')}</TextView>
+            </View>
+            <View style={styles.overviewDivide}></View>
+            <View style={ui.flex1}>
+              {/* <Text style={styles.valueText}>{this.state.glanceData.averageSpend ?? 0}</Text> */}
+              <TextView style={styles.titleText}>{this.state.glanceData.currencySymbol} {this.state.glanceData.averageSpend ?? 0}{/*$t('wallet.perWeek')*/}</TextView>
+              <TextView style={styles.subTitleText}>{$t('wallet.averageSpend')}</TextView>
+            </View>
+            <View style={styles.overviewDivide}></View>
+            <View style={ui.flex1}>
+              {/* <Text style={styles.valueText}>{utils.hour2HHmm(this.state.glanceData.averageTime)}</Text> */}
+              <TextView style={styles.titleText}>{utils.hour2HHmm(this.state.glanceData.averageTime)}{/*$t('wallet.perWeek')*/}</TextView>
+              <TextView style={styles.subTitleText}>{$t('wallet.averageTime')}</TextView>
+            </View>
+          </View>
+        </View>
+        <View style={ui.flex1}>
+          <View style={styles.statisticView}>
+            <TextView style={styles.sectionTitle}>{$t('wallet.statistics4week')}</TextView>
+            <TextView style={styles.statisticTitle}>{this.state.weekdayData[this.state.weekIndex]?.title}</TextView>
+            <View style={styles.barChartView}>
+              { this.state.weekdayData.map((item, index) => (
+                <View
+                  style={styles.barChartItem}
+                  key={index}>
+                  <Text
+                    style={styles.barLabelText}
+                    onPress={() => this.changeWeek(index)}>
+                    {item.label}
+                  </Text>
+                  <Pressable
+                    style={[
+                      styles.barChartValue,
+                      {
+                        height: this.getWeekHeight(item.y),
+                        opacity: index == this.state.weekIndex ? 1 : 0.6
+                      }
+                    ]}
+                    onPress={() => this.changeWeek(index)}
+                  />
+                  <Text style={styles.barLabelText}>{item.x}</Text>
+                </View>
+              ))}
+            </View>
+          </View>
+          <View style={styles.statisticView}>
+            <TextView style={styles.sectionTitle}>{$t('wallet.statistics4HalfYear')}</TextView>
+            <TextView style={styles.statisticTitle}>{this.state.monthData[this.state.monthIndex]?.title}</TextView>
+            <View style={styles.barChartView}>
+              { this.state.monthData.map((item, index) => (
+                <View
+                  style={styles.barChartItem}
+                  key={index}>
+                  <Text
+                    style={styles.barLabelText}
+                    onPress={() => this.changeMonth(index)}>
+                    {item.label}
+                  </Text>
+                  <Pressable
+                    style={[
+                      styles.barChartValue,
+                      {
+                        height: this.getMonthHeight(item.y),
+                        opacity: index == this.state.monthIndex ? 1 : 0.6
+                      }
+                    ]}
+                    onPress={() => this.changeMonth(index)}
+                  />
+                  <Text style={styles.barLabelText}>{item.x}</Text>
+                </View>
+              ))}
+            </View>
+          </View>
+        </View>
+      </View>
+    );
+  }
+}
+
+const animate = {
+  duration: 500,
+  onLoad: {
+    duration: 200
+  }
+}
+
+const axisTheme = {
+  axis: {stroke: "#fff"},
+  grid: {strokeWidth: 0},
+  ticks: {size: 0},
+  tickLabels: {color: '#666', fontSize: 12, padding: 8},
+}
+
+const styles = StyleSheet.create({
+  hide: {
+    display: 'none'
+  },
+  glanceView: {
+    marginTop: 16,
+    marginLeft: 16,
+    marginRight: 16,
+    marginBottom: 4,
+    ...ElevationObject(2),
+    overflow: 'hidden',
+    borderTopLeftRadius: 6,
+    borderTopRightRadius: 6,  
+    backgroundColor: colorLight
+  },
+  glanceTitle: {
+    color: textPrimary,
+    fontSize: 16,
+    paddingTop: 4,
+    paddingLeft: 16,
+    paddingBottom: 4,
+    backgroundColor: '#C4C8DF'
+  },
+  overviewRow: {
+    paddingTop: 16,
+    paddingBottom: 10,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  overviewDivide: {
+    width: 1,
+    height: 12,
+    backgroundColor: '#D9D9D9'
+  },
+  valueText: {
+    color: '#000',
+    fontSize: 22,
+    paddingBottom: 8,
+    textAlign: 'center'
+  },
+  titleText: {
+    color: textPrimary,
+    fontSize: 14,
+    textAlign: 'center'
+  },
+  subTitleText: {
+    color: textCancel,
+    fontSize: 12,
+    textAlign: 'center'
+  },
+  statisticView: {
+    marginTop: 0,
+    paddingBottom: 16,
+    backgroundColor: colorLight
+  },
+  sectionTitle: {
+    color: textPrimary,
+    fontSize: 14,
+    paddingLeft: 16,
+    fontWeight: 'bold'
+  },
+  statisticTitle: {
+    color: textPrimary,
+    fontSize: 14,
+    paddingTop: 24,
+    paddingBottom: 8,
+    textAlign: 'center'
+  },
+  statisticChart: {
+    height: 120
+  },
+  linkText: {
+    ...ui.link,
+    fontSize: 14,
+    paddingRight: 16
+  },
+  barChartView: {
+    height: 200,
+    padding: 16,
+    alignItems: 'flex-end',
+    flexDirection: 'row',
+    justifyContent: 'space-between'
+  },
+  barChartItem: {
+    alignItems: 'center'
+  },
+  barLabelText: {
+    padding: 4,
+    fontSize: 12,
+    textAlign: 'center'
+  },
+  barChartValue: {
+    width: 24,
+    minHeight: 1,
+    backgroundColor: colorAccent
+  }
+})

+ 34 - 21
Strides-APP/app/pages/wallet/Wallet.js

@@ -3,7 +3,7 @@
  * @邠心vbe on 2021/05/07
  */
 import React, { Component } from 'react';
-import { View, Text, StyleSheet, ScrollView, RefreshControl, Image, Pressable } from 'react-native';
+import { View, StyleSheet, ScrollView, RefreshControl, Image, Pressable } from 'react-native';
 import { Balance } from './Payment';
 import { PageList } from '../Router';
 import History from './History';
@@ -12,6 +12,8 @@ import { MyRefreshProps } from '../../components/ThemesConfig';
 import { ElevationObject } from '../../components/Button';
 import TextView from '../../components/TextView';
 import Dialog from '../../components/Dialog';
+import app from '../../../app.json';
+import OverviewV2 from './OverviewV2';
 
 export default class Wallet extends Component {
   constructor(props) {
@@ -45,20 +47,22 @@ export default class Wallet extends Component {
         pageShown: false
       })
     });
-    this.props.navigation.addListener('beforeRemove', (e) => {
-      if (this.state.pageShown) {
-        e.preventDefault();
-        Dialog.showProgressDialog();
-        this.setState({
-          pageShown: false
-        }, () => {
-          setTimeout(() => {
-            Dialog.dismissLoading();
-            goBack();
-          }, 500);
-        });
-      }
-    });
+    if (!app.v3.overview) {
+      this.props.navigation.addListener('beforeRemove', (e) => {
+        if (this.state.pageShown) {
+          e.preventDefault();
+          Dialog.showProgressDialog();
+          this.setState({
+            pageShown: false
+          }, () => {
+            setTimeout(() => {
+              Dialog.dismissLoading();
+              goBack();
+            }, 500);
+          });
+        }
+      });
+    }
   }
 
   changeTab(index) {
@@ -158,12 +162,21 @@ export default class Wallet extends Component {
               </TextView>
             </Pressable>
           </View>
-          <Overview
-            atAglance={false}
-            skeleton={!this.state.pageShown}
-            refresh={this.state.refreshing}
-            refreshed={() => this.stopRefresh()}
-            shown={this.state.tabIndex == 0}/>
+          { app.v3.overview
+          ? <OverviewV2
+              atAglance={false}
+              skeleton={!this.state.pageShown}
+              refresh={this.state.refreshing}
+              refreshed={() => this.stopRefresh()}
+              shown={this.state.tabIndex == 0}/>
+          : <Overview
+              atAglance={false}
+              skeleton={!this.state.pageShown}
+              refresh={this.state.refreshing}
+              refreshed={() => this.stopRefresh()}
+              shown={this.state.tabIndex == 0}/>
+          }
+          
           <History
             refresh={this.state.refreshing}
             refreshed={() => this.stopRefresh()}