@ledvance/ui-biz-bundle 1.1.142 → 1.1.144

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.
Files changed (28) hide show
  1. package/package.json +1 -1
  2. package/src/hooks/DeviceDpStateHooks.ts +1 -1
  3. package/src/modules/flags/FlagPage.tsx +4 -1
  4. package/src/modules/timeSchedule/TimeScheduleEditpage.tsx +1 -1
  5. package/src/modules/timer/TimerPage.tsx +1 -1
  6. package/src/newModules/biorhythm/BiorhythmActions.ts +403 -451
  7. package/src/newModules/biorhythm/BiorhythmBean.ts +230 -230
  8. package/src/newModules/biorhythm/BiorhythmEditPage.tsx +18 -20
  9. package/src/newModules/biorhythm/BiorhythmPage.tsx +653 -698
  10. package/src/newModules/biorhythm/IconSelect.tsx +88 -88
  11. package/src/newModules/biorhythm/Router.ts +33 -33
  12. package/src/newModules/biorhythm/iconListData.ts +30 -30
  13. package/src/newModules/biorhythm/pIdList.ts +35 -35
  14. package/src/newModules/energyConsumption/EnergyConsumptionActions.ts +67 -28
  15. package/src/newModules/energyConsumption/EnergyConsumptionCard.tsx +172 -0
  16. package/src/newModules/energyConsumption/EnergyConsumptionChart.tsx +234 -118
  17. package/src/newModules/energyConsumption/EnergyConsumptionDetail.tsx +3 -0
  18. package/src/newModules/energyConsumption/EnergyConsumptionPage.tsx +16 -0
  19. package/src/newModules/energyConsumption/co2Data.ts +5 -0
  20. package/src/newModules/energyConsumption/component/NewBarChart.tsx +172 -168
  21. package/src/newModules/energyConsumption/component/PowerLineChart.tsx +101 -0
  22. package/src/newModules/energyConsumption/res/energy-chart.png +0 -0
  23. package/src/newModules/energyConsumption/res/index.ts +3 -0
  24. package/src/newModules/fixedTime/FixedTimeDetailPage.tsx +1 -1
  25. package/src/newModules/sleepWakeUp/SleepWakeUpDetailPage.tsx +1 -1
  26. package/src/newModules/swithInching/SwithInching.tsx +1 -1
  27. package/src/newModules/timeSchedule/TimeScheduleActions.ts +12 -12
  28. package/tsconfig.json +73 -46
@@ -1,451 +1,403 @@
1
- import {
2
- BiorhythmBean,
3
- BiorhythmGradientType,
4
- BiorhythmGradientTypeMap,
5
- BiorhythmGradientTypeMap2,
6
- colorTemperatureValue,
7
- colorTempPercent,
8
- getDefRepeatPeriod,
9
- Period,
10
- Plan,
11
- RemoteBiorhythmBean,
12
- } from './BiorhythmBean'
13
- import { useCallback, useEffect, useState, useRef } from 'react'
14
- import { NativeResult, Result } from '@ledvance/base/src/models/modules/Result'
15
- import { useDeviceId, useDp } from '@ledvance/base/src/models/modules/NativePropsSlice'
16
- import { getFeature, NativeApi, putFeature } from '@ledvance/base/src/api/native'
17
- import { hex2Int, spliceByStep } from '@ledvance/base/src/utils/common'
18
- import I18n from '@ledvance/base/src/i18n'
19
- import res from '@ledvance/base/src/res'
20
- import dayjs from 'dayjs'
21
- import { to16 } from '@tuya/tuya-panel-lamp-sdk/lib/utils'
22
- import { useUpdateEffect } from 'ahooks'
23
-
24
- type UseBiorhythmType = (dpKey: string, disabledFeature?: boolean) => [BiorhythmBean, SetBiorhythmType];
25
- type SetBiorhythmType = (biorhythmObj: BiorhythmBean, pushFeature?: boolean) => Promise<Result<any>>;
26
-
27
- let biorhythmTimer: number | undefined = undefined
28
- export const useBiorhythm: UseBiorhythmType = (dpKey: string, disabledFeature?: boolean) => {
29
- const [dp, setDp] = useDp<string, (v: string) => any>(dpKey)
30
- const deviceId = useDeviceId()
31
- const [biorhythmState, setBiorhythmState] = useState(dp2Obj(dp))
32
- const isInternalUpdateRef = useRef(false)
33
- const previousDpRef = useRef(dp)
34
-
35
- const getBiorhythm = () => {
36
- const biorhythm = dp2Obj(dp)
37
- getRemoteBiorhythm(deviceId, biorhythm).then(res => {
38
- if (res.success && res.data) {
39
- setBiorhythmState(dto2Vo({
40
- ...res.data,
41
- enable: biorhythm.enable,
42
- repeatPeriod: biorhythm.repeatPeriod.filter(r => r.enabled).map(r => r.index),
43
- gradientWay: BiorhythmGradientTypeMap[biorhythm.gradient]
44
- }))
45
- }
46
- })
47
- }
48
-
49
- useEffect(() => {
50
- if (disabledFeature) return
51
- biorhythmTimer = setTimeout(() => {
52
- getBiorhythm()
53
- }, 150)
54
- return () => {
55
- if (biorhythmTimer) {
56
- clearTimeout(biorhythmTimer)
57
- biorhythmTimer = undefined
58
- }
59
- }
60
- }, [])
61
-
62
- useUpdateEffect(() => {
63
- if (isInternalUpdateRef.current || disabledFeature) {
64
- if (disabledFeature) {
65
- setBiorhythmState(dp2Obj(dp))
66
- }
67
- if (isInternalUpdateRef.current) {
68
- previousDpRef.current = dp
69
- }
70
- isInternalUpdateRef.current = false
71
- return
72
- }
73
- if (dp?.toLocaleLowerCase() === previousDpRef.current?.toLocaleLowerCase()) {
74
- return
75
- }
76
- getBiorhythm()
77
- }, [dp])
78
-
79
- const setBiorhythmFn = async (biorhythmObj: BiorhythmBean, pushFeature: boolean = true) => {
80
- const dpValue = obj2Dp(biorhythmObj)
81
- isInternalUpdateRef.current = true
82
-
83
- if (pushFeature) {
84
- const putFeatureRes = await putFeature(deviceId, biorhythmFeatureId, vo2Dto(biorhythmObj))
85
- console.log(vo2Dto(biorhythmObj), '< --- biorhythmObj --- >')
86
- if (putFeatureRes.result) {
87
- setBiorhythmState(biorhythmObj)
88
- return setDp(dpValue)
89
- } else {
90
- isInternalUpdateRef.current = false
91
- }
92
- } else {
93
- setBiorhythmState(biorhythmObj)
94
- return setDp(dpValue)
95
- }
96
- return { success: false }
97
- }
98
- return [biorhythmState, setBiorhythmFn]
99
- }
100
-
101
- const biorhythmFeatureId = 'Biorhythm'
102
-
103
- async function getRemoteBiorhythm(deviceId: string, defBiorhythmState: BiorhythmBean): Promise<Result<RemoteBiorhythmBean>> {
104
- const res: NativeResult<RemoteBiorhythmBean> = await getFeature(deviceId, biorhythmFeatureId)
105
- if (!res.data) {
106
- const defData = vo2Dto(defBiorhythmState)
107
- const pushRes = await putFeature(deviceId, biorhythmFeatureId, defData)
108
- if (pushRes.result) {
109
- return getRemoteBiorhythm(deviceId, defBiorhythmState)
110
- }
111
- return {
112
- success: false,
113
- msg: pushRes.msg,
114
- }
115
- }
116
- return {
117
- success: true,
118
- data: res.data,
119
- }
120
- }
121
-
122
- interface RhythmModeSuspendState {
123
- status: boolean
124
- suspendTime: string
125
- }
126
-
127
- export const useRhythmSuspend = (dp: string): [boolean, () => void, (v: string | undefined) => Promise<Result<any>>] => {
128
- const [suspendTime, setSuspendTime] = useState<string | undefined>()
129
- const [biorhythm] = useBiorhythm(dp, true)
130
- const devId = useDeviceId()
131
- const currentTime = dayjs().format('YYYY-MM-DD')
132
-
133
- useEffect(() => {
134
- getSuspendTime()
135
- }, [])
136
-
137
- useUpdateEffect(() => {
138
- if (biorhythm.enable) {
139
- if (suspendTime !== currentTime) {
140
- getSuspendTime()
141
- }
142
- } else {
143
- if (suspendTime !== undefined) {
144
- setSuspendTime(undefined)
145
- putSuspendTime(undefined)
146
- }
147
- }
148
- }, [biorhythm.enable, suspendTime])
149
-
150
- const getSuspendTime = useCallback(() => {
151
- if (suspendTime !== currentTime) {
152
- NativeApi.getJson(devId, 'suspendTime').then(res => {
153
- if (res.success && res.data) {
154
- const suspend = JSON.parse(res.data) as RhythmModeSuspendState
155
- setSuspendTime(suspend.suspendTime)
156
- }
157
- })
158
- }
159
- }, [suspendTime])
160
-
161
- const putSuspendTime = async (tiem?: string) => {
162
- return await NativeApi.putJson(devId, 'suspendTime', JSON.stringify({ status: true, suspendTime: tiem }))
163
- }
164
-
165
- const setRhythSuspend = useCallback(async (time: string | undefined) => {
166
- if (time === suspendTime) return { success: true }
167
- if (!biorhythm.enable) {
168
- setSuspendTime(undefined)
169
- return await putSuspendTime(undefined)
170
- }
171
- const res = await putSuspendTime(time)
172
- setSuspendTime(time)
173
- return res
174
- }, [suspendTime, biorhythm.enable])
175
-
176
- return [suspendTime === currentTime, getSuspendTime, setRhythSuspend]
177
- }
178
-
179
- export function dp2Obj(dp: string): BiorhythmBean {
180
- if (!dp || dp === '0000000000') {
181
- return dp2Obj('0000007f0501060000000000000001061e00000000141901090000000000646401140000000000503201171e000000000000')
182
- }
183
- let dpCopy = dp
184
- // 版本
185
- hex2Int(dpCopy.slice(0, 2))
186
- dpCopy = dpCopy.slice(2)
187
- // 开关
188
- const enable = hex2Int(dpCopy.slice(0, 2)) === 1
189
- dpCopy = dpCopy.slice(2)
190
- // 模式:00 全程渐变,0F 直接渐变
191
- const gradient =
192
- dpCopy.slice(0, 2).toLowerCase() === '00'
193
- ? BiorhythmGradientType.EntireGradient
194
- : BiorhythmGradientType.DirectGradient
195
- dpCopy = dpCopy.slice(2)
196
- // 重复周期
197
- const repeatPeriod: Period[] = hex2Int(dpCopy.slice(0, 2))
198
- .toString(2)
199
- .padStart(7, '0')
200
- .split('')
201
- .reverse()
202
- .map((p, index) => {
203
- return {
204
- index: index === 0 ? 7 : index,
205
- title: getRepeatPeriodTitleByIndex(index),
206
- enabled: p === '1',
207
- }
208
- })
209
- repeatPeriod.sort((a, b) => a.index - b.index)
210
- dpCopy = dpCopy.slice(2)
211
- // 节点个数 (每个节点长度18),最多8个节点
212
- hex2Int(dpCopy.slice(0, 2))
213
- dpCopy = dpCopy.slice(2)
214
- // 节点列表
215
- const planList: Plan[] = dpCopy === '00' ? [] : spliceByStep(dpCopy, 18).map((planHex, index) => {
216
- let hex = planHex
217
- // 节点开关
218
- const enable = hex2Int(hex.slice(0, 2)) === 1
219
- hex = hex.slice(2)
220
- // 小时
221
- const hour = hex2Int(hex.slice(0, 2))
222
- hex = hex.slice(2)
223
- // 分钟
224
- const minute = hex2Int(hex.slice(0, 2))
225
- hex = hex.slice(2)
226
- const time = hour * 60 + minute
227
- // 色调 (色相)
228
- hex2Int(hex.slice(0, 4))
229
- hex = hex.slice(4)
230
- // 饱和度
231
- hex2Int(hex.slice(0, 2))
232
- hex = hex.slice(2)
233
- // 明度
234
- hex2Int(hex.slice(0, 2))
235
- hex = hex.slice(2)
236
- // 亮度
237
- const brightness = hex2Int(hex.slice(0, 2))
238
- hex = hex.slice(2)
239
- // 色温
240
- const colorTemperature = hex2Int(hex.slice(0, 2))
241
- return {
242
- index,
243
- enable,
244
- icon: getNodeIconByIndex(index).icon,
245
- iconId: getNodeIconByIndex(index).iconId,
246
- time,
247
- name: getNodeNameByIndex(index),
248
- colorTemperature,
249
- brightness,
250
- action: [
251
- {
252
- uri: 'model/attribute/set/LightCtrl/ColorTemperature',
253
- startValue: `${colorTemperatureValue(colorTemperature)}`,
254
- },
255
- {
256
- uri: 'model/attribute/set/LightCtrl/Brightness',
257
- startValue: `${brightness}`,
258
- },
259
- ],
260
- }
261
- })
262
- return {
263
- enable: enable,
264
- gradient: gradient,
265
- repeatPeriod: repeatPeriod,
266
- planList: planList,
267
- }
268
- }
269
-
270
- function getNodeNameByIndex(index: number): string {
271
- switch (index) {
272
- case 0:
273
- return I18n.getLang('bio_ryhthm_default_field_text')
274
- case 1:
275
- return I18n.getLang('bio_ryhthm_default_field_text2')
276
- case 2:
277
- return I18n.getLang('bio_ryhthm_default_field_text3')
278
- case 3:
279
- return I18n.getLang('bio_ryhthm_default_field_text4')
280
- case 4:
281
- return I18n.getLang('bio_ryhthm_default_field_text5')
282
- default:
283
- return `Node ${index + 1}`
284
- }
285
- }
286
-
287
- interface NodeIcon {
288
- icon: string
289
- iconId: number
290
- }
291
-
292
- function getNodeIconByIndex(index: number): NodeIcon {
293
- switch (index) {
294
- case 0:
295
- return {
296
- icon: res.rhythm_icon1,
297
- iconId: 1
298
- }
299
- case 1:
300
- return {
301
- icon: res.rhythm_icon2,
302
- iconId: 2
303
- }
304
- case 2:
305
- return {
306
- icon: res.rhythm_icon3,
307
- iconId: 9
308
- }
309
- case 3:
310
- return {
311
- icon: res.rhythm_icon4,
312
- iconId: 3
313
- }
314
- case 4:
315
- return {
316
- icon: res.rhythm_icon12,
317
- iconId: 5
318
- }
319
- case 5:
320
- return {
321
- icon: res.rhythm_icon1,
322
- iconId: 1
323
- }
324
- case 6:
325
- return {
326
- icon: res.rhythm_icon2,
327
- iconId: 2
328
- }
329
- case 7:
330
- return {
331
- icon: res.rhythm_icon3,
332
- iconId: 9
333
- }
334
- default:
335
- return {
336
- icon: res.rhythm_icon1,
337
- iconId: 1
338
- }
339
- }
340
- }
341
-
342
- function getRepeatPeriodTitleByIndex(index: number): string {
343
- let title = ''
344
- switch (index) {
345
- case 0:
346
- title = I18n.getLang('bio_ryhthm_default_weekday7_text')
347
- break
348
- case 1:
349
- title = I18n.getLang('bio_ryhthm_default_weekday1_text')
350
- break
351
- case 2:
352
- title = I18n.getLang('bio_ryhthm_default_weekday2_text')
353
- break
354
- case 3:
355
- title = I18n.getLang('bio_ryhthm_default_weekday3_text')
356
- break
357
- case 4:
358
- title = I18n.getLang('bio_ryhthm_default_weekday4_text')
359
- break
360
- case 5:
361
- title = I18n.getLang('bio_ryhthm_default_weekday5_text')
362
- break
363
- case 6:
364
- title = I18n.getLang('bio_ryhthm_default_weekday6_text')
365
- break
366
- }
367
- return title
368
- }
369
-
370
- function obj2Dp(obj: BiorhythmBean): string {
371
- const versionHex = '00'
372
- const enableHex = obj.enable ? '01' : '00'
373
- const gradientHex = obj.gradient === BiorhythmGradientType.EntireGradient ? '00' : '0F'
374
- const newRepeatPeriod = [obj.repeatPeriod[obj.repeatPeriod.length - 1], ...obj.repeatPeriod.slice(0, -1)]
375
- const repeatPeriodHex = parseInt(
376
- newRepeatPeriod
377
- .map(p => (p.enabled ? '1' : '0'))
378
- .reverse()
379
- .join(''),
380
- 2,
381
- )
382
- .toString(16)
383
- .padStart(2, '0')
384
- const planCountHex = obj.planList.length.toString(16).padStart(2, '0')
385
- const planListHex = obj.planList
386
- .map(plan => {
387
- const enableHex = plan.enable ? '01' : '00'
388
- const hourHex = to16(Math.trunc(plan.time / 60))
389
- const minuteHex = to16(plan.time % 60)
390
- const hsvHex = '00000000'
391
- const brightnessHex = plan.brightness.toString(16).padStart(2, '0')
392
- const colorTemperatureHex = plan.colorTemperature.toString(16).padStart(2, '0')
393
- return enableHex + hourHex + minuteHex + hsvHex + brightnessHex + colorTemperatureHex
394
- })
395
- .join('')
396
- return versionHex + enableHex + gradientHex + repeatPeriodHex + planCountHex + planListHex
397
- }
398
-
399
- /**
400
- * BiorhythmBean 转 RemoteBiorhythmBean
401
- */
402
- function vo2Dto(biorhythmBean: BiorhythmBean): RemoteBiorhythmBean {
403
- return {
404
- enable: biorhythmBean.enable,
405
- repeatPeriod: biorhythmBean.repeatPeriod.filter(r => r.enabled).map(r => r.index),
406
- gradientWay: BiorhythmGradientTypeMap[biorhythmBean.gradient],
407
- rhythmPlan: biorhythmBean.planList.map(plan => {
408
- const hour = Math.trunc(plan.time / 60).toString().padStart(2, '0')
409
- const min = (plan.time % 60).toString().padStart(2, '0')
410
- return {
411
- name: plan.name,
412
- rhythmIcon: plan.icon,
413
- enable: plan.enable,
414
- startTime: `${hour}:${min}`,
415
- sustain: plan.index, // 持续时间涂鸦这边没有,直接用来存ID
416
- action: plan.action,
417
- iconId: plan.iconId,
418
- }
419
- }),
420
- }
421
- }
422
-
423
- /**
424
- * RemoteBiorhythmBean 转 BiorhythmBean
425
- */
426
- function dto2Vo(remoteBiorhythmBean: RemoteBiorhythmBean): BiorhythmBean {
427
- return {
428
- enable: remoteBiorhythmBean.enable,
429
- repeatPeriod: getDefRepeatPeriod().map(repeatItem => {
430
- return {
431
- ...repeatItem,
432
- enabled: remoteBiorhythmBean.repeatPeriod.includes(repeatItem.index),
433
- }
434
- }),
435
- gradient: BiorhythmGradientTypeMap2[remoteBiorhythmBean.gradientWay],
436
- planList: remoteBiorhythmBean.rhythmPlan.map(plan => {
437
- const startTime = plan.startTime.split(':')
438
- return {
439
- index: plan.sustain,
440
- enable: plan.enable,
441
- icon: plan.rhythmIcon,
442
- time: Number(startTime[0]) * 60 + Number(startTime[1]),
443
- name: plan.name,
444
- colorTemperature: colorTempPercent(parseInt(plan.action[0].startValue)),
445
- brightness: parseInt(plan.action[1].startValue),
446
- action: plan.action,
447
- iconId: plan.iconId,
448
- }
449
- }),
450
- }
451
- }
1
+ import { getFeature, NativeApi, putFeature } from '@ledvance/base/src/api/native'
2
+ import I18n from '@ledvance/base/src/i18n'
3
+ import { useDeviceId, useDp } from '@ledvance/base/src/models/modules/NativePropsSlice'
4
+ import { NativeResult, Result } from '@ledvance/base/src/models/modules/Result'
5
+ import res from '@ledvance/base/src/res'
6
+ import { xLog } from '@ledvance/base/src/utils'
7
+ import { hex2Int, spliceByStep } from '@ledvance/base/src/utils/common'
8
+ import { to16 } from '@tuya/tuya-panel-lamp-sdk/lib/utils'
9
+ import { useUpdateEffect } from 'ahooks'
10
+ import dayjs from 'dayjs'
11
+ import { padStart } from 'lodash'
12
+ import { useCallback, useEffect, useRef, useState } from 'react'
13
+ import {
14
+ BiorhythmBean,
15
+ BiorhythmGradientType,
16
+ BiorhythmGradientTypeMap,
17
+ BiorhythmGradientTypeMap2,
18
+ colorTemperatureValue,
19
+ colorTempPercent,
20
+ Plan,
21
+ RemoteBiorhythmBean,
22
+ } from './BiorhythmBean'
23
+
24
+ type UseBiorhythmType = (dpKey: string, disabledFeature?: boolean) => [BiorhythmBean, SetBiorhythmType];
25
+ type SetBiorhythmType = (biorhythmObj: BiorhythmBean, pushFeature?: boolean) => Promise<Result<any>>;
26
+
27
+ let biorhythmTimer: number | undefined = undefined
28
+ export const useBiorhythm: UseBiorhythmType = (dpKey: string, disabledFeature?: boolean) => {
29
+ const [dp, setDp] = useDp<string, (v: string) => any>(dpKey)
30
+ const deviceId = useDeviceId()
31
+ const [biorhythmState, setBiorhythmState] = useState(dp2Obj(dp))
32
+ const isInternalUpdateRef = useRef(false)
33
+ const previousDpRef = useRef(dp)
34
+
35
+ const getBiorhythm = () => {
36
+ const biorhythm = dp2Obj(dp)
37
+ getRemoteBiorhythm(deviceId, biorhythm).then(res => {
38
+ if (res.success && res.data) {
39
+ xLog('getRemoteBiorhythm', res.data, biorhythm)
40
+ setBiorhythmState(dto2Vo({
41
+ ...res.data,
42
+ enable: biorhythm.enable,
43
+ repeatPeriod: biorhythm.weeks,
44
+ gradientWay: BiorhythmGradientTypeMap[biorhythm.gradient]
45
+ }))
46
+ }
47
+ })
48
+ }
49
+
50
+ useEffect(() => {
51
+ if (disabledFeature) return
52
+ biorhythmTimer = setTimeout(() => {
53
+ getBiorhythm()
54
+ }, 150)
55
+ return () => {
56
+ if (biorhythmTimer) {
57
+ clearTimeout(biorhythmTimer)
58
+ biorhythmTimer = undefined
59
+ }
60
+ }
61
+ }, [])
62
+
63
+ useUpdateEffect(() => {
64
+ if (isInternalUpdateRef.current || disabledFeature) {
65
+ if (disabledFeature) {
66
+ setBiorhythmState(dp2Obj(dp))
67
+ }
68
+ if (isInternalUpdateRef.current) {
69
+ previousDpRef.current = dp
70
+ }
71
+ isInternalUpdateRef.current = false
72
+ return
73
+ }
74
+ if (dp?.toLocaleLowerCase() === previousDpRef.current?.toLocaleLowerCase()) {
75
+ return
76
+ }
77
+ getBiorhythm()
78
+ }, [dp])
79
+
80
+ const setBiorhythmFn = async (biorhythmObj: BiorhythmBean, pushFeature: boolean = true) => {
81
+ const dpValue = obj2Dp(biorhythmObj)
82
+ isInternalUpdateRef.current = true
83
+
84
+ if (pushFeature) {
85
+ const putFeatureRes = await putFeature(deviceId, biorhythmFeatureId, vo2Dto(biorhythmObj))
86
+ console.log(vo2Dto(biorhythmObj), '< --- biorhythmObj --- >')
87
+ if (putFeatureRes.result) {
88
+ setBiorhythmState(biorhythmObj)
89
+ return setDp(dpValue)
90
+ } else {
91
+ isInternalUpdateRef.current = false
92
+ }
93
+ } else {
94
+ setBiorhythmState(biorhythmObj)
95
+ return setDp(dpValue)
96
+ }
97
+ return { success: false }
98
+ }
99
+ return [biorhythmState, setBiorhythmFn]
100
+ }
101
+
102
+ const biorhythmFeatureId = 'Biorhythm'
103
+
104
+ async function getRemoteBiorhythm(deviceId: string, defBiorhythmState: BiorhythmBean): Promise<Result<RemoteBiorhythmBean>> {
105
+ const res: NativeResult<RemoteBiorhythmBean> = await getFeature(deviceId, biorhythmFeatureId)
106
+ if (!res.data) {
107
+ const defData = vo2Dto(defBiorhythmState)
108
+ const pushRes = await putFeature(deviceId, biorhythmFeatureId, defData)
109
+ if (pushRes.result) {
110
+ return getRemoteBiorhythm(deviceId, defBiorhythmState)
111
+ }
112
+ return {
113
+ success: false,
114
+ msg: pushRes.msg,
115
+ }
116
+ }
117
+ return {
118
+ success: true,
119
+ data: res.data,
120
+ }
121
+ }
122
+
123
+ interface RhythmModeSuspendState {
124
+ status: boolean
125
+ suspendTime: string
126
+ }
127
+
128
+ export const useRhythmSuspend = (dp: string): [boolean, () => void, (v: string | undefined) => Promise<Result<any>>] => {
129
+ const [suspendTime, setSuspendTime] = useState<string | undefined>()
130
+ const [biorhythm] = useBiorhythm(dp, true)
131
+ const devId = useDeviceId()
132
+ const currentTime = dayjs().format('YYYY-MM-DD')
133
+
134
+ useEffect(() => {
135
+ getSuspendTime()
136
+ }, [])
137
+
138
+ useUpdateEffect(() => {
139
+ if (biorhythm.enable) {
140
+ if (suspendTime !== currentTime) {
141
+ getSuspendTime()
142
+ }
143
+ } else {
144
+ if (suspendTime !== undefined) {
145
+ setSuspendTime(undefined)
146
+ putSuspendTime(undefined)
147
+ }
148
+ }
149
+ }, [biorhythm.enable, suspendTime])
150
+
151
+ const getSuspendTime = useCallback(() => {
152
+ if (suspendTime !== currentTime) {
153
+ NativeApi.getJson(devId, 'suspendTime').then(res => {
154
+ if (res.success && res.data) {
155
+ const suspend = JSON.parse(res.data) as RhythmModeSuspendState
156
+ setSuspendTime(suspend.suspendTime)
157
+ }
158
+ })
159
+ }
160
+ }, [suspendTime])
161
+
162
+ const putSuspendTime = async (tiem?: string) => {
163
+ return await NativeApi.putJson(devId, 'suspendTime', JSON.stringify({ status: true, suspendTime: tiem }))
164
+ }
165
+
166
+ const setRhythSuspend = useCallback(async (time: string | undefined) => {
167
+ if (time === suspendTime) return { success: true }
168
+ if (!biorhythm.enable) {
169
+ setSuspendTime(undefined)
170
+ return await putSuspendTime(undefined)
171
+ }
172
+ const res = await putSuspendTime(time)
173
+ setSuspendTime(time)
174
+ return res
175
+ }, [suspendTime, biorhythm.enable])
176
+
177
+ return [suspendTime === currentTime, getSuspendTime, setRhythSuspend]
178
+ }
179
+
180
+ export function dp2Obj(dp: string): BiorhythmBean {
181
+ if (!dp || dp === '0000000000') {
182
+ return dp2Obj('0000007f0501060000000000000001061e00000000141901090000000000646401140000000000503201171e000000000000')
183
+ }
184
+ let dpCopy = dp
185
+ // 版本
186
+ hex2Int(dpCopy.slice(0, 2))
187
+ dpCopy = dpCopy.slice(2)
188
+ // 开关
189
+ const enable = hex2Int(dpCopy.slice(0, 2)) === 1
190
+ dpCopy = dpCopy.slice(2)
191
+ // 模式:00 全程渐变,0F 直接渐变
192
+ const gradient =
193
+ dpCopy.slice(0, 2).toLowerCase() === '00'
194
+ ? BiorhythmGradientType.EntireGradient
195
+ : BiorhythmGradientType.DirectGradient
196
+ dpCopy = dpCopy.slice(2)
197
+ const weeks = hex2Int(dpCopy.slice(0, 2))
198
+ .toString(2)
199
+ .padStart(8, '0')
200
+ .split('')
201
+ .reverse()
202
+ .map(v => parseInt(v, 10))
203
+ dpCopy = dpCopy.slice(2)
204
+ // 节点个数 (每个节点长度18),最多8个节点
205
+ hex2Int(dpCopy.slice(0, 2))
206
+ dpCopy = dpCopy.slice(2)
207
+ // 节点列表
208
+ const planList: Plan[] = dpCopy === '00' ? [] : spliceByStep(dpCopy, 18).map((planHex, index) => {
209
+ let hex = planHex
210
+ // 节点开关
211
+ const enable = hex2Int(hex.slice(0, 2)) === 1
212
+ hex = hex.slice(2)
213
+ // 小时
214
+ const hour = hex2Int(hex.slice(0, 2))
215
+ hex = hex.slice(2)
216
+ // 分钟
217
+ const minute = hex2Int(hex.slice(0, 2))
218
+ hex = hex.slice(2)
219
+ const time = hour * 60 + minute
220
+ // 色调 (色相)
221
+ hex2Int(hex.slice(0, 4))
222
+ hex = hex.slice(4)
223
+ // 饱和度
224
+ hex2Int(hex.slice(0, 2))
225
+ hex = hex.slice(2)
226
+ // 明度
227
+ hex2Int(hex.slice(0, 2))
228
+ hex = hex.slice(2)
229
+ // 亮度
230
+ const brightness = hex2Int(hex.slice(0, 2))
231
+ hex = hex.slice(2)
232
+ // 色温
233
+ const colorTemperature = hex2Int(hex.slice(0, 2))
234
+ return {
235
+ index,
236
+ enable,
237
+ icon: getNodeIconByIndex(index).icon,
238
+ iconId: getNodeIconByIndex(index).iconId,
239
+ time,
240
+ name: getNodeNameByIndex(index),
241
+ colorTemperature,
242
+ brightness,
243
+ action: [
244
+ {
245
+ uri: 'model/attribute/set/LightCtrl/ColorTemperature',
246
+ startValue: `${colorTemperatureValue(colorTemperature)}`,
247
+ },
248
+ {
249
+ uri: 'model/attribute/set/LightCtrl/Brightness',
250
+ startValue: `${brightness}`,
251
+ },
252
+ ],
253
+ }
254
+ })
255
+ return {
256
+ enable: enable,
257
+ gradient: gradient,
258
+ weeks: weeks,
259
+ planList: planList,
260
+ }
261
+ }
262
+
263
+ function getNodeNameByIndex(index: number): string {
264
+ switch (index) {
265
+ case 0:
266
+ return I18n.getLang('bio_ryhthm_default_field_text')
267
+ case 1:
268
+ return I18n.getLang('bio_ryhthm_default_field_text2')
269
+ case 2:
270
+ return I18n.getLang('bio_ryhthm_default_field_text3')
271
+ case 3:
272
+ return I18n.getLang('bio_ryhthm_default_field_text4')
273
+ case 4:
274
+ return I18n.getLang('bio_ryhthm_default_field_text5')
275
+ default:
276
+ return `Node ${index + 1}`
277
+ }
278
+ }
279
+
280
+ interface NodeIcon {
281
+ icon: string
282
+ iconId: number
283
+ }
284
+
285
+ function getNodeIconByIndex(index: number): NodeIcon {
286
+ switch (index) {
287
+ case 0:
288
+ return {
289
+ icon: res.rhythm_icon1,
290
+ iconId: 1
291
+ }
292
+ case 1:
293
+ return {
294
+ icon: res.rhythm_icon2,
295
+ iconId: 2
296
+ }
297
+ case 2:
298
+ return {
299
+ icon: res.rhythm_icon3,
300
+ iconId: 9
301
+ }
302
+ case 3:
303
+ return {
304
+ icon: res.rhythm_icon4,
305
+ iconId: 3
306
+ }
307
+ case 4:
308
+ return {
309
+ icon: res.rhythm_icon12,
310
+ iconId: 5
311
+ }
312
+ case 5:
313
+ return {
314
+ icon: res.rhythm_icon1,
315
+ iconId: 1
316
+ }
317
+ case 6:
318
+ return {
319
+ icon: res.rhythm_icon2,
320
+ iconId: 2
321
+ }
322
+ case 7:
323
+ return {
324
+ icon: res.rhythm_icon3,
325
+ iconId: 9
326
+ }
327
+ default:
328
+ return {
329
+ icon: res.rhythm_icon1,
330
+ iconId: 1
331
+ }
332
+ }
333
+ }
334
+
335
+ function obj2Dp(obj: BiorhythmBean): string {
336
+ const versionHex = '00'
337
+ const enableHex = obj.enable ? '01' : '00'
338
+ const gradientHex = obj.gradient === BiorhythmGradientType.EntireGradient ? '00' : '0F'
339
+ const weeksValue: string = padStart([...obj.weeks].reverse().join(''), 8, '0');
340
+ const weeksStr = to16(parseInt(weeksValue, 2), 2);
341
+ const planCountHex = obj.planList.length.toString(16).padStart(2, '0')
342
+ const planListHex = obj.planList
343
+ .map(plan => {
344
+ const enableHex = plan.enable ? '01' : '00'
345
+ const hourHex = to16(Math.trunc(plan.time / 60))
346
+ const minuteHex = to16(plan.time % 60)
347
+ const hsvHex = '00000000'
348
+ const brightnessHex = plan.brightness.toString(16).padStart(2, '0')
349
+ const colorTemperatureHex = plan.colorTemperature.toString(16).padStart(2, '0')
350
+ return enableHex + hourHex + minuteHex + hsvHex + brightnessHex + colorTemperatureHex
351
+ })
352
+ .join('')
353
+ return versionHex + enableHex + gradientHex + weeksStr + planCountHex + planListHex
354
+ }
355
+
356
+ /**
357
+ * BiorhythmBean 转 RemoteBiorhythmBean
358
+ */
359
+ function vo2Dto(biorhythmBean: BiorhythmBean): RemoteBiorhythmBean {
360
+ return {
361
+ enable: biorhythmBean.enable,
362
+ repeatPeriod: biorhythmBean.weeks,
363
+ gradientWay: BiorhythmGradientTypeMap[biorhythmBean.gradient],
364
+ rhythmPlan: biorhythmBean.planList.map(plan => {
365
+ const hour = Math.trunc(plan.time / 60).toString().padStart(2, '0')
366
+ const min = (plan.time % 60).toString().padStart(2, '0')
367
+ return {
368
+ name: plan.name,
369
+ rhythmIcon: plan.icon,
370
+ enable: plan.enable,
371
+ startTime: `${hour}:${min}`,
372
+ sustain: plan.index, // 持续时间涂鸦这边没有,直接用来存ID
373
+ action: plan.action,
374
+ iconId: plan.iconId,
375
+ }
376
+ }),
377
+ }
378
+ }
379
+
380
+ /**
381
+ * RemoteBiorhythmBean 转 BiorhythmBean
382
+ */
383
+ function dto2Vo(remoteBiorhythmBean: RemoteBiorhythmBean): BiorhythmBean {
384
+ return {
385
+ enable: remoteBiorhythmBean.enable,
386
+ weeks: remoteBiorhythmBean.repeatPeriod,
387
+ gradient: BiorhythmGradientTypeMap2[remoteBiorhythmBean.gradientWay],
388
+ planList: remoteBiorhythmBean.rhythmPlan.map(plan => {
389
+ const startTime = plan.startTime.split(':')
390
+ return {
391
+ index: plan.sustain,
392
+ enable: plan.enable,
393
+ icon: plan.rhythmIcon,
394
+ time: Number(startTime[0]) * 60 + Number(startTime[1]),
395
+ name: plan.name,
396
+ colorTemperature: colorTempPercent(parseInt(plan.action[0].startValue)),
397
+ brightness: parseInt(plan.action[1].startValue),
398
+ action: plan.action,
399
+ iconId: plan.iconId,
400
+ }
401
+ }),
402
+ }
403
+ }