Overview.js 14 KB

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