@ledvance/ui-biz-bundle 1.1.150 → 1.1.152

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "name": "@ledvance/ui-biz-bundle",
5
5
  "pid": [],
6
6
  "uiid": "",
7
- "version": "1.1.150",
7
+ "version": "1.1.152",
8
8
  "scripts": {},
9
9
  "dependencies": {
10
10
  "@ledvance/base": "^1.x",
@@ -559,5 +559,53 @@ export const defFlagList: FlagUiInfo[] = [
559
559
  name: I18n.getLang('country_VE'),
560
560
  ...defFlagConfig,
561
561
  colors: [{ h: 0, s: 100, v: 100 }, { h: 205, s: 100, v: 100 }, { h: 60, s: 100, v: 100 },],
562
- }
562
+ },
563
+ {
564
+ id: 168,
565
+ name: I18n.getLang('country_JO'),
566
+ ...defFlagConfig,
567
+ colors: [{"h":150,"s":100,"v":48}, {"h":0,"s":0,"v":100}, {"h":0,"s":0,"v":0},{"h":353,"s":92,"v":81}],
568
+ },
569
+ {
570
+ id: 167,
571
+ name: I18n.getLang('country_CV'),
572
+ ...defFlagConfig,
573
+ colors: [{"h":49,"s":100,"v":100}, {"h":356,"s":79,"v":94}, {"h":0,"s":0,"v":100},{"h":218,"s":100,"v":65}],
574
+ },
575
+ {
576
+ id: 166,
577
+ name: I18n.getLang('country_PA'),
578
+ ...defFlagConfig,
579
+ colors: [{"h":219,"s":92,"v":34}, {"h":0,"s":0,"v":100}, {"h":358,"s":92,"v":85}],
580
+ },
581
+ {
582
+ id: 165,
583
+ name: I18n.getLang('country_northern_ireland'),
584
+ ...defFlagConfig,
585
+ colors: [{"h":0,"s":0,"v":100}, {"h":0,"s":100,"v":82}, {"h":0,"s":0,"v":100}],
586
+ },
587
+ {
588
+ id: 164,
589
+ name: I18n.getLang('country_wales'),
590
+ ...defFlagConfig,
591
+ colors: [{"h":142,"s":100,"v":69}, {"h":350,"s":92,"v":78}, {"h":0,"s":0,"v":100}],
592
+ },
593
+ {
594
+ id: 163,
595
+ name: I18n.getLang('country_BA'),
596
+ ...defFlagConfig,
597
+ colors: [{"h":0,"s":0,"v":100}, {"h":214,"s":100,"v":42}, {"h":48,"s":100,"v":100}],
598
+ },
599
+ {
600
+ id: 162,
601
+ name: I18n.getLang('country_north_macedonia'),
602
+ ...defFlagConfig,
603
+ colors: [{"h":56,"s":81,"v":97}, {"h":358,"s":85,"v":85}],
604
+ },
605
+ {
606
+ id: 161,
607
+ name: I18n.getLang('country_werder_bremen'),
608
+ ...defFlagConfig,
609
+ colors: [{"h":0,"s":0,"v":100}, {"h":160,"s":80,"v":34}],
610
+ },
563
611
  ]
@@ -46,7 +46,6 @@ function FlagItem(props: RecommendMoodItemProps) {
46
46
  height: cx(45),
47
47
  marginTop: cx(-5),
48
48
  marginBottom: cx(-10),
49
- fontWeight: 'bold',
50
49
  },
51
50
  gradientItem: {
52
51
  alignItems: 'center',
@@ -57,7 +56,7 @@ function FlagItem(props: RecommendMoodItemProps) {
57
56
  <Card
58
57
  style={[styles.card, props.style]}
59
58
  onPress={props.onPress}>
60
- <View>
59
+ <View accessibilityLabel={'FlagItem'} accessibilityHint={`${props.title}`}>
61
60
  <Spacer height={cx(16)} />
62
61
  <View style={styles.headline}>
63
62
  <View style={{ flexDirection: 'row', flex: 1, paddingRight: cx(5), justifyContent: 'flex-start' }}>
@@ -207,7 +207,10 @@ const FlagPage = (props: { theme?: ThemeType }) => {
207
207
  placeholder={I18n.getLang('country_selection_textfield_headline_search')}
208
208
  style={{ marginHorizontal: cx(24), flex: 1 }}
209
209
  />
210
- <TouchableOpacity style={{ paddingRight: cx(24) }}
210
+ <TouchableOpacity
211
+ style={{ paddingRight: cx(24) }}
212
+ accessibilityLabel={'RefreshButton'}
213
+ accessibilityHint={'RefreshButton'}
211
214
  onPress={() => {
212
215
  showDialog({
213
216
  method: 'confirm',
@@ -10,10 +10,11 @@ import {
10
10
  getSpecifiedTimeDpReportLogs
11
11
  } from '@ledvance/base/src/models/TuyaApi'
12
12
  import { exportCsvFile, localeNumber, loopsText, monthFormat, monthFormatShort } from '@ledvance/base/src/utils/common'
13
- import { overDays } from '@ledvance/base/src/utils'
13
+ import { overDays, xLog } from '@ledvance/base/src/utils'
14
14
  import dayjs from 'dayjs'
15
15
  import CustomParseFormat from 'dayjs/plugin/customParseFormat'
16
16
  import { isEmpty } from 'lodash'
17
+ import { TYSdk } from 'tuya-panel-kit'
17
18
  import { DateType } from './co2Data'
18
19
  import { EnergyData } from './component/EnergyModal'
19
20
  import { OverviewItem } from './EnergyConsumptionPage'
@@ -39,6 +40,11 @@ export async function updatePrice(devId: string, energyData: EnergyData) {
39
40
  return await NativeApi.putJson(devId, 'energiepreise', JSON.stringify(energyData))
40
41
  }
41
42
 
43
+ export async function resetElectricity(devId) {
44
+ const res = await TYSdk.apiRequest('tuya.m.dp.statistics.reset', {devId}, '1.0')
45
+ xLog('resetElectricity res', res)
46
+ }
47
+
42
48
  export async function getElectricity(devId: string, addEleDpCode: string, date: string, dateType: DateType): Promise<OverviewItem[]> {
43
49
  let res: OverviewItem[] = []
44
50
  switch (dateType) {
@@ -175,83 +181,37 @@ function createZeroPaddingPoint(timePoint: dayjs.Dayjs): PowerDataItem {
175
181
  }
176
182
 
177
183
  /**
178
- * 获取设备功率数据(智能填充,高性能,避免在小间隔内插入0值)
184
+ * 获取设备功率数据
179
185
  * @param devId 设备ID
180
186
  * @param powerDpCode 功率数据点编码
181
187
  * @param interval 时间区间(分钟)
182
188
  * @returns 按时间排序的完整数据
183
189
  */
184
- export async function getPowerData(
185
- devId: string,
186
- powerDpCode: string,
187
- interval: number
188
- ): Promise<PowerDataItem[]> {
189
- try {
190
- const now = dayjs();
191
- const endTime = now;
192
- const startTime = now.add(-interval, TIME_UNIT);
193
- const endTimeMs = endTime.valueOf();
194
- const startTimeMs = startTime.valueOf();
195
- const paddingIntervalMs = DATA_POINT_INTERVAL_SEC * 1000;
196
- // 1. 请求已排序的实际数据
197
- const dpResult = await getSpecifiedTimeDpReportLogs(
198
- devId,
199
- [powerDpCode],
200
- 'ASC',
201
- startTimeMs.toString(),
202
- endTimeMs.toString(),
203
- RETRY_CONFIG
204
- );
205
- const validDpResult = Array.isArray(dpResult) ? (dpResult as DpReportSataData[]) : [];
206
- const actualData: PowerDataItem[] = validDpResult
207
- .map((dp) => {
208
- const timeMs = dp.timeStamp * 1000;
209
- if (timeMs < startTimeMs || timeMs > endTimeMs) return null;
210
- return {
211
- key: dayjs.unix(dp.timeStamp).format('HH:mm:ss'),
212
- chartTitle: dayjs.unix(dp.timeStamp).format('MM/DD/YYYY HH:mm:ss'),
213
- time: timeMs,
214
- value: parseFloat(dp.value) / 10,
215
- };
216
- })
217
- .filter((item): item is PowerDataItem => item !== null);
218
- // 如果没有任何真实数据,则生成完整的预设0值数据作为兜底
219
- if (actualData.length === 0) {
220
- const finalData: PowerDataItem[] = [];
221
- let currentTime = startTime;
222
- while (currentTime.valueOf() < endTimeMs) {
223
- finalData.push(createZeroPaddingPoint(currentTime));
224
- currentTime = currentTime.add(DATA_POINT_INTERVAL_SEC, 'second');
225
- }
226
- return finalData;
190
+ export async function getPowerData(devId: string, powerDpCode: string, interval: number): Promise<PowerDataItem[]> {
191
+ const now = dayjs()
192
+ const startTime = now.add(-1 * interval, 'minute').valueOf().toString()
193
+ const endTime = now.valueOf().toString()
194
+ const dpResult = await getSpecifiedTimeDpReportLogs(
195
+ devId,
196
+ [powerDpCode],
197
+ 'ASC',
198
+ startTime,
199
+ endTime,
200
+ {
201
+ maxRetries: 5,
202
+ initialDelay: 1000,
203
+ maxDelay: 30000,
204
+ backoffFactor: 2
227
205
  }
228
- // 2. 高性能线性填充
229
- const finalData: PowerDataItem[] = [];
230
- let lastTimeMs = startTimeMs; // 游标从查询区间的开始时间算起
231
- // 遍历所有真实数据点
232
- actualData.forEach((currentPoint) => {
233
- // 从上一个点的时间开始,用 while 循环填充,直到下一个真实数据点之前
234
- let paddingTimeMs = lastTimeMs + paddingIntervalMs;
235
- while (paddingTimeMs < currentPoint.time) {
236
- finalData.push(createZeroPaddingPoint(dayjs(paddingTimeMs)));
237
- paddingTimeMs += paddingIntervalMs;
238
- }
239
-
240
- // 添加当前的真实数据点
241
- finalData.push(currentPoint);
242
- lastTimeMs = currentPoint.time; // 更新游标
243
- });
244
- // 3. 填充查询末尾的空白区域(从最后一个真实数据点到查询结束时间)
245
- let paddingTimeMs = lastTimeMs + paddingIntervalMs;
246
- while (paddingTimeMs < endTimeMs) {
247
- finalData.push(createZeroPaddingPoint(dayjs(paddingTimeMs)));
248
- paddingTimeMs += paddingIntervalMs;
206
+ ) as DpReportSataData[]
207
+ return dpResult.map(dp => {
208
+ return {
209
+ key: dp.timeStr,
210
+ chartTitle: dayjs.unix(dp.timeStamp).format('MM/DD/YYYY HH:mm:ss'),
211
+ time: dp.timeStamp * 1000,
212
+ value: parseFloat(dp.value) / 10
249
213
  }
250
- return finalData;
251
- } catch (error) {
252
- console.error(`[getPowerData] 失败:devId=${devId}, powerDpCode=${powerDpCode}`, error);
253
- return [];
254
- }
214
+ })
255
215
  }
256
216
 
257
217
  export const exportEnergyCsv = (values: any[][], unit: string) => {
@@ -98,7 +98,7 @@ const EnergyConsumptionCard = (props: EnergyConsumptionProp) => {
98
98
  consumedEnergyItemUnit: {
99
99
  color: props.theme?.global.secondFontColor,
100
100
  fontSize: cx(14),
101
- fontFamily: 'helvetica_neue_lt_std_roman',
101
+ // fontFamily: 'helvetica_neue_lt_std_roman',
102
102
  textAlign: 'center'
103
103
  },
104
104
  subContent: {
@@ -112,13 +112,13 @@ const EnergyConsumptionCard = (props: EnergyConsumptionProp) => {
112
112
  color: props.theme?.global.secondBrand,
113
113
  },
114
114
  titleText: {
115
- fontFamily: 'helvetica_neue_lt_std_roman',
115
+ // fontFamily: 'helvetica_neue_lt_std_roman',
116
116
  fontSize: cx(14),
117
117
  color: props.theme?.global.secondFontColor,
118
118
  textAlign: 'center',
119
119
  },
120
120
  unitText: {
121
- fontFamily: 'helvetica_neue_lt_std_roman',
121
+ // fontFamily: 'helvetica_neue_lt_std_roman',
122
122
  fontSize: cx(14),
123
123
  color: props.theme?.global.secondFontColor,
124
124
  },
@@ -12,7 +12,7 @@ import { EnergyConsumptionChartProps } from '../EnergyConsumptionChart'
12
12
 
13
13
  export const useEnergyData = (params: EnergyConsumptionChartProps, devId: string) => {
14
14
  const isFocused = useIsFocused()
15
- const { addEleDpCode, powerDpCode, price, date, over365Days, over7Days, chartData } = params
15
+ const { addEleDpCode, powerDpCode, price, unit, date, over365Days, over7Days, chartData } = params
16
16
 
17
17
  const getDateType = useCallback((d: string) => {
18
18
  const datejs = dayjs(d)
@@ -34,6 +34,7 @@ export const useEnergyData = (params: EnergyConsumptionChartProps, devId: string
34
34
  headlineText: params.headlineText,
35
35
  chartData: chartData.filter((item) => getDateType(date) !== DateType.Year || item.headlineText.startsWith(date)),
36
36
  price: isNaN(Number(price)) ? 0 : Number(price),
37
+ unit: unit,
37
38
  over365Days: over365Days,
38
39
  over7Days: over7Days,
39
40
  interval: 5,
@@ -49,7 +50,7 @@ export const useEnergyData = (params: EnergyConsumptionChartProps, devId: string
49
50
  }, 5000, { immediate: true })
50
51
 
51
52
  // 副作用:获取数据
52
- useUpdateEffect(() => {
53
+ useEffect(() => {
53
54
  state.loading = true
54
55
  if (state.chartType === ChartType.kWh) {
55
56
  getElectricity(devId, addEleDpCode, state.date, state.dateType)
@@ -143,6 +144,10 @@ export const useEnergyData = (params: EnergyConsumptionChartProps, devId: string
143
144
  OrientationService.lockToPortrait()
144
145
  }
145
146
  }, []),
147
+ setPriceAndUnit: useCallback((newPrice: string, newUnit: string) => {
148
+ state.price = isNaN(Number(newPrice)) ? 0 : Number(newPrice)
149
+ state.unit = newUnit
150
+ }, []),
146
151
  }
147
152
 
148
153
  return { state, actions }
@@ -147,7 +147,7 @@ const EnergyConsumptionDetail = (props: {theme?: ThemeType}) => {
147
147
  },
148
148
  consumptionNum: {
149
149
  color: props.theme?.global.secondBrand,
150
- fontFamily: 'helvetica_neue_lt_std_bd',
150
+ // fontFamily: 'helvetica_neue_lt_std_bd',
151
151
  },
152
152
  subContent: {
153
153
  flex: 1,
@@ -160,7 +160,7 @@ const EnergyConsumptionDetail = (props: {theme?: ThemeType}) => {
160
160
  color: props.theme?.global.secondBrand,
161
161
  },
162
162
  titleText: {
163
- fontFamily: 'helvetica_neue_lt_std_roman',
163
+ // fontFamily: 'helvetica_neue_lt_std_roman',
164
164
  fontSize: cx(14),
165
165
  color: props.theme?.global.secondFontColor,
166
166
  textAlign: 'center',
@@ -1,3 +1,9 @@
1
+ import Segmented from '@ledvance/base/src/components/Segmented'
2
+ import { ChartType } from './co2Data'
3
+ import { EnergyChartSection } from './EnergyConsumptionChart/EnergyChartSection'
4
+ import { PowerChartSection } from './EnergyConsumptionChart/PowerChartSection'
5
+ import { getStyles } from './EnergyConsumptionChart/styles'
6
+ import { useEnergyData } from './EnergyConsumptionChart/useEnergyData'
1
7
  import React, { useEffect, useMemo } from "react";
2
8
  import { ScrollView, StyleSheet, View, Text, Image, TouchableOpacity } from "react-native";
3
9
  import { useNavigation, useIsFocused } from '@react-navigation/core'
@@ -95,6 +101,18 @@ const EnergyConsumptionPage = (props: {theme?: ThemeType}) => {
95
101
  const len = state.overviewList.length
96
102
  return state.overviewList?.length ? `${state.overviewList[len - 1].key} - ${state.overviewList[0].key}` : ''
97
103
  }, [state.overviewList])
104
+ const chartStyles = useMemo(() => getStyles(props.theme), [props.theme])
105
+ const chartParams = useMemo(() => ({
106
+ backTitle,
107
+ headlineText: chartHeadline,
108
+ chartData: state.overviewList,
109
+ price: state.price,
110
+ unit: state.unit,
111
+ addEleDpCode: params.addEleDpCode,
112
+ powerDpCode: params.powerDpCode,
113
+ date: (new Date()).getFullYear().toString(),
114
+ }), [backTitle, chartHeadline, state.overviewList, state.price, state.unit, params.addEleDpCode, params.powerDpCode])
115
+ const { state: chartState, actions } = useEnergyData(chartParams, devId)
98
116
 
99
117
  useInterval(() => {
100
118
  if (isFocused) {
@@ -204,6 +222,7 @@ const EnergyConsumptionPage = (props: {theme?: ThemeType}) => {
204
222
  const v = JSON.parse(res.data)
205
223
  state.price = v?.price || '0'
206
224
  state.unit = v?.unit
225
+ actions.setPriceAndUnit(v?.price, v?.unit || UnitList[0])
207
226
  } else {
208
227
  state.price = '0'
209
228
  }
@@ -213,6 +232,7 @@ const EnergyConsumptionPage = (props: {theme?: ThemeType}) => {
213
232
  updatePrice(devId, data).then()
214
233
  state.price = data.price || '0'
215
234
  state.unit = data.unit
235
+ actions.setPriceAndUnit(data.price, data.unit)
216
236
  }
217
237
 
218
238
  const getEnergyModeTitle = (value: boolean) => {
@@ -246,7 +266,7 @@ const EnergyConsumptionPage = (props: {theme?: ThemeType}) => {
246
266
  },
247
267
  consumptionNum: {
248
268
  color: props.theme?.global.secondBrand,
249
- fontFamily: 'helvetica_neue_lt_std_bd',
269
+ // fontFamily: 'helvetica_neue_lt_std_bd',
250
270
  },
251
271
  subContent: {
252
272
  flex: 1,
@@ -259,7 +279,7 @@ const EnergyConsumptionPage = (props: {theme?: ThemeType}) => {
259
279
  color: props.theme?.global.secondBrand,
260
280
  },
261
281
  titleText: {
262
- fontFamily: 'helvetica_neue_lt_std_roman',
282
+ // fontFamily: 'helvetica_neue_lt_std_roman',
263
283
  fontSize: cx(14),
264
284
  color: props.theme?.global.secondFontColor,
265
285
  textAlign: 'center',
@@ -511,6 +531,23 @@ const EnergyConsumptionPage = (props: {theme?: ThemeType}) => {
511
531
  }}
512
532
  />
513
533
  </Card>
534
+ <Spacer/>
535
+ <ScrollView style={{marginHorizontal: cx(24)}}>
536
+ <Segmented
537
+ options={[
538
+ { label: I18n.getLang('chartdisplay_energy'), value: ChartType.kWh },
539
+ { label: I18n.getLang('chartdisplay_power'), value: ChartType.Watt },
540
+ ]}
541
+ value={chartState.chartType}
542
+ onChange={actions.setChartType}
543
+ />
544
+ {chartState.chartType === ChartType.kWh ? (
545
+ <EnergyChartSection state={chartState} actions={actions} params={chartParams} styles={chartStyles} theme={props.theme}
546
+ chartHeight={cx(400)}/>
547
+ ) : (
548
+ <PowerChartSection state={chartState} actions={actions} styles={chartStyles} theme={props.theme} chartHeight={cx(400)}/>
549
+ )}
550
+ </ScrollView>
514
551
  <Spacer />
515
552
  {/* Annual overview */}
516
553
  {!!state.price && <OverView
@@ -68,7 +68,7 @@ export default withTheme(function DateSelectedItem(props: DateSelectedItemProps)
68
68
  textAlign: 'center',
69
69
  flex: 1,
70
70
  color: props.theme?.textInput.fontColor,
71
- fontFamily: 'helvetica_neue_lt_std_roman',
71
+ // fontFamily: 'helvetica_neue_lt_std_roman',
72
72
  },
73
73
  modalRoot: {paddingTop: cx(20), backgroundColor: theme?.popup.cellBg},
74
74
  modalButtonParent: {flex: 1, height: cx(48)},
@@ -94,7 +94,7 @@ export default withTheme(function DateSwitch(props: DateSwitchProps) {
94
94
  minWidth: cx(200),
95
95
  textAlign: 'center',
96
96
  color: theme?.global.brand,
97
- fontFamily: 'helvetica_neue_lt_std_roman',
97
+ // fontFamily: 'helvetica_neue_lt_std_roman',
98
98
  }}>{state.headlineText}</Text>
99
99
  <TouchableOpacity
100
100
  disabled={state.disableArrowRight}
@@ -61,7 +61,7 @@ export default withTheme(function DateTypeItem(props: DateTypeItemProps) {
61
61
  textAlign: 'center',
62
62
  flex: 1,
63
63
  color: props.theme?.textInput.fontColor,
64
- fontFamily: 'helvetica_neue_lt_std_roman',
64
+ // fontFamily: 'helvetica_neue_lt_std_roman',
65
65
  }}>{state.dateTypeTitle}</Text>
66
66
  </View>
67
67
  </TouchableOpacity>
@@ -117,7 +117,7 @@ const EnergyModal = (props: EnergyModalProps) => {
117
117
  marginEnd: cx(6),
118
118
  fontSize: cx(16),
119
119
  color: props.theme?.textInput.fontColor,
120
- fontFamily: 'helvetica_neue_lt_std_roman',
120
+ // fontFamily: 'helvetica_neue_lt_std_roman',
121
121
  },
122
122
  textInputGroup: {
123
123
  flexDirection: 'row',
@@ -159,7 +159,7 @@ const EnergyModal = (props: EnergyModalProps) => {
159
159
  <View style={{ flexDirection: 'row', alignItems: 'center' }}>
160
160
  <View style={{ flex: 3 }}>
161
161
  <Spacer height={cx(4)} />
162
- <Text style={{ color: props.theme?.global.secondFontColor, marginStart: cx(13), fontFamily: 'helvetica_neue_lt_std_bd' }}>{I18n.getLang('consumption_data_price_per_kwh_headline_text')}</Text>
162
+ <Text style={{ color: props.theme?.global.secondFontColor, marginStart: cx(13), }}>{I18n.getLang('consumption_data_price_per_kwh_headline_text')}</Text>
163
163
  <View style={styles.textInputGroup}>
164
164
  <TextInput
165
165
  value={state.energyData?.price}
@@ -11,24 +11,22 @@ const cx = Utils.RatioUtils.convertX
11
11
 
12
12
  interface BarChartProps {
13
13
  theme?: ThemeType
14
- data: OverviewItem[],
15
- price: number,
16
- unit: string,
17
- height: number,
14
+ data: OverviewItem[]
15
+ price: number
16
+ unit: string
17
+ height: number
18
18
  }
19
19
 
20
20
  const BarChartWithTouch = (props: BarChartProps) => {
21
- const echarts = useRef()
21
+ const echarts = useRef<any>()
22
22
  const { data, height, price, unit, theme } = props
23
- const dataX = data?.map(item => {
24
- return item.chartTitle
25
- })
26
- const dataKwhY = data?.map(item => {
27
- return Number(item.value)
28
- })
29
- const dataPriceY = data?.map(item => {
30
- return ((isNaN(Number(item.value)) ? 0 : Number(item.value)) * price).toFixed(2)
31
- })
23
+
24
+ const dataX = data?.map(item => item.chartTitle)
25
+ const dataKwhY = data?.map(item => Number(item.value))
26
+ const dataPriceY = data?.map(item =>
27
+ ((isNaN(Number(item.value)) ? 0 : Number(item.value)) * price).toFixed(2)
28
+ )
29
+
32
30
  const maxValue = useMemo(() => {
33
31
  let max = Math.max(...dataKwhY)
34
32
  if (max < 0.1) {
@@ -48,134 +46,129 @@ const BarChartWithTouch = (props: BarChartProps) => {
48
46
  const max = Math.max(...dataPriceY.map(it => Number(it)))
49
47
  return max > 999 ? '15%' : '10%'
50
48
  }, [dataPriceY])
51
- const option = {
52
- tooltip: {
53
- show: true,
54
- triggerOn: 'click',
55
- trigger: 'axis',
56
- },
57
- legend: {
58
- show: true,
59
- data: ['kWh', unit],
60
- textStyle: {
61
- color: theme?.global.fontColor,
62
- }
63
- },
64
- grid: {
65
- right: gridRight,
66
- },
67
- xAxis: {
68
- data: dataX,
69
- axisTick: {
70
- show: false,
71
- },
72
- axisLabel: {
49
+
50
+ const chartKey = useMemo(() => {
51
+ return `chart-${price}-${unit}`
52
+ }, [price, unit])
53
+
54
+ /** --- option 保持 useMemo,避免不必要重建 ---**/
55
+ const option = useMemo(() => {
56
+ return {
57
+ tooltip: {
73
58
  show: true,
74
- color: props.theme?.global.secondFontColor,
75
- interval: 'auto',
76
- rotate: 45,
77
- align: 'right',
78
- verticalAlign: 'top',
79
- showMinLabel: true,
80
- showMaxLabel: true,
81
- }
82
- },
83
- yAxis: [{
84
- type: 'value',
85
- name: I18n.getLang('consumption_data_annual_bar_chart_text'),
86
- max: Math.max(maxValue, 0.02),
87
- min: 0,
88
- position: 'left',
89
- axisLabel: {
90
- formatter: function (value) {
91
- const kwh = parseFloat(value)
92
- let toFixed = 2
93
- if (kwh >= 100) {
94
- toFixed = 0
95
- } else if (kwh >= 10) {
96
- toFixed = 1
97
- }
98
- return kwh.toFixed(toFixed)
99
- },
100
- color: props.theme?.global.secondFontColor,
59
+ triggerOn: 'click',
60
+ trigger: 'axis',
101
61
  },
102
- nameTextStyle: {
103
- fontSize: 14,
104
- align: 'left',
105
- padding: [0, 0, 0, cx(-30)],
106
- color: props.theme?.global.secondFontColor,
107
- },
108
- }, {
109
- type: 'value',
110
- name: I18n.formatValue('format_unit', unit),
111
- position: 'right',
112
- alignTicks: true,
113
- max: Math.ceil(price ? maxValue * price * 1.4 : 0),
114
- min: 0,
115
- minInterval: 1,
116
- axisLabel: {
117
- formatter: function (value) {
118
- const price = parseFloat(value)
119
- let toFixed = 2
120
- if (price >= 100) {
121
- toFixed = 0
122
- } else if (price >= 10) {
123
- toFixed = 1
124
- }
125
- return price.toFixed(toFixed)
126
- },
127
- color: props.theme?.global.secondFontColor,
62
+ legend: {
63
+ show: true,
64
+ data: ['kWh', unit],
65
+ textStyle: {
66
+ color: theme?.global?.fontColor,
67
+ }
128
68
  },
129
- nameTextStyle: {
130
- fontSize: 14,
131
- align: 'right',
132
- padding: [0, cx(-30), 0, 0],
133
- color: props.theme?.global.secondFontColor,
69
+ grid: { right: gridRight },
70
+ xAxis: {
71
+ data: dataX,
72
+ axisTick: { show: false },
73
+ axisLabel: {
74
+ show: true,
75
+ color: theme?.global?.secondFontColor,
76
+ interval: 'auto',
77
+ rotate: 45,
78
+ align: 'right',
79
+ verticalAlign: 'top',
80
+ showMinLabel: true,
81
+ showMaxLabel: true,
82
+ }
134
83
  },
135
- }],
136
- series: [
137
- {
138
- name: 'kWh',
139
- type: 'bar',
140
- data: dataKwhY,
141
- itemStyle: {
142
- emphasis: {
143
- color: '#FFC2A9', // Color when bar is clicked
84
+ yAxis: [
85
+ {
86
+ type: 'value',
87
+ name: I18n.getLang('consumption_data_annual_bar_chart_text'),
88
+ max: Math.max(maxValue, 0.02),
89
+ min: 0,
90
+ position: 'left',
91
+ axisLabel: {
92
+ formatter(value) {
93
+ const kwh = parseFloat(value)
94
+ let toFixed = 2
95
+ if (kwh >= 100) toFixed = 0
96
+ else if (kwh >= 10) toFixed = 1
97
+ return kwh.toFixed(toFixed)
98
+ },
99
+ color: theme?.global?.secondFontColor,
100
+ },
101
+ nameTextStyle: {
102
+ fontSize: 14,
103
+ align: 'left',
104
+ padding: [0, 0, 0, cx(-30)],
105
+ color: theme?.global?.secondFontColor,
144
106
  },
145
- color: '#FFC2A9',
146
- borderRadius: 2,
147
107
  },
148
- barMaxWidth: 10,
149
- select: {
108
+ {
109
+ type: 'value',
110
+ name: I18n.formatValue('format_unit', unit),
111
+ position: 'right',
112
+ alignTicks: true,
113
+ max: Math.ceil(price ? maxValue * price * 1.4 : 0),
114
+ min: 0,
115
+ minInterval: 1,
116
+ axisLabel: {
117
+ formatter(value) {
118
+ const priceValue = parseFloat(value)
119
+ let toFixed = 2
120
+ if (priceValue >= 100) toFixed = 0
121
+ else if (priceValue >= 10) toFixed = 1
122
+ return priceValue.toFixed(toFixed)
123
+ },
124
+ color: theme?.global?.secondFontColor,
125
+ },
126
+ nameTextStyle: {
127
+ fontSize: 14,
128
+ align: 'right',
129
+ padding: [0, cx(-30), 0, 0],
130
+ color: theme?.global?.secondFontColor,
131
+ },
132
+ }
133
+ ],
134
+ series: [
135
+ {
136
+ name: 'kWh',
137
+ type: 'bar',
138
+ data: dataKwhY,
150
139
  itemStyle: {
151
- borderColor: '#FFC2A9',
152
- }
140
+ color: '#FFC2A9',
141
+ emphasis: { color: '#FFC2A9' },
142
+ borderRadius: 2,
143
+ },
144
+ barMaxWidth: 10,
145
+ selectedMode: 'single',
153
146
  },
154
- selectedMode: 'single',
155
- },
156
- {
157
- name: unit,
158
- type: 'line',
159
- data: dataPriceY,
160
- yAxisIndex: 1,
161
- smooth: true,
162
- showSymbol: false,
163
- color: '#F49431',
164
- selectedMode: 'single',
147
+ {
148
+ name: unit,
149
+ type: 'line',
150
+ data: dataPriceY,
151
+ yAxisIndex: 1,
152
+ smooth: true,
153
+ showSymbol: false,
154
+ color: '#F49431',
155
+ selectedMode: 'single',
156
+ }
157
+ ],
158
+ dataZoom: {
159
+ start: 0,
160
+ type: 'inside',
161
+ zoomLock: true,
165
162
  }
166
- ],
167
- dataZoom: {
168
- start: 0,
169
- type: 'inside',
170
- zoomLock: true,
171
- },
172
- customMapData: {}
173
- }
163
+ }
164
+ }, [dataX, dataKwhY, dataPriceY, price, unit, maxValue, gridRight, theme])
165
+
174
166
  return (
175
167
  <View style={{ flex: 1 }}>
176
168
  <ECharts
177
- option={option}
169
+ key={chartKey}
178
170
  ref={echarts}
171
+ option={option}
179
172
  height={height}
180
173
  />
181
174
  </View>
@@ -40,7 +40,7 @@ const OverView = (props: OverViewProps) => {
40
40
  listEmptyText: {
41
41
  color: props.theme?.global.fontColor,
42
42
  fontSize: cx(12),
43
- fontFamily: 'helvetica_neue_lt_std_roman',
43
+ // fontFamily: 'helvetica_neue_lt_std_roman',
44
44
  },
45
45
  overviewItemText: {
46
46
  color: props.theme?.global.fontColor,
@@ -65,7 +65,6 @@ const MoodItem = (props: MoodItemProps) => {
65
65
  height: cx(45),
66
66
  marginTop: cx(-5),
67
67
  marginBottom: cx(-10),
68
- fontWeight: 'bold',
69
68
  },
70
69
  moodTypeItem: {
71
70
  flexDirection: 'row',