@ledvance/group-ui-biz-bundle 1.0.141 → 1.0.143
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/biorhythm/BiorhythmDetailPage.tsx +8 -2
- package/src/modules/biorhythm/BiorhythmPage.tsx +4 -4
- package/src/modules/biorhythm/IconSelect.tsx +92 -29
- package/src/modules/diyScene/DiySceneActions.ts +3 -0
- package/src/modules/diyScene/DiySceneEditorPage.tsx +1 -1
- package/src/modules/energyConsumption/EnergyConsumptionActions.ts +1 -1
- package/src/modules/energyConsumption/EnergyConsumptionChart/ChartSection.tsx +61 -69
- package/src/modules/energyConsumption/EnergyConsumptionChart/LandscapeView.tsx +1 -0
- package/src/modules/energyConsumption/EnergyConsumptionChart/styles.ts +8 -4
- package/src/modules/energyConsumption/EnergyConsumptionChart/useEnergyData.ts +4 -2
- package/src/modules/energyConsumption/component/DateSwitch.tsx +10 -8
- package/src/modules/energyConsumption/component/NewBarChart.tsx +23 -3
- package/src/modules/fixedTimeForPlug/FixedTimeForPlugDetailPage.tsx +1 -1
- package/src/modules/fixedTimeForPlug/ItemCard.tsx +2 -2
- package/src/modules/fixedTimeForPlug/Summary.tsx +1 -1
- package/src/modules/fixedTimingForLight/FixedTimingForLightDetailPage.tsx +1 -1
- package/src/modules/fixedTimingForLight/ItemCard.tsx +2 -2
- package/src/modules/fixedTimingForLight/Summary.tsx +1 -1
- package/src/modules/flags/FlagEditPage.tsx +2 -2
- package/src/modules/flags/FlagInfo.tsx +1180 -1174
- package/src/modules/flags/FlagItem.tsx +1 -1
- package/src/modules/lightMode/LightModePage.tsx +1 -1
- package/src/modules/mood/DynamicMoodEditorPage.tsx +2 -2
- package/src/modules/mood/MoodItem.tsx +2 -2
- package/src/modules/mood/RecommendMoodItem.tsx +1 -1
- package/src/modules/mood/StaticMoodEditorPage.tsx +2 -2
- package/src/modules/mood_new/DynamicMoodEditorPage.tsx +2 -2
- package/src/modules/mood_new/MixDynamicMoodEditor.tsx +2 -2
- package/src/modules/mood_new/MoodItem.tsx +2 -2
- package/src/modules/mood_new/RecommendMoodItem.tsx +1 -1
- package/src/modules/mood_new/StaticMoodEditorPage.tsx +1 -1
- package/src/modules/music/MusicPage.tsx +1 -1
- package/src/modules/overchargeSwitch/OverchargeSwitchPage.tsx +1 -1
- package/src/modules/powerOnBehavior/LightBehaviorPage.tsx +2 -2
- package/src/modules/randomTimeForPlug/ItemCard.tsx +2 -2
- package/src/modules/randomTimeForPlug/RandomTimeForPlugDetailPage.tsx +1 -1
- package/src/modules/randomTimeForPlug/Summary.tsx +1 -1
- package/src/modules/randomTimingForLight/ItemCard.tsx +2 -2
- package/src/modules/randomTimingForLight/RandomTimingForLightDetailPage.tsx +1 -1
- package/src/modules/randomTimingForLight/Summary.tsx +1 -1
- package/src/modules/remoteSwitch/RemoteSwitchPage.tsx +1 -1
- package/src/modules/select/SelectPage.tsx +3 -3
- package/src/modules/sleepWakeUp/SleepWakeUpDetailPage.tsx +1 -1
- package/src/modules/sleepWakeUp/SleepWakeUpPage.tsx +4 -4
- package/src/modules/timeSchedule/TimeScheduleDetailPage.tsx +1 -1
- package/src/modules/timeSchedule/components/ScheduleCard.tsx +3 -3
- package/src/modules/timeSchedule/components/Summary.tsx +1 -1
- package/src/modules/timer/TimerPage.tsx +3 -3
package/package.json
CHANGED
|
@@ -121,7 +121,7 @@ const BiorhythmEditPage = (props: { theme?: ThemeType }) => {
|
|
|
121
121
|
title: {
|
|
122
122
|
color: props.theme?.global.fontColor,
|
|
123
123
|
fontSize: cx(16),
|
|
124
|
-
fontFamily: 'helvetica_neue_lt_std_bd',
|
|
124
|
+
// fontFamily: 'helvetica_neue_lt_std_bd',
|
|
125
125
|
paddingVertical: cx(16),
|
|
126
126
|
},
|
|
127
127
|
})
|
|
@@ -204,7 +204,13 @@ const BiorhythmEditPage = (props: { theme?: ThemeType }) => {
|
|
|
204
204
|
</TouchableOpacity>
|
|
205
205
|
</View>
|
|
206
206
|
<Text
|
|
207
|
-
style={{
|
|
207
|
+
style={{
|
|
208
|
+
fontSize: cx(16),
|
|
209
|
+
color: props.theme?.global.fontColor,
|
|
210
|
+
// fontFamily: 'helvetica_neue_lt_std_bd',
|
|
211
|
+
marginTop: cx(33),
|
|
212
|
+
marginBottom: cx(16)
|
|
213
|
+
}}>
|
|
208
214
|
{I18n.getLang('add_new_trigger_time_subheadline_text')}
|
|
209
215
|
</Text>
|
|
210
216
|
<Card>
|
|
@@ -221,7 +221,7 @@ const BiorhythmPage = (props: { theme?: ThemeType }) => {
|
|
|
221
221
|
<Text style={{ color: props.theme?.global.fontColor }}>{text[0]}</Text>
|
|
222
222
|
<Text onPress={openLink}
|
|
223
223
|
style={{
|
|
224
|
-
fontFamily: 'helvetica_neue_lt_std_roman',
|
|
224
|
+
// fontFamily: 'helvetica_neue_lt_std_roman',
|
|
225
225
|
color: props.theme?.button.primary,
|
|
226
226
|
textDecorationLine: 'underline',
|
|
227
227
|
flexWrap: 'wrap',
|
|
@@ -368,7 +368,7 @@ const BiorhythmPage = (props: { theme?: ThemeType }) => {
|
|
|
368
368
|
<Text style={{
|
|
369
369
|
fontSize: cx(16),
|
|
370
370
|
color: props.theme?.textInput.fontColor,
|
|
371
|
-
fontFamily: 'helvetica_neue_lt_std_roman',
|
|
371
|
+
// fontFamily: 'helvetica_neue_lt_std_roman',
|
|
372
372
|
paddingLeft: cx(16),
|
|
373
373
|
}}>
|
|
374
374
|
{
|
|
@@ -564,7 +564,7 @@ const BiorhythmPage = (props: { theme?: ThemeType }) => {
|
|
|
564
564
|
style={{
|
|
565
565
|
fontSize: cx(16),
|
|
566
566
|
color: props.theme?.global.fontColor,
|
|
567
|
-
fontFamily: 'helvetica_neue_lt_std_roman',
|
|
567
|
+
// fontFamily: 'helvetica_neue_lt_std_roman',
|
|
568
568
|
}}
|
|
569
569
|
>
|
|
570
570
|
{convertMinutesTo12HourFormat(item.time, is24Hour)}
|
|
@@ -586,7 +586,7 @@ const BiorhythmPage = (props: { theme?: ThemeType }) => {
|
|
|
586
586
|
style={{
|
|
587
587
|
fontSize: cx(12),
|
|
588
588
|
color: props.theme?.global.secondFontColor,
|
|
589
|
-
fontFamily: 'helvetica_neue_lt_std_roman',
|
|
589
|
+
// fontFamily: 'helvetica_neue_lt_std_roman',
|
|
590
590
|
paddingLeft: cx(20),
|
|
591
591
|
}}
|
|
592
592
|
>
|
|
@@ -1,33 +1,43 @@
|
|
|
1
|
-
import {useNavigation} from '@react-navigation/native'
|
|
2
|
-
import React, {useEffect, useState} from 'react'
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
1
|
+
import { useNavigation, useRoute } from '@react-navigation/native'
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
|
3
|
+
// 导入 Dimensions API 来获取屏幕宽度
|
|
4
|
+
import { Dimensions, Image, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
|
|
5
|
+
import { Utils } from 'tuya-panel-kit'
|
|
6
|
+
import iconList from '../biorhythm/iconListData'
|
|
6
7
|
import LDVTopBar from '@ledvance/base/src/components/ldvTopBar'
|
|
7
8
|
import I18n from '@ledvance/base/src/i18n'
|
|
8
|
-
import { useParams } from '@ledvance/base/src/hooks/Hooks'
|
|
9
9
|
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
10
|
+
import { xLog } from '@ledvance/base/src/utils'
|
|
10
11
|
|
|
11
|
-
const cx = Utils.RatioUtils
|
|
12
|
+
const { convertX: cx } = Utils.RatioUtils
|
|
12
13
|
const { withTheme } = Utils.ThemeUtils
|
|
13
14
|
|
|
14
|
-
interface
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
interface SceneDetailPageParams {
|
|
16
|
+
backText?: string
|
|
17
|
+
id: any
|
|
18
|
+
setIcon: (id) => void,
|
|
17
19
|
iconIdList: any
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
// --- 新增:定义常量,方便维护 ---
|
|
23
|
+
const ICON_WIDTH = cx(32)
|
|
24
|
+
const ICON_MARGIN = cx(10)
|
|
25
|
+
const CONTAINER_HORIZONTAL_PADDING = cx(24)
|
|
26
|
+
// 每个图标占据的总宽度(图片宽度 + 左右margin)
|
|
27
|
+
const ITEM_TOTAL_WIDTH = ICON_WIDTH + ICON_MARGIN * 2
|
|
28
|
+
|
|
29
|
+
function IconSelect(props: { theme?: ThemeType }) {
|
|
21
30
|
const [list, setList] = useState(iconList)
|
|
22
31
|
const navigation = useNavigation()
|
|
23
|
-
const params =
|
|
32
|
+
const params = useRoute().params as SceneDetailPageParams
|
|
33
|
+
|
|
24
34
|
const setColor = id => {
|
|
25
35
|
const newList = list?.map(item => {
|
|
26
36
|
return {
|
|
27
37
|
...item,
|
|
28
38
|
selectStatus: item?.id === id,
|
|
29
39
|
}
|
|
30
|
-
})
|
|
40
|
+
}) as typeof list
|
|
31
41
|
setList(newList)
|
|
32
42
|
}
|
|
33
43
|
useEffect(() => {
|
|
@@ -39,24 +49,74 @@ function IconSelectPage(props: { theme?: ThemeType }) {
|
|
|
39
49
|
selectStatus: item?.id === iconId,
|
|
40
50
|
disabled: iconIdList?.some(val => val === item?.id && val !== iconId),
|
|
41
51
|
}
|
|
42
|
-
})
|
|
52
|
+
}) as typeof list
|
|
43
53
|
setList(newList)
|
|
44
54
|
}, [])
|
|
45
55
|
|
|
56
|
+
const getStyles = useCallback((theme?: ThemeType) => StyleSheet.create({
|
|
57
|
+
container: { flex: 1, flexDirection: 'column' },
|
|
58
|
+
scrollView: { marginHorizontal: CONTAINER_HORIZONTAL_PADDING },
|
|
59
|
+
titleView: { marginTop: cx(40), marginBottom: cx(20) },
|
|
60
|
+
title: { fontSize: cx(24), color: theme?.global.brand },
|
|
61
|
+
iconContainer: {
|
|
62
|
+
flexDirection: 'row',
|
|
63
|
+
flex: 1,
|
|
64
|
+
flexWrap: 'wrap',
|
|
65
|
+
justifyContent: 'space-between',
|
|
66
|
+
alignItems: 'center'
|
|
67
|
+
},
|
|
68
|
+
ghostItem: {
|
|
69
|
+
width: ICON_WIDTH,
|
|
70
|
+
height: 0,
|
|
71
|
+
margin: ICON_MARGIN,
|
|
72
|
+
}
|
|
73
|
+
}), [CONTAINER_HORIZONTAL_PADDING, ICON_WIDTH, ICON_MARGIN])
|
|
74
|
+
|
|
75
|
+
const styles = useMemo(() => getStyles(props.theme), [props.theme])
|
|
76
|
+
|
|
77
|
+
// --- 新增:动态计算需要渲染的幽灵元素数量 ---
|
|
78
|
+
const ghostElements = useMemo(() => {
|
|
79
|
+
|
|
80
|
+
// 1. 获取容器的可用宽度
|
|
81
|
+
const containerWidth = cx(Dimensions.get('window').width) - CONTAINER_HORIZONTAL_PADDING * 2
|
|
82
|
+
|
|
83
|
+
// 2. 计算每行可以容纳多少个元素
|
|
84
|
+
const itemsPerRow = Math.ceil(containerWidth / ITEM_TOTAL_WIDTH)
|
|
85
|
+
// 如果无法容纳任何元素,则不渲染幽灵元素
|
|
86
|
+
if (itemsPerRow <= 0) {
|
|
87
|
+
xLog('No ghost elements needed.')
|
|
88
|
+
return null
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 3. 计算需要补充的幽灵元素数量
|
|
92
|
+
const numberOfItems = list.length
|
|
93
|
+
const itemsInLastRow = numberOfItems % itemsPerRow
|
|
94
|
+
|
|
95
|
+
// 如果最后一行为空或已满,则不需要幽灵元素
|
|
96
|
+
if (itemsInLastRow === 0) {
|
|
97
|
+
return null
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const numberOfGhosts = itemsPerRow - itemsInLastRow
|
|
101
|
+
|
|
102
|
+
// 4. 返回一个包含正确数量幽灵元素的数组
|
|
103
|
+
return Array.from({ length: numberOfGhosts }).map((_, index) => (
|
|
104
|
+
<View key={`ghost-${index}`} style={styles.ghostItem}/>
|
|
105
|
+
))
|
|
106
|
+
}, [list.length]) // 依赖项:当图标总数变化时重新计算
|
|
107
|
+
|
|
46
108
|
return (
|
|
47
|
-
<View style={
|
|
109
|
+
<View style={styles.container}>
|
|
48
110
|
<LDVTopBar
|
|
49
|
-
title={I18n.getLang('add_new_trigger_time_system_back_text')}
|
|
50
|
-
onBackPress={() =>
|
|
51
|
-
navigation.goBack()
|
|
52
|
-
}}
|
|
111
|
+
title={params.backText ?? I18n.getLang('add_new_trigger_time_system_back_text')}
|
|
112
|
+
onBackPress={() => navigation.goBack()}
|
|
53
113
|
/>
|
|
54
|
-
<ScrollView nestedScrollEnabled={true} style={
|
|
55
|
-
<View style={
|
|
56
|
-
<Text style={
|
|
114
|
+
<ScrollView nestedScrollEnabled={true} style={styles.scrollView}>
|
|
115
|
+
<View style={styles.titleView}>
|
|
116
|
+
<Text style={styles.title}>{I18n.getLang('add_new_trigger_time_icon_selection_headline_text')}</Text>
|
|
57
117
|
</View>
|
|
58
|
-
<View
|
|
59
|
-
|
|
118
|
+
<View style={styles.iconContainer}>
|
|
119
|
+
{/* 渲染真实的图标 */}
|
|
60
120
|
{list?.map(item => {
|
|
61
121
|
return <TouchableOpacity
|
|
62
122
|
onPress={() => {
|
|
@@ -67,20 +127,23 @@ function IconSelectPage(props: { theme?: ThemeType }) {
|
|
|
67
127
|
key={item.id}
|
|
68
128
|
>
|
|
69
129
|
<Image
|
|
70
|
-
source={{uri: item?.icon}}
|
|
130
|
+
source={{ uri: item?.icon }}
|
|
71
131
|
style={{
|
|
72
|
-
width:
|
|
73
|
-
height: cx(32),
|
|
74
|
-
margin:
|
|
132
|
+
width: ICON_WIDTH,
|
|
133
|
+
height: cx(32), // 高度保持不变
|
|
134
|
+
margin: ICON_MARGIN,
|
|
75
135
|
tintColor: item?.selectStatus ? props.theme?.icon.primary : item?.disabled && props.theme?.icon.disable || props.theme?.icon.normal,
|
|
76
136
|
}}
|
|
77
137
|
/>
|
|
78
138
|
</TouchableOpacity>
|
|
79
139
|
})}
|
|
140
|
+
|
|
141
|
+
{/* 渲染精确计算出的幽灵元素 */}
|
|
142
|
+
{ghostElements}
|
|
80
143
|
</View>
|
|
81
144
|
</ScrollView>
|
|
82
145
|
</View>
|
|
83
146
|
)
|
|
84
147
|
}
|
|
85
148
|
|
|
86
|
-
export default withTheme(
|
|
149
|
+
export default withTheme(IconSelect)
|
|
@@ -100,6 +100,9 @@ export function useDiySceneId() {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
function decodeLoveScenes(dpValue: string): number[] {
|
|
103
|
+
if (!dpValue) {
|
|
104
|
+
return []
|
|
105
|
+
}
|
|
103
106
|
const loveScenes: number[] = [];
|
|
104
107
|
for (let i = 2; i < dpValue.length; i += 4) {
|
|
105
108
|
const groupHex = dpValue.slice(i, i + 4);
|
|
@@ -180,7 +180,7 @@ const DiySceneEditorPage = (props: { theme?: ThemeType }) => {
|
|
|
180
180
|
deleteBtnText: {
|
|
181
181
|
color: props.theme?.button.fontColor,
|
|
182
182
|
fontSize: cx(16),
|
|
183
|
-
fontFamily: 'helvetica_neue_lt_std_bd',
|
|
183
|
+
// fontFamily: 'helvetica_neue_lt_std_bd',
|
|
184
184
|
},
|
|
185
185
|
})
|
|
186
186
|
|
|
@@ -80,7 +80,7 @@ const getDpResultByYear = async (devIdGroup: string[], addEleDpCode: string, dat
|
|
|
80
80
|
})
|
|
81
81
|
}
|
|
82
82
|
})
|
|
83
|
-
const curMonthList = Object.keys(mergedData).sort((a, b) => parseInt(
|
|
83
|
+
const curMonthList = Object.keys(mergedData).sort((a, b) => parseInt(a) - parseInt(b));
|
|
84
84
|
return curMonthList.map(month => {
|
|
85
85
|
return {
|
|
86
86
|
key: `${monthFormat(month)} ${year}`,
|
|
@@ -2,7 +2,6 @@ import I18n from '@ledvance/base/src/i18n'
|
|
|
2
2
|
import React, { useCallback } from 'react'
|
|
3
3
|
import { Image, TouchableOpacity, View } from 'react-native'
|
|
4
4
|
import { DateType } from '../co2Data'
|
|
5
|
-
import DateSelectedItem from '../component/DateSelectedItem'
|
|
6
5
|
import DateTypeItem from '../component/DateTypeItem'
|
|
7
6
|
import DateSwitch from '../component/DateSwitch'
|
|
8
7
|
import NewBarChart from '../component/NewBarChart'
|
|
@@ -26,105 +25,89 @@ export const ChartSection = ({ isLandscape, state, actions, params, styles, them
|
|
|
26
25
|
|
|
27
26
|
const handleExportCsv = useCallback(() => {
|
|
28
27
|
const displayMode = state.displayMode || 'consumption'
|
|
29
|
-
const consumedData = state.consumptionChartData
|
|
30
|
-
const generatedData = state.generationChartData
|
|
31
|
-
const price = params.price
|
|
32
|
-
const unit = params.unit
|
|
33
|
-
const consumedName = I18n.getLang('chart_legend_consumption')
|
|
34
|
-
const generatedName = I18n.getLang('chart_legend_generation')
|
|
28
|
+
const consumedData = state.consumptionChartData
|
|
29
|
+
const generatedData = state.generationChartData
|
|
30
|
+
const price = params.price
|
|
31
|
+
const unit = params.unit
|
|
32
|
+
const consumedName = I18n.getLang('chart_legend_consumption')
|
|
33
|
+
const generatedName = I18n.getLang('chart_legend_generation')
|
|
35
34
|
// 1. 创建CSV头部 (与之前相同)
|
|
36
|
-
const header = [I18n.getLang('date')]
|
|
35
|
+
const header = [I18n.getLang('date')]
|
|
37
36
|
if (displayMode === 'consumption' || displayMode === 'both') {
|
|
38
|
-
header.push(`${consumedName} (kWh)`, `${consumedName} (${unit})`)
|
|
37
|
+
header.push(`${consumedName} (kWh)`, `${consumedName} (${unit})`)
|
|
39
38
|
}
|
|
40
39
|
if (displayMode === 'generation' || displayMode === 'both') {
|
|
41
|
-
header.push(`${generatedName} (kWh)`, `${generatedName} (${unit})`)
|
|
40
|
+
header.push(`${generatedName} (kWh)`, `${generatedName} (${unit})`)
|
|
42
41
|
}
|
|
43
|
-
const rows = []
|
|
44
|
-
let i = 0
|
|
45
|
-
let j = 0
|
|
42
|
+
const rows = []
|
|
43
|
+
let i = 0 // 指向 consumedData 的指针
|
|
44
|
+
let j = 0 // 指向 generatedData 的指针
|
|
46
45
|
// 2. 双指针合并算法
|
|
47
46
|
while (i < consumedData.length || j < generatedData.length) {
|
|
48
|
-
const consumedItem = consumedData[i]
|
|
49
|
-
const generatedItem = generatedData[j]
|
|
50
|
-
const consumedKey = consumedItem?.headlineText
|
|
51
|
-
const generatedKey = generatedItem?.headlineText
|
|
52
|
-
let rowData = []
|
|
53
|
-
let dateKey = ''
|
|
47
|
+
const consumedItem = consumedData[i]
|
|
48
|
+
const generatedItem = generatedData[j]
|
|
49
|
+
const consumedKey = consumedItem?.headlineText
|
|
50
|
+
const generatedKey = generatedItem?.headlineText
|
|
51
|
+
let rowData = []
|
|
52
|
+
let dateKey = ''
|
|
54
53
|
if (consumedKey === generatedKey) {
|
|
55
|
-
dateKey = consumedItem.key
|
|
56
|
-
const consumedValue = Number(consumedItem.value)
|
|
57
|
-
const generatedValue = Number(generatedItem.value)
|
|
54
|
+
dateKey = consumedItem.key
|
|
55
|
+
const consumedValue = Number(consumedItem.value)
|
|
56
|
+
const generatedValue = Number(generatedItem.value)
|
|
58
57
|
if (displayMode === 'consumption' || displayMode === 'both') {
|
|
59
|
-
rowData.push(consumedValue.toFixed(2), (consumedValue * price).toFixed(2))
|
|
58
|
+
rowData.push(consumedValue.toFixed(2), (consumedValue * price).toFixed(2))
|
|
60
59
|
}
|
|
61
60
|
if (displayMode === 'generation' || displayMode === 'both') {
|
|
62
|
-
rowData.push(generatedValue.toFixed(2), (generatedValue * price).toFixed(2))
|
|
61
|
+
rowData.push(generatedValue.toFixed(2), (generatedValue * price).toFixed(2))
|
|
63
62
|
}
|
|
64
|
-
i
|
|
65
|
-
j
|
|
63
|
+
i++
|
|
64
|
+
j++
|
|
66
65
|
} else if (consumedKey > generatedKey || !generatedKey) {
|
|
67
|
-
dateKey = consumedItem.key
|
|
68
|
-
const consumedValue = Number(consumedItem.value)
|
|
66
|
+
dateKey = consumedItem.key
|
|
67
|
+
const consumedValue = Number(consumedItem.value)
|
|
69
68
|
if (displayMode === 'consumption' || displayMode === 'both') {
|
|
70
|
-
rowData.push(consumedValue.toFixed(2), (consumedValue * price).toFixed(2))
|
|
69
|
+
rowData.push(consumedValue.toFixed(2), (consumedValue * price).toFixed(2))
|
|
71
70
|
}
|
|
72
71
|
if (displayMode === 'generation' || displayMode === 'both') {
|
|
73
72
|
// 在 'generation' 或 'both' 模式下,为缺失的产生数据补0
|
|
74
|
-
rowData.push('0.00', '0.00')
|
|
73
|
+
rowData.push('0.00', '0.00')
|
|
75
74
|
}
|
|
76
|
-
i
|
|
75
|
+
i++
|
|
77
76
|
} else {
|
|
78
|
-
dateKey = generatedItem.key
|
|
79
|
-
const generatedValue = Number(generatedItem.value)
|
|
77
|
+
dateKey = generatedItem.key
|
|
78
|
+
const generatedValue = Number(generatedItem.value)
|
|
80
79
|
if (displayMode === 'consumption' || displayMode === 'both') {
|
|
81
80
|
// 在 'consumption' 或 'both' 模式下,为缺失的消耗数据补0
|
|
82
|
-
rowData.push('0.00', '0.00')
|
|
81
|
+
rowData.push('0.00', '0.00')
|
|
83
82
|
}
|
|
84
83
|
if (displayMode === 'generation' || displayMode === 'both') {
|
|
85
|
-
rowData.push(generatedValue.toFixed(2), (generatedValue * price).toFixed(2))
|
|
84
|
+
rowData.push(generatedValue.toFixed(2), (generatedValue * price).toFixed(2))
|
|
86
85
|
}
|
|
87
|
-
j
|
|
86
|
+
j++
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
// 将日期和处理好的数据行组合起来
|
|
91
|
-
rows.push([dateKey, ...rowData])
|
|
90
|
+
rows.push([dateKey, ...rowData])
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
exportEnergyCsv(header, rows)
|
|
93
|
+
exportEnergyCsv(header, rows)
|
|
95
94
|
}, [state.displayMode, state.consumptionChartData, state.generationChartData, params.price, params.unit])
|
|
96
95
|
|
|
97
96
|
const isDataEmpty = state.consumptionChartData.length <= 0 && state.generationChartData.length <= 0
|
|
98
97
|
|
|
99
98
|
return (
|
|
100
99
|
<>
|
|
101
|
-
{!isLandscape && (
|
|
102
|
-
<View style={styles.dateSwitchContainer}>
|
|
103
|
-
<DateSwitch
|
|
104
|
-
style={{ flex: 1 }}
|
|
105
|
-
date={state.date}
|
|
106
|
-
dateType={state.dateType}
|
|
107
|
-
headlineText={state.headlineText}
|
|
108
|
-
onDateChange={actions.setDate}
|
|
109
|
-
/>
|
|
110
|
-
<TouchableOpacity style={{ width: cx(30) }} onPress={handleExportCsv}>
|
|
111
|
-
<Image
|
|
112
|
-
style={styles.downloadIcon}
|
|
113
|
-
source={{ uri: !isDataEmpty ? res.download_icon : undefined }}
|
|
114
|
-
/>
|
|
115
|
-
</TouchableOpacity>
|
|
116
|
-
</View>
|
|
117
|
-
)}
|
|
118
100
|
<View style={styles.dateControlsContainer}>
|
|
119
101
|
<DateTypeItem
|
|
120
102
|
style={styles.dateTypeItem}
|
|
121
103
|
dateType={state.dateType}
|
|
122
104
|
onDateTypeChange={actions.setDateType}
|
|
123
105
|
/>
|
|
124
|
-
<
|
|
125
|
-
style={
|
|
126
|
-
dateType={state.dateType}
|
|
106
|
+
<DateSwitch
|
|
107
|
+
style={{ flex: 1 }}
|
|
127
108
|
date={state.date}
|
|
109
|
+
dateType={state.dateType}
|
|
110
|
+
headlineText={state.headlineText}
|
|
128
111
|
onDateChange={actions.setDate}
|
|
129
112
|
/>
|
|
130
113
|
</View>
|
|
@@ -132,17 +115,26 @@ export const ChartSection = ({ isLandscape, state, actions, params, styles, them
|
|
|
132
115
|
{isDataEmpty ? (
|
|
133
116
|
<EmptyDataView text={getEmptyDataTip()} theme={theme} styles={styles}/>
|
|
134
117
|
) : (
|
|
135
|
-
!state.loading &&
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
118
|
+
!state.loading && <>
|
|
119
|
+
{!isLandscape && <View style={styles.downloadContainer}>
|
|
120
|
+
<TouchableOpacity
|
|
121
|
+
style={{ width: cx(30) }}
|
|
122
|
+
onPress={handleExportCsv}>
|
|
123
|
+
<Image
|
|
124
|
+
style={styles.downloadIcon}
|
|
125
|
+
source={{ uri: res.download_icon }}/>
|
|
126
|
+
</TouchableOpacity>
|
|
127
|
+
</View>}
|
|
128
|
+
<NewBarChart
|
|
129
|
+
height={chartHeight}
|
|
130
|
+
data={state.chartData}
|
|
131
|
+
displayMode={state.displayMode}
|
|
132
|
+
consumedData={state.consumptionChartData}
|
|
133
|
+
generatedData={state.generationChartData}
|
|
134
|
+
price={state.price}
|
|
135
|
+
unit={params.unit}
|
|
136
|
+
/>
|
|
137
|
+
</>
|
|
146
138
|
)}
|
|
147
139
|
</>
|
|
148
140
|
)
|
|
@@ -18,7 +18,7 @@ export const getStyles = (theme: ThemeType | undefined) => StyleSheet.create({
|
|
|
18
18
|
flexDirection: 'row',
|
|
19
19
|
},
|
|
20
20
|
dateTypeItem: {
|
|
21
|
-
flex:
|
|
21
|
+
flex: 0.5,
|
|
22
22
|
},
|
|
23
23
|
dateSelectedItem: {
|
|
24
24
|
flex: 1,
|
|
@@ -77,12 +77,16 @@ export const getStyles = (theme: ThemeType | undefined) => StyleSheet.create({
|
|
|
77
77
|
downloadButton: {
|
|
78
78
|
width: cx(30),
|
|
79
79
|
},
|
|
80
|
+
downloadContainer: {
|
|
81
|
+
flexDirection: 'row',
|
|
82
|
+
justifyContent: 'flex-end',
|
|
83
|
+
// marginHorizontal: cx(24),
|
|
84
|
+
marginTop: cx(15),
|
|
85
|
+
marginBottom: cx(-15)
|
|
86
|
+
},
|
|
80
87
|
downloadIcon: {
|
|
81
88
|
width: cx(24),
|
|
82
89
|
height: cx(24),
|
|
83
90
|
tintColor: theme?.global.brand,
|
|
84
|
-
position: 'absolute',
|
|
85
|
-
right: 0,
|
|
86
|
-
top: cx(10),
|
|
87
91
|
},
|
|
88
92
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OrientationService } from '@ledvance/base/src/api/OrientationService'
|
|
2
|
-
import { overDays
|
|
2
|
+
import { overDays } from '@ledvance/base/src/utils'
|
|
3
3
|
import { loopsText, monthFormat } from '@ledvance/base/src/utils/common'
|
|
4
4
|
import { useReactive, useUpdateEffect } from 'ahooks'
|
|
5
5
|
import dayjs from 'dayjs'
|
|
@@ -7,10 +7,12 @@ import { useCallback, useEffect } from 'react'
|
|
|
7
7
|
import { DateType } from '../co2Data'
|
|
8
8
|
import { getElectricity } from '../EnergyConsumptionActions'
|
|
9
9
|
import { EnergyConsumptionChartProps } from '../EnergyConsumptionChart'
|
|
10
|
+
import {useIsPad} from "@ledvance/base/src/models/modules/NativePropsSlice"
|
|
10
11
|
|
|
11
12
|
export type EnergyDisplayMode = 'consumption' | 'generation' | 'both';
|
|
12
13
|
|
|
13
14
|
export const useEnergyData = (params: EnergyConsumptionChartProps) => {
|
|
15
|
+
const isPad = useIsPad()
|
|
14
16
|
const { addEleDpCode, price, unit, date, over365Days, over7Days, chartData, deviceIdGroup, consumptionDeviceIds, generationDeviceIds } = params
|
|
15
17
|
|
|
16
18
|
const getDateType = useCallback((d: string) => {
|
|
@@ -26,7 +28,7 @@ export const useEnergyData = (params: EnergyConsumptionChartProps) => {
|
|
|
26
28
|
const initialDateType = getDateType(date)
|
|
27
29
|
const state = useReactive({
|
|
28
30
|
loading: false,
|
|
29
|
-
isSupportLandscape: OrientationService.isSupported(),
|
|
31
|
+
isSupportLandscape: OrientationService.isSupported() && !isPad,
|
|
30
32
|
isLandscape: false,
|
|
31
33
|
dateType: initialDateType,
|
|
32
34
|
date: date,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import ThemeType from "@ledvance/base/src/config/themeType";
|
|
2
2
|
import React, {PropsWithChildren, useCallback, useEffect} from "react";
|
|
3
|
-
import {Image,
|
|
3
|
+
import {Image, TouchableOpacity, View, ViewProps} from "react-native";
|
|
4
4
|
import {Utils} from "tuya-panel-kit";
|
|
5
5
|
import {useReactive} from "ahooks";
|
|
6
6
|
import res from "@ledvance/base/src/res";
|
|
7
7
|
import dayjs from "dayjs";
|
|
8
8
|
import {DateType} from "../co2Data";
|
|
9
|
+
import DateSelectedItem from './DateSelectedItem'
|
|
9
10
|
|
|
10
11
|
const cx = Utils.RatioUtils.convertX;
|
|
11
12
|
const {withTheme} = Utils.ThemeUtils
|
|
@@ -89,13 +90,14 @@ export default withTheme(function DateSwitch(props: DateSwitchProps) {
|
|
|
89
90
|
height={cx(36)}
|
|
90
91
|
width={cx(36)}/>
|
|
91
92
|
</TouchableOpacity>
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
<DateSelectedItem
|
|
94
|
+
style={{flex: 1}}
|
|
95
|
+
dateType={state.dateType}
|
|
96
|
+
date={state.date}
|
|
97
|
+
onDateChange={date => {
|
|
98
|
+
props.onDateChange(date)
|
|
99
|
+
}}
|
|
100
|
+
/>
|
|
99
101
|
<TouchableOpacity
|
|
100
102
|
disabled={state.disableArrowRight}
|
|
101
103
|
onPress={() => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
2
2
|
import I18n from '@ledvance/base/src/i18n'
|
|
3
|
+
import { xLog } from '@ledvance/base/src/utils'
|
|
3
4
|
import ECharts from '@ledvance/react-native-echarts-pro'
|
|
4
5
|
import React, { useMemo, useRef } from 'react'
|
|
5
6
|
import { View } from 'react-native'
|
|
@@ -58,7 +59,15 @@ const BarChartWithTouch = (props: BarChartProps) => {
|
|
|
58
59
|
combinedDataMap.get(key)!.generated = Number(item.value)
|
|
59
60
|
})
|
|
60
61
|
|
|
61
|
-
const sortedKeys = Array.from(combinedDataMap.keys()).sort((a, b) =>
|
|
62
|
+
const sortedKeys = Array.from(combinedDataMap.keys()).sort((a, b) => {
|
|
63
|
+
// 1. 移除非数字字符
|
|
64
|
+
// 2. 转换为整数
|
|
65
|
+
// 3. 进行数字比较
|
|
66
|
+
const numA = parseInt(a.replace(/\D/g, ''), 10);
|
|
67
|
+
const numB = parseInt(b.replace(/\D/g, ''), 10);
|
|
68
|
+
|
|
69
|
+
return numA - numB;
|
|
70
|
+
})
|
|
62
71
|
|
|
63
72
|
const finalDataX: string[] = []
|
|
64
73
|
const finalAlignedConsumed: number[] = []
|
|
@@ -169,6 +178,7 @@ const BarChartWithTouch = (props: BarChartProps) => {
|
|
|
169
178
|
legend: {
|
|
170
179
|
show: true,
|
|
171
180
|
data: legendData,
|
|
181
|
+
top: '5%',
|
|
172
182
|
textStyle: { color: theme?.global.fontColor },
|
|
173
183
|
},
|
|
174
184
|
grid: {
|
|
@@ -192,7 +202,12 @@ const BarChartWithTouch = (props: BarChartProps) => {
|
|
|
192
202
|
name: I18n.getLang('consumption_data_annual_bar_chart_text'),
|
|
193
203
|
max: maxKwhValue,
|
|
194
204
|
min: 0,
|
|
195
|
-
axisLabel: {
|
|
205
|
+
axisLabel: {
|
|
206
|
+
formatter: function (value) {
|
|
207
|
+
return parseFloat(value).toFixed(2);
|
|
208
|
+
},
|
|
209
|
+
color: theme?.global.secondFontColor
|
|
210
|
+
},
|
|
196
211
|
},
|
|
197
212
|
{
|
|
198
213
|
type: 'value',
|
|
@@ -201,7 +216,12 @@ const BarChartWithTouch = (props: BarChartProps) => {
|
|
|
201
216
|
max: maxPriceValue,
|
|
202
217
|
min: 0,
|
|
203
218
|
minInterval: 1,
|
|
204
|
-
axisLabel: {
|
|
219
|
+
axisLabel: {
|
|
220
|
+
formatter: function (value) {
|
|
221
|
+
return parseFloat(value).toFixed(1);
|
|
222
|
+
},
|
|
223
|
+
color: theme?.global.secondFontColor
|
|
224
|
+
},
|
|
205
225
|
},
|
|
206
226
|
],
|
|
207
227
|
series: seriesData,
|
|
@@ -141,7 +141,7 @@ const FixedTimeForPlugDetailPage = (props: { theme?: ThemeType }) => {
|
|
|
141
141
|
color: props.theme?.global.fontColor,
|
|
142
142
|
fontSize: cx(16),
|
|
143
143
|
fontWeight: 'bold',
|
|
144
|
-
fontFamily: 'helvetica_neue_lt_std_bd',
|
|
144
|
+
// fontFamily: 'helvetica_neue_lt_std_bd',
|
|
145
145
|
},
|
|
146
146
|
applyContent: {
|
|
147
147
|
backgroundColor: props.theme?.container.background,
|
|
@@ -40,13 +40,13 @@ const ItemCard = (props: ItemCardProps) => {
|
|
|
40
40
|
color: props.theme?.global.fontColor,
|
|
41
41
|
fontSize: cx(16),
|
|
42
42
|
fontWeight: 'bold',
|
|
43
|
-
fontFamily: 'helvetica_neue_lt_std_bd',
|
|
43
|
+
// fontFamily: 'helvetica_neue_lt_std_bd',
|
|
44
44
|
},
|
|
45
45
|
switchBtn: {},
|
|
46
46
|
loopText: {
|
|
47
47
|
color: props.theme?.global.fontColor,
|
|
48
48
|
fontSize: cx(14),
|
|
49
|
-
fontFamily: 'helvetica_neue_lt_std_roman',
|
|
49
|
+
// fontFamily: 'helvetica_neue_lt_std_roman',
|
|
50
50
|
},
|
|
51
51
|
})
|
|
52
52
|
|