ソースを参照

add app/pages/wallet/Overview.js

wudebin 5 ヶ月 前
コミット
e5898e9b42
1 ファイル変更445 行追加0 行削除
  1. 445 0
      Strides-SPAPP/app/pages/wallet/Overview.js

+ 445 - 0
Strides-SPAPP/app/pages/wallet/Overview.js

@@ -0,0 +1,445 @@
+/**
+ * 钱包概述页面
+ * @邠心vbe on 2021/05/08
+ */
+import React, { Component } from 'react';
+import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
+import { ElevationObject } from '../../components/Button';
+import {VictoryAxis, VictoryBar, VictoryArea, VictoryChart, VictoryTheme, VictoryLabel} from 'victory-native';
+import apiWallet from '../../api/apiWallet';
+import Svg, { Defs, LinearGradient, Stop } from 'react-native-svg';
+import utils from '../../utils/utils';
+import TextView from '../../components/TextView';
+import Dialog from '../../components/Dialog';
+
+const chartThemes = "#A6EB7C"; //配置柱状图颜色
+
+export default class Overview extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      skeleton: true,
+      glanceData: {},
+      monthData: [],
+      weekdayData: [],
+      weekIndex: 0,
+      monthIndex: 0,
+      chartReady: false,
+    };
+    this.nowDataString = new Date().toDateString()
+    this.refreshing = false;
+    this.enableChartArea = true;
+  }
+
+  componentDidMount() {
+    console.log("概述", this.props);
+    Dialog.showProgressDialog();
+    if (!this.props.skeleton) {
+      this.refreshing = true;
+      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();
+      } else if (!this.state.chartReady) {
+        setTimeout(() => {
+          this.setState({
+            chartReady: true
+          })
+        }, 500);
+      }
+    } else if (this.state.chartReady) {
+      this.setState({
+        chartReady: false
+      })
+    }
+  }
+
+  getOverview() {
+    apiWallet.getOverviewData().then(res => {
+      var glanceData = {}
+      var weekdayData = []
+      var monthData = []
+      var weekIndex = 0
+      var monthIndex = 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;
+            }
+            //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;
+            item.y0 = 0;
+            item.label = currency + item.y;
+            item.title = item.x + ' | ' + item.label + ' | ' + item.power + 'kW';
+            /*if (this.enableChartArea) {
+              if (index == 0) {
+                item.label = "     " + currency + item.y
+              } else if (index == res.data.pastSixMonths.length - 1) {
+                item.label = currency + item.y + "     "
+              }
+              item.y += (item.y * 10 + 5);
+            }*/
+            monthData.push(item);
+          });
+        }
+      }
+      this.setState({
+        glanceData: glanceData,
+        weekIndex: weekIndex,
+        monthIndex: monthIndex,
+        weekdayData: weekdayData,
+        monthData: monthData
+      }, () => {
+        this.setState({
+          skeleton: false,
+          chartReady: true
+        }, () => {
+          this.stopRefresh();
+        })
+      });
+      
+    }).catch(err => {
+      toastShort(err);
+      this.stopRefresh();
+    });
+  }
+
+  stopRefresh() {
+    if (this.props.refreshed) {
+      this.props.refreshed();
+    }
+    this.refreshing = false;
+    setTimeout(() => {
+      Dialog.dismissLoading();
+    }, 1000);
+  }
+
+  barTheme = (active) => ({
+    data: { 
+      fill: ({datum, index}) => {
+        return (datum.y > 0 ? (index == active ? colorAccent : chartThemes) : "#999999");
+      }
+    },
+    labels: {
+      fontSize: 12,
+      fill: ({index}) => (index == active ? "#000" : textSecondary)
+    }
+  })
+
+  barSpacesTheme = () => ({
+    data: { 
+      fill: "transparent",
+    },
+    labels: {
+      fontSize: 12,
+      fill: textSecondary
+    }
+  })
+
+  areaTheme = () => ({
+    data: {
+      fill: chartThemes,
+      fillOpacity: 0.7,
+      stroke: colorPrimary,
+      strokeWidth: 1
+    },
+    labels: {
+      fontSize: 1,
+      fill: "transparent"//textSecondary
+    }
+  })
+
+  getFill = ({datum, index}) => (datum.y > 0 ? (index == this.state.monthIndex ? colorAccent : chartThemes) : "#999999");
+
+  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>
+            <Svg height={200}>
+              { this.state.chartReady &&
+                <VictoryChart
+                  theme={VictoryTheme.material}
+                  animate={animate}
+                  height={200}
+                  padding={{top: 50, left: 32, right: 60, bottom: 50}}>
+                  <VictoryAxis style={axisTheme}/>
+                  <VictoryBar
+                    barWidth={25}
+                    style={this.barTheme(this.state.weekIndex)}
+                    data={this.state.weekdayData}
+                    events={[{
+                      target: "data",
+                      eventHandlers: {
+                        onPress: () => {
+                          return [{
+                            target: "data",
+                            mutation: (props) => {
+                              this.setState({
+                                weekIndex: props.index
+                              });
+                            }
+                          }];
+                        }
+                      }
+                    }]}
+                  />
+                </VictoryChart>
+              }
+            </Svg>
+          </View>
+          { this.state.skeleton &&
+            <View style={styles.statisticView}>
+            <TextView style={styles.sectionTitle}>{$t('wallet.statistics4HalfYear')}</TextView>
+            <View style={{height: 200}}></View>
+            </View>
+          }
+          { this.state.monthData.length > 0 &&
+            <View style={styles.statisticView}>
+              <TextView style={styles.sectionTitle}>{$t('wallet.statistics4HalfYear')}</TextView>
+              <TextView style={styles.statisticTitle}>{this.state.monthData[this.state.monthIndex].title}</TextView>
+              {/* <svg style={{height: 0}}>
+                <defs>
+                  <linearGradient id="myGradient" gradientUnits="userSpaceOnUse">
+                    <stop stopColor={chartThemes} stopOpacity="0.8"/>
+                    <stop offset="1" stopColor={chartThemes} stopOpacity="0"/>
+                  </linearGradient>
+                </defs>
+              </svg> */}
+              { this.enableChartArea
+              ? <Svg height={200}>
+                { this.state.chartReady &&
+                  <VictoryChart
+                    theme={VictoryTheme.material}
+                    height={200}
+                    padding={{top: 50, left: 30, right: 60, bottom: 50}}>
+                      <VictoryAxis style={axisTheme}/>
+                      <VictoryArea
+                        style={this.areaTheme()}
+                        data={this.state.monthData}
+                        theme={VictoryTheme.material}
+                        labels={({ datum }) => datum.y}
+                        labelComponent={<VictoryLabel dy={10}/>}
+                      />
+                      <VictoryBar
+                        barWidth={28}
+                        data={this.state.monthData}
+                        style={this.barSpacesTheme()}
+                        events={[{
+                          target: "data",
+                          eventHandlers: {
+                            onPress: () => {
+                              return [{
+                                target: "data",
+                                mutation: (props) => {
+                                  this.setState({
+                                    monthIndex: props.index
+                                  });
+                                }
+                              }];
+                            }
+                          }
+                        }]}
+                      />
+                    </VictoryChart>
+                  }
+                </Svg>
+              : <Svg height={200}>
+                  <VictoryChart
+                    theme={VictoryTheme.material}
+                    height={200}
+                    padding={{top: 50, left: 30, right: 62, bottom: 50}}>
+                    <VictoryAxis style={axisTheme}/>
+                    <VictoryBar
+                      barWidth={28}
+                      data={this.state.monthData}
+                      style={this.barTheme(this.state.monthIndex)}
+                      events={[{
+                        target: "data",
+                        eventHandlers: {
+                          onPress: () => {
+                            return [{
+                              target: "data",
+                              mutation: (props) => {
+                                this.setState({
+                                  monthIndex: props.index
+                                });
+                              }
+                            }];
+                          }
+                        }
+                      }]}
+                    />
+                  </VictoryChart>
+                </Svg>
+              }
+            </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,
+    paddingTop: 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
+  }
+})