@ledvance/ui-biz-bundle 1.1.167 → 1.1.169
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 +1 -1
- package/src/navigation/Routers.ts +1 -0
- package/src/newModules/biorhythm/BiorhythmPage.tsx +1 -0
- package/src/newModules/energyConsumption/EditPriceSegmentContract.tsx +89 -0
- package/src/newModules/energyConsumption/EditPriceSegmentScreen.tsx +89 -0
- package/src/newModules/energyConsumption/EnergyConsumptionActions.ts +5 -1
- package/src/newModules/energyConsumption/EnergyConsumptionChart/EnergyChartSection.tsx +33 -5
- package/src/newModules/energyConsumption/EnergyConsumptionPage.tsx +228 -117
- package/src/newModules/energyConsumption/Router.ts +9 -0
- package/src/newModules/energyConsumption/SetSegmentPricesContract.tsx +423 -0
- package/src/newModules/energyConsumption/SetSegmentedPricesScreen.tsx +189 -0
- package/src/newModules/energyConsumption/component/DateSelectedItem.tsx +3 -1
- package/src/newModules/energyConsumption/component/DateSwitch.tsx +9 -3
- package/src/newModules/energyConsumption/component/EnergyModal.tsx +66 -5
- package/src/newModules/energyConsumption/component/NewBarChart.tsx +63 -5
- package/src/newModules/energyConsumption/component/VerticalDailyPricesIndicator.tsx +175 -0
package/package.json
CHANGED
|
@@ -49,4 +49,5 @@ export const ui_biz_routerKey = {
|
|
|
49
49
|
'ui_biz_switch_gradient': 'ui_biz_switch_gradient',
|
|
50
50
|
'ui_biz_diy_scene_page': 'ui_biz_diy_scene_page',
|
|
51
51
|
'ui_biz_diy_scene_edit_page': 'ui_biz_diy_scene_edit_page',
|
|
52
|
+
'ui_biz_set_segmented_prices': 'ui_biz_set_segmented_prices',
|
|
52
53
|
}
|
|
@@ -250,6 +250,7 @@ const BiorhythmPage = (props: { theme?: ThemeType }) => {
|
|
|
250
250
|
title: I18n.getLang('biorhythm_save_title'),
|
|
251
251
|
placeholder: I18n.getLang('biorhythm_save_placeholder'),
|
|
252
252
|
defaultValue: `${deviceInfo.name}`,
|
|
253
|
+
maxLength: 32,
|
|
253
254
|
cancelText: I18n.getLang('auto_scan_system_cancel'),
|
|
254
255
|
confirmText: I18n.getLang('auto_scan_system_wifi_confirm'),
|
|
255
256
|
inputWrapperStyle: {backgroundColor: props.theme?.textInput.background, borderRadius: cx(10)},
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import ThemeType from "@ledvance/base/src/config/themeType";
|
|
2
|
+
import { parseMinutes, PriceSegment } from "./component/EnergyModal";
|
|
3
|
+
import { Utils } from 'tuya-panel-kit'
|
|
4
|
+
import { StyleSheet } from "react-native";
|
|
5
|
+
|
|
6
|
+
export const useEditPriceSegment = (segment: PriceSegment | undefined,
|
|
7
|
+
onSegmentSet: (s: PriceSegment) => void, theme?: ThemeType,) => {
|
|
8
|
+
const cx = Utils.RatioUtils.convertX
|
|
9
|
+
const startMin = segment?.startMinute ?? 0;
|
|
10
|
+
const endMin = segment?.endMinute ?? 0;
|
|
11
|
+
|
|
12
|
+
const startTime = parseMinutes(startMin);
|
|
13
|
+
const endTime = parseMinutes(endMin);
|
|
14
|
+
const currentPrice = segment?.price ?? 0
|
|
15
|
+
const handleTimeChange = (type: 'startHour' | 'startMinute' | 'endHour' | 'endMinute', value: string) => {
|
|
16
|
+
let startH = Math.floor(startMin / 60);
|
|
17
|
+
let startM = startMin % 60;
|
|
18
|
+
let endH = Math.floor(endMin / 60);
|
|
19
|
+
let endM = endMin % 60;
|
|
20
|
+
|
|
21
|
+
const intVal = parseInt(value, 10) || 0;
|
|
22
|
+
if (type === 'startHour') startH = intVal;
|
|
23
|
+
if (type === 'startMinute') startM = intVal;
|
|
24
|
+
if (type === 'endHour') endH = intVal;
|
|
25
|
+
if (type === 'endMinute') endM = intVal;
|
|
26
|
+
|
|
27
|
+
const updatedSegment: PriceSegment = {
|
|
28
|
+
...(segment ?? {}),
|
|
29
|
+
startMinute: startH * 60 + startM,
|
|
30
|
+
endMinute: endH * 60 + endM,
|
|
31
|
+
} as PriceSegment;
|
|
32
|
+
|
|
33
|
+
onSegmentSet(updatedSegment);
|
|
34
|
+
};
|
|
35
|
+
const handlePriceChange = (t: string) => {
|
|
36
|
+
const value = t.replace(/[^0-9.,]/g, '')
|
|
37
|
+
const tempPrice = Number(value)
|
|
38
|
+
const resultPrice = tempPrice > 999999 ? 999999 : tempPrice
|
|
39
|
+
onSegmentSet({
|
|
40
|
+
...(segment ?? {}),
|
|
41
|
+
price: resultPrice
|
|
42
|
+
} as PriceSegment)
|
|
43
|
+
}
|
|
44
|
+
const style = StyleSheet.create({
|
|
45
|
+
timerHeader: {
|
|
46
|
+
fontSize: cx(16),
|
|
47
|
+
fontWeight: 'bold',
|
|
48
|
+
color: theme?.global.fontColor,
|
|
49
|
+
},
|
|
50
|
+
timerDivider: {
|
|
51
|
+
fontSize: cx(20),
|
|
52
|
+
fontWeight: 'bold',
|
|
53
|
+
color: theme?.global.fontColor, paddingTop: cx(16),
|
|
54
|
+
},
|
|
55
|
+
inputCardViewContainer: {
|
|
56
|
+
flexDirection: 'row',
|
|
57
|
+
paddingHorizontal: cx(16),
|
|
58
|
+
paddingVertical: cx(8),
|
|
59
|
+
alignItems: 'center',
|
|
60
|
+
justifyContent: 'space-between',
|
|
61
|
+
},
|
|
62
|
+
inputSecondaryContainer: {
|
|
63
|
+
flexDirection: 'row',
|
|
64
|
+
borderRadius: cx(4),
|
|
65
|
+
backgroundColor: theme?.textInput.background,
|
|
66
|
+
alignItems: 'center',
|
|
67
|
+
flex: 0.4,
|
|
68
|
+
},
|
|
69
|
+
textInput: {
|
|
70
|
+
height: cx(44),
|
|
71
|
+
marginStart: cx(16),
|
|
72
|
+
marginEnd: cx(6),
|
|
73
|
+
fontSize: cx(16),
|
|
74
|
+
color: theme?.textInput.fontColor,
|
|
75
|
+
},
|
|
76
|
+
textInputSpacer: {
|
|
77
|
+
height: 1,
|
|
78
|
+
position: 'absolute',
|
|
79
|
+
start: cx(4),
|
|
80
|
+
end: cx(4),
|
|
81
|
+
bottom: 0,
|
|
82
|
+
backgroundColor: theme?.textInput.line,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
})
|
|
86
|
+
return {
|
|
87
|
+
style, startTime, endTime, currentPrice, handleTimeChange, handlePriceChange,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -15,7 +15,7 @@ import CustomParseFormat from 'dayjs/plugin/customParseFormat'
|
|
|
15
15
|
import { isEmpty } from 'lodash'
|
|
16
16
|
import { TYSdk } from 'tuya-panel-kit'
|
|
17
17
|
import { DateType } from './co2Data'
|
|
18
|
-
import { EnergyData } from './component/EnergyModal'
|
|
18
|
+
import { DynamicEnergyData, EnergyData } from './component/EnergyModal'
|
|
19
19
|
import { OverviewItem } from './EnergyConsumptionPage'
|
|
20
20
|
|
|
21
21
|
dayjs.extend(CustomParseFormat)
|
|
@@ -39,6 +39,10 @@ export async function updatePrice(devId: string, energyData: EnergyData) {
|
|
|
39
39
|
return await NativeApi.putJson(devId, 'energiepreise', JSON.stringify(energyData))
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
export async function updateDynamicPrice(devId: string, dynamicEnergyData: DynamicEnergyData) {
|
|
43
|
+
return await NativeApi.putJson(devId, 'dynamicenergyprice', JSON.stringify(dynamicEnergyData))
|
|
44
|
+
}
|
|
45
|
+
|
|
42
46
|
export async function resetElectricity(devId) {
|
|
43
47
|
const res = await TYSdk.apiRequest('tuya.m.dp.statistics.reset', {devId}, '1.0')
|
|
44
48
|
xLog('resetElectricity res', res)
|
|
@@ -6,9 +6,10 @@ import { Utils } from 'tuya-panel-kit'
|
|
|
6
6
|
import DateSwitch from '../component/DateSwitch'
|
|
7
7
|
import { DateType } from '../co2Data'
|
|
8
8
|
import DateTypeItem from '../component/DateTypeItem'
|
|
9
|
-
import NewBarChart from '../component/NewBarChart'
|
|
9
|
+
import NewBarChart, { calculateIntervalAveragePrice } from '../component/NewBarChart'
|
|
10
10
|
import { EmptyDataView } from './EmptyDataView'
|
|
11
11
|
import { exportEnergyCsv } from '../EnergyConsumptionActions'
|
|
12
|
+
import { calculateAveragePrice } from '../component/EnergyModal'
|
|
12
13
|
|
|
13
14
|
const { convertX: cx } = Utils.RatioUtils
|
|
14
15
|
|
|
@@ -26,9 +27,27 @@ export const EnergyChartSection = ({ isLandscape, state, actions, params, styles
|
|
|
26
27
|
const isDataEmpty = state.chartData.length <= 0
|
|
27
28
|
|
|
28
29
|
const handleExportCsv = useCallback(() => {
|
|
29
|
-
const values = state.chartData.map(item =>
|
|
30
|
+
const values = state.chartData.map(item => {
|
|
31
|
+
let itemPrice = Number(params.price);
|
|
32
|
+
if (params.energyType === 'dynamic' && params.dynamicData) {
|
|
33
|
+
const intervals = params.isGeneration ? params.dynamicData.generatePrices : params.dynamicData.intervalPrices;
|
|
34
|
+
if (intervals && intervals.length > 0) {
|
|
35
|
+
if (state.dateType === DateType.Day) {
|
|
36
|
+
const hour = parseInt(item.headlineText.split(':')[0]);
|
|
37
|
+
if (!isNaN(hour)) {
|
|
38
|
+
itemPrice = calculateIntervalAveragePrice(intervals, hour * 60, (hour + 1) * 60);
|
|
39
|
+
} else {
|
|
40
|
+
itemPrice = calculateAveragePrice(intervals);
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
itemPrice = calculateAveragePrice(intervals);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return [item.key, item.value, (itemPrice * Number(item.value)).toFixed(2)];
|
|
48
|
+
});
|
|
30
49
|
exportEnergyCsv(values, params.unit)
|
|
31
|
-
}, [state.chartData, params.price, params.unit])
|
|
50
|
+
}, [state.chartData, params.price, params.unit, params.energyType, params.dynamicData, params.isGeneration, state.dateType])
|
|
32
51
|
|
|
33
52
|
return (
|
|
34
53
|
<>
|
|
@@ -51,7 +70,7 @@ export const EnergyChartSection = ({ isLandscape, state, actions, params, styles
|
|
|
51
70
|
) : (
|
|
52
71
|
!state.loading && <>
|
|
53
72
|
{!isLandscape && <View style={styles.downloadContainer}>
|
|
54
|
-
|
|
73
|
+
<TouchableOpacity
|
|
55
74
|
style={{ width: cx(30) }}
|
|
56
75
|
onPress={handleExportCsv}>
|
|
57
76
|
<Image
|
|
@@ -59,7 +78,16 @@ export const EnergyChartSection = ({ isLandscape, state, actions, params, styles
|
|
|
59
78
|
source={{ uri: res.download_icon }}/>
|
|
60
79
|
</TouchableOpacity>
|
|
61
80
|
</View>}
|
|
62
|
-
<NewBarChart
|
|
81
|
+
<NewBarChart
|
|
82
|
+
height={chartHeight}
|
|
83
|
+
data={state.chartData}
|
|
84
|
+
price={state.price}
|
|
85
|
+
unit={params.unit}
|
|
86
|
+
energyType={params.energyType}
|
|
87
|
+
dynamicData={params.dynamicData}
|
|
88
|
+
isGeneration={params.isGeneration}
|
|
89
|
+
dateType={state.dateType}
|
|
90
|
+
/>
|
|
63
91
|
</>
|
|
64
92
|
)}
|
|
65
93
|
</>
|