Overview.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /**
  2. * 钱包概述页面
  3. * @邠心vbe on 2021/05/08
  4. */
  5. import React, { Component } from 'react';
  6. import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
  7. import { ElevationObject } from '../../components/Button';
  8. import {VictoryAxis, VictoryBar, VictoryArea, VictoryChart, VictoryTheme, VictoryLabel} from 'victory-native';
  9. import apiWallet from '../../api/apiWallet';
  10. import Svg, { Defs, LinearGradient, Stop } from 'react-native-svg';
  11. import utils from '../../utils/utils';
  12. const chartThemes = "#6672B8"; //配置柱状图颜色
  13. export default class Overview extends Component {
  14. constructor(props) {
  15. super(props);
  16. this.state = {
  17. glanceData: {},
  18. monthData: [],
  19. weekdayData: [],
  20. weekIndex: 0,
  21. monthIndex: 0,
  22. chartReady: false,
  23. };
  24. this.nowDataString = new Date().toDateString()
  25. this.refreshing = false;
  26. this.enableChartArea = true;
  27. }
  28. componentDidMount() {
  29. this.getOverview();
  30. }
  31. componentDidUpdate() {
  32. if (this.props.shown) {
  33. if (this.props.refresh && !this.refreshing) {
  34. this.refreshing = true;
  35. this.getOverview();
  36. } else if (!this.state.chartReady) {
  37. setTimeout(() => {
  38. this.setState({
  39. chartReady: true
  40. })
  41. }, 100);
  42. }
  43. } else if (this.state.chartReady) {
  44. this.setState({
  45. chartReady: false
  46. })
  47. }
  48. }
  49. getOverview() {
  50. apiWallet.getOverviewData().then(res => {
  51. var glanceData = {}
  52. var weekdayData = []
  53. var monthData = []
  54. var weekIndex = 0
  55. var monthIndex = 0
  56. if (res.data) {
  57. if (res.data.atAGlance) {
  58. glanceData = res.data.atAGlance
  59. }
  60. if (res.data.statisticsForThisWeek) {
  61. res.data.statisticsForThisWeek.forEach((item, index) => {
  62. if (this.nowDataString.indexOf(item.x) >= 0) {
  63. weekIndex = index;
  64. }
  65. //item.y += index + 2;
  66. item.label = currency + item.y;
  67. item.title = item.dateTimeStr + ' | ' + item.label + ' | ' + item.power + 'kw';
  68. weekdayData.push(item);
  69. });
  70. }
  71. if (res.data.pastSixMonths) {
  72. res.data.pastSixMonths.forEach((item, index) => {
  73. if (this.nowDataString.indexOf(item.x) >= 0) {
  74. monthIndex = index;
  75. }
  76. //item.y += index + 3;
  77. item.y0 = 0;
  78. item.label = currency + item.y;
  79. item.title = item.x + ' | ' + item.label + ' | ' + item.power + 'kw';
  80. /*if (this.enableChartArea) {
  81. if (index == 0) {
  82. item.label = " " + currency + item.y
  83. } else if (index == res.data.pastSixMonths.length - 1) {
  84. item.label = currency + item.y + " "
  85. }
  86. //item.y += (item.y * 10 + 5);
  87. }*/
  88. monthData.push(item);
  89. });
  90. }
  91. }
  92. this.setState({
  93. glanceData: glanceData,
  94. weekIndex: weekIndex,
  95. monthIndex: monthIndex,
  96. weekdayData: weekdayData,
  97. monthData: monthData
  98. }, () => {
  99. this.setState({
  100. chartReady: true
  101. })
  102. });
  103. this.stopRefresh();
  104. }).catch(err => {
  105. toastShort(err);
  106. this.stopRefresh();
  107. });
  108. }
  109. stopRefresh() {
  110. if (this.props.refreshed) {
  111. this.props.refreshed();
  112. }
  113. this.refreshing = false;
  114. }
  115. barTheme = (active) => ({
  116. data: {
  117. fill: ({datum, index}) => {
  118. return (datum.y > 0 ? (index == active ? colorAccent : chartThemes) : "#999999");
  119. }
  120. },
  121. labels: {
  122. fontSize: 12,
  123. fill: ({index}) => (index == active ? "#000" : textSecondary)
  124. }
  125. })
  126. barSpacesTheme = () => ({
  127. data: {
  128. fill: "transparent",
  129. },
  130. labels: {
  131. fontSize: 12,
  132. fill: textSecondary
  133. }
  134. })
  135. areaTheme = () => ({
  136. data: {
  137. //fill: chartThemes,
  138. fill: chartThemes,
  139. fillOpacity: 0.7,
  140. stroke: colorPrimary,
  141. strokeWidth: 1
  142. },
  143. labels: {
  144. fontSize: 1,
  145. fill: "transparent"//textSecondary
  146. }
  147. })
  148. getFill = ({datum, index}) => (datum.y > 0 ? (index == this.state.monthIndex ? colorPrimary : chartThemes) : "#999999");
  149. render() {
  150. return (
  151. <View style={this.props.shown ? ui.flex1 : styles.hide}>
  152. { this.props.atAglance &&
  153. <View style={styles.glanceView}>
  154. <Text style={styles.glanceTitle}>At a glance</Text>
  155. <View style={styles.overviewRow}>
  156. <View style={ui.flex1}>
  157. <Text style={styles.valueText}>{this.state.glanceData.averageCharge ?? 0}</Text>
  158. <Text style={styles.titleText}>kWh/Week</Text>
  159. <Text style={styles.subTitleText}>Average Charge</Text>
  160. </View>
  161. <View style={ui.flex1}>
  162. <Text style={styles.valueText}>{this.state.glanceData.averageSpend ?? 0}</Text>
  163. <Text style={styles.titleText}>{currency}/Week</Text>
  164. <Text style={styles.subTitleText}>Average Spend</Text>
  165. </View>
  166. <View style={ui.flex1}>
  167. <Text style={styles.valueText}>{utils.hour2HHmm(this.state.glanceData.averageTime)}</Text>
  168. <Text style={styles.titleText}>Hr/Week</Text>
  169. <Text style={styles.subTitleText}>Average Time</Text>
  170. </View>
  171. </View>
  172. </View>
  173. }
  174. <View style={styles.statisticView}>
  175. <View style={ui.flexcw}>
  176. <Text style={styles.sectionTitle}>For the week of</Text>
  177. {/* <Text style={styles.linkText}>1st Jan to 8th Jan </Text> */}
  178. </View>
  179. <View style={styles.overviewRow}>
  180. <View style={ui.flex1}>
  181. {/* <Text style={styles.valueText}>{this.state.glanceData.averageCharge ?? 0}</Text> */}
  182. <Text style={styles.titleText}>{this.state.glanceData.averageCharge ?? 0} kWh/Week</Text>
  183. <Text style={styles.subTitleText}>Average Charge</Text>
  184. </View>
  185. <View style={styles.overviewDivide}></View>
  186. <View style={ui.flex1}>
  187. {/* <Text style={styles.valueText}>{this.state.glanceData.averageSpend ?? 0}</Text> */}
  188. <Text style={styles.titleText}>{currency}{this.state.glanceData.averageSpend ?? 0}/Week</Text>
  189. <Text style={styles.subTitleText}>Average Spend</Text>
  190. </View>
  191. <View style={styles.overviewDivide}></View>
  192. <View style={ui.flex1}>
  193. {/* <Text style={styles.valueText}>{utils.hour2HHmm(this.state.glanceData.averageTime)}</Text> */}
  194. <Text style={styles.titleText}>{utils.hour2HHmm(this.state.glanceData.averageTime)}/Week</Text>
  195. <Text style={styles.subTitleText}>Average Time</Text>
  196. </View>
  197. </View>
  198. </View>
  199. <View style={ui.flex1}>
  200. <View style={styles.statisticView}>
  201. <Text style={styles.sectionTitle}>Statistics for this week</Text>
  202. <Text style={styles.statisticTitle}>{this.state.weekdayData[this.state.weekIndex]?.title}</Text>
  203. <Svg height={200}>
  204. { this.state.chartReady &&
  205. <VictoryChart
  206. theme={VictoryTheme.material}
  207. animate={animate}
  208. height={200}
  209. padding={{top: 50, left: 32, right: 60, bottom: 50}}>
  210. <VictoryAxis style={axisTheme}/>
  211. <VictoryBar
  212. barWidth={25}
  213. style={this.barTheme(this.state.weekIndex)}
  214. data={this.state.weekdayData}
  215. events={[{
  216. target: "data",
  217. eventHandlers: {
  218. onPress: () => {
  219. return [{
  220. target: "data",
  221. mutation: (props) => {
  222. this.setState({
  223. weekIndex: props.index
  224. });
  225. }
  226. }];
  227. }
  228. }
  229. }]}
  230. />
  231. </VictoryChart>
  232. }
  233. </Svg>
  234. </View>
  235. { this.state.monthData.length > 0 &&
  236. <View style={styles.statisticView}>
  237. <Text style={styles.sectionTitle}>Statistics for the past 6 months</Text>
  238. <Text style={styles.statisticTitle}>{this.state.monthData[this.state.monthIndex].title}</Text>
  239. {/* <svg style={{height: 0}}>
  240. <defs>
  241. <linearGradient id="myGradient" gradientUnits="userSpaceOnUse">
  242. <stop stopColor={chartThemes} stopOpacity="0.8"/>
  243. <stop offset="1" stopColor={chartThemes} stopOpacity="0"/>
  244. </linearGradient>
  245. </defs>
  246. </svg> */}
  247. { this.enableChartArea
  248. ? <Svg height={200}>
  249. { this.state.chartReady &&
  250. <VictoryChart
  251. theme={VictoryTheme.material}
  252. height={200}
  253. padding={{top: 50, left: 30, right: 60, bottom: 50}}>
  254. <VictoryAxis style={axisTheme}/>
  255. <VictoryArea
  256. style={this.areaTheme()}
  257. data={this.state.monthData}
  258. theme={VictoryTheme.material}
  259. labels={({ datum }) => datum.y}
  260. labelComponent={<VictoryLabel dy={10}/>}
  261. />
  262. <VictoryBar
  263. barWidth={28}
  264. data={this.state.monthData}
  265. style={this.barSpacesTheme()}
  266. events={[{
  267. target: "data",
  268. eventHandlers: {
  269. onPress: () => {
  270. return [{
  271. target: "data",
  272. mutation: (props) => {
  273. this.setState({
  274. monthIndex: props.index
  275. });
  276. }
  277. }];
  278. }
  279. }
  280. }]}
  281. />
  282. </VictoryChart>
  283. }
  284. </Svg>
  285. : <Svg height={200}>
  286. <VictoryChart
  287. theme={VictoryTheme.material}
  288. height={200}
  289. padding={{top: 50, left: 30, right: 62, bottom: 50}}>
  290. <VictoryAxis style={axisTheme}/>
  291. <VictoryBar
  292. barWidth={28}
  293. data={this.state.monthData}
  294. style={this.barTheme(this.state.monthIndex)}
  295. events={[{
  296. target: "data",
  297. eventHandlers: {
  298. onPress: () => {
  299. return [{
  300. target: "data",
  301. mutation: (props) => {
  302. this.setState({
  303. monthIndex: props.index
  304. });
  305. }
  306. }];
  307. }
  308. }
  309. }]}
  310. />
  311. </VictoryChart>
  312. </Svg>
  313. }
  314. </View>
  315. }
  316. </View>
  317. </View>
  318. );
  319. }
  320. }
  321. const animate = {
  322. duration: 500,
  323. onLoad: {
  324. duration: 200
  325. }
  326. }
  327. const axisTheme = {
  328. axis: {stroke: "#fff"},
  329. grid: {strokeWidth: 0},
  330. ticks: {size: 0},
  331. tickLabels: {color: '#666', fontSize: 12, padding: 8},
  332. }
  333. const styles = StyleSheet.create({
  334. hide: {
  335. display: 'none'
  336. },
  337. glanceView: {
  338. marginTop: 16,
  339. marginLeft: 16,
  340. marginRight: 16,
  341. marginBottom: 4,
  342. ...ElevationObject(2),
  343. overflow: 'hidden',
  344. borderTopLeftRadius: 6,
  345. borderTopRightRadius: 6,
  346. backgroundColor: colorLight
  347. },
  348. glanceTitle: {
  349. color: textPrimary,
  350. fontSize: 16,
  351. paddingTop: 4,
  352. paddingLeft: 16,
  353. paddingBottom: 4,
  354. backgroundColor: '#C4C8DF'
  355. },
  356. overviewRow: {
  357. paddingTop: 16,
  358. paddingBottom: 10,
  359. alignItems: 'center',
  360. flexDirection: 'row'
  361. },
  362. overviewDivide: {
  363. width: 1,
  364. height: 12,
  365. backgroundColor: '#D9D9D9'
  366. },
  367. valueText: {
  368. color: '#000',
  369. fontSize: 22,
  370. paddingBottom: 8,
  371. textAlign: 'center'
  372. },
  373. titleText: {
  374. color: textPrimary,
  375. fontSize: 14,
  376. textAlign: 'center'
  377. },
  378. subTitleText: {
  379. color: textCancel,
  380. fontSize: 12,
  381. textAlign: 'center'
  382. },
  383. statisticView: {
  384. marginTop: 0,
  385. paddingTop: 16,
  386. backgroundColor: colorLight
  387. },
  388. sectionTitle: {
  389. color: textPrimary,
  390. fontSize: 14,
  391. paddingLeft: 16,
  392. fontWeight: 'bold'
  393. },
  394. statisticTitle: {
  395. color: textPrimary,
  396. fontSize: 14,
  397. paddingTop: 24,
  398. paddingBottom: 8,
  399. textAlign: 'center'
  400. },
  401. statisticChart: {
  402. height: 120
  403. },
  404. linkText: {
  405. ...ui.link,
  406. fontSize: 14,
  407. paddingRight: 16
  408. }
  409. })