@ledvance/ui-biz-bundle 1.1.105 → 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.
@@ -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 {getDataWithSpecified, getDpResultByHour, getDpResultByMonth} from "@ledvance/base/src/models/TuyaApi";
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
- const res = await getDpResultByMonth(devId, addEleDpCode, 'sum')
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={{alignItems: 'center', justifyContent: 'center', flex: 1, marginStart: cx(24)}}>
151
- <Text style={{fontSize: cx(24), color: props.theme?.global.brand}}>{state.headlineText}</Text>
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 = Math.max(...dataKwhY);
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.ceil(maxValue),
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 '@ledvance/ui-biz-bundle/src/modules/flags/FlagActions';
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.card.background,
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.global.fontColor }} />
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, { useCallback, useEffect, useMemo } from 'react';
2
- import {
3
- FlatList,
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 { cloneDeep, isEqual } from 'lodash';
16
- import { useReactive } from 'ahooks';
17
- import { SwitchButton, TimerPicker, Utils } from 'tuya-panel-kit';
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 { convertTo12HourFormat, loopText, showDialog } from '@ledvance/base/src/utils/common';
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
- useDeviceId,
32
- useMoods,
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 { useParams } from '@ledvance/base/src/hooks/Hooks';
21
+ import {useParams} from '@ledvance/base/src/hooks/Hooks';
41
22
  import ManualSettings from './components/ManuaSettings';
42
- import { defDeviceData, defFanLightDeviceData, defMixDeviceData, defStripDeviceData } from './TimeScheduleActions';
23
+ import {
24
+ defDeviceData,
25
+ defFanLightDeviceData,
26
+ defMixDeviceData,
27
+ defMoodStripDeviceData,
28
+ defStripDeviceData
29
+ } from './TimeScheduleActions';
43
30
  import MoodItem from '../mood/MoodItem';
44
- import { getRemoteMoodList } from '../mood/MoodActions';
45
- import { MoodUIInfo } from '../mood/Interface';
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 ? <FlatList
477
- data={state.moods}
478
- renderItem={({ item }) => {
479
- return (
480
- <MoodItem
481
- enable={getMoodItemEnable(item)}
482
- mood={item}
483
- isMix={!!(params.isMixLight || params.isCeilingLight)}
484
- onSwitch={_ => {
485
- state.mood = cloneDeep(item);
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
- ListHeaderComponent={() => <Spacer height={cx(10)} />}
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
- : DeviceType.LightSource
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
- : defDeviceData;
718
+ : deviceType === DeviceType.MoodStrip
719
+ ? defMoodStripDeviceData
720
+ : defDeviceData;
644
721
 
645
722
  return {
646
723
  type: deviceType as any,