@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.
Files changed (49) hide show
  1. package/package.json +1 -1
  2. package/src/modules/biorhythm/BiorhythmDetailPage.tsx +8 -2
  3. package/src/modules/biorhythm/BiorhythmPage.tsx +4 -4
  4. package/src/modules/biorhythm/IconSelect.tsx +92 -29
  5. package/src/modules/diyScene/DiySceneActions.ts +3 -0
  6. package/src/modules/diyScene/DiySceneEditorPage.tsx +1 -1
  7. package/src/modules/energyConsumption/EnergyConsumptionActions.ts +1 -1
  8. package/src/modules/energyConsumption/EnergyConsumptionChart/ChartSection.tsx +61 -69
  9. package/src/modules/energyConsumption/EnergyConsumptionChart/LandscapeView.tsx +1 -0
  10. package/src/modules/energyConsumption/EnergyConsumptionChart/styles.ts +8 -4
  11. package/src/modules/energyConsumption/EnergyConsumptionChart/useEnergyData.ts +4 -2
  12. package/src/modules/energyConsumption/component/DateSwitch.tsx +10 -8
  13. package/src/modules/energyConsumption/component/NewBarChart.tsx +23 -3
  14. package/src/modules/fixedTimeForPlug/FixedTimeForPlugDetailPage.tsx +1 -1
  15. package/src/modules/fixedTimeForPlug/ItemCard.tsx +2 -2
  16. package/src/modules/fixedTimeForPlug/Summary.tsx +1 -1
  17. package/src/modules/fixedTimingForLight/FixedTimingForLightDetailPage.tsx +1 -1
  18. package/src/modules/fixedTimingForLight/ItemCard.tsx +2 -2
  19. package/src/modules/fixedTimingForLight/Summary.tsx +1 -1
  20. package/src/modules/flags/FlagEditPage.tsx +2 -2
  21. package/src/modules/flags/FlagInfo.tsx +1180 -1174
  22. package/src/modules/flags/FlagItem.tsx +1 -1
  23. package/src/modules/lightMode/LightModePage.tsx +1 -1
  24. package/src/modules/mood/DynamicMoodEditorPage.tsx +2 -2
  25. package/src/modules/mood/MoodItem.tsx +2 -2
  26. package/src/modules/mood/RecommendMoodItem.tsx +1 -1
  27. package/src/modules/mood/StaticMoodEditorPage.tsx +2 -2
  28. package/src/modules/mood_new/DynamicMoodEditorPage.tsx +2 -2
  29. package/src/modules/mood_new/MixDynamicMoodEditor.tsx +2 -2
  30. package/src/modules/mood_new/MoodItem.tsx +2 -2
  31. package/src/modules/mood_new/RecommendMoodItem.tsx +1 -1
  32. package/src/modules/mood_new/StaticMoodEditorPage.tsx +1 -1
  33. package/src/modules/music/MusicPage.tsx +1 -1
  34. package/src/modules/overchargeSwitch/OverchargeSwitchPage.tsx +1 -1
  35. package/src/modules/powerOnBehavior/LightBehaviorPage.tsx +2 -2
  36. package/src/modules/randomTimeForPlug/ItemCard.tsx +2 -2
  37. package/src/modules/randomTimeForPlug/RandomTimeForPlugDetailPage.tsx +1 -1
  38. package/src/modules/randomTimeForPlug/Summary.tsx +1 -1
  39. package/src/modules/randomTimingForLight/ItemCard.tsx +2 -2
  40. package/src/modules/randomTimingForLight/RandomTimingForLightDetailPage.tsx +1 -1
  41. package/src/modules/randomTimingForLight/Summary.tsx +1 -1
  42. package/src/modules/remoteSwitch/RemoteSwitchPage.tsx +1 -1
  43. package/src/modules/select/SelectPage.tsx +3 -3
  44. package/src/modules/sleepWakeUp/SleepWakeUpDetailPage.tsx +1 -1
  45. package/src/modules/sleepWakeUp/SleepWakeUpPage.tsx +4 -4
  46. package/src/modules/timeSchedule/TimeScheduleDetailPage.tsx +1 -1
  47. package/src/modules/timeSchedule/components/ScheduleCard.tsx +3 -3
  48. package/src/modules/timeSchedule/components/Summary.tsx +1 -1
  49. package/src/modules/timer/TimerPage.tsx +3 -3
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "name": "@ledvance/group-ui-biz-bundle",
5
5
  "pid": [],
6
6
  "uiid": "",
7
- "version": "1.0.141",
7
+ "version": "1.0.143",
8
8
  "scripts": {},
9
9
  "dependencies": {
10
10
  "@ledvance/base": "^1.x",
@@ -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={{ fontSize: cx(16), color: props.theme?.global.fontColor, fontFamily: 'helvetica_neue_lt_std_bd', marginTop: cx(33), marginBottom: cx(16) }}>
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
- import {Image, ScrollView, Text, TouchableOpacity, View} from 'react-native'
4
- import {Utils} from 'tuya-panel-kit'
5
- import iconList from './iconListData'
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.convertX
12
+ const { convertX: cx } = Utils.RatioUtils
12
13
  const { withTheme } = Utils.ThemeUtils
13
14
 
14
- interface IconSelectPageParams {
15
- id: string | number
16
- setIcon: (id: string | number) => void,
15
+ interface SceneDetailPageParams {
16
+ backText?: string
17
+ id: any
18
+ setIcon: (id) => void,
17
19
  iconIdList: any
18
20
  }
19
21
 
20
- function IconSelectPage(props: { theme?: ThemeType }) {
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 = useParams<IconSelectPageParams>()
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={{flex: 1, flexDirection: 'column'}}>
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={{marginHorizontal: cx(24)}}>
55
- <View style={{marginTop: cx(40), marginBottom: cx(20)}}>
56
- <Text style={{fontSize: cx(24), color: props.theme?.global.brand}}>{I18n.getLang('add_new_trigger_time_icon_selection_headline_text')}</Text>
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
- style={{flexDirection: 'row', flex: 1, flexWrap: 'wrap', justifyContent: 'space-between', alignItems: 'flex-start'}}>
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: cx(32),
73
- height: cx(32),
74
- margin: cx(10),
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(IconSelectPage)
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(b) - parseInt(a));
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; // 指向 consumedData 的指针
45
- let j = 0; // 指向 generatedData 的指针
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
- <DateSelectedItem
125
- style={styles.dateSelectedItem}
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
- <NewBarChart
137
- height={chartHeight}
138
- data={state.chartData}
139
- displayMode={state.displayMode}
140
- consumedData={state.consumptionChartData}
141
- generatedData={state.generationChartData}
142
- price={state.price}
143
- unit={params.unit}
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
  )
@@ -31,6 +31,7 @@ export const LandscapeView = ({ state, actions, params, styles, theme, screenWid
31
31
 
32
32
  <View style={styles.landscapeContent}>
33
33
  <ChartSection
34
+ isLandscape={true}
34
35
  state={state}
35
36
  actions={actions}
36
37
  params={params}
@@ -18,7 +18,7 @@ export const getStyles = (theme: ThemeType | undefined) => StyleSheet.create({
18
18
  flexDirection: 'row',
19
19
  },
20
20
  dateTypeItem: {
21
- flex: 1,
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, xLog } from '@ledvance/base/src/utils'
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, Text, TouchableOpacity, View, ViewProps} from "react-native";
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
- <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>
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) => b.localeCompare(a))
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: { color: theme?.global.secondFontColor },
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: { color: theme?.global.secondFontColor },
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