@ledvance/group-ui-biz-bundle 1.0.159 → 1.0.161

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.159",
7
+ "version": "1.0.161",
8
8
  "scripts": {},
9
9
  "dependencies": {
10
10
  "@ledvance/base": "^1.x",
@@ -0,0 +1,108 @@
1
+ import React, { useState } from "react";
2
+ import ThemeType from "@ledvance/base/src/config/themeType";
3
+ import { parseMinutes, PriceSegment } from "./component/EnergyModal";
4
+ import { Utils } from 'tuya-panel-kit'
5
+ import { StyleSheet } from "react-native";
6
+ import {exchangeNumber} from "@ledvance/base/src/utils/common";
7
+
8
+ export const useEditPriceSegment = (segment: PriceSegment | undefined,
9
+ onSegmentSet: (s: PriceSegment) => void, theme?: ThemeType,) => {
10
+ const cx = Utils.RatioUtils.convertX
11
+ const startMin = segment?.startMinute ?? 0;
12
+ const endMin = segment?.endMinute ?? 0;
13
+
14
+ const startTime = parseMinutes(startMin);
15
+ const endTime = parseMinutes(endMin);
16
+
17
+ const [priceStr, setPriceStr] = useState<string>(() => {
18
+ if (segment?.price === undefined) {
19
+ return '0';
20
+ }
21
+ return segment.price.toString();
22
+ });
23
+
24
+ const handleTimeChange = (type: 'startHour' | 'startMinute' | 'endHour' | 'endMinute', value: string) => {
25
+ let startH = Math.floor(startMin / 60);
26
+ let startM = startMin % 60;
27
+ let endH = Math.floor(endMin / 60);
28
+ let endM = endMin % 60;
29
+
30
+ const intVal = parseInt(value, 10) || 0;
31
+ if (type === 'startHour') startH = intVal;
32
+ if (type === 'startMinute') startM = intVal;
33
+ if (type === 'endHour') endH = intVal;
34
+ if (type === 'endMinute') endM = intVal;
35
+
36
+ const updatedSegment: PriceSegment = {
37
+ ...(segment ?? {}),
38
+ startMinute: startH * 60 + startM,
39
+ endMinute: endH * 60 + endM,
40
+ } as PriceSegment;
41
+
42
+ onSegmentSet(updatedSegment);
43
+ };
44
+
45
+ const handlePriceChange = (t: string) => {
46
+ const cleaned = exchangeNumber(t)
47
+ const parsed = parseFloat(cleaned);
48
+ let numericVal = isNaN(parsed) ? 0 : parsed;
49
+ if (numericVal > 999999) {
50
+ numericVal = 999999;
51
+ setPriceStr('999999');
52
+ } else {
53
+ setPriceStr(t);
54
+ }
55
+
56
+ onSegmentSet({
57
+ ...(segment ?? {}),
58
+ price: numericVal
59
+ } as PriceSegment);
60
+ };
61
+
62
+ const style = StyleSheet.create({
63
+ timerHeader: {
64
+ fontSize: cx(16),
65
+ fontWeight: 'bold',
66
+ color: theme?.global.fontColor,
67
+ },
68
+ timerDivider: {
69
+ fontSize: cx(20),
70
+ fontWeight: 'bold',
71
+ color: theme?.global.fontColor, paddingTop: cx(16),
72
+ },
73
+ inputCardViewContainer: {
74
+ flexDirection: 'row',
75
+ paddingHorizontal: cx(16),
76
+ paddingVertical: cx(8),
77
+ alignItems: 'center',
78
+ justifyContent: 'space-between',
79
+ },
80
+ inputSecondaryContainer: {
81
+ flexDirection: 'row',
82
+ borderRadius: cx(4),
83
+ backgroundColor: theme?.textInput.background,
84
+ alignItems: 'center',
85
+ flex: 0.4,
86
+ },
87
+ textInput: {
88
+ height: cx(44),
89
+ marginStart: cx(16),
90
+ marginEnd: cx(6),
91
+ fontSize: cx(16),
92
+ color: theme?.textInput.fontColor,
93
+ flex:1,
94
+ },
95
+ textInputSpacer: {
96
+ height: 1,
97
+ position: 'absolute',
98
+ start: cx(4),
99
+ end: cx(4),
100
+ bottom: 0,
101
+ backgroundColor: theme?.textInput.line,
102
+ }
103
+
104
+ })
105
+ return {
106
+ style, startTime, endTime, currentPrice: priceStr, handleTimeChange, handlePriceChange,
107
+ }
108
+ }
@@ -0,0 +1,89 @@
1
+ import React, { } from 'react';
2
+ import ThemeType from "@ledvance/base/src/config/themeType";
3
+ import { PriceSegment } from "./component/EnergyModal";
4
+ import { Utils } from 'tuya-panel-kit'
5
+ import { Text, TextInput, View } from "react-native";
6
+ import Spacer from '@ledvance/base/src/components/Spacer';
7
+ import Card from '@ledvance/base/src/components/Card';
8
+ import LdvPickerView from '@ledvance/base/src/components/LdvPickerView';
9
+ import I18n from '@ledvance/base/src/i18n';
10
+ import { useEditPriceSegment } from './EditPriceSegmentContract';
11
+
12
+ const { withTheme } = Utils.ThemeUtils
13
+ const cx = Utils.RatioUtils.convertX
14
+
15
+ const EditPriceSegmentScreen = (props: EditPriceProps) => {
16
+ const {style, startTime, endTime, currentPrice, handleTimeChange, handlePriceChange } = useEditPriceSegment(
17
+ props.segment,
18
+ props.onSegmentSet,
19
+ props.theme,
20
+ )
21
+ return (
22
+ <View >
23
+ <Spacer />
24
+ {/* Timer Picker */}
25
+ <View style={{ flexDirection: 'row' }}>
26
+ {/* Start Time */}
27
+ <View style={{ flex: 0.45, alignItems: 'center' }}>
28
+ <Text style={style.timerHeader}>{I18n.getLang('add_randomtimecycle_timestart_topic')}</Text>
29
+ <LdvPickerView
30
+ hour={startTime.hour}
31
+ minute={startTime.minute}
32
+ setHour={(hour) => {
33
+ handleTimeChange('startHour', hour)
34
+ }}
35
+ setMinute={(minute) => {
36
+ handleTimeChange('startMinute', minute)
37
+ }}
38
+ minuteLoop={false}
39
+ minutesStep={30}
40
+ />
41
+ </View>
42
+ {/* Divider */}
43
+ <View style={{ flex: 0.1, justifyContent: 'center', alignItems: 'center' }}>
44
+ <Text style={style.timerDivider}>-</Text>
45
+ </View>
46
+ {/* End Time */}
47
+ <View style={{ flex: 0.45, alignItems: 'center' }}>
48
+ <Text style={style.timerHeader}>{I18n.getLang('add_randomtimecycle_timeend_topic')}</Text>
49
+ <LdvPickerView
50
+ hour={endTime.hour}
51
+ minute={endTime.minute}
52
+ setHour={(hour) => {
53
+ handleTimeChange('endHour', hour)
54
+ }}
55
+ setMinute={(minute) => {
56
+ handleTimeChange('endMinute', minute)
57
+ }}
58
+ minuteLoop={false}
59
+ minutesStep={30}
60
+ isAdd59MinsWhen23Clock={true}
61
+ />
62
+ </View>
63
+ </View>
64
+ <Spacer />
65
+ {/* Price Input */}
66
+ <Card style={{ elevation: cx(1) }}
67
+ containerStyle={style.inputCardViewContainer}>
68
+ <Text style={style.timerHeader}>{I18n.getLang('consumption_data_price_per_kwh_headline_text')}</Text>
69
+ <View style={style.inputSecondaryContainer}>
70
+ <TextInput
71
+ value={currentPrice.toString()}
72
+ onChangeText={handlePriceChange}
73
+ style={style.textInput}
74
+ keyboardType="numeric"
75
+ />
76
+ <View style={style.textInputSpacer} />
77
+ </View>
78
+ </Card>
79
+ </View>
80
+ )
81
+
82
+ }
83
+
84
+ export default withTheme(EditPriceSegmentScreen)
85
+ export interface EditPriceProps {
86
+ segment?: PriceSegment,
87
+ theme?: ThemeType,
88
+ onSegmentSet: (segment: PriceSegment) => void,
89
+ }
@@ -11,16 +11,22 @@ import { DateType } from "./co2Data";
11
11
  import { OverviewItem } from "./EnergyConsumptionPage";
12
12
  import dayjs from "dayjs";
13
13
  import { isNumber } from "lodash";
14
- import { EnergyData, UnitList } from "./component/EnergyModal";
14
+ import {DynamicEnergyData, EnergyData, PriceSegment, UnitList} from "./component/EnergyModal";
15
15
  import {NativeApi} from "@ledvance/base/src/api/native";
16
16
  import {xLog, retryWithBackoff} from "@ledvance/base/src/utils"
17
17
 
18
18
  interface LightConfig {
19
19
  energyConsumption?: EnergyData
20
+ dynamicenergyprice?: DynamicEnergyData
20
21
  }
21
22
 
22
23
  export const useEnergyConsumption = () => {
23
- return useGroupEzvizConfig<LightConfig, EnergyData>('energyConsumption', { unit: UnitList[0], price: '' })
24
+ return useGroupEzvizConfig<LightConfig, EnergyData>('energyConsumption',
25
+ { unit: UnitList[0], price: '' , energyType: 'fixed', generatePrice:''})
26
+ }
27
+ export const useDynamicPrice = () => {
28
+ return useGroupEzvizConfig<LightConfig, DynamicEnergyData>('dynamicenergyprice',
29
+ {intervalPrices: [] as PriceSegment[], generatePrices: [] as PriceSegment[]})
24
30
  }
25
31
 
26
32
  export const unitDivision = (str: string) => {
@@ -4,11 +4,12 @@ import { Image, TouchableOpacity, View } from 'react-native'
4
4
  import { DateType } from '../co2Data'
5
5
  import DateTypeItem from '../component/DateTypeItem'
6
6
  import DateSwitch from '../component/DateSwitch'
7
- import NewBarChart from '../component/NewBarChart'
7
+ import NewBarChart, { calculateIntervalAveragePrice } from '../component/NewBarChart'
8
8
  import { EmptyDataView } from './EmptyDataView'
9
9
  import { exportEnergyCsv } from '../EnergyConsumptionActions'
10
10
  import { Utils } from 'tuya-panel-kit'
11
11
  import res from '@ledvance/base/src/res'
12
+ import { calculateAveragePrice } from '../component/EnergyModal'
12
13
 
13
14
  const { convertX: cx } = Utils.RatioUtils
14
15
 
@@ -42,6 +43,27 @@ export const ChartSection = ({ isLandscape, state, actions, params, styles, them
42
43
  const rows = []
43
44
  let i = 0 // 指向 consumedData 的指针
44
45
  let j = 0 // 指向 generatedData 的指针
46
+
47
+ const getDynamicPrice = (key: string, isGen: boolean) => {
48
+ let itemPrice = Number(price);
49
+ if (params.energyType === 'dynamic' && params.dynamicData) {
50
+ const intervals = isGen ? params.dynamicData.generatePrices : params.dynamicData.intervalPrices;
51
+ if (intervals && intervals.length > 0) {
52
+ if (state.dateType === DateType.Day) {
53
+ const hour = parseInt(key.split(':')[0]);
54
+ if (!isNaN(hour)) {
55
+ itemPrice = calculateIntervalAveragePrice(intervals, hour * 60, (hour + 1) * 60);
56
+ } else {
57
+ itemPrice = calculateAveragePrice(intervals);
58
+ }
59
+ } else {
60
+ itemPrice = calculateAveragePrice(intervals);
61
+ }
62
+ }
63
+ }
64
+ return itemPrice;
65
+ }
66
+
45
67
  // 2. 双指针合并算法
46
68
  while (i < consumedData.length || j < generatedData.length) {
47
69
  const consumedItem = consumedData[i]
@@ -55,10 +77,12 @@ export const ChartSection = ({ isLandscape, state, actions, params, styles, them
55
77
  const consumedValue = Number(consumedItem.value)
56
78
  const generatedValue = Number(generatedItem.value)
57
79
  if (displayMode === 'consumption' || displayMode === 'both') {
58
- rowData.push(consumedValue.toFixed(2), (consumedValue * price).toFixed(2))
80
+ const itemPrice = getDynamicPrice(consumedKey, false)
81
+ rowData.push(consumedValue.toFixed(2), (consumedValue * itemPrice).toFixed(2))
59
82
  }
60
83
  if (displayMode === 'generation' || displayMode === 'both') {
61
- rowData.push(generatedValue.toFixed(2), (generatedValue * price).toFixed(2))
84
+ const itemPrice = getDynamicPrice(generatedKey, true)
85
+ rowData.push(generatedValue.toFixed(2), (generatedValue * itemPrice).toFixed(2))
62
86
  }
63
87
  i++
64
88
  j++
@@ -66,7 +90,8 @@ export const ChartSection = ({ isLandscape, state, actions, params, styles, them
66
90
  dateKey = consumedItem.key
67
91
  const consumedValue = Number(consumedItem.value)
68
92
  if (displayMode === 'consumption' || displayMode === 'both') {
69
- rowData.push(consumedValue.toFixed(2), (consumedValue * price).toFixed(2))
93
+ const itemPrice = getDynamicPrice(consumedKey, false)
94
+ rowData.push(consumedValue.toFixed(2), (consumedValue * itemPrice).toFixed(2))
70
95
  }
71
96
  if (displayMode === 'generation' || displayMode === 'both') {
72
97
  // 在 'generation' 或 'both' 模式下,为缺失的产生数据补0
@@ -81,7 +106,8 @@ export const ChartSection = ({ isLandscape, state, actions, params, styles, them
81
106
  rowData.push('0.00', '0.00')
82
107
  }
83
108
  if (displayMode === 'generation' || displayMode === 'both') {
84
- rowData.push(generatedValue.toFixed(2), (generatedValue * price).toFixed(2))
109
+ const itemPrice = getDynamicPrice(generatedKey, true)
110
+ rowData.push(generatedValue.toFixed(2), (generatedValue * itemPrice).toFixed(2))
85
111
  }
86
112
  j++
87
113
  }
@@ -91,7 +117,7 @@ export const ChartSection = ({ isLandscape, state, actions, params, styles, them
91
117
  }
92
118
 
93
119
  exportEnergyCsv(header, rows)
94
- }, [state.displayMode, state.consumptionChartData, state.generationChartData, params.price, params.unit])
120
+ }, [state.displayMode, state.consumptionChartData, state.generationChartData, params.price, params.unit, params.energyType, params.dynamicData, state.dateType])
95
121
 
96
122
  const isDataEmpty = state.consumptionChartData.length <= 0 && state.generationChartData.length <= 0
97
123
 
@@ -133,6 +159,9 @@ export const ChartSection = ({ isLandscape, state, actions, params, styles, them
133
159
  generatedData={state.generationChartData}
134
160
  price={state.price}
135
161
  unit={params.unit}
162
+ energyType={params.energyType}
163
+ dynamicData={params.dynamicData}
164
+ dateType={state.dateType}
136
165
  />
137
166
  </>
138
167
  )}
@@ -27,14 +27,20 @@ import {
27
27
  monthFormat,
28
28
  monthFormatShort,
29
29
  } from '@ledvance/base/src/utils/common';
30
- import {getEnergyGenerationValue, unitDivision, useEnergyConsumption} from './EnergyConsumptionActions';
31
- import EnergyPopup, { EnergyData } from './component/EnergyModal';
30
+ import {
31
+ getEnergyGenerationValue,
32
+ unitDivision,
33
+ useDynamicPrice,
34
+ useEnergyConsumption
35
+ } from './EnergyConsumptionActions';
36
+ import EnergyPopup, {EnergyData, EnergyType, calculateAveragePrice, PriceSegment, DynamicEnergyData} from './component/EnergyModal';
32
37
  import { carbonDioxideEmission, countryAndRegion } from './co2Data';
33
38
  import { EnergyConsumptionDetailProps } from './EnergyConsumptionDetail';
34
39
  import { EnergyConsumptionChartProps } from './EnergyConsumptionChart';
35
40
  import SegmentControl from '@ledvance/base/src/components/segmentControl';
36
41
  import ThemeType from '@ledvance/base/src/config/themeType'
37
42
  import { exportEnergyCsv } from "./EnergyConsumptionActions";
43
+ import { SetSegmentedPricesParams } from './SetSegmentedPricesScreen';
38
44
 
39
45
  const { convertX: cx } = Utils.RatioUtils;
40
46
  const { withTheme } = Utils.ThemeUtils;
@@ -71,6 +77,7 @@ interface EnergyConsumptionState {
71
77
  popupType: PopupType;
72
78
  co2Saved: string;
73
79
  isSolarMode: boolean
80
+ pricingType: EnergyType,
74
81
  loading: boolean
75
82
  collapsed: boolean
76
83
  }
@@ -80,6 +87,36 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
80
87
  const navigation = useNavigation();
81
88
  const timeZoneCity = useTimeZoneCity();
82
89
  const [energyData, setEnergyData] = useEnergyConsumption()
90
+ const [dynamicData, setDynamicData] = useDynamicPrice()
91
+
92
+ const parsePrice = (dynamicCosts: PriceSegment[], dynamicGenerates: PriceSegment[], fixedModel?: any): string => {
93
+ const type = fixedModel?.energyType ?? 'fixed'
94
+ const usingPrice = state.isSolarMode ? (fixedModel?.generatePrice ?? fixedModel?.price) : fixedModel?.price;
95
+ if (type === 'dynamic') {
96
+ const usingIntervals = state.isSolarMode ? dynamicGenerates : dynamicCosts;
97
+ const dynamicPrice = usingIntervals && usingIntervals.length > 0
98
+ ? String(calculateAveragePrice(usingIntervals))
99
+ : usingPrice;
100
+ return String(dynamicPrice ?? '0');
101
+ } else {
102
+ return String(usingPrice ?? '0');
103
+ }
104
+ }
105
+
106
+ const initialPrice = useMemo(() => {
107
+ const type = energyData.energyType ?? 'fixed'
108
+ const usingPrice = !params.wifiPlugGroup.length ? (energyData.generatePrice ?? energyData.price) : energyData.price;
109
+ if (type === 'dynamic') {
110
+ const usingIntervals = !params.wifiPlugGroup.length ? (dynamicData?.generatePrices || []) : (dynamicData?.intervalPrices || []);
111
+ const dynamicPrice = usingIntervals && usingIntervals.length > 0
112
+ ? String(calculateAveragePrice(usingIntervals))
113
+ : usingPrice;
114
+ return String(dynamicPrice ?? '0');
115
+ } else {
116
+ return String(usingPrice ?? '0');
117
+ }
118
+ }, [energyData, dynamicData, params.wifiPlugGroup.length])
119
+
83
120
  const state = useReactive<EnergyConsumptionState>({
84
121
  solarTodayElectricity: '0',
85
122
  solarTotalElectricity: '0',
@@ -87,8 +124,9 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
87
124
  wifiTotalElectricity: '0',
88
125
  solarOverviewList: [],
89
126
  wifiOverviewList: [],
90
- price: energyData.price,
127
+ price: initialPrice,
91
128
  unit: energyData.unit,
129
+ pricingType: energyData.energyType ?? "fixed",
92
130
  showPopup: false,
93
131
  popupType: '',
94
132
  co2Saved: '0',
@@ -98,9 +136,11 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
98
136
  });
99
137
 
100
138
  useUpdateEffect(() => {
101
- state.price = energyData.price
139
+ state.pricingType = energyData.energyType ?? 'fixed'
140
+ state.price = parsePrice(dynamicData?.intervalPrices || [], dynamicData?.generatePrices || [], energyData)
102
141
  state.unit = energyData.unit
103
- }, [JSON.stringify(energyData)])
142
+ actions.setPriceAndUnit(state.price, state.unit)
143
+ }, [JSON.stringify(energyData), JSON.stringify(dynamicData), state.isSolarMode])
104
144
 
105
145
  const chartHeadline = useMemo(() => {
106
146
  const overview = state.isSolarMode ? state.solarOverviewList : state.wifiOverviewList
@@ -123,8 +163,10 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
123
163
  displayMode: state.isSolarMode ? 'generation' : 'consumption',
124
164
  consumptionDeviceIds: params.wifiPlugGroup,
125
165
  generationDeviceIds: params.solarPlugGroup,
166
+ energyType: state.pricingType,
167
+ dynamicData: dynamicData,
126
168
  }
127
- }, [backTitle, chartHeadline, state.price, state.unit, params.addEleDpCode, state.isSolarMode, params.wifiPlugGroup, params.solarPlugGroup])
169
+ }, [backTitle, chartHeadline, state.price, state.unit, params.addEleDpCode, state.isSolarMode, params.wifiPlugGroup, params.solarPlugGroup, state.pricingType, dynamicData])
128
170
 
129
171
  const { state: chartState, actions } = useEnergyData(chartParams);
130
172
  const chartStyles = useMemo(() => getStyles(props.theme), [props.theme]);
@@ -226,10 +268,18 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
226
268
  }
227
269
 
228
270
  const updateEnergyData = (data: EnergyData) => {
229
- setEnergyData(data).then()
230
- state.price = data.price;
231
- state.unit = data.unit;
232
- actions.setPriceAndUnit(data.price, data.unit)
271
+ const internationalPrice = exchangeNumber(data.price)
272
+ const newEnergyData = {
273
+ ...energyData,
274
+ unit: data.unit,
275
+ energyType: 'fixed',
276
+ [state.isSolarMode ? 'generatePrice' : 'price']: internationalPrice,
277
+ }
278
+ setEnergyData(newEnergyData).then()
279
+ state.price = internationalPrice || '0'
280
+ state.unit = data.unit
281
+ state.pricingType = 'fixed'
282
+ actions.setPriceAndUnit(state.price, data.unit)
233
283
  };
234
284
 
235
285
  const backTitle = useMemo(() => {
@@ -336,6 +386,7 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
336
386
  (params.solarPlugGroup.length && params.wifiPlugGroup.length) ?
337
387
  <View style={{ marginBottom: cx(5) }}>
338
388
  <SegmentControl
389
+ marginHorizontal={cx(0)}
339
390
  title1={I18n.getLang('consumption_data_annual_bar_chart_system_back_text')}
340
391
  title2={I18n.getLang('sockets_headline_power')}
341
392
  isFirst={!state.isSolarMode}
@@ -404,6 +455,41 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
404
455
  </View>
405
456
  </Card>
406
457
  <Spacer />
458
+ {/* pricing radio button*/}
459
+ <View style={{ marginBottom: cx(5) }}>
460
+ <SegmentControl
461
+ marginHorizontal={cx(0)}
462
+ title1={I18n.getLang('consumption_energy_type_fixed')}
463
+ title2={I18n.getLang('consumption_energy_type_dynamic')}
464
+ isFirst={state.pricingType === 'fixed'}
465
+ tabStyle={{paddingHorizontal: cx(15)}}
466
+ setIsFirst={(v) => {
467
+ const value = v ? 'fixed' : 'dynamic'
468
+ const fixedModel = energyData ?? {
469
+ price: '0',
470
+ unit: '$',
471
+ energyType: 'fixed',
472
+ generatePrice: '0',
473
+ }
474
+ state.loading = true
475
+ setEnergyData({
476
+ ...fixedModel,
477
+ energyType: value,
478
+ }).then((res) => {
479
+ state.loading = false
480
+ if (res && res.success) {
481
+ state.pricingType = value
482
+ if (value === 'fixed') {
483
+ state.price = state.isSolarMode ? (fixedModel.generatePrice || fixedModel.price) : fixedModel.price
484
+ } else {
485
+ const segments = state.isSolarMode ? (dynamicData?.generatePrices || []) : (dynamicData?.intervalPrices || [])
486
+ state.price = String(calculateAveragePrice(segments))
487
+ }
488
+ actions.setPriceAndUnit(state.price, state.unit)
489
+ }
490
+ })
491
+ }} />
492
+ </View>
407
493
  {/* 365 day */}
408
494
  <Card style={styles.cardContainer}>
409
495
  <View style={{ flexDirection: 'row', alignItems: 'center' }}>
@@ -503,11 +589,11 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
503
589
  : '-'}
504
590
  </Text>
505
591
  </View>
506
- <TouchableOpacity
507
- onPress={() => {
508
- state.showPopup = true;
509
- state.popupType = 'money';
510
- }}
592
+ {state.pricingType === 'fixed' &&<TouchableOpacity
593
+ onPress={() => {
594
+ state.showPopup = true;
595
+ state.popupType = 'money';
596
+ }}
511
597
  >
512
598
  <View style={styles.priceButton}>
513
599
  <Text style={{ color: props.theme?.button.fontColor }}>
@@ -515,6 +601,56 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
515
601
  </Text>
516
602
  </View>
517
603
  </TouchableOpacity>
604
+ }
605
+ {state.pricingType === 'dynamic' && (
606
+ <TouchableOpacity
607
+ onPress={() => {
608
+ navigation.navigate(ui_biz_routerKey.group_ui_biz_set_segmented_prices, {
609
+ backTitle: backTitle,
610
+ dynamicData: dynamicData ?? {
611
+ intervalPrices: [],
612
+ generatePrices: [],
613
+ },
614
+ priceUnit: state.unit,
615
+ isGenerate: state.isSolarMode,
616
+ onSetPriceSements: async (segments: PriceSegment[], currency: string): Promise<boolean> => {
617
+ console.log("onSetPriceSements ", JSON.stringify(segments), currency)
618
+ const fixedModel = energyData ?? {
619
+ price: '0',
620
+ unit: '$',
621
+ energyType: 'fixed',
622
+ generatePrice: '0',
623
+ }
624
+ const dynamicModel = {
625
+ ...dynamicData,
626
+ [state.isSolarMode ? 'generatePrices' : 'intervalPrices']: segments
627
+ }
628
+ const [fixedRes, dynamicRes] = await Promise.all([
629
+ setEnergyData({ ...fixedModel, energyType: 'dynamic', unit: currency }),
630
+ setDynamicData(dynamicModel)
631
+ ])
632
+ const isDynamicSuccess = dynamicRes && dynamicRes.success
633
+ const isRegularSuccess = fixedRes && fixedRes.success
634
+ const isAllSuccess = isDynamicSuccess && isRegularSuccess
635
+ if (isAllSuccess) {
636
+ state.price = String(calculateAveragePrice(segments)) // 价格
637
+ state.pricingType = 'dynamic'
638
+ state.unit = currency
639
+ actions.setPriceAndUnit(state.price, currency)
640
+ }
641
+ return !!isAllSuccess
642
+ }
643
+ } as SetSegmentedPricesParams)
644
+ }}
645
+ >
646
+ <View style={styles.priceButton}>
647
+ <Text style={{ color: props.theme?.button.fontColor }}>
648
+ {I18n.getLang('consumption_data_field_dynamic_money')}
649
+ </Text>
650
+ </View>
651
+ </TouchableOpacity>
652
+ )}
653
+
518
654
  </View>
519
655
  </View>
520
656
  </Card>
@@ -581,15 +717,12 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
581
717
  ? 'home_screen_home_dialog_yes_con'
582
718
  : 'auto_scan_system_wifi_confirm'
583
719
  )}
584
- energyData={{ price: state.price, unit: state.unit }}
720
+ energyData={{ price: state.popupType === 'money' ? (state.isSolarMode ? (energyData?.generatePrice ?? '0') : (energyData?.price ?? '0')) : state.price, unit: state.unit }}
585
721
  onConfirm={energyData => {
586
722
  state.popupType = '';
587
723
  state.showPopup = false;
588
724
  if (energyData) {
589
- updateEnergyData({
590
- ...energyData,
591
- price: exchangeNumber(energyData.price),
592
- });
725
+ updateEnergyData(energyData);
593
726
  }
594
727
  }}
595
728
  onCancel={() => {
@@ -2,6 +2,7 @@ import {NavigationRoute} from "tuya-panel-kit";
2
2
  import EnergyConsumptionPage from "./EnergyConsumptionPage";
3
3
  import EnergyConsumptionDetail from "./EnergyConsumptionDetail";
4
4
  import EnergyConsumptionChart from "./EnergyConsumptionChart/index";
5
+ import SetSegmentedPricesScreen from "./SetSegmentedPricesScreen";
5
6
  import {ui_biz_routerKey} from "../../navigation/Routers";
6
7
 
7
8
  const EnergyConsumptionPageRouters: NavigationRoute[] = [
@@ -29,6 +30,14 @@ const EnergyConsumptionPageRouters: NavigationRoute[] = [
29
30
  showOfflineView: false,
30
31
  }
31
32
  },
33
+ {
34
+ name: ui_biz_routerKey.group_ui_biz_set_segmented_prices,
35
+ component: SetSegmentedPricesScreen,
36
+ options:{
37
+ hideTopbar: true,
38
+ showOfflineView: false,
39
+ }
40
+ },
32
41
  ]
33
42
 
34
43
  export default EnergyConsumptionPageRouters