bookingTabViewComponent.tsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import React, { useState, useCallback, useEffect } from 'react';
  2. import { ActivityIndicator, View, RefreshControl } from 'react-native';
  3. import { useQuery, QueryClient, QueryClientProvider } from '@tanstack/react-query';
  4. import TabViewComponent, { TabItem } from './tabView';
  5. import { chargeStationService } from '../../service/chargeStationService';
  6. const queryClient = new QueryClient();
  7. interface BookingTabViewComponentProps {
  8. titles: string[];
  9. }
  10. // 更新 findStationByConnectorId 函数以增加安全性
  11. const findStationByConnectorId = (allStations, targetConnectorId) => {
  12. if (!Array.isArray(allStations) || !targetConnectorId) {
  13. return undefined;
  14. }
  15. return allStations.find((station) =>
  16. station?.snapshot?.EquipmentInfos?.some((equipment) =>
  17. equipment?.ConnectorInfos?.some((connector) => connector?.ConnectorID === targetConnectorId)
  18. )
  19. );
  20. };
  21. const fetchReservationsAndStations = async () => {
  22. try {
  23. const [reservationResponse, allStationsResponse] = await Promise.allSettled([
  24. chargeStationService.fetchReservationHistories(),
  25. chargeStationService.fetchAllChargeStations()
  26. ]);
  27. const reservations = reservationResponse.status === 'fulfilled' ? reservationResponse.value : [];
  28. const stations = allStationsResponse.status === 'fulfilled' ? allStationsResponse.value : [];
  29. return {
  30. reservations: Array.isArray(reservations) ? reservations : [],
  31. stations: Array.isArray(stations) ? stations : []
  32. };
  33. } catch (error) {
  34. return { reservations: [], stations: [] };
  35. }
  36. };
  37. const processReservations = (reservations, allStations, isFuture): TabItem[] => {
  38. // 确保参数是数组类型
  39. const validReservations = Array.isArray(reservations) ? reservations : [];
  40. const validStations = Array.isArray(allStations) ? allStations : [];
  41. const now = Date.now();
  42. return validReservations
  43. .filter((reservation) => {
  44. // 添加安全检查
  45. if (!reservation || !reservation.end_time) return false;
  46. const endTime = Date.parse(reservation.end_time);
  47. if (isNaN(endTime)) return false;
  48. return isFuture ? endTime > now : endTime <= now;
  49. })
  50. .sort((a, b) => {
  51. // 添加安全检查
  52. if (!a?.end_time || !b?.end_time) return 0;
  53. const aTime = Date.parse(a.end_time);
  54. const bTime = Date.parse(b.end_time);
  55. if (isNaN(aTime) || isNaN(bTime)) return 0;
  56. return isFuture ? aTime - bTime : bTime - aTime;
  57. })
  58. .slice(0, 33)
  59. .map((reservation) => {
  60. // 添加对 reservation 的安全检查
  61. if (!reservation) {
  62. return {} as TabItem; // 返回默认对象
  63. }
  64. let snapshot = {};
  65. try {
  66. snapshot = reservation.snapshot ? JSON.parse(reservation.snapshot) : {};
  67. } catch (e) {
  68. console.warn('Error parsing snapshot:', e);
  69. }
  70. let stationInfo = null;
  71. if (snapshot?.stationID) {
  72. stationInfo = validStations.find((station) => station?.id === snapshot.stationID);
  73. } else if (snapshot?.connector) {
  74. stationInfo = findStationByConnectorId(validStations, snapshot.connector);
  75. }
  76. // 确保时间字段存在
  77. const bookTime = reservation.book_time ? new Date(reservation.book_time) : new Date();
  78. const actualEndTime = reservation.actual_end_time ? new Date(reservation.actual_end_time) : new Date();
  79. return {
  80. imgURL: require('../../assets/dummyStationPicture.png'),
  81. date: `${bookTime.getMonth() + 1}月${bookTime.getDate()}`,
  82. time: bookTime.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit', hour12: false }),
  83. actual_end_time: actualEndTime.toLocaleTimeString('zh-CN', {
  84. hour: '2-digit',
  85. minute: '2-digit',
  86. hour12: false
  87. }),
  88. chargeStationName: stationInfo?.snapshot?.StationName || 'Unknown Station',
  89. chargeStationAddress: stationInfo?.snapshot?.Address || 'Unknown Address',
  90. stationLng: stationInfo?.snapshot?.StationLng || '',
  91. stationLat: stationInfo?.snapshot?.StationLat || '',
  92. distance: '',
  93. format_order_id: reservation.format_order_id || '',
  94. actual_total_power: reservation.actual_total_power || 0,
  95. total_fee: reservation.total_fee || 0,
  96. withdraw_fee: reservation.withdraw_fee || 0,
  97. actual_fee: (reservation.total_fee || 0) - (reservation.withdraw_fee || 0),
  98. current_price: snapshot?.current_price || 0,
  99. total_power: reservation.total_power || 0,
  100. } as TabItem;
  101. });
  102. };
  103. const BookingTabViewComponentInner: React.FC<BookingTabViewComponentProps> = ({ titles }) => {
  104. const { data, isLoading, error } = useQuery(
  105. {
  106. queryKey: ['reservationsAndStations'],
  107. queryFn: fetchReservationsAndStations,
  108. staleTime: 0,
  109. gcTime: 0,
  110. refetchOnMount: true,
  111. refetchOnWindowFocus: true
  112. });
  113. if (isLoading) {
  114. return (
  115. <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
  116. <ActivityIndicator size="large" color="#34657b" />
  117. </View>
  118. );
  119. }
  120. if (error) {
  121. console.error('Error fetching data:', error);
  122. return null;
  123. }
  124. if (!data) {
  125. return null;
  126. }
  127. // 确保即使 data 为 undefined 也能安全处理
  128. const reservations = Array.isArray(data?.reservations) ? data.reservations : [];
  129. const stations = Array.isArray(data?.stations) ? data.stations : [];
  130. const tabItems = processReservations(reservations, stations, true);
  131. const completedReservationTabItems = processReservations(reservations, stations, false);
  132. return (
  133. <TabViewComponent
  134. titles={titles}
  135. tabItems={tabItems}
  136. completedReservationTabItems={completedReservationTabItems}
  137. isLoading={false}
  138. />
  139. );
  140. };
  141. const BookingTabViewComponent: React.FC<BookingTabViewComponentProps> = (props) => (
  142. <QueryClientProvider client={queryClient}>
  143. <BookingTabViewComponentInner {...props} />
  144. </QueryClientProvider>
  145. );
  146. export default BookingTabViewComponent;