@ledvance/group-ui-biz-bundle 1.0.136 → 1.0.138
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 +2 -1
- package/src/modules/energyConsumption/EnergyConsumptionChart/ChartSection.tsx +53 -0
- package/src/modules/energyConsumption/EnergyConsumptionChart/EmptyDataView.tsx +21 -0
- package/src/modules/energyConsumption/EnergyConsumptionChart/LandscapeView.tsx +32 -0
- package/src/modules/energyConsumption/EnergyConsumptionChart/PortraitView.tsx +58 -0
- package/src/modules/energyConsumption/EnergyConsumptionChart/index.tsx +36 -0
- package/src/modules/energyConsumption/EnergyConsumptionChart/styles.ts +83 -0
- package/src/modules/energyConsumption/EnergyConsumptionChart/useEnergyData.ts +112 -0
- package/src/modules/energyConsumption/EnergyConsumptionChart/useScreenDimensions.ts +36 -0
- package/src/modules/energyConsumption/EnergyConsumptionChart.tsx +2 -212
- package/src/modules/energyConsumption/EnergyConsumptionPage.tsx +20 -14
- package/src/modules/energyConsumption/Router.ts +1 -1
- package/src/modules/energyConsumption/component/DateSelectedItem.tsx +2 -2
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.
|
|
7
|
+
"version": "1.0.138",
|
|
8
8
|
"scripts": {},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@ledvance/base": "^1.x",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"prop-types": "^15.6.1",
|
|
18
18
|
"react": "16.8.3",
|
|
19
19
|
"react-native": "0.59.10",
|
|
20
|
+
"react-native-orientation-locker": "^1.7.0",
|
|
20
21
|
"react-native-svg": "5.5.1",
|
|
21
22
|
"tuya-panel-kit": "^4.9.4"
|
|
22
23
|
},
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import I18n from '@ledvance/base/src/i18n'
|
|
2
|
+
import React, { useCallback } from 'react'
|
|
3
|
+
import { View } from 'react-native'
|
|
4
|
+
import { DateType } from '../co2Data'
|
|
5
|
+
import DateSelectedItem from '../component/DateSelectedItem'
|
|
6
|
+
import DateTypeItem from '../component/DateTypeItem'
|
|
7
|
+
import NewBarChart from '../component/NewBarChart'
|
|
8
|
+
import { EmptyDataView } from './EmptyDataView'
|
|
9
|
+
|
|
10
|
+
export const ChartSection = ({ state, actions, params, styles, theme, chartHeight }) => {
|
|
11
|
+
const getEmptyDataTip = useCallback(() => {
|
|
12
|
+
if (state.over365Days && state.dateType !== DateType.Day) {
|
|
13
|
+
return I18n.getLang('energyconsumption_Daylimit')
|
|
14
|
+
}
|
|
15
|
+
if (state.dateType === DateType.Day && state.over7Days) {
|
|
16
|
+
return I18n.getLang('energyconsumption_hourlylimit')
|
|
17
|
+
}
|
|
18
|
+
return I18n.getLang('energyconsumption_emptydata')
|
|
19
|
+
}, [state.dateType, state.over365Days, state.over7Days])
|
|
20
|
+
|
|
21
|
+
const isDataEmpty = state.chartData.length <= 0
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
<View style={styles.dateControlsContainer}>
|
|
26
|
+
<DateTypeItem
|
|
27
|
+
style={styles.dateTypeItem}
|
|
28
|
+
dateType={state.dateType}
|
|
29
|
+
onDateTypeChange={actions.setDateType}
|
|
30
|
+
/>
|
|
31
|
+
<DateSelectedItem
|
|
32
|
+
style={styles.dateSelectedItem}
|
|
33
|
+
dateType={state.dateType}
|
|
34
|
+
date={state.date}
|
|
35
|
+
onDateChange={actions.setDate}
|
|
36
|
+
/>
|
|
37
|
+
</View>
|
|
38
|
+
|
|
39
|
+
{isDataEmpty ? (
|
|
40
|
+
<EmptyDataView text={getEmptyDataTip()} theme={theme} styles={styles}/>
|
|
41
|
+
) : (
|
|
42
|
+
!state.loading && (
|
|
43
|
+
<NewBarChart
|
|
44
|
+
height={chartHeight}
|
|
45
|
+
data={state.chartData}
|
|
46
|
+
price={state.price}
|
|
47
|
+
unit={params.unit}
|
|
48
|
+
/>
|
|
49
|
+
)
|
|
50
|
+
)}
|
|
51
|
+
</>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import InfoText from '@ledvance/base/src/components/InfoText'
|
|
2
|
+
import Spacer from '@ledvance/base/src/components/Spacer'
|
|
3
|
+
import res from '@ledvance/base/src/res'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
import { Image, View } from 'react-native'
|
|
6
|
+
import { Utils } from 'tuya-panel-kit'
|
|
7
|
+
|
|
8
|
+
const { convertX: cx } = Utils.RatioUtils
|
|
9
|
+
|
|
10
|
+
export const EmptyDataView = ({ text, theme, styles, height }) => (
|
|
11
|
+
<View style={[styles.listEmptyView, { height }]}>
|
|
12
|
+
<Image style={styles.listEmptyImage} source={{ uri: res.ldv_timer_empty }}/>
|
|
13
|
+
<Spacer height={cx(5)}/>
|
|
14
|
+
<InfoText
|
|
15
|
+
text={text}
|
|
16
|
+
icon={res.ic_info}
|
|
17
|
+
textStyle={styles.listEmptyText}
|
|
18
|
+
contentColor={theme?.global.fontColor}
|
|
19
|
+
/>
|
|
20
|
+
</View>
|
|
21
|
+
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import I18n from '@ledvance/base/src/i18n'
|
|
2
|
+
import res from '@ledvance/base/src/res'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Image, Text, TouchableOpacity, View } from 'react-native'
|
|
5
|
+
import { Utils } from 'tuya-panel-kit'
|
|
6
|
+
import { ChartSection } from './ChartSection'
|
|
7
|
+
|
|
8
|
+
const { convertX: cx, width } = Utils.RatioUtils
|
|
9
|
+
|
|
10
|
+
export const LandscapeView = ({ state, actions, params, styles, theme, screenWidth, screenHeight }) => (
|
|
11
|
+
<View style={[styles.landscapeContainer, { width: screenWidth, height: screenHeight }]}>
|
|
12
|
+
<View style={styles.landscapeHeader}>
|
|
13
|
+
<Text style={styles.landscapeTitle}>
|
|
14
|
+
{I18n.getLang('chartdisplay_energy')}
|
|
15
|
+
</Text>
|
|
16
|
+
<TouchableOpacity onPress={actions.toggleLandscape}>
|
|
17
|
+
<Image source={{ uri: res.screen_normal }} style={styles.normalScreenIcon}/>
|
|
18
|
+
</TouchableOpacity>
|
|
19
|
+
</View>
|
|
20
|
+
|
|
21
|
+
<View style={styles.landscapeContent}>
|
|
22
|
+
<ChartSection
|
|
23
|
+
state={state}
|
|
24
|
+
actions={actions}
|
|
25
|
+
params={params}
|
|
26
|
+
styles={styles}
|
|
27
|
+
theme={theme}
|
|
28
|
+
chartHeight={screenHeight - cx(110)}
|
|
29
|
+
/>
|
|
30
|
+
</View>
|
|
31
|
+
</View>
|
|
32
|
+
)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import Page from '@ledvance/base/src/components/Page'
|
|
2
|
+
import res from '@ledvance/base/src/res'
|
|
3
|
+
import React, { useCallback } from 'react'
|
|
4
|
+
import { Image, ScrollView, TouchableOpacity, View } from 'react-native'
|
|
5
|
+
import { Utils } from 'tuya-panel-kit'
|
|
6
|
+
import DateSwitch from '../component/DateSwitch'
|
|
7
|
+
import { exportEnergyCsv } from '../EnergyConsumptionActions'
|
|
8
|
+
import { ChartSection } from './ChartSection'
|
|
9
|
+
|
|
10
|
+
const { convertX: cx } = Utils.RatioUtils
|
|
11
|
+
|
|
12
|
+
export const PortraitView = ({ state, actions, params, styles, theme }) => {
|
|
13
|
+
|
|
14
|
+
const handleExportCsv = useCallback(() => {
|
|
15
|
+
const values = state.chartData.map(item => [item.key, item.value, (Number(params.price) * Number(item.value)).toFixed(2)])
|
|
16
|
+
exportEnergyCsv(values, params.unit)
|
|
17
|
+
}, [state.chartData, params.price, params.unit])
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Page
|
|
21
|
+
backText={params.backTitle}
|
|
22
|
+
showGreenery={false}
|
|
23
|
+
loading={state.loading}
|
|
24
|
+
greeneryIcon={res.energy_consumption_greenery}
|
|
25
|
+
rightButtonIcon={state.isSupportLandscape ? res.screen_full : undefined}
|
|
26
|
+
rightButtonStyle={styles.fullScreenIcon}
|
|
27
|
+
rightButtonIconClick={actions.toggleLandscape}
|
|
28
|
+
headlineContent={
|
|
29
|
+
<View style={styles.headlineContainer}>
|
|
30
|
+
<DateSwitch
|
|
31
|
+
style={styles.dateSwitch}
|
|
32
|
+
date={state.date}
|
|
33
|
+
dateType={state.dateType}
|
|
34
|
+
headlineText={state.headlineText}
|
|
35
|
+
onDateChange={actions.setDate}
|
|
36
|
+
/>
|
|
37
|
+
<TouchableOpacity style={styles.downloadButton} onPress={handleExportCsv}>
|
|
38
|
+
<Image
|
|
39
|
+
style={styles.downloadIcon}
|
|
40
|
+
source={{ uri: !(state.chartData.length <= 0) ? res.download_icon : undefined }}
|
|
41
|
+
/>
|
|
42
|
+
</TouchableOpacity>
|
|
43
|
+
</View>
|
|
44
|
+
}
|
|
45
|
+
>
|
|
46
|
+
<ScrollView nestedScrollEnabled={true} style={styles.scrollViewContent}>
|
|
47
|
+
<ChartSection
|
|
48
|
+
state={state}
|
|
49
|
+
actions={actions}
|
|
50
|
+
params={params}
|
|
51
|
+
styles={styles}
|
|
52
|
+
theme={theme}
|
|
53
|
+
chartHeight={cx(400)}
|
|
54
|
+
/>
|
|
55
|
+
</ScrollView>
|
|
56
|
+
</Page>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
2
|
+
import { useRoute } from '@react-navigation/core'
|
|
3
|
+
import React, { useMemo } from 'react'
|
|
4
|
+
import { Utils } from 'tuya-panel-kit'
|
|
5
|
+
import { EnergyConsumptionChartProps } from '../EnergyConsumptionChart'
|
|
6
|
+
import { LandscapeView } from './LandscapeView'
|
|
7
|
+
import { PortraitView } from './PortraitView'
|
|
8
|
+
import { getStyles } from './styles'
|
|
9
|
+
|
|
10
|
+
import { useEnergyData } from './useEnergyData'
|
|
11
|
+
import { useScreenDimensions } from './useScreenDimensions'
|
|
12
|
+
|
|
13
|
+
const { withTheme } = Utils.ThemeUtils;
|
|
14
|
+
|
|
15
|
+
const EnergyConsumptionGroupChartComponent = (props: { theme?: ThemeType }) => {
|
|
16
|
+
const params = useRoute().params as EnergyConsumptionChartProps;
|
|
17
|
+
|
|
18
|
+
const { state, actions } = useEnergyData(params);
|
|
19
|
+
const styles = useMemo(() => getStyles(props.theme), [props.theme]);
|
|
20
|
+
const { width: screenWidth, height: screenHeight } = useScreenDimensions()
|
|
21
|
+
if (state.isLandscape) {
|
|
22
|
+
return <LandscapeView
|
|
23
|
+
state={state}
|
|
24
|
+
actions={actions}
|
|
25
|
+
params={params}
|
|
26
|
+
styles={styles}
|
|
27
|
+
theme={props.theme}
|
|
28
|
+
screenWidth={screenWidth}
|
|
29
|
+
screenHeight={screenHeight}
|
|
30
|
+
/>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return <PortraitView state={state} actions={actions} params={params} styles={styles} theme={props.theme} />;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default withTheme(EnergyConsumptionGroupChartComponent);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
2
|
+
import { StyleSheet } from 'react-native'
|
|
3
|
+
import { Utils } from 'tuya-panel-kit'
|
|
4
|
+
|
|
5
|
+
const { convertX: cx, height } = Utils.RatioUtils
|
|
6
|
+
|
|
7
|
+
export const getStyles = (theme: ThemeType | undefined) => StyleSheet.create({
|
|
8
|
+
// Portrait Styles
|
|
9
|
+
scrollViewContent: {
|
|
10
|
+
marginHorizontal: cx(24),
|
|
11
|
+
},
|
|
12
|
+
dateControlsContainer: {
|
|
13
|
+
flexDirection: 'row',
|
|
14
|
+
},
|
|
15
|
+
dateTypeItem: {
|
|
16
|
+
flex: 1,
|
|
17
|
+
},
|
|
18
|
+
dateSelectedItem: {
|
|
19
|
+
flex: 1,
|
|
20
|
+
marginStart: cx(10),
|
|
21
|
+
marginBottom: cx(15),
|
|
22
|
+
},
|
|
23
|
+
fullScreenIcon: {
|
|
24
|
+
tintColor: theme?.global.brand,
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// Landscape Styles
|
|
28
|
+
landscapeContainer: {
|
|
29
|
+
flex: 1,
|
|
30
|
+
backgroundColor: theme?.global.background,
|
|
31
|
+
// width: cx(height + 20),
|
|
32
|
+
paddingVertical: cx(30),
|
|
33
|
+
paddingHorizontal: cx(20),
|
|
34
|
+
},
|
|
35
|
+
landscapeHeader: {
|
|
36
|
+
flexDirection: 'row',
|
|
37
|
+
justifyContent: 'space-between',
|
|
38
|
+
alignItems: 'center',
|
|
39
|
+
},
|
|
40
|
+
landscapeTitle: {
|
|
41
|
+
color: theme?.global.fontColor,
|
|
42
|
+
fontSize: cx(16),
|
|
43
|
+
fontWeight: 'bold',
|
|
44
|
+
},
|
|
45
|
+
landscapeContent: {
|
|
46
|
+
flex: 1,
|
|
47
|
+
},
|
|
48
|
+
normalScreenIcon: {
|
|
49
|
+
width: cx(50),
|
|
50
|
+
height: cx(50),
|
|
51
|
+
tintColor: theme?.icon.normal
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// Common Styles
|
|
55
|
+
listEmptyView: {
|
|
56
|
+
alignItems: 'center',
|
|
57
|
+
},
|
|
58
|
+
listEmptyImage: {
|
|
59
|
+
width: cx(180),
|
|
60
|
+
height: cx(180),
|
|
61
|
+
},
|
|
62
|
+
listEmptyText: {
|
|
63
|
+
flex: 0,
|
|
64
|
+
},
|
|
65
|
+
headlineContainer: {
|
|
66
|
+
width: '100%',
|
|
67
|
+
flexDirection: 'row'
|
|
68
|
+
},
|
|
69
|
+
dateSwitch: {
|
|
70
|
+
flex: 1,
|
|
71
|
+
},
|
|
72
|
+
downloadButton: {
|
|
73
|
+
width: cx(30),
|
|
74
|
+
},
|
|
75
|
+
downloadIcon: {
|
|
76
|
+
width: cx(24),
|
|
77
|
+
height: cx(24),
|
|
78
|
+
tintColor: theme?.global.brand,
|
|
79
|
+
position: 'absolute',
|
|
80
|
+
right: 0,
|
|
81
|
+
top: cx(10),
|
|
82
|
+
},
|
|
83
|
+
})
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { OrientationService } from '@ledvance/base/src/api/OrientationService'
|
|
2
|
+
import { overDays } from '@ledvance/base/src/utils'
|
|
3
|
+
import { loopsText, monthFormat } from '@ledvance/base/src/utils/common'
|
|
4
|
+
import { useReactive, useUpdateEffect } from 'ahooks'
|
|
5
|
+
import dayjs from 'dayjs'
|
|
6
|
+
import { useCallback } from 'react'
|
|
7
|
+
import { DateType } from '../co2Data'
|
|
8
|
+
import { getElectricity } from '../EnergyConsumptionActions'
|
|
9
|
+
import { EnergyConsumptionChartProps } from '../EnergyConsumptionChart'
|
|
10
|
+
|
|
11
|
+
export const useEnergyData = (params: EnergyConsumptionChartProps) => {
|
|
12
|
+
const { addEleDpCode, price, date, over365Days, over7Days, chartData, deviceIdGroup } = params
|
|
13
|
+
|
|
14
|
+
const getDateType = useCallback((d: string) => {
|
|
15
|
+
const datejs = dayjs(d)
|
|
16
|
+
if (datejs.isValid()) {
|
|
17
|
+
if (datejs.format('YYYY') === d) return DateType.Year
|
|
18
|
+
if (datejs.format('YYYYMM') === d) return DateType.Month
|
|
19
|
+
if (datejs.format('YYYY/MM/DD') === d) return DateType.Day
|
|
20
|
+
}
|
|
21
|
+
return DateType.Day
|
|
22
|
+
}, [])
|
|
23
|
+
|
|
24
|
+
const initialDateType = getDateType(date)
|
|
25
|
+
const state = useReactive({
|
|
26
|
+
loading: false,
|
|
27
|
+
isSupportLandscape: OrientationService.isSupported(),
|
|
28
|
+
isLandscape: false,
|
|
29
|
+
dateType: initialDateType,
|
|
30
|
+
date: date,
|
|
31
|
+
headlineText: initialDateType === DateType.Year ? date : params.headlineText,
|
|
32
|
+
chartData: chartData.filter((item) => initialDateType !== DateType.Year || item.headlineText.startsWith(date)),
|
|
33
|
+
price: isNaN(Number(price)) ? 0 : Number(price),
|
|
34
|
+
over365Days: over365Days,
|
|
35
|
+
over7Days: over7Days,
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const updateHeadlineText = useCallback((date: dayjs.Dayjs) => {
|
|
39
|
+
const year = date.year().toString();
|
|
40
|
+
const month = (date.month() + 1).toString().padStart(2, '0');
|
|
41
|
+
const day = date.date().toString().padStart(2, '0');
|
|
42
|
+
const dayOfWeek = date.day() % 7;
|
|
43
|
+
switch (state.dateType) {
|
|
44
|
+
case DateType.Year:
|
|
45
|
+
state.headlineText = year;
|
|
46
|
+
break
|
|
47
|
+
case DateType.Month:
|
|
48
|
+
state.headlineText = `${monthFormat(month)} ${year}`;
|
|
49
|
+
break
|
|
50
|
+
case DateType.Day:
|
|
51
|
+
state.headlineText = `${day}.${month}.${year} (${loopsText[dayOfWeek]})`;
|
|
52
|
+
break
|
|
53
|
+
}
|
|
54
|
+
}, [state.dateType])
|
|
55
|
+
|
|
56
|
+
useUpdateEffect(() => {
|
|
57
|
+
state.loading = true
|
|
58
|
+
getElectricity(deviceIdGroup, addEleDpCode, state.date, state.dateType)
|
|
59
|
+
.then((res) => {
|
|
60
|
+
state.chartData = res
|
|
61
|
+
state.loading = false
|
|
62
|
+
})
|
|
63
|
+
.catch(() => {
|
|
64
|
+
state.loading = false
|
|
65
|
+
})
|
|
66
|
+
}, [state.date])
|
|
67
|
+
|
|
68
|
+
useUpdateEffect(() => {
|
|
69
|
+
state.over365Days = overDays(state.date, 365)
|
|
70
|
+
state.over7Days = overDays(state.date, 7)
|
|
71
|
+
updateHeadlineText(dayjs(state.date))
|
|
72
|
+
}, [state.date])
|
|
73
|
+
|
|
74
|
+
useUpdateEffect(() => {
|
|
75
|
+
const d = dayjs()
|
|
76
|
+
const year = d.year().toString()
|
|
77
|
+
const month = (d.month() + 1).toString().padStart(2, '0')
|
|
78
|
+
const day = d.date().toString().padStart(2, '0')
|
|
79
|
+
switch (state.dateType) {
|
|
80
|
+
case DateType.Year:
|
|
81
|
+
state.date = year
|
|
82
|
+
break
|
|
83
|
+
case DateType.Month:
|
|
84
|
+
state.date = `${year}${month}`
|
|
85
|
+
break
|
|
86
|
+
case DateType.Day:
|
|
87
|
+
state.date = `${year}${month}${day}`
|
|
88
|
+
break
|
|
89
|
+
}
|
|
90
|
+
}, [state.dateType])
|
|
91
|
+
|
|
92
|
+
const actions = {
|
|
93
|
+
setDate: useCallback((newDate: string) => {
|
|
94
|
+
state.date = newDate
|
|
95
|
+
}, []),
|
|
96
|
+
setDateType: useCallback((type: DateType) => {
|
|
97
|
+
state.dateType = type
|
|
98
|
+
}, []),
|
|
99
|
+
toggleLandscape: useCallback(() => {
|
|
100
|
+
if (!state.isSupportLandscape) return
|
|
101
|
+
const newIsLandscape = !state.isLandscape
|
|
102
|
+
state.isLandscape = newIsLandscape
|
|
103
|
+
if (newIsLandscape) {
|
|
104
|
+
OrientationService.lockToLandscape()
|
|
105
|
+
} else {
|
|
106
|
+
OrientationService.lockToPortrait()
|
|
107
|
+
}
|
|
108
|
+
}, []),
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return { state, actions }
|
|
112
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import { Dimensions, ScaledSize, Platform } from 'react-native'
|
|
3
|
+
import { Utils } from 'tuya-panel-kit'
|
|
4
|
+
|
|
5
|
+
const { width, height, statusBarHeight } = Utils.RatioUtils
|
|
6
|
+
|
|
7
|
+
export const useScreenDimensions = () => {
|
|
8
|
+
const { width: screenWidth, height: screenHeight } = Dimensions.get('window')
|
|
9
|
+
const [screenData, setScreenData] = useState({
|
|
10
|
+
width: screenWidth,
|
|
11
|
+
height: screenHeight,
|
|
12
|
+
})
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (Platform.OS === 'android') {
|
|
15
|
+
setScreenData({
|
|
16
|
+
width: height,
|
|
17
|
+
height: width - statusBarHeight,
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
const onChange = (result: { window: ScaledSize }) => {
|
|
21
|
+
if (Platform.OS === 'ios') {
|
|
22
|
+
setScreenData(result.window)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Subscribe to dimension changes
|
|
26
|
+
Dimensions.addEventListener('change', onChange)
|
|
27
|
+
// Don't forget to unsubscribe on cleanup
|
|
28
|
+
return () => {
|
|
29
|
+
Dimensions.removeEventListener('change', onChange)
|
|
30
|
+
}
|
|
31
|
+
}, [])
|
|
32
|
+
return {
|
|
33
|
+
...screenData,
|
|
34
|
+
isLandscape: screenData.width > screenData.height,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,27 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { View, StyleSheet, Image, TouchableOpacity } from "react-native";
|
|
3
|
-
import { useRoute } from '@react-navigation/core'
|
|
4
|
-
import Page from "@ledvance/base/src/components/Page";
|
|
5
|
-
import res from "@ledvance/base/src/res";
|
|
6
|
-
import I18n from "@ledvance/base/src/i18n";
|
|
7
|
-
import { Utils } from "tuya-panel-kit";
|
|
8
|
-
import { loopsText, monthFormat } from "@ledvance/base/src/utils/common";
|
|
9
|
-
import { OverviewItem } from "./EnergyConsumptionPage";
|
|
10
|
-
import Spacer from "@ledvance/base/src/components/Spacer";
|
|
11
|
-
import InfoText from "@ledvance/base/src/components/InfoText";
|
|
12
|
-
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
13
|
-
import { overDays } from "@ledvance/base/src/utils/index";
|
|
14
|
-
import dayjs from "dayjs";
|
|
15
|
-
import { DateType } from "./co2Data";
|
|
16
|
-
import { useReactive, useUpdateEffect } from "ahooks";
|
|
17
|
-
import DateTypeItem from "./component/DateTypeItem";
|
|
18
|
-
import DateSelectedItem from "./component/DateSelectedItem";
|
|
19
|
-
import NewBarChart from "./component/NewBarChart";
|
|
20
|
-
import { exportEnergyCsv, getElectricity } from "./EnergyConsumptionActions";
|
|
21
|
-
import DateSwitch from "./component/DateSwitch";
|
|
22
|
-
|
|
23
|
-
const { convertX: cx } = Utils.RatioUtils
|
|
24
|
-
const { withTheme } = Utils.ThemeUtils
|
|
1
|
+
import { OverviewItem } from './EnergyConsumptionPage'
|
|
25
2
|
|
|
26
3
|
export interface EnergyConsumptionChartProps {
|
|
27
4
|
addEleDpCode: string
|
|
@@ -34,191 +11,4 @@ export interface EnergyConsumptionChartProps {
|
|
|
34
11
|
price: string,
|
|
35
12
|
unit: string,
|
|
36
13
|
date: string,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const EnergyConsumptionChart = (props: { theme?: ThemeType }) => {
|
|
40
|
-
const params = useRoute().params as EnergyConsumptionChartProps
|
|
41
|
-
const { backTitle, price, unit, date, addEleDpCode, deviceIdGroup, over365Days, over7Days } = params;
|
|
42
|
-
|
|
43
|
-
const styles = StyleSheet.create({
|
|
44
|
-
listEmptyView: {
|
|
45
|
-
alignItems: 'center',
|
|
46
|
-
},
|
|
47
|
-
listEmptyImage: {
|
|
48
|
-
width: cx(200),
|
|
49
|
-
height: cx(200),
|
|
50
|
-
},
|
|
51
|
-
listEmptyText: {
|
|
52
|
-
flex: 0
|
|
53
|
-
},
|
|
54
|
-
downloadIcon: {
|
|
55
|
-
width: cx(24),
|
|
56
|
-
height: cx(24),
|
|
57
|
-
tintColor: props.theme?.global.brand,
|
|
58
|
-
position: 'absolute',
|
|
59
|
-
right: 0,
|
|
60
|
-
top: cx(10)
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
const getDateType = useCallback((date: string) => {
|
|
65
|
-
const datejs = dayjs(date);
|
|
66
|
-
if (datejs.isValid()) {
|
|
67
|
-
if (datejs.format('YYYY') === date) {
|
|
68
|
-
return DateType.Year;
|
|
69
|
-
} else if (datejs.format('YYYYMM') === date) {
|
|
70
|
-
return DateType.Month;
|
|
71
|
-
} else if (datejs.format('YYYY/MM/DD') === date) {
|
|
72
|
-
return DateType.Day;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return DateType.Day;
|
|
76
|
-
}, []);
|
|
77
|
-
|
|
78
|
-
const dateType = getDateType(date);
|
|
79
|
-
const state = useReactive({
|
|
80
|
-
loading: false,
|
|
81
|
-
dateType: dateType,
|
|
82
|
-
date: date,
|
|
83
|
-
headlineText: dateType === DateType.Year ? date : params.headlineText,
|
|
84
|
-
chartData: params.chartData.filter((item) => {
|
|
85
|
-
return dateType !== DateType.Year || item.headlineText.startsWith(date)
|
|
86
|
-
}),
|
|
87
|
-
price: isNaN(Number(price)) ? 0 : Number(price),
|
|
88
|
-
over365Days: over365Days,
|
|
89
|
-
over7Days: over7Days,
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
useUpdateEffect(() => {
|
|
93
|
-
state.over365Days = overDays(state.date, 365);
|
|
94
|
-
state.over7Days = overDays(state.date, 7);
|
|
95
|
-
updateHeadlineText(dayjs(state.date));
|
|
96
|
-
state.loading = true;
|
|
97
|
-
getElectricity(deviceIdGroup, addEleDpCode, state.date, state.dateType).then((res) => {
|
|
98
|
-
state.chartData = res;
|
|
99
|
-
state.loading = false;
|
|
100
|
-
}).catch(() => {
|
|
101
|
-
state.loading = false;
|
|
102
|
-
});
|
|
103
|
-
}, [state.date]);
|
|
104
|
-
|
|
105
|
-
useUpdateEffect(() => {
|
|
106
|
-
const date = dayjs();
|
|
107
|
-
const year = date.year().toString();
|
|
108
|
-
const month = (date.month() + 1).toString().padStart(2, '0');
|
|
109
|
-
const day = date.date().toString().padStart(2, '0');
|
|
110
|
-
switch (state.dateType) {
|
|
111
|
-
case DateType.Year:
|
|
112
|
-
state.date = year;
|
|
113
|
-
break
|
|
114
|
-
case DateType.Month:
|
|
115
|
-
state.date = `${year}${month}`
|
|
116
|
-
break
|
|
117
|
-
case DateType.Day:
|
|
118
|
-
state.date = `${year}${month}${day}`
|
|
119
|
-
break
|
|
120
|
-
}
|
|
121
|
-
}, [state.dateType]);
|
|
122
|
-
|
|
123
|
-
const updateHeadlineText = useCallback((date: dayjs.Dayjs) => {
|
|
124
|
-
const year = date.year().toString();
|
|
125
|
-
const month = (date.month() + 1).toString().padStart(2, '0');
|
|
126
|
-
const day = date.date().toString().padStart(2, '0');
|
|
127
|
-
const dayOfWeek = date.day() % 7;
|
|
128
|
-
switch (state.dateType) {
|
|
129
|
-
case DateType.Year:
|
|
130
|
-
state.headlineText = year;
|
|
131
|
-
break
|
|
132
|
-
case DateType.Month:
|
|
133
|
-
state.headlineText = `${monthFormat(month)} ${year}`;
|
|
134
|
-
break
|
|
135
|
-
case DateType.Day:
|
|
136
|
-
state.headlineText = `${day}.${month}.${year} (${loopsText[dayOfWeek]})`;
|
|
137
|
-
break
|
|
138
|
-
}
|
|
139
|
-
}, [state.dateType, state.headlineText]);
|
|
140
|
-
|
|
141
|
-
const getEmptyDataTip = useCallback(() => {
|
|
142
|
-
if (state.over365Days && state.dateType !== DateType.Day) {
|
|
143
|
-
return I18n.getLang('energyconsumption_Daylimit')
|
|
144
|
-
}
|
|
145
|
-
if (state.dateType === DateType.Day && state.over7Days) {
|
|
146
|
-
return I18n.getLang('energyconsumption_hourlylimit')
|
|
147
|
-
}
|
|
148
|
-
return I18n.getLang('energyconsumption_emptydata')
|
|
149
|
-
}, [state.dateType, state.over365Days, state.over7Days]);
|
|
150
|
-
|
|
151
|
-
return (
|
|
152
|
-
<Page
|
|
153
|
-
backText={backTitle}
|
|
154
|
-
showGreenery={false}
|
|
155
|
-
greeneryIcon={res.energy_consumption_greenery}
|
|
156
|
-
loading={state.loading}
|
|
157
|
-
headlineContent={
|
|
158
|
-
<View style={{ width: '100%', flexDirection: 'row' }}>
|
|
159
|
-
<DateSwitch
|
|
160
|
-
style={{ flex: 1 }}
|
|
161
|
-
date={state.date}
|
|
162
|
-
dateType={state.dateType}
|
|
163
|
-
headlineText={state.headlineText}
|
|
164
|
-
onDateChange={(date) => {
|
|
165
|
-
state.date = date;
|
|
166
|
-
}} />
|
|
167
|
-
<TouchableOpacity
|
|
168
|
-
style={{ width: cx(30) }}
|
|
169
|
-
onPress={() => {
|
|
170
|
-
const values = state.chartData.map(item => [item.key, item.value, (Number(params.price) * Number(item.value)).toFixed(2)])
|
|
171
|
-
exportEnergyCsv(values, params.unit)
|
|
172
|
-
}}>
|
|
173
|
-
<Image
|
|
174
|
-
style={styles.downloadIcon}
|
|
175
|
-
source={{ uri: state.chartData?.length ? res.download_icon : undefined}} />
|
|
176
|
-
</TouchableOpacity>
|
|
177
|
-
</View>
|
|
178
|
-
}
|
|
179
|
-
>
|
|
180
|
-
<View style={{ marginHorizontal: cx(24) }}>
|
|
181
|
-
<View style={{ flexDirection: 'row' }}>
|
|
182
|
-
<DateTypeItem
|
|
183
|
-
style={{ flex: 1 }}
|
|
184
|
-
dateType={state.dateType}
|
|
185
|
-
onDateTypeChange={(dateType) => {
|
|
186
|
-
state.dateType = dateType;
|
|
187
|
-
}} />
|
|
188
|
-
<DateSelectedItem
|
|
189
|
-
style={{ flex: 1, marginStart: cx(10), marginBottom: cx(15) }}
|
|
190
|
-
dateType={state.dateType}
|
|
191
|
-
date={state.date}
|
|
192
|
-
onDateChange={date => {
|
|
193
|
-
state.date = date;
|
|
194
|
-
}}
|
|
195
|
-
/>
|
|
196
|
-
|
|
197
|
-
</View>
|
|
198
|
-
{
|
|
199
|
-
(state.chartData.length <= 0) ? (
|
|
200
|
-
<View style={styles.listEmptyView}>
|
|
201
|
-
<Spacer height={cx(26)} />
|
|
202
|
-
<Image
|
|
203
|
-
style={styles.listEmptyImage}
|
|
204
|
-
source={{ uri: res.ldv_timer_empty }} />
|
|
205
|
-
<Spacer height={cx(14)} />
|
|
206
|
-
<InfoText
|
|
207
|
-
text={getEmptyDataTip()}
|
|
208
|
-
icon={res.ic_info}
|
|
209
|
-
textStyle={styles.listEmptyText}
|
|
210
|
-
contentColor={props.theme?.global.fontColor}
|
|
211
|
-
/>
|
|
212
|
-
</View>
|
|
213
|
-
) : (
|
|
214
|
-
state.chartData.length > 0 && !state.loading &&
|
|
215
|
-
<NewBarChart height={cx(400)} data={state.chartData} price={state.price}
|
|
216
|
-
unit={unit} />
|
|
217
|
-
)
|
|
218
|
-
}
|
|
219
|
-
</View>
|
|
220
|
-
</Page>
|
|
221
|
-
)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export default withTheme(EnergyConsumptionChart)
|
|
14
|
+
}
|
|
@@ -375,21 +375,27 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
|
|
|
375
375
|
{/* 365 day */}
|
|
376
376
|
<Card style={styles.cardContainer}>
|
|
377
377
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
378
|
-
<
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
378
|
+
<View>
|
|
379
|
+
<View style={{height: cx(35), justifyContent: 'center'}}>
|
|
380
|
+
<Text style={styles.cardTitle}>{I18n.getLang('consumption_data_field1_headline_text')}</Text>
|
|
381
|
+
</View>
|
|
382
|
+
<View style={{height: cx(35), justifyContent: 'center'}}>
|
|
383
|
+
<Text style={styles.cardTitle}>{I18n.getLang('consumption_data_field3_headline_text')}</Text>
|
|
384
|
+
</View>
|
|
384
385
|
</View>
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
{
|
|
391
|
-
</
|
|
392
|
-
<
|
|
386
|
+
<View>
|
|
387
|
+
<View style={{ flexDirection: 'row', alignItems: 'flex-end', marginLeft: cx(10) }}>
|
|
388
|
+
<Text style={[styles.consumptionNum, { fontSize: cx(30), marginRight: cx(8) }]}>
|
|
389
|
+
{localeNumber(state.isSolarMode ? state.solarTodayElectricity : state.wifiTodayElectricity)}
|
|
390
|
+
</Text>
|
|
391
|
+
<Text style={[styles.consumptionNum, { fontSize: cx(20), marginBottom: cx(4) }]}>kWh</Text>
|
|
392
|
+
</View>
|
|
393
|
+
<View style={{ flexDirection: 'row', alignItems: 'flex-end', marginLeft: cx(10) }}>
|
|
394
|
+
<Text style={[styles.consumptionNum, { fontSize: cx(30), marginRight: cx(8) }]}>
|
|
395
|
+
{localeNumber(state.isSolarMode ? state.solarTotalElectricity : state.wifiTotalElectricity)}
|
|
396
|
+
</Text>
|
|
397
|
+
<Text style={[styles.consumptionNum, { fontSize: cx(20), marginBottom: cx(4) }]}>kWh</Text>
|
|
398
|
+
</View>
|
|
393
399
|
</View>
|
|
394
400
|
</View>
|
|
395
401
|
<Spacer />
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {NavigationRoute} from "tuya-panel-kit";
|
|
2
2
|
import EnergyConsumptionPage from "./EnergyConsumptionPage";
|
|
3
3
|
import EnergyConsumptionDetail from "./EnergyConsumptionDetail";
|
|
4
|
-
import EnergyConsumptionChart from "./EnergyConsumptionChart";
|
|
4
|
+
import EnergyConsumptionChart from "./EnergyConsumptionChart/index";
|
|
5
5
|
import {ui_biz_routerKey} from "../../navigation/Routers";
|
|
6
6
|
|
|
7
7
|
const EnergyConsumptionPageRouters: NavigationRoute[] = [
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import ThemeType from "@ledvance/base/src/config/themeType";
|
|
2
|
-
import React, {PropsWithChildren,
|
|
2
|
+
import React, {PropsWithChildren, useEffect} from "react";
|
|
3
3
|
import {StyleSheet, Text, TouchableOpacity, View, ViewProps} from "react-native";
|
|
4
4
|
import {DatePicker, Modal, Utils} from "tuya-panel-kit";
|
|
5
5
|
import {useReactive} from "ahooks";
|
|
6
6
|
import I18n from "@ledvance/base/src/i18n/index";
|
|
7
7
|
import dayjs from "dayjs";
|
|
8
|
-
import {DateType} from "
|
|
8
|
+
import {DateType} from "../co2Data";
|
|
9
9
|
|
|
10
10
|
const {convertX: cx} = Utils.RatioUtils
|
|
11
11
|
const {withTheme} = Utils.ThemeUtils
|