@ledvance/group-ui-biz-bundle 1.0.141 → 1.0.142
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/IconSelect.tsx +92 -29
- 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/flags/FlagInfo.tsx +1180 -1174
package/package.json
CHANGED
|
@@ -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)
|
|
@@ -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,
|