chargingDetailsPageComponent.tsx 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. import { View, Text, Pressable, Dimensions,Image, StyleSheet } from 'react-native';
  2. import { SafeAreaView } from 'react-native-safe-area-context';
  3. import { router, useLocalSearchParams } from 'expo-router';
  4. import { CrossLogoSvg } from '../global/SVG';
  5. import { useEffect, useMemo, useState, useRef } from 'react';
  6. import { chargeStationService } from '../../service/chargeStationService';
  7. import { ChargingDetails, Remark, ElectricityPrice, Special } from '../../service/type/chargeStationType';
  8. import { format, parseISO } from 'date-fns';
  9. const ChargingDetailsPageComponent = () => {
  10. const screenHeight = Dimensions.get('window').height;
  11. const params = useLocalSearchParams();
  12. const [list, setList] = useState<ChargingDetails>({} as ChargingDetails);
  13. const [remark, setRemark] = useState<Remark>({} as Remark);
  14. const [time, setTime] = useState<string>('');
  15. useEffect(() => {
  16. const fetchData = async () => {
  17. const res = await chargeStationService.fetchChargingDetails(params.id.toString())
  18. if (res) {
  19. // If res is an array, take the first item; otherwise, set as is
  20. setList(Array.isArray(res) ? res[0] : {} as ChargingDetails);
  21. setRemark(JSON.parse(res[0]?.remark || '{}') as Remark)
  22. // 解析并格式化日期
  23. const startTime = parseISO(res[0].actual_start_time);
  24. const endTime = parseISO(res[0].actual_end_time);
  25. // 格式化为指定格式
  26. const formattedDate = `${format(startTime, 'yyyy/MM/dd HH:mm:ss')}-${format(endTime, 'HH:mm:ss')}`;
  27. setTime(formattedDate)
  28. }
  29. };
  30. fetchData();
  31. }, [])
  32. const totalPrice = useMemo(() => {
  33. if (list.promotion_name) {
  34. const price = list?.connector?.EquipmentID?.StationID?.price
  35. if (price && remark.TotalPower) {
  36. return `${(price * remark.TotalPower).toFixed(1)}`
  37. }
  38. return '0'
  39. } else {
  40. if (list.total_fee && list.withdraw_fee) {
  41. let actual_fee = list.total_fee - list.withdraw_fee
  42. const value = actual_fee <= 0? '0': actual_fee % 1 === 0? `${actual_fee}`: `${actual_fee.toFixed(1)}`
  43. return value
  44. }
  45. return '0';
  46. }
  47. }, [list]);
  48. return (
  49. <SafeAreaView className="flex-1 bg-white" edges={['top']}>
  50. <View style={{ minHeight: screenHeight, flex: 1 }}>
  51. <View className="mx-[5%]" style={{ marginTop: 25}}>
  52. <Pressable
  53. onPress={() => {
  54. if (router.canGoBack()) {
  55. router.back();
  56. } else {
  57. router.replace('/accountMainPage');
  58. }
  59. }}
  60. >
  61. <CrossLogoSvg />
  62. </Pressable>
  63. <View className="items-center px-3">
  64. {/* <View className="flex-3 items-center justify-end" style={{}}> */}
  65. <Image
  66. source={require('../../assets/ccLogo.png')}
  67. resizeMode="contain"
  68. style={{
  69. width: screenHeight > 750 ? 200 : 110,
  70. height: screenHeight > 750 ? 200 : 110
  71. }}
  72. />
  73. <Text style={styles.totalPrice}>{totalPrice}</Text>
  74. <View style={styles.viewLine}></View>
  75. <View className='w-full flex-row justify-between mt-6 pr-10'>
  76. <Text style={styles.leftLable}>訂單编號: </Text>
  77. <Text style={styles.rightLable}>{list.format_order_id}</Text>
  78. </View>
  79. <View className='w-full flex-row justify-between my-3 pr-10'>
  80. <Text style={styles.leftLable}>充電時間: </Text>
  81. <Text style={styles.rightLable}>{time}</Text>
  82. </View>
  83. <View className='w-full flex-row justify-between pr-10 mb-4'>
  84. <Text style={styles.leftLable}>充電站位置:</Text>
  85. <Text style={styles.rightLable}>{params.chargeStationName}</Text>
  86. </View>
  87. <View style={styles.viewLine}></View>
  88. <ChargingDataComponent list={list} remark={remark} totalPrice={totalPrice}/>
  89. <View style={styles.viewLine}></View>
  90. <View className='w-full flex-row justify-between mt-6 pr-10'>
  91. <View>
  92. <Text style={styles.leftLable}>實付:</Text>
  93. {list.promotion_name ? <Text style={{fontSize: 12, color:'#888888'}}>優惠券支付</Text>: null}
  94. </View>
  95. <Text style={styles.rightLable}>${totalPrice}</Text>
  96. </View>
  97. </View>
  98. </View>
  99. <View style={{ width: "100%",height: 130 }} />
  100. </View>
  101. </SafeAreaView>
  102. );
  103. };
  104. interface ChargingDataComponentProps {
  105. list: ChargingDetails;
  106. totalPrice: string;
  107. remark: Remark;
  108. }
  109. const ChargingDataComponent: React.FC<ChargingDataComponentProps> = ({
  110. list,
  111. totalPrice,
  112. remark
  113. }) => {
  114. const [price, setPrice] = useState<number>(0);
  115. const hasFetchedPrice = useRef(false); // 添加 ref 跟踪是否已获取过价格
  116. useEffect(() => {
  117. if (!list.promotion_name && !hasFetchedPrice.current && list.actual_start_time) {
  118. chargeStationService.fetchElectricityPrice(list.pricemodel_id || 'a').then(res => {
  119. hasFetchedPrice.current = true; // 标记为已调用
  120. const date = new Date(list.actual_start_time);
  121. const str = (date.toLocaleString('en-US', { weekday: 'short' })).toLowerCase();
  122. if (res && res.length > 0) {
  123. if (remark.RushKwh) {
  124. const obj = (res[1][str as keyof ElectricityPrice]) as Special
  125. setPrice(obj.price)
  126. }
  127. if (remark.ElseKwh) {
  128. const obj = (res[2][str as keyof ElectricityPrice]) as Special
  129. setPrice(obj.price)
  130. }
  131. if (remark.OffKwh) {
  132. const obj = (res[0][str as keyof ElectricityPrice]) as Special
  133. setPrice(obj.price)
  134. }
  135. }
  136. })
  137. }
  138. }, [list.actual_start_time])
  139. if (!list.promotion_name) {
  140. return (
  141. <View>
  142. {(remark.RushKwh) ?
  143. <View>
  144. <View className='w-full flex-row justify-between mt-4 pr-10'>
  145. <Text style={styles.leftLable}>峰時總電量: </Text>
  146. <Text style={styles.rightLable}>{remark.RushKwh?.toFixed(1)}</Text>
  147. </View>
  148. <View className='w-full flex-row justify-between my-3 pr-10'>
  149. <Text style={styles.leftLable}>峰時電價(09:00-20:59): </Text>
  150. <Text style={styles.rightLable}>${price}</Text>
  151. </View>
  152. <View className='w-full flex-row justify-between pr-10 mb-3'>
  153. <Text style={styles.leftLable}>峰時總電費:</Text>
  154. <Text style={styles.rightLable}>${totalPrice}</Text>
  155. </View>
  156. </View>: null }
  157. {(remark.ElseKwh) ?
  158. <View>
  159. <View className='w-full flex-row justify-between mt-4 pr-10'>
  160. <Text style={styles.leftLable}>平時總電量: </Text>
  161. <Text style={styles.rightLable}>{remark.ElseKwh?.toFixed(1)}</Text>
  162. </View>
  163. <View className='w-full flex-row justify-between my-3 pr-10'>
  164. <Text style={styles.leftLable}>平時電價(09:00-20:59): </Text>
  165. <Text style={styles.rightLable}>${price}</Text>
  166. </View>
  167. <View className='w-full flex-row justify-between pr-10 mb-3'>
  168. <Text style={styles.leftLable}>平時總電費:</Text>
  169. <Text style={styles.rightLable}>${totalPrice}</Text>
  170. </View>
  171. </View>: null }
  172. {(remark.OffKwh) ?
  173. <View>
  174. <View className='w-full flex-row justify-between mt-4 pr-10'>
  175. <Text style={styles.leftLable}>穀時總電量: </Text>
  176. <Text style={styles.rightLable}>{remark.OffKwh?.toFixed(1)}</Text>
  177. </View>
  178. <View className='w-full flex-row justify-between my-3 pr-10'>
  179. <Text style={styles.leftLable}>穀時電價(09:00-20:59): </Text>
  180. <Text style={styles.rightLable}>${price}</Text>
  181. </View>
  182. <View className='w-full flex-row justify-between pr-10 mb-3'>
  183. <Text style={styles.leftLable}>穀時總電費:</Text>
  184. <Text style={styles.rightLable}>${totalPrice}</Text>
  185. </View>
  186. </View>: null }
  187. </View>
  188. )
  189. } else {
  190. return (
  191. <View>
  192. <View className='w-full flex-row justify-between mt-4 pr-10'>
  193. <Text style={styles.leftLable}>總電量: </Text>
  194. <Text style={styles.rightLable}>{remark.TotalPower?.toFixed(1)}</Text>
  195. </View>
  196. <View className='w-full flex-row justify-between my-3 pr-10'>
  197. <Text style={styles.leftLable}>電價: </Text>
  198. <Text style={styles.rightLable}>${list?.connector?.EquipmentID?.StationID?.price}</Text>
  199. </View>
  200. <View className='w-full flex-row justify-between pr-10 mb-3'>
  201. <Text style={styles.leftLable}>總電費: </Text>
  202. <Text style={styles.rightLable}>${totalPrice}</Text>
  203. </View>
  204. </View>
  205. )
  206. }
  207. }
  208. const styles = StyleSheet.create({
  209. viewLine: {
  210. width: '100%',
  211. height: 1,
  212. backgroundColor: '#E5E5E5',
  213. },
  214. totalPrice: {
  215. fontSize: 26,
  216. fontWeight: 'bold',
  217. marginBottom: 25,
  218. },
  219. leftLable: {
  220. fontSize: 18,
  221. color:'#888888',
  222. },
  223. rightLable: {
  224. fontSize: 17
  225. },
  226. })
  227. export default ChargingDetailsPageComponent;