| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- import { View, Text, Pressable, Dimensions,Image, StyleSheet, ScrollView } from 'react-native';
- import { SafeAreaView } from 'react-native-safe-area-context';
- import { router, useLocalSearchParams } from 'expo-router';
- import { CrossLogoSvg } from '../global/SVG';
- import { useEffect, useMemo, useState, useRef } from 'react';
- import { chargeStationService } from '../../service/chargeStationService';
- import { ChargingDetails, Remark, ElectricityPrice, Special } from '../../service/type/chargeStationType';
- import { format, parseISO } from 'date-fns';
- const ChargingDetailsPageComponent = () => {
- const screenHeight = Dimensions.get('window').height;
- const params = useLocalSearchParams();
- const [list, setList] = useState<ChargingDetails>({} as ChargingDetails);
- const [remark, setRemark] = useState<Remark>({} as Remark);
- const [time, setTime] = useState<string>('');
- useEffect(() => {
- const fetchData = async () => {
- const res = await chargeStationService.fetchChargingDetails(params.id.toString())
- if (res) {
- const firstItem = Array.isArray(res) && res.length > 0 ? res[0] : null;
- // 设置充电详情
- setList(firstItem || ({} as ChargingDetails));
- // 安全地解析 remark 字段
- let parsedRemark: Remark = {} as Remark;
- if (firstItem?.remark) {
- try {
- parsedRemark = JSON.parse(firstItem.remark) as Remark;
- } catch (e) {
- console.warn('Failed to parse remark:', e);
- parsedRemark = {} as Remark;
- }
- }
- setRemark(parsedRemark);
- // 解析并格式化日期
- const startTime = res[0].actual_start_time? parseISO(res[0].actual_start_time): null
- const endTime = res[0].actual_end_time?parseISO(res[0].actual_end_time): null
- let formattedDate = '';
- if (startTime && endTime) {
- // 格式化为指定格式
- formattedDate = `${format(startTime, 'yyyy/MM/dd HH:mm:ss')}-${format(endTime, 'HH:mm:ss')}`;
- } else {
- formattedDate = 'Invalid Time';
- }
- setTime(formattedDate)
- }
- };
- fetchData();
- }, [])
- const totalPrice = useMemo(() => {
- if (list.promotion_name) {
- const price = list?.connector?.EquipmentID?.StationID?.price
- if (price && remark.TotalPower) {
- return `${(price * remark.TotalPower).toFixed(1)}`
- }
- return '0'
- } else {
- if (list.total_fee && list.withdraw_fee) {
- let actual_fee = list.total_fee - list.withdraw_fee
- const value = actual_fee <= 0? '0': actual_fee % 1 === 0? `${actual_fee}`: `${actual_fee.toFixed(1)}`
- return value
- }
- return '0';
- }
- }, [list]);
- const couponPrice = useMemo(() => {
- if (list.promotion_name) {
- let actual_fee = (list.total_fee - list.withdraw_fee) > 0 ? (list.total_fee - list.withdraw_fee) : 0;
- return actual_fee.toFixed(1)
- }
- }, [list])
- return (
- <SafeAreaView className="flex-1 bg-white" edges={['top']}>
- <ScrollView>
- <View style={{ minHeight: screenHeight, flex: 1 }}>
- <View className="mx-[3%]" style={{ marginTop: 25}}>
- <Pressable
- onPress={() => {
- if (router.canGoBack()) {
- router.back();
- } else {
- router.replace('/accountMainPage');
- }
- }}
- >
- <CrossLogoSvg />
- </Pressable>
- <View className="items-center px-3">
- <Image
- source={require('../../assets/ccLogo.png')}
- resizeMode="contain"
- style={{
- width: 100,
- height: 100
- }}
- />
- <Text style={styles.totalPrice}>{list.promotion_name? couponPrice:totalPrice}</Text>
- <View style={styles.viewLine}></View>
- <View className='w-full flex-row justify-between mt-6'>
- <Text style={styles.leftLable}>訂單编號: </Text>
- <View style={{ flex: 1, marginLeft: 5 }}>
- <Text style={styles.rightLable}>{list.format_order_id}</Text>
- </View>
- </View>
- <View className='w-full flex-row justify-between my-3'>
- <Text style={styles.leftLable}>充電時間: </Text>
- <View style={{ flex: 1, marginLeft: 5 }}>
- <Text style={styles.rightLable}>{time}</Text>
- </View>
- </View>
- <View className='w-full flex-row justify-between mb-4'>
- <Text style={styles.leftLable}>充電站位置:</Text>
- <View style={{ flex: 1, marginLeft: 5 }}>
- <Text style={styles.rightLable}>{params.chargeStationName}</Text>
- </View>
- </View>
- <View style={styles.viewLine}></View>
- <ChargingDataComponent list={list} remark={remark} totalPrice={totalPrice}/>
- <View style={styles.viewLine}></View>
- <View className='w-full flex-row justify-between mt-6'>
- <View>
- <Text style={styles.leftLable}>實付:</Text>
- {list.promotion_name ? <Text style={{fontSize: 12, color:'#888888'}}>優惠券支付</Text>: null}
- </View>
- <Text style={styles.rightLable}>${list.promotion_name? couponPrice:totalPrice}</Text>
- </View>
- </View>
- </View>
- </View>
- </ScrollView>
- </SafeAreaView>
- );
- };
- interface ChargingDataComponentProps {
- list: ChargingDetails;
- totalPrice: string;
- remark: Remark;
- }
- const ChargingDataComponent: React.FC<ChargingDataComponentProps> = ({
- list,
- totalPrice,
- remark
- }) => {
- const hasFetchedPrice = useRef(false); // 添加 ref 跟踪是否已获取过价格
- const [rush, setRush] = useState<Special>({} as Special)
- const [elses, setElses ] = useState<Special>({} as Special)
- const [off, setOff] = useState<Special>({} as Special)
- useEffect(() => {
- if (!list.promotion_name && !hasFetchedPrice.current && list.actual_start_time) {
- chargeStationService.fetchElectricityPrice(list.pricemodel_id || 'a').then(res => {
- hasFetchedPrice.current = true; // 标记为已调用
- const date = new Date(list.actual_start_time);
- const str = (date.toLocaleString('en-US', { weekday: 'short' })).toLowerCase();
- if (res && res.length > 0) {
- if (remark.RushKwh) {
- const obj = (res[1][str as keyof ElectricityPrice]) as Special
- setRush(obj)
- }
- if (remark.ElseKwh) {
- const obj = (res[2][str as keyof ElectricityPrice]) as Special
- setElses(obj)
- }
- if (remark.OffKwh) {
- const obj = (res[0][str as keyof ElectricityPrice]) as Special
- setOff(obj)
- }
- }
- })
- }
- }, [list.actual_start_time])
-
- if (!list.promotion_name) {
- return (
- <View>
- {(remark.RushKwh) ?
- <View>
- <View className='w-full flex-row justify-between mt-4'>
- <Text style={styles.leftLable}>峰時總電量: </Text>
- <Text style={styles.rightLable}>{remark.RushKwh?.toFixed(1)}</Text>
- </View>
- <View className='w-full flex-row justify-between my-3'>
- <Text style={styles.leftLable}>峰時電價({rush.from}-{rush.to}):</Text>
- <Text style={styles.rightLable}>${rush.price}</Text>
- </View>
- <View className='w-full flex-row justify-between mb-3'>
- <Text style={styles.leftLable}>峰時總電費:</Text>
-
- <Text style={styles.rightLable}>${remark.RushCharge?.toFixed(1)}</Text>
- </View>
- </View>: null }
- {(remark.ElseKwh) ?
- <View>
- <View className='w-full flex-row justify-between mt-4'>
- <Text style={styles.leftLable}>平時總電量: </Text>
- <Text style={styles.rightLable}>{remark.ElseKwh?.toFixed(1)}</Text>
- </View>
- <View className='w-full flex-row justify-between my-3'>
- <Text style={styles.leftLable}>平時電價({elses.from}-{elses.to}):</Text>
- <Text style={styles.rightLable}>${elses.price}</Text>
- </View>
- <View className='w-full flex-row justify-between mb-3'>
- <Text style={styles.leftLable}>平時總電費:</Text>
-
- <Text style={styles.rightLable}>${remark.ElseCharge?.toFixed(1)}</Text>
- </View>
- </View>: null }
- {(remark.OffKwh) ?
- <View>
- <View className='w-full flex-row justify-between mt-4'>
- <Text style={styles.leftLable}>穀時總電量: </Text>
- <Text style={styles.rightLable}>{remark.OffKwh?.toFixed(1)}</Text>
- </View>
- <View className='w-full flex-row justify-between my-3'>
- <Text style={styles.leftLable}>穀時電價({off.from}-{off.to}): </Text>
- <Text style={styles.rightLable}>${off.price}</Text>
- </View>
- <View className='w-full flex-row justify-between mb-3'>
- <Text style={styles.leftLable}>穀時總電費:</Text>
- <Text style={styles.rightLable}>${remark.OffCharge?.toFixed(1)}</Text>
- </View>
- </View>: null }
- </View>
- )
- } else {
- return (
- <View>
- <View className='w-full flex-row justify-between mt-4'>
- <Text style={styles.leftLable}>總電量: </Text>
- <Text style={styles.rightLable}>{remark.TotalPower?.toFixed(1)}</Text>
- </View>
- <View className='w-full flex-row justify-between my-3'>
- <Text style={styles.leftLable}>電價: </Text>
- <Text style={styles.rightLable}>${list?.connector?.EquipmentID?.StationID?.price}</Text>
- </View>
- <View className='w-full flex-row justify-between mb-3'>
- <Text style={styles.leftLable}>總電費: </Text>
-
- <Text style={styles.rightLable}>${totalPrice}</Text>
- </View>
- </View>
- )
- }
- }
- const styles = StyleSheet.create({
- viewLine: {
- width: '100%',
- height: 1,
- backgroundColor: '#E5E5E5',
- },
- totalPrice: {
- fontSize: 26,
- fontWeight: 'bold',
- marginBottom: 25,
- },
- leftLable: {
- fontSize: 18,
- color:'#888888',
- },
- rightLable: {
- fontSize: 17,
- flex: 1,
- flexWrap: 'wrap',
- textAlign: 'right',
- },
- })
- export default ChargingDetailsPageComponent;
|