@ledvance/group-ui-biz-bundle 1.0.84 → 1.0.86

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/group-ui-biz-bundle",
5
5
  "pid": [],
6
6
  "uiid": "",
7
- "version": "1.0.84",
7
+ "version": "1.0.86",
8
8
  "scripts": {},
9
9
  "dependencies": {
10
10
  "@ledvance/base": "^1.x",
@@ -1,4 +1,11 @@
1
- import { useFeatureHook } from "@ledvance/base/src/models/modules/NativePropsSlice";
1
+ import {useGroupEzvizConfig} from "@ledvance/base/src/models/modules/NativePropsSlice";
2
+ import {getDataWithSpecified, getDpResultByHour, getDpResultByMonth} from "@ledvance/base/src/models/TuyaApi";
3
+ import {overDays} from "@ledvance/base/src/utils";
4
+ import {loopsText, monthFormat, monthFormatShort} from "@ledvance/base/src/utils/common";
5
+ import {DateType} from "@ledvance/group-ui-biz-bundle/src/modules/energyConsumption/co2Data";
6
+ import {OverviewItem} from "@ledvance/group-ui-biz-bundle/src/modules/energyConsumption/EnergyConsumptionPage";
7
+ import dayjs from "dayjs";
8
+ import {isNumber} from "lodash";
2
9
  import {EnergyData, UnitList} from "./component/EnergyModal";
3
10
 
4
11
  interface LightConfig {
@@ -6,7 +13,7 @@ interface LightConfig {
6
13
  }
7
14
 
8
15
  export const useEnergyConsumption = () =>{
9
- return useFeatureHook<LightConfig, EnergyData>('energyConsumption', {unit: UnitList[0], price: ''})
16
+ return useGroupEzvizConfig<LightConfig, EnergyData>('energyConsumption', {unit: UnitList[0], price: ''})
10
17
  }
11
18
 
12
19
  export const unitDivision = (str: string) => {
@@ -16,3 +23,140 @@ export const unitDivision = (str: string) => {
16
23
  const name = str.split(unit)[0]
17
24
  return [name, unit]
18
25
  }
26
+
27
+
28
+ export async function getElectricity(devIdGroup: string[], addEleDpCode: string, date: string, dateType: DateType): Promise<OverviewItem[]> {
29
+ let res: OverviewItem[] = []
30
+ switch (dateType) {
31
+ case DateType.Year:
32
+ res = await getDpResultByYear(devIdGroup, addEleDpCode, date)
33
+ break
34
+ case DateType.Month:
35
+ res = await getDpResultByYearMonth(devIdGroup, addEleDpCode, date)
36
+ break
37
+ case DateType.Day:
38
+ res = await getDpResultByDate(devIdGroup, addEleDpCode, date);
39
+ break
40
+ }
41
+ return res
42
+ }
43
+
44
+ const getDpResultByYear = async (devIdGroup: string[], addEleDpCode: string, dateStr: string): Promise<OverviewItem[]> => {
45
+ const year = dateStr;
46
+ const promiseGroup = devIdGroup.map(devId =>
47
+ getDpResultByMonth(devId, addEleDpCode, 'sum').catch(error => ({error}))
48
+ );
49
+ const res = await Promise.all(promiseGroup);
50
+ // @ts-ignore
51
+ const successGroup: DpResultByMonthResData[] = res.filter(v => !v.error);
52
+ const mergedData = {}
53
+ successGroup.forEach(item => {
54
+ const monthData = item.years[year];
55
+ if (monthData) {
56
+ Object.keys(monthData).forEach(month => {
57
+ if (mergedData[month] === undefined) {
58
+ mergedData[month] = 0
59
+ }
60
+ const monthNum = Number(monthData[month])
61
+ mergedData[month] += Number(isNumber(monthNum) ? monthNum : 0)
62
+ })
63
+ }
64
+ })
65
+ const curMonthList = Object.keys(mergedData).sort((a, b) => parseInt(b) - parseInt(a));
66
+ return curMonthList.map(month => {
67
+ return {
68
+ key: `${monthFormat(month)} ${year}`,
69
+ value: (Number(mergedData[month]) || 0).toFixed(2),
70
+ headlineText: `${year}${month}`,
71
+ chartTitle: `${monthFormatShort(month)}\n${year}`
72
+ }
73
+ })
74
+ }
75
+
76
+
77
+ const getDpResultByYearMonth = async (deviceIdGroup: string[], addEleDpCode: string, dateStr: string): Promise<OverviewItem[]> => {
78
+ const date = dayjs(dateStr)
79
+ const startDay = date.startOf('month').format('YYYYMMDD')
80
+ const endDay = date.endOf('month').format('YYYYMMDD')
81
+ if (overDays(startDay, 365)) {
82
+ console.log("getDpResultByYearMonth overDays true")
83
+ return []
84
+ }
85
+ const promiseGroup = deviceIdGroup.map(devId => getDataWithSpecified(devId, addEleDpCode, startDay, endDay, 'sum').catch(error => ({error})))
86
+ const res = await Promise.all(promiseGroup);
87
+ // @ts-ignore
88
+ const successGroup: DpResultByDataWithSpecifiedResData[] = res.filter(v => !v.error);
89
+ const mergedData = {}
90
+ successGroup.forEach(item => {
91
+ if (item.result) {
92
+ Object.keys(item.result).forEach(day => {
93
+ if (mergedData[day] === undefined) {
94
+ mergedData[day] = 0
95
+ }
96
+ const dayNum = Number(item.result[day])
97
+ mergedData[day] += Number(isNumber(dayNum) ? dayNum : 0)
98
+ })
99
+ }
100
+ })
101
+ return Object.keys(mergedData).filter(v => Number(mergedData[v]) > 0).map(time => {
102
+ // 提取年、月和日
103
+ const year = time.slice(0, 4);
104
+ const month = time.slice(4, 6);
105
+ const day = time.slice(6, 8);
106
+
107
+ // 格式化为 'YYYY/MM/DD' 格式
108
+ const formattedDate = `${year}/${month}/${day}`
109
+ const dateStr = `${day}/${month}/${year}`
110
+ const dateObj = dayjs(formattedDate, "YYYY/MM/DD");
111
+ const dayOfWeek = dateObj.day() % 7;
112
+ const key = `${dateStr} (${loopsText[dayOfWeek]})`
113
+ return {
114
+ key,
115
+ value: Number(mergedData[time] || 0).toFixed(2),
116
+ headlineText: formattedDate,
117
+ chartTitle: `${Number(key?.split('/')[0])}\n${loopsText[dayOfWeek]}`
118
+ }
119
+ })
120
+ }
121
+
122
+
123
+ const getDpResultByDate = async (deviceIdGroup: string[], addEleDpCode: string, date: string): Promise<OverviewItem[]> => {
124
+ if (overDays(date, 7)) {
125
+ console.log("getDpResultByDate overDays true")
126
+ return []
127
+ }
128
+ const promiseGroup = deviceIdGroup.map(devId => getDpResultByHour(devId, addEleDpCode, date, 'sum').catch(error => ({error})))
129
+ const res = await Promise.all(promiseGroup);
130
+ // @ts-ignore
131
+ const successGroup: DpResultByDataWithSpecifiedResData[] = res.filter(v => !v.error);
132
+ const mergedData = {}
133
+ successGroup.forEach(item => {
134
+ if (item) {
135
+ Object.keys(item).forEach(day => {
136
+ if (mergedData[day] === undefined) {
137
+ mergedData[day] = 0
138
+ }
139
+ const dayNum = Number(item[day])
140
+ mergedData[day] += Number(isNumber(dayNum) ? dayNum : 0)
141
+ })
142
+ }
143
+ })
144
+
145
+
146
+ const list: Array<OverviewItem> = []
147
+ const resData = Object.keys(mergedData)?.map(val => {
148
+ return {key: Number(val?.slice(8, 10)), value: Number(mergedData[val])}
149
+ })
150
+ for (let i = 0; i <= 23; i++) {
151
+ const hourData = resData?.find(val => val?.key === i)
152
+ const hourKey = hourData?.key || i
153
+ const hourValue = Number(hourData?.value) || 0
154
+ list.push({
155
+ key: `${hourKey.toString().padStart(2, '0')}:00`,
156
+ value: hourValue,
157
+ chartTitle: `${hourKey}:00`,
158
+ headlineText: `${hourKey}:00`
159
+ })
160
+ }
161
+ return list
162
+ }
@@ -1,16 +1,23 @@
1
- import React from "react";
1
+ import React, { useCallback } from "react";
2
2
  import { Platform, View, StyleSheet, Image } from "react-native";
3
3
  import { useRoute } from '@react-navigation/core'
4
4
  import Page from "@ledvance/base/src/components/Page";
5
5
  import res from "@ledvance/base/src/res";
6
6
  import I18n from "@ledvance/base/src/i18n";
7
7
  import { Utils } from "tuya-panel-kit";
8
- import BarChart from "./component/BarChart";
9
- import { exportFile } from "@ledvance/base/src/utils/common";
8
+ import { exportFile, loopsText, monthFormat } from "@ledvance/base/src/utils/common";
10
9
  import { OverviewItem } from "./EnergyConsumptionPage";
11
10
  import Spacer from "@ledvance/base/src/components/Spacer";
12
11
  import InfoText from "@ledvance/base/src/components/InfoText";
13
12
  import ThemeType from '@ledvance/base/src/config/themeType'
13
+ import {overDays} from "@ledvance/base/src/utils/index";
14
+ import dayjs from "dayjs";
15
+ import { DateType } from "@ledvance/group-ui-biz-bundle/src/modules/energyConsumption/co2Data";
16
+ import { useReactive, useUpdateEffect } from "ahooks";
17
+ import DateTypeItem from "@ledvance/group-ui-biz-bundle/src/modules/energyConsumption/component/DateTypeItem";
18
+ import DateSelectedItem from "@ledvance/group-ui-biz-bundle/src/modules/energyConsumption/component/DateSelectedItem";
19
+ import NewBarChart from "@ledvance/group-ui-biz-bundle/src/modules/energyConsumption/component/NewBarChart";
20
+ import { getElectricity } from "@ledvance/group-ui-biz-bundle/src/modules/energyConsumption/EnergyConsumptionActions";
14
21
 
15
22
  const { convertX: cx, height, width } = Utils.RatioUtils
16
23
  const { withTheme } = Utils.ThemeUtils
@@ -20,12 +27,16 @@ export interface EnergyConsumptionChartProps {
20
27
  headlineText: string
21
28
  chartData: OverviewItem[],
22
29
  over365Days?: boolean
23
- over7Days?: boolean
30
+ over7Days?: boolean,
31
+ deviceIdGroup: string[];
32
+ price: string,
33
+ unit: string,
34
+ date: string,
24
35
  }
25
36
 
26
37
  const EnergyConsumptionChart = (props: { theme?: ThemeType }) => {
27
38
  const params = useRoute().params as EnergyConsumptionChartProps
28
- const computeNum = Platform.OS === 'ios' && 180 || 130
39
+ const {price, unit, date, addEleDpCode,deviceIdGroup,over365Days, over7Days} = params;
29
40
 
30
41
  const styles = StyleSheet.create({
31
42
  listEmptyView: {
@@ -35,40 +46,149 @@ const EnergyConsumptionChart = (props: { theme?: ThemeType }) => {
35
46
  width: cx(200),
36
47
  height: cx(200),
37
48
  },
38
- })
49
+ listEmptyText: {
50
+ flex: 0
51
+ },
52
+ });
53
+
54
+ const getDateType = useCallback((date: string) => {
55
+ const datejs = dayjs(date);
56
+ if (datejs.isValid()) {
57
+ if (datejs.format('YYYY') === date) {
58
+ return DateType.Year;
59
+ } else if (datejs.format('YYYYMM') === date) {
60
+ return DateType.Month;
61
+ } else if (datejs.format('YYYY/MM/DD') === date) {
62
+ return DateType.Day;
63
+ }
64
+ }
65
+ return DateType.Day;
66
+ }, []);
67
+
68
+ const dateType = getDateType(date);
69
+ const state = useReactive({
70
+ loading: false,
71
+ dateType: dateType,
72
+ date: date,
73
+ headlineText: dateType === DateType.Year ? date : params.headlineText,
74
+ chartData: params.chartData.filter((item) => {
75
+ return dateType !== DateType.Year || item.headlineText.startsWith(date)
76
+ }),
77
+ price: isNaN(Number(price)) ? 0 : Number(price),
78
+ over365Days: over365Days,
79
+ over7Days: over7Days,
80
+ });
81
+
82
+ useUpdateEffect(() => {
83
+ state.over365Days = overDays(state.date, 365);
84
+ state.over7Days = overDays(state.date, 7);
85
+ updateHeadlineText(dayjs(state.date));
86
+ state.loading = true;
87
+ getElectricity(deviceIdGroup, addEleDpCode, state.date, state.dateType).then((res) => {
88
+ state.chartData = res;
89
+ state.loading = false;
90
+ })
91
+ }, [state.date]);
92
+
93
+ useUpdateEffect(() => {
94
+ const date = dayjs();
95
+ const year = date.year().toString();
96
+ const month = (date.month() + 1).toString().padStart(2, '0');
97
+ const day = date.date().toString().padStart(2, '0');
98
+ switch (state.dateType) {
99
+ case DateType.Year:
100
+ state.date = year;
101
+ break
102
+ case DateType.Month:
103
+ state.date = `${year}${month}`
104
+ break
105
+ case DateType.Day:
106
+ state.date = `${year}${month}${day}`
107
+ break
108
+ }
109
+ }, [state.dateType]);
110
+
111
+ const updateHeadlineText = useCallback((date: dayjs.Dayjs) => {
112
+ const year = date.year().toString();
113
+ const month = (date.month() + 1).toString().padStart(2, '0');
114
+ const day = date.date().toString().padStart(2, '0');
115
+ const dayOfWeek = date.day() % 7;
116
+ switch (state.dateType) {
117
+ case DateType.Year:
118
+ state.headlineText = year;
119
+ break
120
+ case DateType.Month:
121
+ state.headlineText = `${monthFormat(month)} ${year}`;
122
+ break
123
+ case DateType.Day:
124
+ state.headlineText = `${day}/${month}/${year}\n${loopsText[dayOfWeek]}`;
125
+ break
126
+ }
127
+ }, [state.dateType, state.headlineText]);
128
+
129
+ const getEmptyDataTip = useCallback(() => {
130
+ if (state.over365Days) {
131
+ return I18n.getLang('energyconsumption_Daylimit')
132
+ }
133
+ if (state.dateType === DateType.Day && state.over7Days) {
134
+ return I18n.getLang('energyconsumption_hourlylimit')
135
+ }
136
+ return I18n.getLang('energyconsumption_emptydata')
137
+ }, [state.dateType, state.over365Days, state.over7Days]);
39
138
 
40
139
  return (
41
- <Page
42
- backText={I18n.getLang('consumption_data_annual_bar_chart_system_back_text')}
43
- headlineText={params.headlineText}
44
- headlineIcon={params.chartData?.length ? res.download_icon : undefined}
45
- onHeadlineIconClick={() => {
46
- exportFile(params.chartData)
47
- }}
48
- showGreenery={false}
49
- greeneryIcon={res.energy_consumption_greenery}
50
- >
51
- <View style={{ marginHorizontal: cx(24) }}>
52
- {
53
- params.over7Days ? (
54
- <View style={styles.listEmptyView}>
55
- <Spacer height={cx(26)} />
56
- <Image
57
- style={styles.listEmptyImage}
58
- source={{ uri: res.ldv_timer_empty }} />
59
- <Spacer height={cx(14)} />
60
- <InfoText
61
- text={I18n.getLang('energyconsumption_hourlylimit')}
62
- icon={res.ic_info}
63
- contentColor={props.theme?.global.fontColor}
64
- />
65
- </View>
66
- ) : (
67
- <BarChart height={height - cx(computeNum)} data={params.chartData} width={width - cx(80)} />
68
- )
69
- }
70
- </View>
71
- </Page>
140
+ <Page
141
+ backText={I18n.getLang('consumption_data_annual_bar_chart_system_back_text')}
142
+ headlineText={state.headlineText}
143
+ headlineIcon={state.chartData?.length ? res.download_icon : undefined}
144
+ onHeadlineIconClick={() => {
145
+ exportFile(state.chartData,params.price,params.unit)
146
+ }}
147
+ showGreenery={false}
148
+ greeneryIcon={res.energy_consumption_greenery}
149
+ loading={state.loading}
150
+ >
151
+ <View style={{ marginHorizontal: cx(24) }}>
152
+ <View style={{flexDirection: 'row'}}>
153
+ <DateTypeItem
154
+ style={{flex: 1}}
155
+ dateType={state.dateType}
156
+ onDateTypeChange={(dateType) => {
157
+ state.dateType = dateType;
158
+ }}/>
159
+ <DateSelectedItem
160
+ style={{flex: 1, marginStart: cx(10),marginBottom:cx(15)}}
161
+ dateType={state.dateType}
162
+ date={state.date}
163
+ onDateChange={date => {
164
+ state.date = date;
165
+ }}
166
+ />
167
+
168
+ </View>
169
+ {
170
+ (state.chartData.length <= 0) ? (
171
+ <View style={styles.listEmptyView}>
172
+ <Spacer height={cx(26)} />
173
+ <Image
174
+ style={styles.listEmptyImage}
175
+ source={{ uri: res.ldv_timer_empty }} />
176
+ <Spacer height={cx(14)} />
177
+ <InfoText
178
+ text={getEmptyDataTip()}
179
+ icon={res.ic_info}
180
+ textStyle={styles.listEmptyText}
181
+ contentColor={props.theme?.global.fontColor}
182
+ />
183
+ </View>
184
+ ) : (
185
+ state.chartData.length > 0 && !state.loading &&
186
+ <NewBarChart height={400} data={state.chartData} price={state.price}
187
+ unit={unit}/>
188
+ )
189
+ }
190
+ </View>
191
+ </Page>
72
192
  )
73
193
  }
74
194
 
@@ -216,7 +216,7 @@ const EnergyConsumptionDetail = (props: { theme?: ThemeType }) => {
216
216
  headlineText={params.curMonth.key}
217
217
  headlineIcon={state.overviewList.length ? res.download_icon : undefined}
218
218
  onHeadlineIconClick={() => {
219
- exportFile(state.overviewList)
219
+ exportFile(state.overviewList, params.price, params.unit);
220
220
  }}
221
221
  showGreenery={false}
222
222
  greeneryIcon={res.energy_consumption_greenery}
@@ -301,7 +301,12 @@ const EnergyConsumptionDetail = (props: { theme?: ThemeType }) => {
301
301
  navigation.navigate(ui_biz_routerKey.group_ui_biz_energy_consumption_chart, {
302
302
  headlineText: params.curMonth.key,
303
303
  chartData: state.overviewList,
304
- over365Days: state.over365Days
304
+ over365Days: state.over365Days,
305
+ price:state.price,
306
+ unit:state.unit,
307
+ addEleDpCode:params.addEleDpCode,
308
+ date:params.curMonth.headlineText,
309
+ deviceIdGroup: params.deviceIdGroup,
305
310
  } as EnergyConsumptionChartProps)
306
311
  }}
307
312
  overviewItemClick={async (item) => {
@@ -312,7 +317,11 @@ const EnergyConsumptionDetail = (props: { theme?: ThemeType }) => {
312
317
  headlineText: item.key,
313
318
  chartData: res,
314
319
  over7Days: state.over7Days,
315
- addEleDpCode: params.addEleDpCode
320
+ addEleDpCode: params.addEleDpCode,
321
+ price:state.price,
322
+ unit:state.unit,
323
+ date:item.headlineText,
324
+ deviceIdGroup: params.deviceIdGroup,
316
325
  } as EnergyConsumptionChartProps)
317
326
  }}
318
327
  overViewList={state.overviewList}
@@ -285,7 +285,7 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
285
285
  )}
286
286
  headlineIcon={(state.isSolarMode ? state.solarOverviewList : state.wifiOverviewList).length ? res.download_icon : undefined}
287
287
  onHeadlineIconClick={() => {
288
- exportFile(state.isSolarMode ? state.solarOverviewList : state.wifiOverviewList);
288
+ exportFile(state.isSolarMode ? state.solarOverviewList : state.wifiOverviewList, state.price, state.unit);
289
289
  }}
290
290
  showGreenery={state.isSolarMode}
291
291
  greeneryIcon={res.energy_consumption_greenery}
@@ -457,14 +457,19 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
457
457
  <Spacer height={cx(30)} />
458
458
  {/* Annual overview */}
459
459
  <OverView
460
- style={{ marginHorizontal: cx(24) }}
461
- headlineText={I18n.getLang('consumption_data_field4_headline_text')}
462
- headlineClick={() => {
463
- navigation.navigate(ui_biz_routerKey.group_ui_biz_energy_consumption_chart, {
464
- headlineText: chartHeadline,
465
- chartData: state.isSolarMode ? state.solarOverviewList : state.wifiOverviewList
466
- } as EnergyConsumptionChartProps)
467
- }}
460
+ style={{marginHorizontal: cx(24)}}
461
+ headlineText={I18n.getLang('consumption_data_field4_headline_text')}
462
+ headlineClick={() => {
463
+ navigation.navigate(ui_biz_routerKey.group_ui_biz_energy_consumption_chart, {
464
+ headlineText: chartHeadline,
465
+ chartData: state.isSolarMode ? state.solarOverviewList : state.wifiOverviewList,
466
+ price: state.price,
467
+ unit: state.unit,
468
+ addEleDpCode: params.addEleDpCode,
469
+ date: (new Date()).getFullYear().toString(),
470
+ deviceIdGroup: state.isSolarMode ? params.solarPlugGroup : params.wifiPlugGroup,
471
+ } as EnergyConsumptionChartProps)
472
+ }}
468
473
  overviewItemClick={(item) => {
469
474
  navigation.navigate(ui_biz_routerKey.group_ui_biz_energy_consumption_detail, {
470
475
  addEleDpCode: params.addEleDpCode,
@@ -23653,3 +23653,9 @@ export const carbonDioxideEmission = (name, list) => {
23653
23653
  const order = emissionData?.find(item => item.nation === nationCode)?.value
23654
23654
  return order || emissionData?.find(item => item.nation === 'World')?.value
23655
23655
  }
23656
+
23657
+ export enum DateType {
23658
+ Year = 'Year',
23659
+ Month = 'Month',
23660
+ Day = 'Day',
23661
+ }
@@ -0,0 +1,168 @@
1
+ import ThemeType from "@ledvance/base/src/config/themeType";
2
+ import React, {PropsWithChildren, useCallback, useEffect} from "react";
3
+ import {StyleSheet, Text, TouchableOpacity, View, ViewProps} from "react-native";
4
+ import {DatePicker, Modal, Utils} from "tuya-panel-kit";
5
+ import {useReactive} from "ahooks";
6
+ import I18n from "@ledvance/base/src/i18n/index";
7
+ import dayjs from "dayjs";
8
+ import {DateType} from "@ledvance/group-ui-biz-bundle/src/modules/energyConsumption/co2Data";
9
+
10
+ const {convertX: cx} = Utils.RatioUtils
11
+ const {withTheme} = Utils.ThemeUtils
12
+
13
+ interface DateSelectedItemProps extends PropsWithChildren<ViewProps> {
14
+ theme?: ThemeType
15
+ date: string,
16
+ dateType: DateType,
17
+ onDateChange: (string) => void
18
+ }
19
+
20
+ const getModalMode = (dateType) => {
21
+ switch (dateType) {
22
+ case DateType.Year:
23
+ return 'year';
24
+ case DateType.Month:
25
+ return 'month';
26
+ case DateType.Day:
27
+ default:
28
+ return 'date';
29
+ }
30
+ }
31
+
32
+ const getDateForDateType = (year, month, day, dateType: DateType) => {
33
+ const monthOfYear = month.toString().padStart(2, '0');
34
+ const dayOfMonth = day.toString().padStart(2, '0');
35
+ switch (dateType) {
36
+ case DateType.Year:
37
+ return `${year}`
38
+ case DateType.Month:
39
+ return `${year}${monthOfYear}`;
40
+ case DateType.Day:
41
+ return `${year}${monthOfYear}${dayOfMonth}`;
42
+ }
43
+ }
44
+
45
+ export default withTheme(function DateSelectedItem(props: DateSelectedItemProps) {
46
+ const {dateType, date, onDateChange, theme} = props;
47
+ const state = useReactive({
48
+ showDateModal: false,
49
+ date: date,
50
+ selectedDate: date,
51
+ dateType: dateType,
52
+ modalMode: getModalMode(dateType),
53
+ });
54
+
55
+ const styles = StyleSheet.create({
56
+ root: {
57
+ width: '100%',
58
+ flexDirection: 'row',
59
+ borderRadius: cx(4),
60
+ backgroundColor: props.theme?.textInput.background,
61
+ alignItems: 'center',
62
+ height: cx(44),
63
+ borderBottomWidth: cx(1),
64
+ borderBottomColor: props.theme?.textInput.line,
65
+ },
66
+ date: {
67
+ fontSize: cx(16),
68
+ textAlign: 'center',
69
+ flex: 1,
70
+ color: props.theme?.textInput.fontColor,
71
+ fontFamily: 'helvetica_neue_lt_std_roman',
72
+ },
73
+ modalRoot: {paddingTop: cx(20), backgroundColor: theme?.popup.cellBg},
74
+ modalButtonParent: {flex: 1, height: cx(48)},
75
+ modalButton: {
76
+ height: '100%',
77
+ alignItems: 'center',
78
+ justifyContent: 'center'
79
+ },
80
+ modalConfirm: {
81
+ textAlign: 'center',
82
+ color: theme?.popup.confirmFontColor,
83
+ fontWeight: 'bold',
84
+ fontSize: cx(16)
85
+ },
86
+ modalCancel: {
87
+ textAlign: 'center',
88
+ color: theme?.popup.cancelFontColor,
89
+ fontSize: cx(16)
90
+ }
91
+ });
92
+
93
+ useEffect(() => {
94
+ state.dateType = dateType;
95
+ const datejs = dayjs(date)
96
+ switch (dateType) {
97
+ case DateType.Year:
98
+ state.date = `${datejs.year()}`;
99
+ break
100
+ case DateType.Month:
101
+ state.date = `${datejs.month() + 1}/${datejs.year()}`;
102
+ break
103
+ case DateType.Day:
104
+ state.date = `${datejs.date()}/${datejs.month() + 1}/${datejs.year()}`;
105
+ }
106
+ state.modalMode = getModalMode(dateType);
107
+ }, [dateType, date]);
108
+
109
+ return (<View style={props.style}>
110
+ <TouchableOpacity
111
+ style={{width: '100%',}}
112
+ onPress={() => {
113
+ state.showDateModal = true;
114
+ }}
115
+ >
116
+ <View style={styles.root}>
117
+ <Text style={styles.date}>{state.date}</Text>
118
+ </View>
119
+ </TouchableOpacity>
120
+
121
+ <Modal
122
+ visible={state.showDateModal}
123
+ onCancel={() => {
124
+ state.showDateModal = false;
125
+ }}>
126
+ <View style={styles.modalRoot}>
127
+ <DatePicker
128
+ defaultDate={dayjs(date).toDate()}
129
+ mode={state.modalMode}
130
+ dateSortKeys={['day', 'month', 'year']}
131
+ maxDate={new Date()}
132
+ style={{backgroundColor: theme?.popup.cellBg}}
133
+ pickerFontColor={theme?.global.fontColor}
134
+ onDateChange={date => {
135
+ if (date) {
136
+ state.selectedDate = getDateForDateType(
137
+ date.getFullYear(),
138
+ date.getMonth() + 1,
139
+ date.getDate(),
140
+ dateType,
141
+ )
142
+ }
143
+ }
144
+ }
145
+ />
146
+ <View style={{flexDirection: 'row'}}>
147
+ <TouchableOpacity style={styles.modalButtonParent} onPress={() => {
148
+ state.showDateModal = false;
149
+ }}>
150
+ <View style={styles.modalButton}>
151
+ <Text style={styles.modalCancel}>{I18n.getLang('auto_scan_system_cancel')}</Text>
152
+ </View>
153
+ </TouchableOpacity>
154
+ <TouchableOpacity style={styles.modalButtonParent} onPress={() => {
155
+ state.showDateModal = false;
156
+ onDateChange(state.selectedDate);
157
+ }}>
158
+ <View style={styles.modalButton}>
159
+ <Text style={styles.modalConfirm}>{I18n.getLang('auto_scan_system_wifi_confirm')}</Text>
160
+ </View>
161
+ </TouchableOpacity>
162
+ </View>
163
+ </View>
164
+ </Modal>
165
+
166
+ </View>)
167
+ })
168
+
@@ -0,0 +1,89 @@
1
+ import ThemeType from "@ledvance/base/src/config/themeType";
2
+ import React, {PropsWithChildren} from "react";
3
+ import {Text, TouchableOpacity, View, ViewProps} from "react-native";
4
+ import {Modal, Utils} from "tuya-panel-kit";
5
+ import {useReactive, useUpdateEffect} from "ahooks";
6
+ import I18n from "@ledvance/base/src/i18n/index";
7
+ import { DateType } from "@ledvance/group-ui-biz-bundle/src/modules/energyConsumption/co2Data";
8
+
9
+ const {convertX: cx} = Utils.RatioUtils
10
+ const {withTheme} = Utils.ThemeUtils
11
+
12
+ interface DateTypeItemProps extends PropsWithChildren<ViewProps> {
13
+ theme?: ThemeType
14
+ dateType: string,
15
+ onDateTypeChange: (dateType: DateType) => void
16
+ }
17
+
18
+ export default withTheme(function DateTypeItem(props: DateTypeItemProps) {
19
+ const {dateType} = props;
20
+ const state = useReactive({
21
+ showDateTypeModal: false,
22
+ dateType: dateType,
23
+ });
24
+ useUpdateEffect(() => {
25
+ state.dateType = dateType;
26
+ }, [dateType])
27
+ return (<View style={props.style}>
28
+ <TouchableOpacity
29
+ style={{width: '100%',}}
30
+ onPress={() => {
31
+ state.showDateTypeModal = true;
32
+ }}
33
+ >
34
+ <View
35
+ style={{
36
+ width: '100%',
37
+ flexDirection: 'row',
38
+ borderRadius: cx(4),
39
+ backgroundColor: props.theme?.textInput.background,
40
+ alignItems: 'center',
41
+ height: cx(44),
42
+ borderBottomWidth: cx(1),
43
+ borderBottomColor: props.theme?.textInput.line,
44
+ }}
45
+ >
46
+ <Text style={{
47
+ fontSize: cx(16),
48
+ textAlign: 'center',
49
+ flex: 1,
50
+ color: props.theme?.textInput.fontColor,
51
+ fontFamily: 'helvetica_neue_lt_std_roman',
52
+ }}>{state.dateType}</Text>
53
+ </View>
54
+ </TouchableOpacity>
55
+
56
+ <Modal.List
57
+ type={'radio'}
58
+ visible={state.showDateTypeModal}
59
+ value={state.dateType}
60
+ dataSource={[
61
+ {
62
+ title: I18n.getLang('day'),
63
+ key: DateType.Day,
64
+ value: DateType.Day,
65
+ },
66
+ {
67
+ title: I18n.getLang('month'),
68
+ key: DateType.Month,
69
+ value: DateType.Month,
70
+ },
71
+ {
72
+ title: I18n.getLang('year'),
73
+ key: DateType.Year,
74
+ value: DateType.Year,
75
+ }
76
+ ]}
77
+ onCancel={() => {
78
+ state.showDateTypeModal = false;
79
+ }}
80
+ title={I18n.getLang('date_type')}
81
+ cancelText={I18n.getLang('auto_scan_system_cancel')}
82
+ confirmText={I18n.getLang('auto_scan_system_wifi_confirm')}
83
+ onConfirm={(item: DateType) => {
84
+ state.showDateTypeModal = false;
85
+ props.onDateTypeChange(item)
86
+ }}
87
+ />
88
+ </View>)
89
+ })
@@ -0,0 +1,141 @@
1
+ import React, {useRef} from 'react';
2
+ import {View} from 'react-native';
3
+ import ECharts from '@ledvance/react-native-echarts-pro';
4
+ import I18n from "@ledvance/base/src/i18n";
5
+ import ThemeType from "@ledvance/base/src/config/themeType";
6
+ import {Utils} from "tuya-panel-kit";
7
+ import {OverviewItem} from "../EnergyConsumptionPage";
8
+
9
+ const {withTheme} = Utils.ThemeUtils
10
+
11
+ interface BarChartProps {
12
+ theme?: ThemeType
13
+ data: OverviewItem[],
14
+ price: number,
15
+ unit: string,
16
+ height: number
17
+ }
18
+
19
+ const BarChartWithTouch = (props: BarChartProps) => {
20
+ const echarts = useRef();
21
+ const {data, height, price, unit, theme} = props;
22
+ const dataX = data?.map(item => {
23
+ return item.chartTitle;
24
+ });
25
+ const dataKwhY = data?.map(item => {
26
+ return Number(item.value);
27
+ });
28
+ const dataPriceY = data?.map(item => {
29
+ return ((isNaN(Number(item.value)) ? 0 : Number(item.value)) * price).toFixed(2);
30
+ });
31
+ const maxValue = Math.max(...dataKwhY);
32
+ const option = {
33
+ tooltip: {
34
+ show: true,
35
+ triggerOn: 'click',
36
+ trigger: 'axis',
37
+ },
38
+ legend: {
39
+ show: true,
40
+ data: ['kWh', unit],
41
+ textStyle: {
42
+ color: theme?.global.fontColor,
43
+ }
44
+ },
45
+ xAxis: {
46
+ data: dataX,
47
+ axisTick: {
48
+ show: false,
49
+ },
50
+ axisLabel: {
51
+ show: true,
52
+ color: props.theme?.global.secondFontColor,
53
+ interval: 0,
54
+ }
55
+ },
56
+ yAxis: [{
57
+ type: 'value',
58
+ name: I18n.getLang('consumption_data_annual_bar_chart_text'),
59
+ max: Math.ceil(maxValue),
60
+ min: 0,
61
+ position: 'left',
62
+ axisLabel: {
63
+ formatter: function (value) {
64
+ return parseFloat(value).toFixed(2);
65
+ },
66
+ color:props.theme?.global.secondFontColor,
67
+ },
68
+ nameTextStyle: {
69
+ fontSize: 14,
70
+ color: props.theme?.global.secondFontColor,
71
+ },
72
+ }, {
73
+ type: 'value',
74
+ name: I18n.formatValue('format_unit', unit),
75
+ position: 'right',
76
+ alignTicks: true,
77
+ max: Math.ceil(price ? maxValue * price * 1.4 : 0),
78
+ min: 0,
79
+ minInterval: 1,
80
+ axisLabel: {
81
+ formatter: function (value) {
82
+ return parseFloat(value).toFixed(1);
83
+ },
84
+ color:props.theme?.global.secondFontColor,
85
+ },
86
+ nameTextStyle: {
87
+ fontSize: 14,
88
+ color: props.theme?.global.secondFontColor,
89
+ },
90
+ }],
91
+ series: [
92
+ {
93
+ name: 'kWh',
94
+ type: 'bar',
95
+ data: dataKwhY,
96
+ itemStyle: {
97
+ emphasis: {
98
+ color: '#FFC2A9', // Color when bar is clicked
99
+ },
100
+ color: '#FFC2A9',
101
+ borderRadius: 2,
102
+ },
103
+ barMaxWidth: 10,
104
+ select: {
105
+ itemStyle: {
106
+ borderColor: '#FFC2A9',
107
+ }
108
+ },
109
+ selectedMode: 'single',
110
+ },
111
+ {
112
+ name: unit,
113
+ type: 'line',
114
+ data: dataPriceY,
115
+ yAxisIndex: 1,
116
+ smooth: true,
117
+ showSymbol: false,
118
+ color: '#F49431',
119
+ selectedMode: "single",
120
+ }
121
+ ],
122
+ dataZoom: {
123
+ start: 0,
124
+ type: "inside",
125
+ maxValueSpan: 5,
126
+ zoomLock: true,
127
+ },
128
+ customMapData: {}
129
+ };
130
+ return (
131
+ <View style={{flex: 1}}>
132
+ <ECharts
133
+ option={option}
134
+ ref={echarts}
135
+ height={height}
136
+ />
137
+ </View>
138
+ );
139
+ };
140
+
141
+ export default withTheme(BarChartWithTouch)