@ledvance/group-ui-biz-bundle 1.0.160 → 1.0.163
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/energyConsumption/EditPriceSegmentContract.tsx +108 -0
- package/src/modules/energyConsumption/EditPriceSegmentScreen.tsx +89 -0
- package/src/modules/energyConsumption/EnergyConsumptionActions.ts +8 -2
- package/src/modules/energyConsumption/EnergyConsumptionChart/ChartSection.tsx +35 -6
- package/src/modules/energyConsumption/EnergyConsumptionPage.tsx +462 -293
- package/src/modules/energyConsumption/Router.ts +9 -0
- package/src/modules/energyConsumption/SetSegmentPricesContract.tsx +461 -0
- package/src/modules/energyConsumption/SetSegmentedPricesScreen.tsx +201 -0
- package/src/modules/energyConsumption/component/EnergyModal.tsx +73 -13
- package/src/modules/energyConsumption/component/NewBarChart.tsx +71 -3
- package/src/modules/energyConsumption/component/VerticalDailyPricesIndicator.tsx +175 -0
- package/src/modules/fixedTimeForPlug/FixedTimeForPlugPage.tsx +40 -38
- package/src/modules/fixedTimingForLight/FixedTimingForLightPage.tsx +40 -38
- package/src/modules/randomTimeForPlug/RandomTimeForPlugPage.tsx +41 -38
- package/src/modules/randomTimingForLight/RandomTimingForLightPage.tsx +40 -38
- package/src/modules/timeSchedule/TimeSchedulePage.tsx +13 -13
- package/src/navigation/Routers.ts +1 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, {useEffect} from "react";
|
|
2
2
|
import Card from "@ledvance/base/src/components/Card";
|
|
3
3
|
import Spacer from "@ledvance/base/src/components/Spacer";
|
|
4
4
|
import TextFieldStyleButton from "@ledvance/base/src/components/TextFieldStyleButton";
|
|
@@ -9,6 +9,7 @@ import { Utils, Modal, Popup } from "tuya-panel-kit";
|
|
|
9
9
|
import { useReactive, useUpdateEffect } from "ahooks";
|
|
10
10
|
import { cloneDeep } from "lodash";
|
|
11
11
|
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
12
|
+
import EditPriceSegmentScreen from "../EditPriceSegmentScreen";
|
|
12
13
|
|
|
13
14
|
const { convertX: cx, height, statusBarHeight } = Utils.RatioUtils
|
|
14
15
|
const { withTheme } = Utils.ThemeUtils
|
|
@@ -29,28 +30,77 @@ export const UnitList = [
|
|
|
29
30
|
I18n.getLang('consumption_data_price_per_kwh_currency_value13'),
|
|
30
31
|
]
|
|
31
32
|
|
|
33
|
+
export interface PriceSegment {
|
|
34
|
+
startMinute: number; // 0~1439
|
|
35
|
+
endMinute: number; // 0~1439
|
|
36
|
+
price: number;
|
|
37
|
+
}
|
|
38
|
+
export function calculateAveragePrice(
|
|
39
|
+
intervals: PriceSegment[],
|
|
40
|
+
): number {
|
|
41
|
+
let totalPrice = 0
|
|
42
|
+
for(const item of intervals) {
|
|
43
|
+
const hrs = (item.endMinute - item.startMinute)/60
|
|
44
|
+
totalPrice += (hrs * item.price)
|
|
45
|
+
}
|
|
46
|
+
return totalPrice/24
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
export const parseMinutes = (totalMinutes: number | undefined) => {
|
|
50
|
+
if (!totalMinutes) {
|
|
51
|
+
return { hour: '00', minute: '00' };
|
|
52
|
+
}
|
|
53
|
+
const h = Math.floor(totalMinutes / 60);
|
|
54
|
+
const m = totalMinutes % 60;
|
|
55
|
+
return {
|
|
56
|
+
hour: h.toString().padStart(2, '0'),
|
|
57
|
+
minute: m.toString().padStart(2, '0')
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type EnergyType = 'fixed' | 'dynamic'
|
|
62
|
+
//固定价格能量模型
|
|
32
63
|
export interface EnergyData {
|
|
33
64
|
price: string
|
|
34
65
|
unit: string
|
|
66
|
+
energyType?: EnergyType
|
|
67
|
+
generatePrice?: string
|
|
68
|
+
}
|
|
69
|
+
//动态价格能量模型
|
|
70
|
+
export interface DynamicEnergyData{
|
|
71
|
+
intervalPrices?: PriceSegment[]
|
|
72
|
+
generatePrices?: PriceSegment[]
|
|
35
73
|
}
|
|
74
|
+
|
|
36
75
|
interface EnergyModalProps {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
76
|
+
theme?: ThemeType
|
|
77
|
+
visible: boolean
|
|
78
|
+
popupType: 'money' | 'co2' | 'unit' | 'segment_price'
|
|
79
|
+
title: string
|
|
80
|
+
confirmText?: string
|
|
81
|
+
cancelText?: string
|
|
82
|
+
energyData?: EnergyData
|
|
83
|
+
motionType?: 'none'
|
|
84
|
+
editingPriceSegment?: PriceSegment
|
|
85
|
+
onConfirm?: (data?: EnergyData) => void
|
|
86
|
+
onPriceSegmentConfirm?: (segment?: PriceSegment) => void
|
|
87
|
+
onCancel?: () => void
|
|
47
88
|
}
|
|
48
89
|
const EnergyModal = (props: EnergyModalProps) => {
|
|
49
90
|
const state = useReactive({
|
|
50
91
|
energyData: cloneDeep(props.energyData),
|
|
51
|
-
unitPopup: false
|
|
92
|
+
unitPopup: false,
|
|
93
|
+
editingPriceSegment: cloneDeep(props.editingPriceSegment)
|
|
52
94
|
})
|
|
53
|
-
|
|
95
|
+
useEffect(()=>{
|
|
96
|
+
if(props.visible) {
|
|
97
|
+
if(!props.editingPriceSegment){
|
|
98
|
+
state.editingPriceSegment = { startMinute: 0, endMinute: 0, price: 0 }
|
|
99
|
+
} else {
|
|
100
|
+
state.editingPriceSegment = props.editingPriceSegment
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}, [props.visible,props.editingPriceSegment])
|
|
54
104
|
|
|
55
105
|
const openLink = (url: string) => {
|
|
56
106
|
Linking.openURL(url).catch((error) => console.error('无法打开链接:', error));
|
|
@@ -217,6 +267,14 @@ const EnergyModal = (props: EnergyModalProps) => {
|
|
|
217
267
|
</Card>
|
|
218
268
|
</View>
|
|
219
269
|
)
|
|
270
|
+
} else if(props.popupType === 'segment_price'){
|
|
271
|
+
return (
|
|
272
|
+
<EditPriceSegmentScreen
|
|
273
|
+
segment={state.editingPriceSegment}
|
|
274
|
+
onSegmentSet={(segment)=>{
|
|
275
|
+
state.editingPriceSegment = segment
|
|
276
|
+
}}/>
|
|
277
|
+
)
|
|
220
278
|
} else {
|
|
221
279
|
return (
|
|
222
280
|
<View>
|
|
@@ -306,6 +364,8 @@ const EnergyModal = (props: EnergyModalProps) => {
|
|
|
306
364
|
<Text style={{ color: props.theme?.global.fontColor, fontSize: cx(16), fontWeight: 'bold' }}>{props.title}</Text>
|
|
307
365
|
<TouchableOpacity onPress={() => {
|
|
308
366
|
props.onConfirm && props.onConfirm(state.energyData)
|
|
367
|
+
console.log("wayne_check innner check segment ->", JSON.stringify(state.editingPriceSegment))
|
|
368
|
+
props.onPriceSegmentConfirm && props.onPriceSegmentConfirm(state.editingPriceSegment)
|
|
309
369
|
}}>
|
|
310
370
|
<Text style={{ color: props.theme?.button.primary, fontSize: cx(16) }}>{props.confirmText}</Text>
|
|
311
371
|
</TouchableOpacity>
|
|
@@ -7,6 +7,8 @@ import { View } from 'react-native'
|
|
|
7
7
|
import { Utils } from 'tuya-panel-kit'
|
|
8
8
|
import { OverviewItem } from '../EnergyConsumptionPage'
|
|
9
9
|
import { EnergyDisplayMode } from '../EnergyConsumptionChart/useEnergyData'
|
|
10
|
+
import { calculateAveragePrice, PriceSegment, DynamicEnergyData } from './EnergyModal'
|
|
11
|
+
import { DateType } from '../co2Data'
|
|
10
12
|
|
|
11
13
|
const { withTheme } = Utils.ThemeUtils
|
|
12
14
|
interface BarChartProps {
|
|
@@ -19,6 +21,35 @@ interface BarChartProps {
|
|
|
19
21
|
unit: string;
|
|
20
22
|
height: number;
|
|
21
23
|
displayMode?: EnergyDisplayMode;
|
|
24
|
+
energyType?: string;
|
|
25
|
+
dynamicData?: DynamicEnergyData;
|
|
26
|
+
dateType?: DateType;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//算出固定时间间隔内的平均价格,目前用于计算柱状图每一个小时的价格
|
|
30
|
+
export function calculateIntervalAveragePrice(
|
|
31
|
+
intervals: PriceSegment[],
|
|
32
|
+
startMinute: number,
|
|
33
|
+
endMinute: number
|
|
34
|
+
): number {
|
|
35
|
+
let totalWeightedPrice = 0;
|
|
36
|
+
let totalTimeOverlap = 0;
|
|
37
|
+
|
|
38
|
+
for (const item of intervals) {
|
|
39
|
+
const overlapStart = Math.max(item.startMinute, startMinute);
|
|
40
|
+
const overlapEnd = Math.min(item.endMinute, endMinute);
|
|
41
|
+
|
|
42
|
+
if (overlapStart < overlapEnd) {
|
|
43
|
+
const duration = overlapEnd - overlapStart;
|
|
44
|
+
totalWeightedPrice += duration * item.price;
|
|
45
|
+
totalTimeOverlap += duration;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (totalTimeOverlap > 0) {
|
|
50
|
+
return totalWeightedPrice / totalTimeOverlap;
|
|
51
|
+
}
|
|
52
|
+
return 0;
|
|
22
53
|
}
|
|
23
54
|
|
|
24
55
|
const BarChartWithTouch = (props: BarChartProps) => {
|
|
@@ -33,6 +64,9 @@ const BarChartWithTouch = (props: BarChartProps) => {
|
|
|
33
64
|
height,
|
|
34
65
|
theme,
|
|
35
66
|
displayMode = 'consumption',
|
|
67
|
+
energyType,
|
|
68
|
+
dynamicData,
|
|
69
|
+
dateType,
|
|
36
70
|
} = props
|
|
37
71
|
|
|
38
72
|
const chartKey = useMemo(() => {
|
|
@@ -80,11 +114,45 @@ const BarChartWithTouch = (props: BarChartProps) => {
|
|
|
80
114
|
const consumedVal = dataPoint.consumed || 0
|
|
81
115
|
const generatedVal = dataPoint.generated || 0
|
|
82
116
|
|
|
117
|
+
let consumedPrice = price
|
|
118
|
+
let generatedPrice = price
|
|
119
|
+
|
|
120
|
+
if (energyType === 'dynamic' && dynamicData) {
|
|
121
|
+
// Consumed price
|
|
122
|
+
const costIntervals = dynamicData.intervalPrices || []
|
|
123
|
+
if (costIntervals.length > 0) {
|
|
124
|
+
if (dateType === DateType.Day) {
|
|
125
|
+
const hour = parseInt(key.split(':')[0]);
|
|
126
|
+
if (!isNaN(hour)) {
|
|
127
|
+
consumedPrice = calculateIntervalAveragePrice(costIntervals, hour * 60, (hour + 1) * 60);
|
|
128
|
+
} else {
|
|
129
|
+
consumedPrice = calculateAveragePrice(costIntervals);
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
consumedPrice = calculateAveragePrice(costIntervals);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Generated price
|
|
136
|
+
const generateIntervals = dynamicData.generatePrices || []
|
|
137
|
+
if (generateIntervals.length > 0) {
|
|
138
|
+
if (dateType === DateType.Day) {
|
|
139
|
+
const hour = parseInt(key.split(':')[0]);
|
|
140
|
+
if (!isNaN(hour)) {
|
|
141
|
+
generatedPrice = calculateIntervalAveragePrice(generateIntervals, hour * 60, (hour + 1) * 60);
|
|
142
|
+
} else {
|
|
143
|
+
generatedPrice = calculateAveragePrice(generateIntervals);
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
generatedPrice = calculateAveragePrice(generateIntervals);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
83
151
|
finalDataX.push(dataPoint.title)
|
|
84
152
|
finalAlignedConsumed.push(consumedVal)
|
|
85
153
|
finalAlignedGenerated.push(generatedVal)
|
|
86
|
-
finalAlignedConsumedPrice.push((consumedVal *
|
|
87
|
-
finalAlignedGeneratedPrice.push((generatedVal *
|
|
154
|
+
finalAlignedConsumedPrice.push((consumedVal * consumedPrice).toFixed(2))
|
|
155
|
+
finalAlignedGeneratedPrice.push((generatedVal * generatedPrice).toFixed(2))
|
|
88
156
|
})
|
|
89
157
|
|
|
90
158
|
return {
|
|
@@ -94,7 +162,7 @@ const BarChartWithTouch = (props: BarChartProps) => {
|
|
|
94
162
|
alignedConsumedPrice: finalAlignedConsumedPrice,
|
|
95
163
|
alignedGeneratedPrice: finalAlignedGeneratedPrice,
|
|
96
164
|
}
|
|
97
|
-
}, [consumedData, generatedData, price])
|
|
165
|
+
}, [consumedData, generatedData, price, energyType, dynamicData, dateType])
|
|
98
166
|
|
|
99
167
|
// 图例 & series 动态生成
|
|
100
168
|
const { legendData, seriesData } = useMemo(() => {
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import React, {useState} from 'react'
|
|
2
|
+
import { PriceSegment } from "./EnergyModal"
|
|
3
|
+
import { Utils } from 'tuya-panel-kit'
|
|
4
|
+
import {View, StyleSheet, StyleProp, ViewStyle, LayoutChangeEvent} from 'react-native'
|
|
5
|
+
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
6
|
+
import _ from 'lodash'
|
|
7
|
+
|
|
8
|
+
const { withTheme } = Utils.ThemeUtils
|
|
9
|
+
const cx = Utils.RatioUtils.convertX
|
|
10
|
+
|
|
11
|
+
interface VerticalDailyPricesIndicatorProps {
|
|
12
|
+
theme?: ThemeType
|
|
13
|
+
data: PriceSegment[]
|
|
14
|
+
selectingData?: PriceSegment
|
|
15
|
+
style?: StyleProp<ViewStyle>
|
|
16
|
+
getSegmentColor:(startMinute: number, price: number)=>string,
|
|
17
|
+
}
|
|
18
|
+
interface DrawBlock {
|
|
19
|
+
startMinute: number,
|
|
20
|
+
endMinute: number,
|
|
21
|
+
price: number,
|
|
22
|
+
isEmpty: boolean,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const convertToDrawBlocks = (sortedSegments: PriceSegment[]): DrawBlock[] => {
|
|
26
|
+
const blocks: DrawBlock[] = [];
|
|
27
|
+
let ptr = 0;
|
|
28
|
+
const TOTAL_MINUTES = 1439; // (0 ~ 1439)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
for (const segment of sortedSegments) {
|
|
32
|
+
//早时补白
|
|
33
|
+
if (segment.startMinute > ptr) {
|
|
34
|
+
blocks.push({
|
|
35
|
+
startMinute: ptr,
|
|
36
|
+
endMinute: segment.startMinute, //直到现时起点
|
|
37
|
+
price:0,
|
|
38
|
+
isEmpty: true,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//现时色块
|
|
43
|
+
blocks.push({
|
|
44
|
+
startMinute: segment.startMinute,
|
|
45
|
+
endMinute: segment.endMinute,
|
|
46
|
+
price:segment.price,
|
|
47
|
+
isEmpty: false,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
//现时末点指针
|
|
51
|
+
ptr = segment.endMinute;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//未来时补白
|
|
55
|
+
if (ptr < TOTAL_MINUTES) {
|
|
56
|
+
blocks.push({
|
|
57
|
+
startMinute: ptr, //从现时末点
|
|
58
|
+
endMinute: TOTAL_MINUTES,
|
|
59
|
+
price:0,
|
|
60
|
+
isEmpty: true,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return blocks;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const VerticalDailyPricesIndicator = (props: VerticalDailyPricesIndicatorProps) => {
|
|
68
|
+
|
|
69
|
+
//计算百分比
|
|
70
|
+
const getSegmentHeightPercent = (segment: DrawBlock): number => {
|
|
71
|
+
const duration = segment.endMinute - segment.startMinute
|
|
72
|
+
return (duration / 1439) * 100
|
|
73
|
+
}
|
|
74
|
+
const [indicatorHeight, setIndicatorHeight] = useState<number>(0)
|
|
75
|
+
const markerHeight = indicatorHeight / 24
|
|
76
|
+
const handleLayout = (event: LayoutChangeEvent) => {
|
|
77
|
+
const { height } = event.nativeEvent.layout;
|
|
78
|
+
if (Math.abs(indicatorHeight - height) > 0.1) {
|
|
79
|
+
setIndicatorHeight(height);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const sortedSegments = convertToDrawBlocks([...props.data])
|
|
83
|
+
|
|
84
|
+
const styles = StyleSheet.create({
|
|
85
|
+
container: {
|
|
86
|
+
flexDirection: 'row',
|
|
87
|
+
alignItems: 'flex-start',
|
|
88
|
+
height: '100%',
|
|
89
|
+
},
|
|
90
|
+
indicatorWrapper: {
|
|
91
|
+
position: 'absolute',
|
|
92
|
+
top: 0,
|
|
93
|
+
left: 0,
|
|
94
|
+
height: indicatorHeight,
|
|
95
|
+
width: cx(30),
|
|
96
|
+
borderRadius: cx(4),
|
|
97
|
+
overflow: 'hidden',
|
|
98
|
+
alignItems: 'center',
|
|
99
|
+
},
|
|
100
|
+
segmentBlock: {
|
|
101
|
+
alignItems: 'center',
|
|
102
|
+
justifyContent: 'center',
|
|
103
|
+
},
|
|
104
|
+
expandedLabel: {
|
|
105
|
+
paddingVertical: cx(4),
|
|
106
|
+
paddingHorizontal: cx(2),
|
|
107
|
+
fontSize: cx(8),
|
|
108
|
+
fontWeight: 'bold',
|
|
109
|
+
color: '#fff',
|
|
110
|
+
},
|
|
111
|
+
timelineMarker: {
|
|
112
|
+
position: 'absolute',
|
|
113
|
+
left: -cx(28),
|
|
114
|
+
width: cx(20),
|
|
115
|
+
height: 1,
|
|
116
|
+
backgroundColor: props.theme?.global.fontColor,
|
|
117
|
+
opacity: 0.3,
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<View style={[styles.container, props.style]} onLayout={handleLayout}>
|
|
123
|
+
{/* Timeline Markers */}
|
|
124
|
+
<View style={{height: indicatorHeight, paddingVertical: 0 }}>
|
|
125
|
+
{_.times(24,(index)=>index).map((hour) => (
|
|
126
|
+
<View key={hour} style={{ alignItems: 'flex-start',}}>
|
|
127
|
+
<View style={{width: cx(8), height: markerHeight}}>
|
|
128
|
+
<View style={{width:'100%',height:cx(1), backgroundColor:props.theme?.global.secondFontColor}}></View>
|
|
129
|
+
</View>
|
|
130
|
+
</View>
|
|
131
|
+
))
|
|
132
|
+
}
|
|
133
|
+
</View>
|
|
134
|
+
<View style={{ height: indicatorHeight, width: cx(30), position: 'relative', alignItems: 'center', justifyContent: 'center' }}>
|
|
135
|
+
{/*Vertical bar */}
|
|
136
|
+
<View style={{
|
|
137
|
+
width: cx(10),
|
|
138
|
+
height: indicatorHeight,
|
|
139
|
+
backgroundColor: props.theme?.segment.background,
|
|
140
|
+
borderRadius: cx(1)
|
|
141
|
+
}} />
|
|
142
|
+
{/* Vertical Indicator Bar */}
|
|
143
|
+
<View style={[styles.indicatorWrapper]}>
|
|
144
|
+
{sortedSegments.map((segment) => {
|
|
145
|
+
const heightPercent = getSegmentHeightPercent(segment)
|
|
146
|
+
const height = (heightPercent / 100) * indicatorHeight
|
|
147
|
+
const isSelected = props.selectingData?.startMinute === segment.startMinute &&
|
|
148
|
+
props.selectingData?.endMinute === segment.endMinute
|
|
149
|
+
const color = segment.isEmpty ? 'transparent': props.getSegmentColor(segment.startMinute, segment.price)
|
|
150
|
+
|
|
151
|
+
if (isSelected) {
|
|
152
|
+
console.log(`wayne_check isSelected item inner start min: ${segment.startMinute},end min: ${segment.endMinute}`);
|
|
153
|
+
}
|
|
154
|
+
return (
|
|
155
|
+
<View
|
|
156
|
+
key={`${segment.startMinute}-${segment.endMinute}`}
|
|
157
|
+
style={[
|
|
158
|
+
styles.segmentBlock,
|
|
159
|
+
{
|
|
160
|
+
height,
|
|
161
|
+
backgroundColor: color,
|
|
162
|
+
width: isSelected ? cx(30) : cx(15),
|
|
163
|
+
zIndex: isSelected ? 10 : 1,
|
|
164
|
+
}
|
|
165
|
+
]}
|
|
166
|
+
/>
|
|
167
|
+
)
|
|
168
|
+
})}
|
|
169
|
+
</View>
|
|
170
|
+
</View>
|
|
171
|
+
</View>
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export default withTheme(VerticalDailyPricesIndicator)
|
|
@@ -122,50 +122,52 @@ const FixedTimeForPlugPage = (props: { theme?: ThemeType}) => {
|
|
|
122
122
|
|
|
123
123
|
const renderList = () => {
|
|
124
124
|
return (
|
|
125
|
-
|
|
125
|
+
<>
|
|
126
126
|
<Text style={styles.execTip}>{I18n.getLang('timeschedule_overview_description_text')}</Text>
|
|
127
127
|
<Spacer height={cx(10)}/>
|
|
128
128
|
{isMaxNum && <View style={{marginHorizontal: cx(24), flexDirection: 'row'}}>
|
|
129
129
|
<Image style={styles.maxImg} source={{uri: res.ic_warning_amber}}/>
|
|
130
130
|
<Text style={styles.maxTip}>{I18n.getLang('randomtimecycle_warning_max_number_text')}</Text>
|
|
131
131
|
</View>}
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
close
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
132
|
+
<ScrollView nestedScrollEnabled={true}>
|
|
133
|
+
<FlatList
|
|
134
|
+
data={fixedTimeList}
|
|
135
|
+
renderItem={({item}) => (
|
|
136
|
+
<ItemCard
|
|
137
|
+
item={item}
|
|
138
|
+
is24Hour={params.is24Hour}
|
|
139
|
+
onSwitch={async (v) => {
|
|
140
|
+
await onPost('set', {
|
|
141
|
+
...item,
|
|
142
|
+
enable: v,
|
|
143
|
+
settingTime: new Date().getTime()
|
|
144
|
+
})
|
|
145
|
+
}}
|
|
146
|
+
onPress={() => {
|
|
147
|
+
onAddOrEditItem('edit', item)
|
|
148
|
+
}}
|
|
149
|
+
onLongPress={async () => {
|
|
150
|
+
showDialog({
|
|
151
|
+
method: 'confirm',
|
|
152
|
+
title: I18n.getLang('cancel_dialog_delete_item_fixedtimecycle_titel'),
|
|
153
|
+
subTitle: I18n.getLang('cancel_dialog_delete_item_fixedtimecycle_description'),
|
|
154
|
+
onConfirm: async (_, {close}) => {
|
|
155
|
+
close()
|
|
156
|
+
state.loading = true
|
|
157
|
+
await onPost('del', item)
|
|
158
|
+
state.loading = false
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
}}
|
|
162
|
+
/>
|
|
163
|
+
)}
|
|
164
|
+
keyExtractor={(item: any) => `${item?.index}`}
|
|
165
|
+
ItemSeparatorComponent={() => <Spacer/>}
|
|
166
|
+
ListHeaderComponent={<Spacer height={cx(10)}/>}
|
|
167
|
+
ListFooterComponent={<Spacer/>}
|
|
168
|
+
/>
|
|
169
|
+
</ScrollView>
|
|
170
|
+
</>
|
|
169
171
|
)
|
|
170
172
|
}
|
|
171
173
|
const renderEmpty = () => {
|
|
@@ -126,50 +126,52 @@ const FixedTimeForLightPage = (props: { theme?: ThemeType}) => {
|
|
|
126
126
|
|
|
127
127
|
const renderList = () => {
|
|
128
128
|
return (
|
|
129
|
-
|
|
129
|
+
<>
|
|
130
130
|
<Text style={styles.execTip}>{I18n.getLang('timeschedule_overview_description_text')}</Text>
|
|
131
131
|
<Spacer height={cx(10)}/>
|
|
132
132
|
{isMaxNum && <View style={{marginHorizontal: cx(24), flexDirection: 'row'}}>
|
|
133
133
|
<Image style={styles.maxImg} source={{uri: res.ic_warning_amber}}/>
|
|
134
134
|
<Text style={styles.maxTip}>{I18n.getLang('fixedtimecycle_warning_max_number_text')}</Text>
|
|
135
135
|
</View>}
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
close
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
136
|
+
<ScrollView nestedScrollEnabled={true}>
|
|
137
|
+
<FlatList
|
|
138
|
+
data={fixedTimingList}
|
|
139
|
+
renderItem={({item}) => (
|
|
140
|
+
<ItemCard
|
|
141
|
+
item={item}
|
|
142
|
+
is24Hour={params.is24Hour}
|
|
143
|
+
onSwitch={async (v) => {
|
|
144
|
+
await onPost('set', {
|
|
145
|
+
...item,
|
|
146
|
+
power: v,
|
|
147
|
+
settingTime: new Date().getTime()
|
|
148
|
+
})
|
|
149
|
+
}}
|
|
150
|
+
onPress={() => {
|
|
151
|
+
onAddOrEditItem('edit', item)
|
|
152
|
+
}}
|
|
153
|
+
onLongPress={async () => {
|
|
154
|
+
showDialog({
|
|
155
|
+
method: 'confirm',
|
|
156
|
+
title: I18n.getLang('cancel_dialog_delete_item_fixedtimecycle_titel'),
|
|
157
|
+
subTitle: I18n.getLang('cancel_dialog_delete_item_fixedtimecycle_description'),
|
|
158
|
+
onConfirm: async (_, {close}) => {
|
|
159
|
+
close()
|
|
160
|
+
state.loading = true
|
|
161
|
+
await onPost('del', item)
|
|
162
|
+
state.loading = false
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
}}
|
|
166
|
+
/>
|
|
167
|
+
)}
|
|
168
|
+
keyExtractor={(item: any) => `${item?.index}`}
|
|
169
|
+
ItemSeparatorComponent={() => <Spacer/>}
|
|
170
|
+
ListHeaderComponent={<Spacer height={cx(10)}/>}
|
|
171
|
+
ListFooterComponent={<Spacer/>}
|
|
172
|
+
/>
|
|
173
|
+
</ScrollView>
|
|
174
|
+
</>
|
|
173
175
|
)
|
|
174
176
|
}
|
|
175
177
|
const renderEmpty = () => {
|