@ledvance/group-ui-biz-bundle 1.0.130 → 1.0.132

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.130",
7
+ "version": "1.0.132",
8
8
  "scripts": {},
9
9
  "dependencies": {
10
10
  "@ledvance/base": "^1.x",
@@ -0,0 +1,249 @@
1
+ import { DeviceInfo, NativeApi, queryDpIds } from '@ledvance/base/src/api/native'
2
+ import Card from '@ledvance/base/src/components/Card'
3
+ import Spacer from '@ledvance/base/src/components/Spacer'
4
+ import ThemeType from '@ledvance/base/src/config/themeType'
5
+ import I18n from '@ledvance/base/src/i18n'
6
+ import { useGroupDevices, useUAGroupInfo } from '@ledvance/base/src/models/modules/NativePropsSlice'
7
+ import { xLog } from '@ledvance/base/src/utils'
8
+ import { localeNumber } from '@ledvance/base/src/utils/common'
9
+ import { useIsFocused, useNavigation } from '@react-navigation/native'
10
+ import { useReactive, useUpdateEffect } from 'ahooks'
11
+ import React, { useEffect, useMemo, useRef } from 'react'
12
+ import { Image, StyleSheet, Text, View } from 'react-native'
13
+ import { Utils } from 'tuya-panel-kit'
14
+ import { ui_biz_routerKey } from '../../navigation/Routers'
15
+ import { getEnergyGenerationValue, } from './EnergyConsumptionActions'
16
+ import { EnergyConsumptionPageProps } from './EnergyConsumptionPage'
17
+ import Res from './res'
18
+
19
+ const { convertX: cx } = Utils.RatioUtils
20
+ const { withTheme } = Utils.ThemeUtils
21
+
22
+ export interface EnergyConsumptionProp {
23
+ theme?: ThemeType
24
+ electricDpCode: string
25
+ powerDpCode: string
26
+ addEleDpCode: string
27
+ }
28
+
29
+ const SolarPlugPid = 'rcqe1i17x0vrvws7'
30
+
31
+ const EnergyConsumptionCard = (props: EnergyConsumptionProp) => {
32
+ const navigation = useNavigation()
33
+ const isFocused = useIsFocused()
34
+ const uaGroupInfo = useUAGroupInfo()
35
+ const [groupDevices] = useGroupDevices()
36
+ const updateEnergy: any = useRef()
37
+
38
+ const state = useReactive({
39
+ solarPowerSum: 0,
40
+ solarCurrentSum: 0,
41
+ wifiPowerSum: 0,
42
+ wifiCurrentSum: 0,
43
+ totalPowerSum: 0,
44
+ totalCurrentSum: 0,
45
+ loading: false,
46
+ generationCache: {}
47
+ })
48
+
49
+ useEffect(() => {
50
+ if (groupDevices && groupDevices.length) {
51
+ getEnergyConsumption(groupDevices).then()
52
+ }
53
+ }, [groupDevices])
54
+
55
+ const isOnlyGeneration = useMemo(() => groupDevices.every(device => state.generationCache[device.tuyaDeviceId]), [groupDevices, JSON.stringify(state.generationCache)])
56
+ const hasGeneration = useMemo(() => groupDevices.some(device => state.generationCache[device.tuyaDeviceId]), [groupDevices, JSON.stringify(state.generationCache)])
57
+
58
+ useEffect(() => {
59
+ if (isFocused) {
60
+ updateEnergy.current = setInterval(() => {
61
+ xLog('setInterval========')
62
+ groupDevices.forEach(item => {
63
+ const jsonData = JSON.stringify([props.electricDpCode, props.powerDpCode])
64
+ queryDpIds(jsonData, item.tuyaDeviceId).then()
65
+ })
66
+ NativeApi.getGroupDevices(uaGroupInfo.tyGroupId).then(res => {
67
+ if (res.success && res.data) {
68
+ getEnergyConsumption(res.data).then()
69
+ }
70
+ })
71
+ }, 10000)
72
+ }
73
+
74
+ return () => clearInterval(updateEnergy.current)
75
+ }, [isFocused, groupDevices.length])
76
+
77
+ const isGenerationFromCache = async (tyPid: string, deviceId: string) => {
78
+ const cache = state.generationCache[deviceId]
79
+ if (cache !== undefined) {
80
+ return cache
81
+ }
82
+ const data = await getEnergyGenerationValue(deviceId)
83
+ const generationMode = data?.generationMode || false
84
+ const isGeneration = (tyPid === SolarPlugPid) !== generationMode
85
+ state.generationCache[deviceId] = isGeneration
86
+ return isGeneration
87
+ }
88
+
89
+ const getEnergyConsumption = async (groupDevices: DeviceInfo[]) => {
90
+ let power = 0
91
+ let current = 0
92
+ let solarPower = 0
93
+ let solarCurrent = 0
94
+ const powerDp = props.powerDpCode
95
+ const currentDp = props.electricDpCode
96
+
97
+ for (const device of groupDevices) {
98
+ if (device.dps) {
99
+ const isSolarDevice = await isGenerationFromCache(device.tyPid, device.tuyaDeviceId)
100
+ const dps = JSON.parse(device.dps)
101
+ if (isSolarDevice) {
102
+ solarPower += dps[powerDp] ?? 0
103
+ solarCurrent += dps[currentDp] ?? 0
104
+ } else {
105
+ power += dps[powerDp] ?? 0
106
+ current += dps[currentDp] ?? 0
107
+ }
108
+ }
109
+ }
110
+ state.wifiCurrentSum = current
111
+ state.wifiPowerSum = power / 10
112
+ state.solarCurrentSum = solarCurrent
113
+ state.solarPowerSum = solarPower / 10
114
+ }
115
+
116
+ useUpdateEffect(() => {
117
+ if (hasGeneration) {
118
+ if (isOnlyGeneration) {
119
+ state.totalCurrentSum = state.solarCurrentSum
120
+ state.totalPowerSum = state.solarPowerSum
121
+ } else {
122
+ state.totalCurrentSum = state.wifiCurrentSum - state.solarCurrentSum
123
+ state.totalPowerSum = state.wifiPowerSum - state.solarPowerSum
124
+ }
125
+ } else {
126
+ state.totalCurrentSum = state.wifiCurrentSum
127
+ state.totalPowerSum = state.wifiPowerSum
128
+ }
129
+ }, [state.solarCurrentSum, state.solarPowerSum, state.wifiCurrentSum, state.wifiPowerSum, isOnlyGeneration, hasGeneration])
130
+
131
+ const energyText = useMemo(() => {
132
+ return I18n.getLang(isOnlyGeneration ? 'sockets_headline_power' : !hasGeneration ? 'sockets_ce' : 'group_energytotal')
133
+ }, [hasGeneration, isOnlyGeneration])
134
+
135
+ const unitDivision = (str: string) => {
136
+ if (!str) {
137
+ return ['', '']
138
+ }
139
+ const strIndex = str.indexOf('(') || str.indexOf('(')
140
+ const unit = str.substring(strIndex)
141
+ const name = str.split(unit)[0]
142
+ return [name, unit]
143
+ }
144
+
145
+ const styles = StyleSheet.create({
146
+ consumedEnergyCard: {
147
+ marginHorizontal: cx(24),
148
+ },
149
+ consumedEnergyHeadline: {
150
+ flexDirection: 'row',
151
+ justifyContent: 'space-between',
152
+ alignItems: 'center',
153
+ marginHorizontal: cx(16),
154
+ },
155
+ consumedEnergyCardTitle: {
156
+ color: props.theme?.global.fontColor,
157
+ fontSize: cx(16),
158
+ // fontFamily: 'helvetica_neue_lt_std_bd',
159
+ fontWeight: 'bold',
160
+ },
161
+ consumedEnergyContent: {
162
+ flexDirection: 'row',
163
+ },
164
+ consumedEnergyItem: {
165
+ flex: 1,
166
+ alignItems: 'center',
167
+ },
168
+ consumedEnergyItemValue: {
169
+ color: props.theme?.global.secondBrand,
170
+ fontSize: cx(24),
171
+ // fontFamily: 'helvetica_neue_lt_std_bd',
172
+ fontWeight: 'bold',
173
+ },
174
+ consumedEnergyItemUnit: {
175
+ color: props.theme?.global.secondFontColor,
176
+ fontSize: cx(14),
177
+ fontFamily: 'helvetica_neue_lt_std_roman',
178
+ textAlign: 'center'
179
+ },
180
+ subContent: {
181
+ flex: 1,
182
+ alignItems: 'center',
183
+ marginBottom: cx(9)
184
+ },
185
+ valueText: {
186
+ fontSize: cx(24),
187
+ fontWeight: 'bold',
188
+ color: props.theme?.global.secondBrand,
189
+ },
190
+ titleText: {
191
+ fontFamily: 'helvetica_neue_lt_std_roman',
192
+ fontSize: cx(14),
193
+ color: props.theme?.global.secondFontColor,
194
+ textAlign: 'center',
195
+ },
196
+ unitText: {
197
+ fontFamily: 'helvetica_neue_lt_std_roman',
198
+ fontSize: cx(14),
199
+ color: props.theme?.global.secondFontColor,
200
+ },
201
+ })
202
+
203
+ const ConsumedEnergyItem = (props: { value: number, unit: string }) => {
204
+ return (
205
+ <View style={styles.subContent}>
206
+ <Text style={styles.valueText}>{(props.value) || 0}</Text>
207
+ <Spacer height={cx(4)}/>
208
+ <Text style={styles.titleText}>
209
+ {unitDivision(props.unit)[0]}
210
+ </Text>
211
+ <Text style={styles.titleText}>
212
+ {unitDivision(props.unit)[1]}
213
+ </Text>
214
+ </View>
215
+ )
216
+ }
217
+
218
+ return <Card
219
+ style={styles.consumedEnergyCard}
220
+ onPress={() => navigation.navigate(ui_biz_routerKey.group_ui_biz_energy_consumption, {
221
+ solarCurrentSum: state.solarCurrentSum,
222
+ solarPowerSum: state.solarPowerSum,
223
+ wifiCurrentSum: state.wifiCurrentSum,
224
+ wifiPowerSum: state.wifiPowerSum,
225
+ solarPlugGroup: groupDevices.filter(device => state.generationCache[device.tuyaDeviceId]).map(d => d.tuyaDeviceId),
226
+ wifiPlugGroup: groupDevices.filter(device => !state.generationCache[device.tuyaDeviceId]).map(d => d.tuyaDeviceId),
227
+ addEleDpCode: props.addEleDpCode,
228
+ backText: energyText
229
+ } as EnergyConsumptionPageProps)}>
230
+ <Spacer height={cx(16)}/>
231
+ <View style={styles.consumedEnergyHeadline}>
232
+ <Text
233
+ style={styles.consumedEnergyCardTitle}>{energyText}</Text>
234
+ <Image source={Res.energyChart} style={{ width: cx(24), height: cx(24), tintColor: props.theme?.icon.normal }}/>
235
+ </View>
236
+ <Spacer height={cx(18)}/>
237
+ <View style={styles.consumedEnergyContent}>
238
+ <ConsumedEnergyItem
239
+ value={localeNumber(state.totalPowerSum)}
240
+ unit={I18n.getLang('consumption_data_field2_value_text1')}/>
241
+ <ConsumedEnergyItem
242
+ value={localeNumber(state.totalCurrentSum)}
243
+ unit={I18n.getLang('consumption_data_field2_value_text2')}/>
244
+ </View>
245
+ <Spacer height={cx(17)}/>
246
+ </Card>
247
+ }
248
+
249
+ export default withTheme(EnergyConsumptionCard)
@@ -346,7 +346,20 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
346
346
  <Spacer height={cx(10)} />
347
347
  </Card>
348
348
  <Spacer />
349
- <Card style={styles.cardContainer}>
349
+ <Card
350
+ style={styles.cardContainer}
351
+ onPress={() => {
352
+ navigation.navigate(ui_biz_routerKey.group_ui_biz_energy_consumption_chart, {
353
+ headlineText: chartHeadline,
354
+ chartData: state.isSolarMode ? state.solarOverviewList : state.wifiOverviewList,
355
+ price: state.price,
356
+ unit: state.unit,
357
+ addEleDpCode: params.addEleDpCode,
358
+ date: (new Date()).getFullYear().toString(),
359
+ deviceIdGroup: state.isSolarMode ? params.solarPlugGroup : params.wifiPlugGroup,
360
+ } as EnergyConsumptionChartProps)
361
+ }}
362
+ >
350
363
  <Text style={styles.cardTitle}>
351
364
  {I18n.getLang('consumption_data_field2_headline_text')}
352
365
  </Text>
@@ -1,180 +1,182 @@
1
- import React, {useMemo, 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";
1
+ import ThemeType from '@ledvance/base/src/config/themeType'
2
+ import I18n from '@ledvance/base/src/i18n'
3
+ import ECharts from '@ledvance/react-native-echarts-pro'
4
+ import React, { useMemo, useRef } from 'react'
5
+ import { View } from 'react-native'
6
+ import { Utils } from 'tuya-panel-kit'
7
+ import { OverviewItem } from '../EnergyConsumptionPage'
8
8
 
9
- const {withTheme} = Utils.ThemeUtils
10
- const cx = Utils.RatioUtils.convertX;
9
+ const { withTheme } = Utils.ThemeUtils
10
+ const cx = Utils.RatioUtils.convertX
11
11
 
12
12
  interface BarChartProps {
13
- theme?: ThemeType
14
- data: OverviewItem[],
15
- price: number,
16
- unit: string,
17
- height: number
13
+ theme?: ThemeType
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();
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
- });
32
- const maxValue = useMemo(() => {
33
- let max = Math.max(...dataKwhY)
34
- if (max < 0.1) {
35
- max += 0.02
36
- max = max - (max % 0.02)
37
- } else if (max < 1) {
38
- max += 0.2
39
- max = max - (max % 0.2)
40
- } else if (max < 10) {
41
- max = Math.ceil(max) + 2
42
- max = max - (max % 2)
43
- }
44
- return max
45
- }, [dataKwhY]);
46
- const gridRight = useMemo(() => {
47
- const max = Math.max(...dataPriceY.map(it => Number(it)))
48
- return max > 999 ? '15%' : '10%'
49
- }, [dataPriceY])
50
- const option = {
51
- tooltip: {
52
- show: true,
53
- triggerOn: 'click',
54
- trigger: 'axis',
21
+ const echarts = useRef()
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
+ })
32
+ const maxValue = useMemo(() => {
33
+ let max = Math.max(...dataKwhY)
34
+ if (max < 0.1) {
35
+ max += 0.02
36
+ max = max - (max % 0.02)
37
+ } else if (max < 1) {
38
+ max += 0.2
39
+ max = max - (max % 0.2)
40
+ } else if (max < 10) {
41
+ max = Math.ceil(max) + 2
42
+ max = max - (max % 2)
43
+ }
44
+ return max
45
+ }, [dataKwhY])
46
+ const gridRight = useMemo(() => {
47
+ const max = Math.max(...dataPriceY.map(it => Number(it)))
48
+ return max > 999 ? '15%' : '10%'
49
+ }, [dataPriceY])
50
+ const option = {
51
+ tooltip: {
52
+ show: true,
53
+ triggerOn: 'click',
54
+ trigger: 'axis',
55
+ },
56
+ legend: {
57
+ show: true,
58
+ data: ['kWh', unit],
59
+ textStyle: {
60
+ color: theme?.global.fontColor,
61
+ }
62
+ },
63
+ grid: {
64
+ right: gridRight,
65
+ },
66
+ xAxis: {
67
+ data: dataX,
68
+ axisTick: {
69
+ show: false,
70
+ },
71
+ axisLabel: {
72
+ show: true,
73
+ color: props.theme?.global.secondFontColor,
74
+ interval: 'auto',
75
+ rotate: 45,
76
+ align: 'right',
77
+ verticalAlign: 'top'
78
+ }
79
+ },
80
+ yAxis: [{
81
+ type: 'value',
82
+ name: I18n.getLang('consumption_data_annual_bar_chart_text'),
83
+ max: Math.max(maxValue, 0.02),
84
+ min: 0,
85
+ position: 'left',
86
+ axisLabel: {
87
+ formatter: function (value) {
88
+ const kwh = parseFloat(value)
89
+ let toFixed = 2
90
+ if (kwh >= 100) {
91
+ toFixed = 0
92
+ } else if (kwh >= 10) {
93
+ toFixed = 1
94
+ }
95
+ return kwh.toFixed(toFixed)
55
96
  },
56
- legend: {
57
- show: true,
58
- data: ['kWh', unit],
59
- textStyle: {
60
- color: theme?.global.fontColor,
61
- }
97
+ color: props.theme?.global.secondFontColor,
98
+ },
99
+ nameTextStyle: {
100
+ fontSize: 14,
101
+ align: 'left',
102
+ padding: [0, 0, 0, cx(-30)],
103
+ color: props.theme?.global.secondFontColor,
104
+ },
105
+ }, {
106
+ type: 'value',
107
+ name: I18n.formatValue('format_unit', unit),
108
+ position: 'right',
109
+ alignTicks: true,
110
+ max: Math.ceil(price ? maxValue * price * 1.4 : 0),
111
+ min: 0,
112
+ minInterval: 1,
113
+ axisLabel: {
114
+ formatter: function (value) {
115
+ const price = parseFloat(value)
116
+ let toFixed = 2
117
+ if (price >= 100) {
118
+ toFixed = 0
119
+ } else if (price >= 10) {
120
+ toFixed = 1
121
+ }
122
+ return price.toFixed(toFixed)
62
123
  },
63
- grid: {
64
- right: gridRight,
124
+ color: props.theme?.global.secondFontColor,
125
+ },
126
+ nameTextStyle: {
127
+ fontSize: 14,
128
+ align: 'right',
129
+ padding: [0, cx(-30), 0, 0],
130
+ color: props.theme?.global.secondFontColor,
131
+ },
132
+ }],
133
+ series: [
134
+ {
135
+ name: 'kWh',
136
+ type: 'bar',
137
+ data: dataKwhY,
138
+ itemStyle: {
139
+ emphasis: {
140
+ color: '#FFC2A9', // Color when bar is clicked
141
+ },
142
+ color: '#FFC2A9',
143
+ borderRadius: 2,
65
144
  },
66
- xAxis: {
67
- data: dataX,
68
- axisTick: {
69
- show: false,
70
- },
71
- axisLabel: {
72
- show: true,
73
- color: props.theme?.global.secondFontColor,
74
- interval: 0,
75
- }
145
+ barMaxWidth: 10,
146
+ select: {
147
+ itemStyle: {
148
+ borderColor: '#FFC2A9',
149
+ }
76
150
  },
77
- yAxis: [{
78
- type: 'value',
79
- name: I18n.getLang('consumption_data_annual_bar_chart_text'),
80
- max: Math.max(maxValue, 0.02),
81
- min: 0,
82
- position: 'left',
83
- axisLabel: {
84
- formatter: function (value) {
85
- const kwh=parseFloat(value);
86
- let toFixed = 2;
87
- if (kwh >= 100) {
88
- toFixed = 0;
89
- } else if (kwh >= 10) {
90
- toFixed = 1;
91
- }
92
- return kwh.toFixed(toFixed);
93
- },
94
- color:props.theme?.global.secondFontColor,
95
- },
96
- nameTextStyle: {
97
- fontSize: 14,
98
- align:'left',
99
- padding: [0, 0, 0, cx(-30)],
100
- color: props.theme?.global.secondFontColor,
101
- },
102
- }, {
103
- type: 'value',
104
- name: I18n.formatValue('format_unit', unit),
105
- position: 'right',
106
- alignTicks: true,
107
- max: Math.ceil(price ? maxValue * price * 1.4 : 0),
108
- min: 0,
109
- minInterval: 1,
110
- axisLabel: {
111
- formatter: function (value) {
112
- const price=parseFloat(value);
113
- let toFixed = 2;
114
- if (price >= 100) {
115
- toFixed = 0;
116
- } else if (price >= 10) {
117
- toFixed = 1;
118
- }
119
- return price.toFixed(toFixed);
120
- },
121
- color:props.theme?.global.secondFontColor,
122
- },
123
- nameTextStyle: {
124
- fontSize: 14,
125
- align:'right',
126
- padding: [0, cx(-30), 0, 0],
127
- color: props.theme?.global.secondFontColor,
128
- },
129
- }],
130
- series: [
131
- {
132
- name: 'kWh',
133
- type: 'bar',
134
- data: dataKwhY,
135
- itemStyle: {
136
- emphasis: {
137
- color: '#FFC2A9', // Color when bar is clicked
138
- },
139
- color: '#FFC2A9',
140
- borderRadius: 2,
141
- },
142
- barMaxWidth: 10,
143
- select: {
144
- itemStyle: {
145
- borderColor: '#FFC2A9',
146
- }
147
- },
148
- selectedMode: 'single',
149
- },
150
- {
151
- name: unit,
152
- type: 'line',
153
- data: dataPriceY,
154
- yAxisIndex: 1,
155
- smooth: true,
156
- showSymbol: false,
157
- color: '#F49431',
158
- selectedMode: "single",
159
- }
160
- ],
161
- dataZoom: {
162
- start: 0,
163
- type: "inside",
164
- maxValueSpan: 5,
165
- zoomLock: true,
166
- },
167
- customMapData: {}
168
- };
169
- return (
170
- <View style={{flex: 1}}>
171
- <ECharts
172
- option={option}
173
- ref={echarts}
174
- height={height}
175
- />
176
- </View>
177
- );
178
- };
151
+ selectedMode: 'single',
152
+ },
153
+ {
154
+ name: unit,
155
+ type: 'line',
156
+ data: dataPriceY,
157
+ yAxisIndex: 1,
158
+ smooth: true,
159
+ showSymbol: false,
160
+ color: '#F49431',
161
+ selectedMode: 'single',
162
+ }
163
+ ],
164
+ dataZoom: {
165
+ start: 0,
166
+ type: 'inside',
167
+ zoomLock: true,
168
+ },
169
+ customMapData: {}
170
+ }
171
+ return (
172
+ <View style={{ flex: 1 }}>
173
+ <ECharts
174
+ option={option}
175
+ ref={echarts}
176
+ height={height}
177
+ />
178
+ </View>
179
+ )
180
+ }
179
181
 
180
182
  export default withTheme(BarChartWithTouch)
@@ -0,0 +1,3 @@
1
+ export default {
2
+ energyChart: require('./energy-chart.png')
3
+ }
@@ -17,7 +17,7 @@ import Spacer from "@ledvance/base/src/components/Spacer";
17
17
  import Summary from "./Summary";
18
18
  import {parseHour12} from "@tuya/tuya-panel-lamp-sdk/lib/utils";
19
19
  import DeleteButton from "@ledvance/base/src/components/DeleteButton";
20
- import LdvPickerView from "@ledvance/base/src/components/ldvPickerView";
20
+ import LdvPickerView from "@ledvance/base/src/components/LdvPickerView";
21
21
  import ThemeType from '@ledvance/base/src/config/themeType'
22
22
 
23
23
  const {parseTimer} = Utils.TimeUtils
@@ -20,7 +20,7 @@ import Card from "@ledvance/base/src/components/Card";
20
20
  import LdvSwitch from "@ledvance/base/src/components/ldvSwitch";
21
21
  import LampAdjustView from "@ledvance/base/src/components/LampAdjustView";
22
22
  import {parseHour12} from "@tuya/tuya-panel-lamp-sdk/lib/utils";
23
- import LdvPickerView from "@ledvance/base/src/components/ldvPickerView";
23
+ import LdvPickerView from "@ledvance/base/src/components/LdvPickerView";
24
24
  import ThemeType from '@ledvance/base/src/config/themeType'
25
25
 
26
26
  const {parseTimer} = Utils.TimeUtils
@@ -30,7 +30,7 @@ export default function RecommendMoodItem(props: RecommendMoodItemProps) {
30
30
  value={''}
31
31
  style={styles.content}
32
32
  titleStyle={styles.title}
33
- iconStyle={{
33
+ arrowStyle={{
34
34
  color: '#000',
35
35
  size: cx(16),
36
36
  }} />
@@ -63,7 +63,7 @@ const RecommendMixMoodItem = (props: RecommendMixMoodItemProps) => {
63
63
  value={''}
64
64
  style={styles.content}
65
65
  titleStyle={styles.title}
66
- iconStyle={{
66
+ arrowStyle={{
67
67
  color: props.theme?.global.fontColor,
68
68
  size: cx(16),
69
69
  }}
@@ -7,7 +7,7 @@ import res from '@ledvance/base/src/res';
7
7
  import { TimerPicker, Utils } from 'tuya-panel-kit';
8
8
  import { useReactive, useUpdateEffect } from 'ahooks';
9
9
  import TextField from '@ledvance/base/src/components/TextField';
10
- import LdvPickerView from '@ledvance/base/src/components/ldvPickerView';
10
+ import LdvPickerView from '@ledvance/base/src/components/LdvPickerView';
11
11
  import LdvWeekView from '@ledvance/base/src/components/weekSelect';
12
12
  import {
13
13
  convertMinutesTo12HourFormat,
@@ -4,7 +4,7 @@ import Page from "@ledvance/base/src/components/Page";
4
4
  import {useUAGroupInfo} from "@ledvance/base/src/models/modules/NativePropsSlice";
5
5
  import {useNavigation} from '@react-navigation/native'
6
6
  import {SwitchButton, Utils} from "tuya-panel-kit";
7
- import LdvPickerView from "@ledvance/base/src/components/ldvPickerView";
7
+ import LdvPickerView from "@ledvance/base/src/components/LdvPickerView";
8
8
  import I18n from '@ledvance/base/src/i18n'
9
9
  import {defSwitchInching, SwitchInchingItem, SwitchInchingPageParams, useSwitchInching} from "./SwitchInchingAction";
10
10
  import ThemeType from '@ledvance/base/src/config/themeType'
@@ -1,5 +1,5 @@
1
1
  import I18n from "@ledvance/base/src/i18n";
2
- import { AdjustType, DiySceneInfo } from "@ledvance/base/src/utils/interface";
2
+ import { AdjustType, ApplyForItem, DiySceneInfo } from "@ledvance/base/src/utils/interface";
3
3
  import { MoodInfo, MoodUIInfo } from "../mood_new/Interface";
4
4
 
5
5
  export interface IAddSingleTime {
@@ -62,16 +62,6 @@ export interface HSV {
62
62
  v: number;
63
63
  }
64
64
 
65
- export type Category = 'light' | 'socket' | 'fan' | 'mainLight' | 'secondaryLight'
66
-
67
- export interface ApplyForItem {
68
- name?: string
69
- key: string;
70
- dp: string;
71
- type: Category;
72
- enable: boolean;
73
- }
74
-
75
65
  interface judgmentSupport {
76
66
  isSupportColor: boolean;
77
67
  isSupportBrightness: boolean;
@@ -102,6 +92,7 @@ export enum DeviceType {
102
92
  FanLight = 'fanLight',
103
93
  MoodStrip = 'moodStrip',
104
94
  Shutter = 'shutter',
95
+ OsramFanLight = 'osramFanLight',
105
96
  }
106
97
  // export type DeviceType = 'LightSource' | 'CeilingLight' | 'StringLight' | 'StripLight' | 'MixLight';
107
98
 
@@ -144,6 +135,11 @@ export interface ShutterData extends DeviceData {
144
135
  percentControl: number
145
136
  }
146
137
 
138
+ export interface OsramFanLightData extends DeviceData {
139
+ fanMode: 'fresh' | 'nature'
140
+ fanSpeed: number
141
+ }
142
+
147
143
  export type ComponentConfig =
148
144
  | { type: DeviceType.LightSource; deviceData: DeviceData }
149
145
  | { type: DeviceType.MixLight; deviceData: MixLightData }
@@ -152,6 +148,8 @@ export type ComponentConfig =
152
148
  | { type: DeviceType.FanLight; deviceData: FanLightData }
153
149
  | { type: DeviceType.MoodStrip; deviceData: MoodStripData}
154
150
  | { type: DeviceType.Shutter; deviceData: ShutterData}
151
+ | { type: DeviceType.OsramFanLight; deviceData: OsramFanLightData}
152
+
155
153
  export interface TimeScheduleDetailState {
156
154
  timeSchedule: Timer;
157
155
  dps: Record<string, any>;
@@ -47,7 +47,13 @@ export const defMoodStripDeviceData = {
47
47
 
48
48
  export const defShutterDeviceData = {
49
49
  percentControl: 100
50
- };
50
+ }
51
+
52
+ export const defOsramFanLightDeviceData = {
53
+ ...defDeviceData,
54
+ fanSpeed: 1,
55
+ fanMode: 'fresh',
56
+ }
51
57
 
52
58
  export const addTimeSchedule = async (props: IAddSingleTime) => {
53
59
  try {
@@ -19,7 +19,6 @@ import Spacer from '@ledvance/base/src/components/Spacer';
19
19
  import LdvWeekView from '@ledvance/base/src/components/weekSelect';
20
20
  import { convertTo12HourFormat, loopText, showDialog } from '@ledvance/base/src/utils/common';
21
21
  import {
22
- ApplyForItem,
23
22
  ComponentConfig,
24
23
  DeviceType,
25
24
  TimeScheduleDetailState,
@@ -37,7 +36,7 @@ import DeleteButton from '@ledvance/base/src/components/DeleteButton';
37
36
  import SegmentControl from '@ledvance/base/src/components/segmentControl';
38
37
  import { useParams } from '@ledvance/base/src/hooks/Hooks';
39
38
  import ManualSettings from './components/ManuaSettings';
40
- import { defDeviceData, defMixDeviceData, defStripDeviceData, defFanLightDeviceData, defMoodStripDeviceData, defShutterDeviceData } from './TimeScheduleActions';
39
+ import { defDeviceData, defMixDeviceData, defStripDeviceData, defFanLightDeviceData, defMoodStripDeviceData, defShutterDeviceData, defOsramFanLightDeviceData } from './TimeScheduleActions';
41
40
  import MoodItem from '../mood_new/MoodItem';
42
41
  import Summary from './components/Summary'
43
42
  import { getRemoteMoodList } from '../mood_new/MoodActions'
@@ -45,7 +44,7 @@ import { MoodInfo, MoodUIInfo } from '../mood_new/Interface';
45
44
  import InfoText from '@ledvance/base/src/components/InfoText';
46
45
  import ThemeType from '@ledvance/base/src/config/themeType'
47
46
  import Tag from '@ledvance/base/src/components/Tag';
48
- import { DiySceneInfo } from '@ledvance/base/src/utils/interface';
47
+ import { ApplyForItem, DiySceneInfo } from '@ledvance/base/src/utils/interface';
49
48
  import DiySceneItem from '@ledvance/base/src/components/DiySceneItem';
50
49
 
51
50
  const { convertX: cx } = Utils.RatioUtils;
@@ -679,7 +678,8 @@ const getDefaultManual = (props: TimeScheduleDetailPageParams): ComponentConfig
679
678
  isFanLight: DeviceType.FanLight,
680
679
  isCeilingLight: DeviceType.CeilingLight,
681
680
  isMoodStrip: DeviceType.MoodStrip,
682
- isShutter: DeviceType.Shutter
681
+ isShutter: DeviceType.Shutter,
682
+ isOsramFanLight: DeviceType.OsramFanLight,
683
683
  };
684
684
 
685
685
  const deviceType = Object.entries(deviceTypeMap)
@@ -693,6 +693,7 @@ const getDefaultManual = (props: TimeScheduleDetailPageParams): ComponentConfig
693
693
  [DeviceType.FanLight]: defFanLightDeviceData,
694
694
  [DeviceType.MoodStrip]: defMoodStripDeviceData,
695
695
  [DeviceType.Shutter]: defShutterDeviceData,
696
+ [DeviceType.OsramFanLight]: defOsramFanLightDeviceData,
696
697
  [DeviceType.LightSource]: defDeviceData,
697
698
  };
698
699
 
@@ -37,6 +37,7 @@ export interface TimeSchedulePageParams {
37
37
  isUVCFan?: boolean;
38
38
  isMoodStrip?: boolean
39
39
  isShutter?: boolean
40
+ isOsramFan?: boolean
40
41
  applyForList: ApplyForItem[];
41
42
  applyForDisabled?: boolean; // 是否可以选择apply for
42
43
  manualDataDp2Obj: (dps: Record<string, any>) => DeviceStateType;
@@ -8,6 +8,7 @@ import {
8
8
  directOptions,
9
9
  modeOptions,
10
10
  ShutterData,
11
+ OsramFanLightData,
11
12
  } from '../Interface';
12
13
  import { View } from 'react-native';
13
14
  import Card from '@ledvance/base/src/components/Card';
@@ -28,6 +29,8 @@ import { cctToColor } from '@ledvance/base/src/utils/cctUtils';
28
29
  import {hsv2Hex, mapFloatToRange } from '@ledvance/base/src/utils';
29
30
  import { AdjustType, ApplyForItem } from '@ledvance/base/src/utils/interface';
30
31
  import LdvSlider from '@ledvance/base/src/components/ldvSlider';
32
+ import OsramFanAdjustView from '@ledvance/base/src/components/OsramFanAdjustView'
33
+
31
34
  const { convertX: cx } = Utils.RatioUtils;
32
35
  const { withTheme } = Utils.ThemeUtils
33
36
 
@@ -112,7 +115,7 @@ function ManualSettings(props: ManualSettingProps) {
112
115
  state.applyFlag = Symbol()
113
116
  }}
114
117
  />
115
- {item.enable && (item.type !== 'socket' && item.type !== 'fan') && (
118
+ {item.enable && !['socket', 'fan', 'osramFan'].includes(item.type) && (
116
119
  <LampAdjustView
117
120
  isSupportColor={props.isSupportColor}
118
121
  isSupportBrightness={props.isSupportBrightness}
@@ -206,6 +209,30 @@ function ManualSettings(props: ManualSettingProps) {
206
209
  />
207
210
  )}
208
211
 
212
+ {item.enable && item.type === 'osramFan' && (
213
+ <OsramFanAdjustView
214
+ hideFanSwitch={true}
215
+ fanSwitch={item.enable}
216
+ setFanSwitch={() => {}}
217
+ fanSpeed={(state.deviceData as OsramFanLightData).fanSpeed}
218
+ setFanSpeed={(v: number) => {
219
+ state.deviceData = {
220
+ ...state.deviceData,
221
+ fanSpeed: v
222
+ }
223
+ state.manualFlag = Symbol()
224
+ }}
225
+ fanMode={(state.deviceData as OsramFanLightData).fanMode}
226
+ setFanMode={(v: 'fresh' | 'nature') => {
227
+ state.deviceData = {
228
+ ...state.deviceData,
229
+ fanMode: v
230
+ }
231
+ state.manualFlag = Symbol()
232
+ }}
233
+ />
234
+ )}
235
+
209
236
  <ApplyForDeviceList
210
237
  devices={cloneDeep(groupDevices)}
211
238
  />
@@ -22,6 +22,7 @@ export interface TimerTask {
22
22
  stringOnMin: I18nKey
23
23
  stringOffMin: I18nKey
24
24
  cloudKey: 'lightingInfo' | 'socketInfo' | 'fanInfo' | 'plugCountDownInfo'
25
+ displayToDpValue?: (value: number) => number
25
26
  }
26
27
 
27
28
  export enum TaskStatus {
@@ -65,6 +66,7 @@ export function useTimerTasks(timerSettableDps: TimerSettableDp[], devIdGroup: s
65
66
  stringOnMin: timerSettableDp.stringOnMin,
66
67
  stringOffMin: timerSettableDp.stringOffMin,
67
68
  cloudKey: timerSettableDp.cloudKey,
69
+ displayToDpValue: timerSettableDp.displayToDpValue,
68
70
  }))
69
71
  }, [JSON.stringify(timerSettableDps)])
70
72
 
@@ -75,7 +77,7 @@ export function useTimerTasks(timerSettableDps: TimerSettableDp[], devIdGroup: s
75
77
  timerTasks => {
76
78
  const dps = {}
77
79
  timerTasks.forEach(task => {
78
- dps[task.dp.code] = task.duration
80
+ dps[task.dp.code] = task.displayToDpValue ? task.displayToDpValue(task.duration) : task.duration
79
81
  const featureKey = timerSettableDps.find(timerSettableDp => timerSettableDp.dp.code === task.dp.code)?.cloudKey
80
82
  devIdGroup.forEach(devId => {
81
83
  NativeApi.putJson(devId, task.cloudKey ?? featureKey, JSON.stringify({ [getKey('Status', task.dp.code)]: !!task.duration, [getKey('StartTime', task.dp.code)]: dayjs(task.startTime * 1000).format('YYYY-MM-DD HH:mm:ss'), progressAllNumber: task.duration }))
@@ -176,6 +178,7 @@ export interface TimerSettableDp {
176
178
  stringOnMin: I18nKey
177
179
  stringOffMin: I18nKey
178
180
  cloudKey: 'lightingInfo' | 'socketInfo' | 'fanInfo' | 'plugCountDownInfo'
181
+ displayToDpValue?: (value: number) => number
179
182
  }
180
183
 
181
184
  export interface TimerPageParams {
@@ -4,7 +4,7 @@ import I18n from '@ledvance/base/src/i18n'
4
4
  import Page from '@ledvance/base/src/components/Page'
5
5
  import {Utils} from 'tuya-panel-kit'
6
6
  import {useUAGroupInfo} from '@ledvance/base/src/models/modules/NativePropsSlice'
7
- import LdvPickerView from '@ledvance/base/src/components/ldvPickerView'
7
+ import LdvPickerView from '@ledvance/base/src/components/LdvPickerView'
8
8
  import {useReactive} from 'ahooks'
9
9
  import Spacer from '@ledvance/base/src/components/Spacer'
10
10
  import DeleteButton from '@ledvance/base/src/components/DeleteButton'
package/tsconfig.json CHANGED
@@ -1,51 +1,76 @@
1
1
  {
2
- "compilerOptions": {
3
- /* Basic Options */
4
- "target": "ES2017",
5
- /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
6
- "module": "commonjs",
7
- /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
8
- "jsx": "react",
9
- /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
2
+ "compilerOptions": {
3
+ /* Basic Options */
4
+ "target": "ES2017",
5
+ "lib": ["es2017"],
6
+ /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
7
+ "module": "commonjs",
8
+ /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
9
+ "jsx": "react",
10
+ /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
10
11
 
11
- /* Strict Type-Checking Options */
12
- /* "strict": true /* Enable all strict type-checking options. */
13
- "noImplicitAny": false,
14
- /* Raise error on expressions and declarations with an implied 'any' type. */
15
- "strictNullChecks": true,
16
- /* Enable strict null checks. */
12
+ /* Strict Type-Checking Options */
13
+ /* "strict": true /* Enable all strict type-checking options. */
14
+ "noImplicitAny": false,
15
+ /* Raise error on expressions and declarations with an implied 'any' type. */
16
+ "strictNullChecks": true,
17
+ /* Enable strict null checks. */
17
18
 
18
- /* Additional Checks */
19
- "noUnusedLocals": true,
20
- /* Report errors on unused locals. */
21
- "noUnusedParameters": true,
22
- /* Report errors on unused parameters. */
19
+ /* Additional Checks */
20
+ "noUnusedLocals": true,
21
+ /* Report errors on unused locals. */
22
+ "noUnusedParameters": true,
23
+ /* Report errors on unused parameters. */
23
24
 
24
- /* .d.ts config */
25
- "declaration": true,
26
- "emitDeclarationOnly": true,
27
-
28
- /* Module Resolution Options */
29
- "moduleResolution": "node",
30
- /* Specify module resolution strategy: 'node' (Node.js) or 'classic' */
31
- "types": ["react", "react-native"],
32
- /* Type declaration files to be included in compilation. */
33
- "typeRoots": ["@types/*.d.ts"],
34
- "allowSyntheticDefaultImports": true,
35
- /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
36
- "esModuleInterop": true,
37
- /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
38
- "baseUrl": "./src",
39
- "paths": {
40
- "@api": ["./api"],
41
- "@components": ["./components"],
42
- "@config": ["./config"],
43
- "@i18n": ["./i18n"],
44
- "@models": ["./models"],
45
- "@res": ["./res"],
46
- "@utils": ["./utils"]
47
- }
48
- },
49
- "include": ["src/**/*.ts","src/**/*.tsx"],
50
- "exclude": ["node_modules",".yalc"]
25
+ /* .d.ts config */
26
+ "declaration": true,
27
+ "emitDeclarationOnly": true,
28
+ /* Module Resolution Options */
29
+ "moduleResolution": "node",
30
+ /* Specify module resolution strategy: 'node' (Node.js) or 'classic' */
31
+ "types": [
32
+ "react",
33
+ "react-native"
34
+ ],
35
+ /* Type declaration files to be included in compilation. */
36
+ "typeRoots": [
37
+ "@types/*.d.ts"
38
+ ],
39
+ "allowSyntheticDefaultImports": true,
40
+ /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
41
+ "esModuleInterop": true,
42
+ /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
43
+ "baseUrl": "./src",
44
+ "paths": {
45
+ "@api": [
46
+ "./api"
47
+ ],
48
+ "@components": [
49
+ "./components"
50
+ ],
51
+ "@config": [
52
+ "./config"
53
+ ],
54
+ "@i18n": [
55
+ "./i18n"
56
+ ],
57
+ "@models": [
58
+ "./models"
59
+ ],
60
+ "@res": [
61
+ "./res"
62
+ ],
63
+ "@utils": [
64
+ "./utils"
65
+ ]
66
+ }
67
+ },
68
+ "include": [
69
+ "src/**/*.ts",
70
+ "src/**/*.tsx"
71
+ ],
72
+ "exclude": [
73
+ "node_modules",
74
+ ".yalc"
75
+ ]
51
76
  }