@ledvance/ui-biz-bundle 1.1.104 → 1.1.106
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/modules/timer/TimerPageAction.ts +0 -1
- package/src/navigation/Routers.ts +3 -1
- package/src/newModules/diyScene/DefaultScenes.ts +438 -0
- package/src/newModules/diyScene/DiySceneActions.ts +232 -0
- package/src/newModules/diyScene/DiySceneEditorPage.tsx +359 -0
- package/src/newModules/diyScene/DiyScenePage.tsx +297 -0
- package/src/newModules/diyScene/Router.ts +25 -0
- package/src/newModules/energyConsumption/EnergyConsumptionActions.ts +15 -2
- package/src/newModules/energyConsumption/EnergyConsumptionChart.tsx +31 -10
- package/src/newModules/energyConsumption/component/DateSwitch.tsx +111 -0
- package/src/newModules/energyConsumption/component/NewBarChart.tsx +16 -3
- package/src/newModules/mood/MoodPage.tsx +3 -3
- package/src/newModules/timeSchedule/Interface.ts +19 -7
- package/src/newModules/timeSchedule/TimeScheduleActions.ts +6 -0
- package/src/newModules/timeSchedule/TimeScheduleDetailPage.tsx +134 -57
- package/src/newModules/timeSchedule/TimeSchedulePage.tsx +32 -31
- package/src/newModules/timeSchedule/components/ManuaSettings.tsx +42 -9
|
@@ -2,7 +2,12 @@ import {useDp} from "@ledvance/base/src/models/modules/NativePropsSlice";
|
|
|
2
2
|
import {localeNumber, loopsText, monthFormat, monthFormatShort} from "@ledvance/base/src/utils/common";
|
|
3
3
|
import {EnergyData} from "./component/EnergyModal";
|
|
4
4
|
import {NativeApi} from "@ledvance/base/src/api/native";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
DpResultByMonthResData,
|
|
7
|
+
getDataWithSpecified,
|
|
8
|
+
getDpResultByHour,
|
|
9
|
+
getDpResultByMonth
|
|
10
|
+
} from "@ledvance/base/src/models/TuyaApi";
|
|
6
11
|
import {DateType} from "@ledvance/ui-biz-bundle/src/newModules/energyConsumption/co2Data";
|
|
7
12
|
import {OverviewItem} from "@ledvance/ui-biz-bundle/src/newModules/energyConsumption/EnergyConsumptionPage";
|
|
8
13
|
import {overDays} from "@ledvance/base/src/utils/index";
|
|
@@ -44,8 +49,13 @@ export async function getElectricity(devId: string, addEleDpCode: string, date:
|
|
|
44
49
|
return res
|
|
45
50
|
}
|
|
46
51
|
|
|
52
|
+
let dpResultByMonthCache: DpResultByMonthResData | undefined = undefined
|
|
47
53
|
const getDpResultByYear = async (devId: string, addEleDpCode: string, dateStr: string): Promise<OverviewItem[]> => {
|
|
48
|
-
|
|
54
|
+
let res: DpResultByMonthResData | undefined;
|
|
55
|
+
if (!dpResultByMonthCache) {
|
|
56
|
+
dpResultByMonthCache = await getDpResultByMonth(devId, addEleDpCode, 'sum')
|
|
57
|
+
}
|
|
58
|
+
res = dpResultByMonthCache;
|
|
49
59
|
if (!isEmpty(res)) {
|
|
50
60
|
if (!isEmpty(res.years)) {
|
|
51
61
|
const year = dateStr;
|
|
@@ -105,6 +115,9 @@ const getDpResultByDate = async (devId: string, addEleDpCode: string, date: stri
|
|
|
105
115
|
return []
|
|
106
116
|
}
|
|
107
117
|
const res = await getDpResultByHour(devId, addEleDpCode, date, 'sum')
|
|
118
|
+
if (!res) {
|
|
119
|
+
return []
|
|
120
|
+
}
|
|
108
121
|
const list: Array<OverviewItem> = []
|
|
109
122
|
const resData = Object.keys(res)?.map(val => {
|
|
110
123
|
return {key: Number(val?.slice(8, 10)), value: Number(res[val])}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useCallback } from "react";
|
|
2
|
-
import {Image, Platform, StyleSheet, View, Text} from "react-native";
|
|
2
|
+
import {Image, Platform, StyleSheet, View, Text, TouchableOpacity} from "react-native";
|
|
3
3
|
import {useRoute} from '@react-navigation/core'
|
|
4
4
|
import Page from "@ledvance/base/src/components/Page";
|
|
5
5
|
import res from "@ledvance/base/src/res";
|
|
@@ -19,6 +19,7 @@ import DateSelectedItem from "@ledvance/ui-biz-bundle/src/newModules/energyConsu
|
|
|
19
19
|
import {useReactive, useUpdateEffect} from "ahooks";
|
|
20
20
|
import {getElectricity} from "@ledvance/ui-biz-bundle/src/newModules/energyConsumption/EnergyConsumptionActions";
|
|
21
21
|
import {useDeviceId} from "@ledvance/base/src/models/modules/NativePropsSlice";
|
|
22
|
+
import DateSwitch from "@ledvance/ui-biz-bundle/src/newModules/energyConsumption/component/DateSwitch";
|
|
22
23
|
|
|
23
24
|
const {convertX: cx} = Utils.RatioUtils
|
|
24
25
|
const {withTheme} = Utils.ThemeUtils
|
|
@@ -50,6 +51,14 @@ const EnergyConsumptionChart = (props: { theme?: ThemeType }) => {
|
|
|
50
51
|
listEmptyText: {
|
|
51
52
|
flex: 0
|
|
52
53
|
},
|
|
54
|
+
downloadIcon: {
|
|
55
|
+
width: cx(24),
|
|
56
|
+
height: cx(24),
|
|
57
|
+
tintColor: props.theme?.global.brand,
|
|
58
|
+
position: 'absolute',
|
|
59
|
+
right: 0,
|
|
60
|
+
top: cx(10)
|
|
61
|
+
}
|
|
53
62
|
});
|
|
54
63
|
|
|
55
64
|
const getDateType = useCallback((date: string) => {
|
|
@@ -64,7 +73,7 @@ const EnergyConsumptionChart = (props: { theme?: ThemeType }) => {
|
|
|
64
73
|
}
|
|
65
74
|
}
|
|
66
75
|
return DateType.Day;
|
|
67
|
-
}, [])
|
|
76
|
+
}, []);
|
|
68
77
|
const dateType = getDateType(date);
|
|
69
78
|
const state = useReactive({
|
|
70
79
|
loading: false,
|
|
@@ -87,11 +96,13 @@ const EnergyConsumptionChart = (props: { theme?: ThemeType }) => {
|
|
|
87
96
|
getElectricity(devId, addEleDpCode, state.date, state.dateType).then((res) => {
|
|
88
97
|
state.chartData = res;
|
|
89
98
|
state.loading = false;
|
|
90
|
-
})
|
|
99
|
+
}).catch(()=>{
|
|
100
|
+
state.loading = false;
|
|
101
|
+
});
|
|
91
102
|
}, [state.date]);
|
|
92
103
|
|
|
93
104
|
const getEmptyDataTip = useCallback(() => {
|
|
94
|
-
if (state.over365Days) {
|
|
105
|
+
if (state.over365Days && state.dateType !== DateType.Day) {
|
|
95
106
|
return I18n.getLang('energyconsumption_Daylimit')
|
|
96
107
|
}
|
|
97
108
|
if (state.dateType === DateType.Day && state.over7Days) {
|
|
@@ -139,16 +150,26 @@ const EnergyConsumptionChart = (props: { theme?: ThemeType }) => {
|
|
|
139
150
|
return (
|
|
140
151
|
<Page
|
|
141
152
|
backText={I18n.getLang('consumption_data_annual_bar_chart_system_back_text')}
|
|
142
|
-
headlineIcon={state.chartData?.length ? res.download_icon : undefined}
|
|
143
|
-
onHeadlineIconClick={() => {
|
|
144
|
-
exportFile(state.chartData,params.price,params.unit)
|
|
145
|
-
}}
|
|
146
153
|
showGreenery={false}
|
|
147
154
|
loading={state.loading}
|
|
148
155
|
greeneryIcon={res.energy_consumption_greenery}
|
|
149
156
|
headlineContent={
|
|
150
|
-
<View style={{
|
|
151
|
-
<
|
|
157
|
+
<View style={{width: '100%',flexDirection:'row'}}>
|
|
158
|
+
<DateSwitch
|
|
159
|
+
style={{flex: 1}}
|
|
160
|
+
date={state.date}
|
|
161
|
+
dateType={state.dateType}
|
|
162
|
+
headlineText={state.headlineText}
|
|
163
|
+
onDateChange={(date) => {
|
|
164
|
+
state.date = date;
|
|
165
|
+
}}/>
|
|
166
|
+
<TouchableOpacity onPress={() => {
|
|
167
|
+
exportFile(state.chartData, params.price, params.unit)
|
|
168
|
+
}}>
|
|
169
|
+
<Image
|
|
170
|
+
style={styles.downloadIcon}
|
|
171
|
+
source={state.chartData?.length ? res.download_icon : undefined}/>
|
|
172
|
+
</TouchableOpacity>
|
|
152
173
|
</View>
|
|
153
174
|
}
|
|
154
175
|
>
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import ThemeType from "@ledvance/base/src/config/themeType";
|
|
2
|
+
import React, {PropsWithChildren, useCallback, useEffect} from "react";
|
|
3
|
+
import {Image, Text, TouchableOpacity, View, ViewProps} from "react-native";
|
|
4
|
+
import {Utils} from "tuya-panel-kit";
|
|
5
|
+
import {useReactive} from "ahooks";
|
|
6
|
+
import {DateType} from "@ledvance/ui-biz-bundle/src/newModules/energyConsumption/co2Data";
|
|
7
|
+
import res from "@ledvance/base/src/res";
|
|
8
|
+
import dayjs from "dayjs";
|
|
9
|
+
|
|
10
|
+
const cx = Utils.RatioUtils.convertX;
|
|
11
|
+
const {withTheme} = Utils.ThemeUtils
|
|
12
|
+
|
|
13
|
+
interface DateSwitchProps extends PropsWithChildren<ViewProps> {
|
|
14
|
+
theme?: ThemeType
|
|
15
|
+
headlineText: string,
|
|
16
|
+
date: string,
|
|
17
|
+
dateType: DateType,
|
|
18
|
+
onDateChange: (string) => void
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default withTheme(function DateSwitch(props: DateSwitchProps) {
|
|
22
|
+
const {dateType, date, onDateChange, theme, headlineText} = props;
|
|
23
|
+
const state = useReactive({
|
|
24
|
+
date: date,
|
|
25
|
+
dateType: dateType,
|
|
26
|
+
headlineText: headlineText,
|
|
27
|
+
disableArrowLeft: false,
|
|
28
|
+
disableArrowRight: false,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
state.date = date;
|
|
33
|
+
state.headlineText = headlineText;
|
|
34
|
+
state.dateType = dateType;
|
|
35
|
+
const {canPreChangeDate, canNextChangeDate} = canPreOrNextChangeDate(dayjs(date));
|
|
36
|
+
state.disableArrowRight = !canNextChangeDate;
|
|
37
|
+
state.disableArrowLeft = !canPreChangeDate;
|
|
38
|
+
}, [date, headlineText, dateType]);
|
|
39
|
+
|
|
40
|
+
const canPreOrNextChangeDate = useCallback((datejs: dayjs.Dayjs) => {
|
|
41
|
+
const minDatejs = dayjs('2000-1-1');
|
|
42
|
+
const nowDatejs = dayjs();
|
|
43
|
+
const year = datejs.year();
|
|
44
|
+
const month = (datejs.month() + 1).toString().padStart(2, '0');
|
|
45
|
+
const day = datejs.date().toString().padStart(2, '0');
|
|
46
|
+
const dateType = state.dateType;
|
|
47
|
+
const dateUnit = dateType === DateType.Year ? 'year' : (dateType === DateType.Month ? 'month' : 'day');
|
|
48
|
+
let canPreChangeDate = datejs.isAfter(minDatejs, dateUnit);
|
|
49
|
+
let canNextChangeDate = datejs.isBefore(nowDatejs, dateUnit);
|
|
50
|
+
let date: string | undefined = undefined;
|
|
51
|
+
if (datejs >= minDatejs && datejs <= nowDatejs) {
|
|
52
|
+
switch (state.dateType) {
|
|
53
|
+
case DateType.Day:
|
|
54
|
+
date = `${year}${month}${day}`;
|
|
55
|
+
break
|
|
56
|
+
case DateType.Month:
|
|
57
|
+
date = `${year}${month}`;
|
|
58
|
+
break
|
|
59
|
+
case DateType.Year:
|
|
60
|
+
date = `${year}`;
|
|
61
|
+
break
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {date, canPreChangeDate, canNextChangeDate};
|
|
65
|
+
}, [state.dateType]);
|
|
66
|
+
|
|
67
|
+
const changeDate = useCallback((isNextDate: boolean) => {
|
|
68
|
+
const datejs = dayjs(state.date)
|
|
69
|
+
const dateType = state.dateType
|
|
70
|
+
const dateUnit = dateType === DateType.Year ? 'year' : (dateType === DateType.Month ? 'month' : 'day');
|
|
71
|
+
const newDatejs = datejs.add(isNextDate ? 1 : -1, dateUnit);
|
|
72
|
+
const {date, canPreChangeDate, canNextChangeDate} = canPreOrNextChangeDate(newDatejs);
|
|
73
|
+
state.disableArrowRight = !canNextChangeDate;
|
|
74
|
+
state.disableArrowLeft = !canPreChangeDate;
|
|
75
|
+
if (date) {
|
|
76
|
+
onDateChange(date);
|
|
77
|
+
}
|
|
78
|
+
}, [state.date, canPreOrNextChangeDate, state.disableArrowRight, state.disableArrowLeft, onDateChange]);
|
|
79
|
+
|
|
80
|
+
return (<View style={[props.style, {flexDirection: 'row', alignItems: 'center', justifyContent: 'center'}]}>
|
|
81
|
+
<TouchableOpacity
|
|
82
|
+
disabled={state.disableArrowLeft}
|
|
83
|
+
onPress={() => {
|
|
84
|
+
changeDate(false);
|
|
85
|
+
}}>
|
|
86
|
+
<Image
|
|
87
|
+
source={res.arrow_left}
|
|
88
|
+
style={{tintColor: state.disableArrowLeft ? theme?.global.disabledFontColor : theme?.global.brand}}
|
|
89
|
+
height={cx(36)}
|
|
90
|
+
width={cx(36)}/>
|
|
91
|
+
</TouchableOpacity>
|
|
92
|
+
<Text style={{
|
|
93
|
+
fontSize: cx(24),
|
|
94
|
+
minWidth: cx(200),
|
|
95
|
+
textAlign: 'center',
|
|
96
|
+
color: theme?.global.brand,
|
|
97
|
+
fontFamily: 'helvetica_neue_lt_std_roman',
|
|
98
|
+
}}>{state.headlineText}</Text>
|
|
99
|
+
<TouchableOpacity
|
|
100
|
+
disabled={state.disableArrowRight}
|
|
101
|
+
onPress={() => {
|
|
102
|
+
changeDate(true);
|
|
103
|
+
}}>
|
|
104
|
+
<Image
|
|
105
|
+
source={res.arrow_right}
|
|
106
|
+
style={{tintColor: state.disableArrowRight ? theme?.global.disabledFontColor : theme?.global.brand}}
|
|
107
|
+
height={cx(36)}
|
|
108
|
+
width={cx(36)}/>
|
|
109
|
+
</TouchableOpacity>
|
|
110
|
+
</View>)
|
|
111
|
+
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {useRef} from 'react';
|
|
1
|
+
import React, {useMemo, useRef} from 'react';
|
|
2
2
|
import {View} from 'react-native';
|
|
3
3
|
import ECharts from '@ledvance/react-native-echarts-pro';
|
|
4
4
|
import I18n from "@ledvance/base/src/i18n";
|
|
@@ -28,7 +28,20 @@ const BarChartWithTouch = (props: BarChartProps) => {
|
|
|
28
28
|
const dataPriceY = data?.map(item => {
|
|
29
29
|
return ((isNaN(Number(item.value)) ? 0 : Number(item.value)) * price).toFixed(2);
|
|
30
30
|
});
|
|
31
|
-
const maxValue =
|
|
31
|
+
const maxValue = useMemo(() => {
|
|
32
|
+
let max = Math.max(...dataKwhY)
|
|
33
|
+
if (max < 0.1) {
|
|
34
|
+
max += 0.02
|
|
35
|
+
max = max - (max % 0.02)
|
|
36
|
+
} else if (max < 1) {
|
|
37
|
+
max += 0.2
|
|
38
|
+
max = max - (max % 0.2)
|
|
39
|
+
} else if (max < 10) {
|
|
40
|
+
max = Math.ceil(max) + 2
|
|
41
|
+
max = max - (max % 2)
|
|
42
|
+
}
|
|
43
|
+
return max
|
|
44
|
+
}, [dataKwhY]);
|
|
32
45
|
const option = {
|
|
33
46
|
tooltip: {
|
|
34
47
|
show: true,
|
|
@@ -56,7 +69,7 @@ const BarChartWithTouch = (props: BarChartProps) => {
|
|
|
56
69
|
yAxis: [{
|
|
57
70
|
type: 'value',
|
|
58
71
|
name: I18n.getLang('consumption_data_annual_bar_chart_text'),
|
|
59
|
-
max: Math.
|
|
72
|
+
max: Math.max(maxValue, 0.02),
|
|
60
73
|
min: 0,
|
|
61
74
|
position: 'left',
|
|
62
75
|
axisLabel: {
|
|
@@ -23,7 +23,7 @@ import { getRemoteMoodList, useMoodScene } from './MoodActions';
|
|
|
23
23
|
import { useParams } from '@ledvance/base/src/hooks/Hooks';
|
|
24
24
|
import { ui_biz_routerKey } from '../../navigation/Routers'
|
|
25
25
|
import { cloneDeep, filter, map } from 'lodash';
|
|
26
|
-
import { saveFlagMode } from '
|
|
26
|
+
import { saveFlagMode } from '../../modules/flags/FlagActions';
|
|
27
27
|
import { SceneStatusType, WorkMode } from '@ledvance/base/src/utils/interface';
|
|
28
28
|
import { showDialog } from '@ledvance/base/src/utils/common';
|
|
29
29
|
import I18n from '@ledvance/base/src/i18n';
|
|
@@ -311,7 +311,7 @@ const MoodPage = (props: { theme?: ThemeType }) => {
|
|
|
311
311
|
right: cx(60),
|
|
312
312
|
top: Platform.OS === 'android' ? cx(90) : cx(130),
|
|
313
313
|
maxWidth: cx(200),
|
|
314
|
-
backgroundColor: props.theme
|
|
314
|
+
backgroundColor: props.theme?.card.background,
|
|
315
315
|
},
|
|
316
316
|
popoverItem: {
|
|
317
317
|
padding: cx(5),
|
|
@@ -365,7 +365,7 @@ const MoodPage = (props: { theme?: ThemeType }) => {
|
|
|
365
365
|
})
|
|
366
366
|
}}
|
|
367
367
|
>
|
|
368
|
-
<Image source={res.ic_refresh} style={{ width: cx(24), height: cx(24), tintColor: props.theme
|
|
368
|
+
<Image source={res.ic_refresh} style={{ width: cx(24), height: cx(24), tintColor: props.theme?.global.fontColor }} />
|
|
369
369
|
</TouchableOpacity>
|
|
370
370
|
<Spacer height={cx(10)} />
|
|
371
371
|
{state.originMoods.length >= MAX_MOOD_COUNT && (
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import I18n from "@ledvance/base/src/i18n";
|
|
2
|
+
import { AdjustType, DiySceneInfo } from "@ledvance/base/src/utils/interface";
|
|
2
3
|
import { MoodInfo, MoodUIInfo } from "../mood/Interface";
|
|
3
4
|
|
|
4
5
|
export interface Timer {
|
|
@@ -27,8 +28,8 @@ export interface HSV {
|
|
|
27
28
|
export type Category = 'light' | 'socket' | 'fan' | 'mainLight' | 'secondaryLight'
|
|
28
29
|
|
|
29
30
|
export interface ApplyForItem {
|
|
30
|
-
name?: string
|
|
31
|
-
index?: number
|
|
31
|
+
name?: string
|
|
32
|
+
index?: number
|
|
32
33
|
key: string;
|
|
33
34
|
dp: string;
|
|
34
35
|
type: Category;
|
|
@@ -45,6 +46,7 @@ interface judgmentSupport {
|
|
|
45
46
|
isMixLight?: boolean;
|
|
46
47
|
isFanLight?: boolean;
|
|
47
48
|
isUVCFan?: boolean;
|
|
49
|
+
isMoodStrip?: boolean;
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
export interface ManualSettingProps extends judgmentSupport {
|
|
@@ -63,7 +65,8 @@ export enum DeviceType {
|
|
|
63
65
|
MixLight = 'mixLight',
|
|
64
66
|
StripLight = 'stripLight',
|
|
65
67
|
CeilingLight = 'ceilingLight',
|
|
66
|
-
FanLight = 'fanLight'
|
|
68
|
+
FanLight = 'fanLight',
|
|
69
|
+
MoodStrip = 'moodStrip',
|
|
67
70
|
}
|
|
68
71
|
// export type DeviceType = 'LightSource' | 'CeilingLight' | 'StringLight' | 'StripLight' | 'MixLight';
|
|
69
72
|
|
|
@@ -93,12 +96,16 @@ export interface StripLightData extends DeviceData {
|
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
export interface FanLightData extends DeviceData {
|
|
96
|
-
fanSpeed: number
|
|
99
|
+
fanSpeed: number
|
|
97
100
|
direction: 'forward' | 'reverse'
|
|
98
101
|
mode: 'nature' | 'normal'
|
|
99
102
|
disinfect: boolean
|
|
100
103
|
}
|
|
101
104
|
|
|
105
|
+
export interface MoodStripData extends DeviceData {
|
|
106
|
+
adjustType: AdjustType
|
|
107
|
+
}
|
|
108
|
+
|
|
102
109
|
export type ComponentConfig =
|
|
103
110
|
| { type: DeviceType.LightSource; deviceData: DeviceData }
|
|
104
111
|
| { type: DeviceType.MixLight; deviceData: MixLightData }
|
|
@@ -106,6 +113,7 @@ export type ComponentConfig =
|
|
|
106
113
|
| { type: DeviceType.CeilingLight; deviceData: StripLightData }
|
|
107
114
|
| { type: DeviceType.FanLight; deviceData: FanLightData }
|
|
108
115
|
| { type: DeviceType.PowerStrip; deviceData: DeviceData}
|
|
116
|
+
| { type: DeviceType.MoodStrip; deviceData: MoodStripData}
|
|
109
117
|
|
|
110
118
|
export interface TimeScheduleDetailState {
|
|
111
119
|
timeSchedule: Timer;
|
|
@@ -117,14 +125,18 @@ export interface TimeScheduleDetailState {
|
|
|
117
125
|
loading: boolean;
|
|
118
126
|
moodLoading: boolean;
|
|
119
127
|
manualData: ComponentConfig;
|
|
120
|
-
mood?: MoodInfo;
|
|
121
|
-
moods: MoodUIInfo[];
|
|
128
|
+
mood?: MoodInfo | DiySceneInfo;
|
|
129
|
+
moods: MoodUIInfo[] | DiySceneInfo[];
|
|
130
|
+
filterMoods: MoodUIInfo[] | DiySceneInfo[];
|
|
131
|
+
staticTagChecked: boolean;
|
|
132
|
+
dynamicTagChecked: boolean;
|
|
133
|
+
diyTagChecked: boolean;
|
|
122
134
|
timerId: any;
|
|
123
135
|
moodName: string;
|
|
124
136
|
}
|
|
125
137
|
export interface DeviceStateType {
|
|
126
138
|
deviceData: ComponentConfig
|
|
127
|
-
mood?: MoodInfo
|
|
139
|
+
mood?: MoodInfo | DiySceneInfo
|
|
128
140
|
isManual: boolean
|
|
129
141
|
}
|
|
130
142
|
|
|
@@ -2,6 +2,7 @@ import { NativeApi } from '@ledvance/base/src/api/native';
|
|
|
2
2
|
import { Timer, TimerActions } from './Interface';
|
|
3
3
|
import { parseJSON } from '@tuya/tuya-panel-lamp-sdk/lib/utils';
|
|
4
4
|
import { ColorList } from '@ledvance/base/src/components/StripAdjustView';
|
|
5
|
+
import {AdjustType} from "@ledvance/base/src/utils/interface";
|
|
5
6
|
|
|
6
7
|
export const defDeviceData = {
|
|
7
8
|
h: 0,
|
|
@@ -32,6 +33,11 @@ export const defFanLightDeviceData = {
|
|
|
32
33
|
disinfect: false
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
export const defMoodStripDeviceData = {
|
|
37
|
+
...defDeviceData,
|
|
38
|
+
adjustType: AdjustType.COLOUR
|
|
39
|
+
};
|
|
40
|
+
|
|
35
41
|
export const getTimeSchedule = async (deviceId: string): Promise<Timer[]> => {
|
|
36
42
|
const res = await NativeApi.getAllTaskTimer(deviceId);
|
|
37
43
|
if (res.success && Array.isArray(res.data)) {
|
|
@@ -1,50 +1,40 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
Image,
|
|
5
|
-
ScrollView,
|
|
6
|
-
StyleSheet,
|
|
7
|
-
Text,
|
|
8
|
-
TouchableOpacity,
|
|
9
|
-
View,
|
|
10
|
-
} from 'react-native';
|
|
11
|
-
import { useNavigation } from '@react-navigation/core';
|
|
1
|
+
import React, {useCallback, useEffect, useMemo} from 'react';
|
|
2
|
+
import {FlatList, Image, ScrollView, StyleSheet, Text, TouchableOpacity, View,} from 'react-native';
|
|
3
|
+
import {useNavigation} from '@react-navigation/core';
|
|
12
4
|
import Page from '@ledvance/base/src/components/Page';
|
|
13
5
|
import I18n from '@ledvance/base/src/i18n';
|
|
14
6
|
import TextField from '@ledvance/base/src/components/TextField';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
7
|
+
import {cloneDeep, isEqual} from 'lodash';
|
|
8
|
+
import {useReactive} from 'ahooks';
|
|
9
|
+
import {SwitchButton, TimerPicker, Utils} from 'tuya-panel-kit';
|
|
18
10
|
import Spacer from '@ledvance/base/src/components/Spacer';
|
|
19
11
|
import LdvWeekView from '@ledvance/base/src/components/weekSelect';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
ApplyForItem,
|
|
23
|
-
ComponentConfig,
|
|
24
|
-
DeviceType,
|
|
25
|
-
TimeScheduleDetailState,
|
|
26
|
-
Timer,
|
|
27
|
-
TimerActions,
|
|
28
|
-
} from './Interface';
|
|
12
|
+
import {convertTo12HourFormat, loopText, showDialog} from '@ledvance/base/src/utils/common';
|
|
13
|
+
import {ApplyForItem, ComponentConfig, DeviceType, Timer, TimerActions, TimeScheduleDetailState,} from './Interface';
|
|
29
14
|
import res from '@ledvance/base/src/res';
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
useSystemTimeFormate,
|
|
34
|
-
} from '@ledvance/base/src/models/modules/NativePropsSlice';
|
|
35
|
-
import { TimeSchedulePageParams } from './TimeSchedulePage';
|
|
36
|
-
import { Result } from '@ledvance/base/src/models/modules/Result';
|
|
15
|
+
import {useDeviceId, useMoods, useSystemTimeFormate,} from '@ledvance/base/src/models/modules/NativePropsSlice';
|
|
16
|
+
import {TimeSchedulePageParams} from './TimeSchedulePage';
|
|
17
|
+
import {Result} from '@ledvance/base/src/models/modules/Result';
|
|
37
18
|
import DeleteButton from '@ledvance/base/src/components/DeleteButton';
|
|
38
19
|
import InfoText from '@ledvance/base/src/components/InfoText';
|
|
39
20
|
import SegmentControl from '@ledvance/base/src/components/segmentControl';
|
|
40
|
-
import {
|
|
21
|
+
import {useParams} from '@ledvance/base/src/hooks/Hooks';
|
|
41
22
|
import ManualSettings from './components/ManuaSettings';
|
|
42
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
defDeviceData,
|
|
25
|
+
defFanLightDeviceData,
|
|
26
|
+
defMixDeviceData,
|
|
27
|
+
defMoodStripDeviceData,
|
|
28
|
+
defStripDeviceData
|
|
29
|
+
} from './TimeScheduleActions';
|
|
43
30
|
import MoodItem from '../mood/MoodItem';
|
|
44
|
-
import {
|
|
45
|
-
import { MoodUIInfo
|
|
31
|
+
import {getRemoteMoodList} from '../mood/MoodActions';
|
|
32
|
+
import {MoodInfo, MoodUIInfo} from '../mood/Interface';
|
|
46
33
|
import Summary from '@ledvance/base/src/components/Summary'
|
|
47
34
|
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
35
|
+
import Tag from "@ledvance/base/src/components/Tag";
|
|
36
|
+
import DiySceneItem from '@ledvance/base/src/components/DiySceneItem';
|
|
37
|
+
import {DiySceneInfo} from "@ledvance/base/src/utils/interface";
|
|
48
38
|
|
|
49
39
|
const { convertX: cx } = Utils.RatioUtils;
|
|
50
40
|
const { toFixedString } = Utils.NumberUtils;
|
|
@@ -63,6 +53,7 @@ const TimeScheduleDetailPage = (props: { theme?: ThemeType }) => {
|
|
|
63
53
|
const navigation = useNavigation();
|
|
64
54
|
const devId = useDeviceId();
|
|
65
55
|
const [moods, setMoods] = useMoods();
|
|
56
|
+
type MoodsType = typeof params.isMoodStrip extends true ? DiySceneInfo[] : MoodUIInfo[]
|
|
66
57
|
const state = useReactive<TimeScheduleDetailState>({
|
|
67
58
|
timeSchedule: params.mode === 'add' ? newTimeSchedule() : cloneDeep(params.timeSchedule),
|
|
68
59
|
dps: params.mode === 'add' ? {} : params.timeSchedule.dps,
|
|
@@ -78,6 +69,10 @@ const TimeScheduleDetailPage = (props: { theme?: ThemeType }) => {
|
|
|
78
69
|
: params.manualDataDp2Obj(params.timeSchedule.dps).deviceData,
|
|
79
70
|
mood: params.mode === 'add' ? undefined : params.manualDataDp2Obj(params.timeSchedule.dps)?.mood,
|
|
80
71
|
moods: cloneDeep(moods),
|
|
72
|
+
filterMoods: cloneDeep(moods),
|
|
73
|
+
staticTagChecked: true,
|
|
74
|
+
dynamicTagChecked: true,
|
|
75
|
+
diyTagChecked: true,
|
|
81
76
|
timerId: undefined,
|
|
82
77
|
moodName: '',
|
|
83
78
|
});
|
|
@@ -149,15 +144,37 @@ const TimeScheduleDetailPage = (props: { theme?: ThemeType }) => {
|
|
|
149
144
|
useEffect(() => {
|
|
150
145
|
if (state.moods?.length) {
|
|
151
146
|
state.moodName =
|
|
152
|
-
state.moods.find(m =>
|
|
147
|
+
(state.moods as MoodsType).find(m =>
|
|
153
148
|
params.isCeilingLight
|
|
154
|
-
? m.mainLamp.id === state.mood?.mainLamp.id &&
|
|
155
|
-
m.secondaryLamp.id === state.mood?.secondaryLamp.id
|
|
149
|
+
? m.mainLamp.id === (state.mood as MoodInfo)?.mainLamp.id &&
|
|
150
|
+
m.secondaryLamp.id === (state.mood as MoodInfo)?.secondaryLamp.id
|
|
156
151
|
: m.id === state.mood?.id
|
|
157
152
|
)?.name || '';
|
|
158
153
|
}
|
|
159
154
|
}, [state.mood, state.moods]);
|
|
160
155
|
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
if (params.isMoodStrip) {
|
|
158
|
+
state.filterMoods = (state.moods as DiySceneInfo[]).filter(item => {
|
|
159
|
+
return [state.staticTagChecked, state.dynamicTagChecked, state.diyTagChecked].every(it => !it)
|
|
160
|
+
|| (state.staticTagChecked && item.type === 'Static')
|
|
161
|
+
|| (state.dynamicTagChecked && item.type === 'Dynamic')
|
|
162
|
+
|| (state.diyTagChecked && item.type === 'DIY')
|
|
163
|
+
})
|
|
164
|
+
} else {
|
|
165
|
+
state.filterMoods = (state.moods as MoodsType).filter(item => {
|
|
166
|
+
return (
|
|
167
|
+
(state.staticTagChecked && state.dynamicTagChecked) ||
|
|
168
|
+
(!state.staticTagChecked && !state.dynamicTagChecked) ||
|
|
169
|
+
(state.staticTagChecked && item.mainLamp.nodes.length < 2) ||
|
|
170
|
+
(state.dynamicTagChecked &&
|
|
171
|
+
(item.secondaryLamp.nodes.length > 1 || item.mainLamp.nodes.length > 1))
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
}, [state.staticTagChecked, state.dynamicTagChecked, state.diyTagChecked, state.moods]);
|
|
177
|
+
|
|
161
178
|
const getFormateTime = useCallback((time: number | string) => {
|
|
162
179
|
if (typeof time === 'number') {
|
|
163
180
|
return `${toFixedString(Math.trunc(time / 60), 2)}:${toFixedString(time % 60, 2)}`;
|
|
@@ -208,7 +225,7 @@ const TimeScheduleDetailPage = (props: { theme?: ThemeType }) => {
|
|
|
208
225
|
}, [params.applyForList.length, params.applyForDisabled]);
|
|
209
226
|
|
|
210
227
|
const getMoodItemEnable = useCallback((item: MoodUIInfo) => {
|
|
211
|
-
return params.isCeilingLight ? ((item.mainLamp.id === state.mood?.mainLamp?.id) && (item.secondaryLamp.id === state.mood?.secondaryLamp?.id)) : item.id === state.mood?.id
|
|
228
|
+
return params.isCeilingLight ? ((item.mainLamp.id === (state.mood as MoodInfo)?.mainLamp?.id) && (item.secondaryLamp.id === (state.mood as MoodInfo)?.secondaryLamp?.id)) : item.id === state.mood?.id
|
|
212
229
|
}, [state.mood, params.isCeilingLight])
|
|
213
230
|
|
|
214
231
|
const styles = StyleSheet.create({
|
|
@@ -284,6 +301,10 @@ const TimeScheduleDetailPage = (props: { theme?: ThemeType }) => {
|
|
|
284
301
|
color: props.theme?.global.fontColor,
|
|
285
302
|
fontSize: cx(14)
|
|
286
303
|
},
|
|
304
|
+
tagLine: {
|
|
305
|
+
flexDirection: 'row',
|
|
306
|
+
marginHorizontal: cx(24),
|
|
307
|
+
}
|
|
287
308
|
});
|
|
288
309
|
|
|
289
310
|
return (
|
|
@@ -473,25 +494,77 @@ const TimeScheduleDetailPage = (props: { theme?: ThemeType }) => {
|
|
|
473
494
|
}}
|
|
474
495
|
/>
|
|
475
496
|
) : (
|
|
476
|
-
!showMoodFanSelectText ?
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
497
|
+
!showMoodFanSelectText ? (
|
|
498
|
+
<View>
|
|
499
|
+
{!(params.isStringLight || params.isStripLight) && <View style={styles.tagLine}>
|
|
500
|
+
<Tag
|
|
501
|
+
checked={state.staticTagChecked}
|
|
502
|
+
text={I18n.getLang('mood_overview_filter_name_text1')}
|
|
503
|
+
onCheckedChange={checked => {
|
|
504
|
+
state.staticTagChecked = checked;
|
|
505
|
+
}}
|
|
506
|
+
/>
|
|
507
|
+
<Spacer width={cx(8)} height={0} />
|
|
508
|
+
<Tag
|
|
509
|
+
checked={state.dynamicTagChecked}
|
|
510
|
+
text={I18n.getLang('mood_overview_filter_name_text2')}
|
|
511
|
+
onCheckedChange={checked => {
|
|
512
|
+
state.dynamicTagChecked = checked;
|
|
513
|
+
}}
|
|
514
|
+
/>
|
|
515
|
+
{
|
|
516
|
+
params.isMoodStrip && <>
|
|
517
|
+
<Spacer width={cx(8)} height={0}/>
|
|
518
|
+
<Tag
|
|
519
|
+
checked={state.diyTagChecked}
|
|
520
|
+
text={I18n.getLang('mood_overview_field_chip_diy')}
|
|
521
|
+
onCheckedChange={checked => {
|
|
522
|
+
state.diyTagChecked = checked;
|
|
523
|
+
}}
|
|
524
|
+
/>
|
|
525
|
+
</>
|
|
526
|
+
}
|
|
527
|
+
</View>}
|
|
528
|
+
{params.isMoodStrip ? <FlatList
|
|
529
|
+
data={state.filterMoods as DiySceneInfo[]}
|
|
530
|
+
renderItem={({item}) => {
|
|
531
|
+
return (
|
|
532
|
+
<DiySceneItem
|
|
533
|
+
enable={item.id === state.mood?.id}
|
|
534
|
+
scene={item}
|
|
535
|
+
onSwitch={_ => {
|
|
536
|
+
state.mood = cloneDeep(item);
|
|
537
|
+
}}
|
|
538
|
+
/>
|
|
539
|
+
);
|
|
540
|
+
}}
|
|
541
|
+
ListHeaderComponent={() => <Spacer height={cx(10)}/>}
|
|
542
|
+
ItemSeparatorComponent={() => <Spacer/>}
|
|
543
|
+
ListFooterComponent={() => <Spacer/>}
|
|
544
|
+
keyExtractor={item => `${item.name}`}
|
|
545
|
+
/> :
|
|
546
|
+
<FlatList
|
|
547
|
+
data={state.filterMoods as MoodUIInfo[]}
|
|
548
|
+
renderItem={({ item }) => {
|
|
549
|
+
return (
|
|
550
|
+
<MoodItem
|
|
551
|
+
enable={getMoodItemEnable(item)}
|
|
552
|
+
mood={item}
|
|
553
|
+
isMix={!!(params.isMixLight || params.isCeilingLight)}
|
|
554
|
+
onSwitch={_ => {
|
|
555
|
+
state.mood = cloneDeep(item);
|
|
556
|
+
}}
|
|
557
|
+
/>
|
|
558
|
+
);
|
|
486
559
|
}}
|
|
560
|
+
ListHeaderComponent={() => <Spacer height={cx(10)} />}
|
|
561
|
+
ItemSeparatorComponent={() => <Spacer />}
|
|
562
|
+
ListFooterComponent={() => <Spacer />}
|
|
563
|
+
keyExtractor={item => `${item.name}`}
|
|
487
564
|
/>
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
ItemSeparatorComponent={() => <Spacer />}
|
|
492
|
-
ListFooterComponent={() => <Spacer />}
|
|
493
|
-
keyExtractor={item => `${item.name}`}
|
|
494
|
-
/> : <View></View>
|
|
565
|
+
}
|
|
566
|
+
</View>
|
|
567
|
+
) : <View></View>
|
|
495
568
|
)}
|
|
496
569
|
<Spacer />
|
|
497
570
|
|
|
@@ -632,7 +705,9 @@ const getDefaultManual = (props: TimeScheduleDetailPageParams): ComponentConfig
|
|
|
632
705
|
? DeviceType.FanLight
|
|
633
706
|
: props.isCeilingLight
|
|
634
707
|
? DeviceType.CeilingLight
|
|
635
|
-
:
|
|
708
|
+
: props.isMoodStrip
|
|
709
|
+
? DeviceType.MoodStrip
|
|
710
|
+
: DeviceType.LightSource
|
|
636
711
|
const deviceData =
|
|
637
712
|
(deviceType === DeviceType.StripLight || deviceType === DeviceType.CeilingLight)
|
|
638
713
|
? defStripDeviceData
|
|
@@ -640,7 +715,9 @@ const getDefaultManual = (props: TimeScheduleDetailPageParams): ComponentConfig
|
|
|
640
715
|
? defMixDeviceData
|
|
641
716
|
: deviceType === DeviceType.FanLight
|
|
642
717
|
? defFanLightDeviceData
|
|
643
|
-
:
|
|
718
|
+
: deviceType === DeviceType.MoodStrip
|
|
719
|
+
? defMoodStripDeviceData
|
|
720
|
+
: defDeviceData;
|
|
644
721
|
|
|
645
722
|
return {
|
|
646
723
|
type: deviceType as any,
|