|
|
@@ -24,6 +24,17 @@ interface OrderDetailData {
|
|
|
actualStartDate: string
|
|
|
expectedEndDate: string
|
|
|
actualEndDate: string | null
|
|
|
+ orderPersons?: Array<{
|
|
|
+ id: number
|
|
|
+ workStatus: string
|
|
|
+ joinDate: string
|
|
|
+ person?: {
|
|
|
+ name: string
|
|
|
+ gender: string
|
|
|
+ disabilityType: string
|
|
|
+ phone: string
|
|
|
+ }
|
|
|
+ }>
|
|
|
}
|
|
|
|
|
|
const OrderDetail: React.FC = () => {
|
|
|
@@ -31,11 +42,6 @@ const OrderDetail: React.FC = () => {
|
|
|
const orderIdParam = router.params.id ? parseInt(router.params.id) : null
|
|
|
const orderId = orderIdParam && !Number.isNaN(orderIdParam) ? orderIdParam : null
|
|
|
|
|
|
- const [persons, setPersons] = useState<any[]>([])
|
|
|
- const [videos, setVideos] = useState<any[]>([])
|
|
|
- const [checkinStats, setCheckinStats] = useState({ current: 0, total: 0, percentage: 0 })
|
|
|
- const [salaryVideoStats, setSalaryVideoStats] = useState({ current: 0, total: 0, percentage: 0 })
|
|
|
- const [taxVideoStats, setTaxVideoStats] = useState({ current: 0, total: 0, percentage: 0 })
|
|
|
|
|
|
// 获取订单详情查询函数
|
|
|
const fetchOrderDetailQuery = async (id: number) => {
|
|
|
@@ -52,6 +58,7 @@ const OrderDetail: React.FC = () => {
|
|
|
throw new Error('API返回数据为空')
|
|
|
}
|
|
|
// 转换API数据到UI格式
|
|
|
+ const orderPersons = data?.orderPersons || []
|
|
|
return {
|
|
|
id: data?.id ?? 0,
|
|
|
orderNumber: data?.orderName ? `ORDER-${data.id}` : `ORDER-${data?.id ?? 0}`,
|
|
|
@@ -65,11 +72,44 @@ const OrderDetail: React.FC = () => {
|
|
|
platform: data?.platformId ? `平台${data.platformId}` : '未知平台',
|
|
|
channel: '未知渠道', // data?.channelName 不存在
|
|
|
expectedPeople: 0, // data?.expectedPersonCount 不存在
|
|
|
- actualPeople: 0, // data?.actualPersonCount 不存在
|
|
|
- expectedStartDate: '未设置', // data?.expectedStartDate 不存在
|
|
|
- actualStartDate: '未设置', // data?.actualStartDate 不存在
|
|
|
+ actualPeople: orderPersons.length,
|
|
|
+ expectedStartDate: data?.expectedStartDate ? new Date(data.expectedStartDate).toISOString().split('T')[0] : '未设置',
|
|
|
+ actualStartDate: data?.actualStartDate ? new Date(data.actualStartDate).toISOString().split('T')[0] : '未设置',
|
|
|
expectedEndDate: '未设置', // data?.expectedEndDate 不存在
|
|
|
- actualEndDate: null,
|
|
|
+ actualEndDate: data?.actualEndDate ? new Date(data.actualEndDate).toISOString().split('T')[0] : null,
|
|
|
+ orderPersons: orderPersons.map((op: any) => ({
|
|
|
+ id: op.id,
|
|
|
+ workStatus: op.workStatus || 'unknown',
|
|
|
+ joinDate: op.joinDate ? new Date(op.joinDate).toISOString().split('T')[0] : '未知日期',
|
|
|
+ person: op.person ? {
|
|
|
+ name: op.person.name || '未知姓名',
|
|
|
+ gender: op.person.gender || '未知',
|
|
|
+ disabilityType: op.person.disabilityType || '未知类型',
|
|
|
+ phone: op.person.phone || '未知电话'
|
|
|
+ } : undefined
|
|
|
+ }))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取订单视频查询函数(模拟数据)
|
|
|
+ const fetchOrderVideosQuery = async (orderId: number) => {
|
|
|
+ // TODO: 集成真实API,使用 enterpriseOrderClient['company-videos'].$get
|
|
|
+ // 暂时返回模拟数据
|
|
|
+ return [
|
|
|
+ { id: 1, name: '2024-01月打卡视频', type: 'checkin_video' as const, size: '15MB', uploadTime: '2024-01-15' },
|
|
|
+ { id: 2, name: '1月工资发放视频', type: 'salary_video' as const, size: '20MB', uploadTime: '2024-01-20' },
|
|
|
+ { id: 3, name: '个税申报视频', type: 'tax_video' as const, size: '12MB', uploadTime: '2024-01-25' },
|
|
|
+ ] as VideoItem[]
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取订单统计数据查询函数(模拟数据)
|
|
|
+ const fetchOrderStatisticsQuery = async (orderId: number) => {
|
|
|
+ // TODO: 集成真实API,使用 enterpriseOrderClient['checkin-statistics'].$get 和 ['video-statistics'].$get
|
|
|
+ // 暂时返回模拟数据
|
|
|
+ return {
|
|
|
+ checkinStats: { current: 24, total: 30, percentage: 80 },
|
|
|
+ salaryVideoStats: { current: 18, total: 30, percentage: 60 },
|
|
|
+ taxVideoStats: { current: 15, total: 30, percentage: 50 },
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -84,6 +124,44 @@ const OrderDetail: React.FC = () => {
|
|
|
enabled: !!orderId,
|
|
|
})
|
|
|
|
|
|
+ // 视频查询接口
|
|
|
+ interface VideoItem {
|
|
|
+ id: number
|
|
|
+ name: string
|
|
|
+ type: 'checkin_video' | 'salary_video' | 'tax_video'
|
|
|
+ size: string
|
|
|
+ uploadTime: string
|
|
|
+ }
|
|
|
+
|
|
|
+ // 统计数据接口
|
|
|
+ interface StatisticsData {
|
|
|
+ checkinStats: { current: number, total: number, percentage: number }
|
|
|
+ salaryVideoStats: { current: number, total: number, percentage: number }
|
|
|
+ taxVideoStats: { current: number, total: number, percentage: number }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用React Query获取订单视频
|
|
|
+ const {
|
|
|
+ data: videos = [],
|
|
|
+ isLoading: videosLoading,
|
|
|
+ error: videosError,
|
|
|
+ } = useQuery<VideoItem[], Error>({
|
|
|
+ queryKey: ['order-videos', orderId],
|
|
|
+ queryFn: () => orderId ? fetchOrderVideosQuery(orderId) : Promise.reject(new Error('未找到订单ID')),
|
|
|
+ enabled: !!orderId,
|
|
|
+ })
|
|
|
+
|
|
|
+ // 使用React Query获取订单统计数据
|
|
|
+ const {
|
|
|
+ data: statistics,
|
|
|
+ isLoading: statisticsLoading,
|
|
|
+ error: statisticsError,
|
|
|
+ } = useQuery<StatisticsData, Error>({
|
|
|
+ queryKey: ['order-statistics', orderId],
|
|
|
+ queryFn: () => orderId ? fetchOrderStatisticsQuery(orderId) : Promise.reject(new Error('未找到订单ID')),
|
|
|
+ enabled: !!orderId,
|
|
|
+ })
|
|
|
+
|
|
|
// 处理查询错误
|
|
|
useEffect(() => {
|
|
|
if (queryError) {
|
|
|
@@ -93,17 +171,26 @@ const OrderDetail: React.FC = () => {
|
|
|
icon: 'none'
|
|
|
})
|
|
|
}
|
|
|
- }, [queryError])
|
|
|
-
|
|
|
- // 处理查询成功
|
|
|
- useEffect(() => {
|
|
|
- if (order) {
|
|
|
- // TODO: 获取关联人才、视频、统计数据
|
|
|
- // 暂时使用空数组
|
|
|
- setPersons([])
|
|
|
- setVideos([])
|
|
|
+ if (videosError) {
|
|
|
+ console.error('获取订单视频错误:', videosError)
|
|
|
+ Taro.showToast({
|
|
|
+ title: '获取视频数据失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
}
|
|
|
- }, [order])
|
|
|
+ if (statisticsError) {
|
|
|
+ console.error('获取订单统计错误:', statisticsError)
|
|
|
+ Taro.showToast({
|
|
|
+ title: '获取统计数据失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }, [queryError, videosError, statisticsError])
|
|
|
+
|
|
|
+ // 组合加载状态和错误状态
|
|
|
+ const isLoadingAll = isLoading || videosLoading || statisticsLoading
|
|
|
+ const hasError = queryError || videosError || statisticsError
|
|
|
+ const errorMessage = queryError?.message || videosError?.message || statisticsError?.message || '加载数据失败'
|
|
|
|
|
|
// 状态标签和样式辅助函数
|
|
|
const getStatusLabel = (status: string | undefined) => {
|
|
|
@@ -157,13 +244,13 @@ const OrderDetail: React.FC = () => {
|
|
|
className="h-screen overflow-y-auto px-4 pb-4 pt-0"
|
|
|
scrollY
|
|
|
>
|
|
|
- {isLoading ? (
|
|
|
+ {isLoadingAll ? (
|
|
|
<View className="flex items-center justify-center h-64">
|
|
|
<Text className="text-gray-500">加载中...</Text>
|
|
|
</View>
|
|
|
- ) : queryError ? (
|
|
|
+ ) : hasError ? (
|
|
|
<View className="flex items-center justify-center h-64">
|
|
|
- <Text className="text-red-500">{queryError.message}</Text>
|
|
|
+ <Text className="text-red-500">{errorMessage}</Text>
|
|
|
</View>
|
|
|
) : !order ? (
|
|
|
<View className="flex items-center justify-center h-64">
|
|
|
@@ -245,23 +332,23 @@ const OrderDetail: React.FC = () => {
|
|
|
<View className="bg-blue-50 rounded-lg p-2 text-center flex flex-col">
|
|
|
<Text className="text-xs text-gray-600">本月打卡</Text>
|
|
|
<Text className="text-sm font-bold text-gray-800">
|
|
|
- {checkinStats.current}/{checkinStats.total}
|
|
|
+ {statistics?.checkinStats.current || 0}/{statistics?.checkinStats.total || 0}
|
|
|
</Text>
|
|
|
- <Text className="text-xs text-gray-500">{checkinStats.percentage}%</Text>
|
|
|
+ <Text className="text-xs text-gray-500">{statistics?.checkinStats.percentage || 0}%</Text>
|
|
|
</View>
|
|
|
<View className="bg-green-50 rounded-lg p-2 text-center flex flex-col">
|
|
|
<Text className="text-xs text-gray-600">工资视频</Text>
|
|
|
<Text className="text-sm font-bold text-gray-800">
|
|
|
- {salaryVideoStats.current}/{salaryVideoStats.total}
|
|
|
+ {statistics?.salaryVideoStats.current || 0}/{statistics?.salaryVideoStats.total || 0}
|
|
|
</Text>
|
|
|
- <Text className="text-xs text-gray-500">{salaryVideoStats.percentage}%</Text>
|
|
|
+ <Text className="text-xs text-gray-500">{statistics?.salaryVideoStats.percentage || 0}%</Text>
|
|
|
</View>
|
|
|
<View className="bg-purple-50 rounded-lg p-2 text-center flex flex-col">
|
|
|
<Text className="text-xs text-gray-600">个税视频</Text>
|
|
|
<Text className="text-sm font-bold text-gray-800">
|
|
|
- {taxVideoStats.current}/{taxVideoStats.total}
|
|
|
+ {statistics?.taxVideoStats.current || 0}/{statistics?.taxVideoStats.total || 0}
|
|
|
</Text>
|
|
|
- <Text className="text-xs text-gray-500">{taxVideoStats.percentage}%</Text>
|
|
|
+ <Text className="text-xs text-gray-500">{statistics?.taxVideoStats.percentage || 0}%</Text>
|
|
|
</View>
|
|
|
</View>
|
|
|
<View className="flex items-center text-blue-500 text-sm" onClick={() => console.log('查看详细打卡记录')}>
|
|
|
@@ -275,21 +362,21 @@ const OrderDetail: React.FC = () => {
|
|
|
<Text className="font-semibold text-gray-700">关联人才</Text>
|
|
|
</View>
|
|
|
<View className="space-y-3">
|
|
|
- {persons.map((person) => (
|
|
|
- <View key={person.id} className="flex justify-between items-center border-b border-gray-100 pb-2">
|
|
|
+ {order?.orderPersons?.map((orderPerson) => (
|
|
|
+ <View key={orderPerson.id} className="flex justify-between items-center border-b border-gray-100 pb-2">
|
|
|
<View className="flex flex-col">
|
|
|
- <Text className="font-medium text-gray-800">{person.name}</Text>
|
|
|
+ <Text className="font-medium text-gray-800">{orderPerson.person?.name || '未知姓名'}</Text>
|
|
|
<Text className="text-xs text-gray-500">
|
|
|
- {person.gender} · {person.disabilityType} · 入职: {person.joinDate}
|
|
|
+ {orderPerson.person?.gender || '未知'} · {orderPerson.person?.disabilityType || '未知类型'} · 入职: {orderPerson.joinDate}
|
|
|
</Text>
|
|
|
</View>
|
|
|
<Text className={`text-xs px-2 py-1 rounded-full ${
|
|
|
- person.workStatus === 'working' ? 'bg-green-100 text-green-800' :
|
|
|
- person.workStatus === 'pre_working' ? 'bg-yellow-100 text-yellow-800' :
|
|
|
+ orderPerson.workStatus === 'working' ? 'bg-green-100 text-green-800' :
|
|
|
+ orderPerson.workStatus === 'pre_working' ? 'bg-yellow-100 text-yellow-800' :
|
|
|
'bg-gray-100 text-gray-800'
|
|
|
}`}>
|
|
|
- {person.workStatus === 'working' ? '已就业' :
|
|
|
- person.workStatus === 'pre_working' ? '待就业' : '未就业'}
|
|
|
+ {orderPerson.workStatus === 'working' ? '已就业' :
|
|
|
+ orderPerson.workStatus === 'pre_working' ? '待就业' : '未就业'}
|
|
|
</Text>
|
|
|
</View>
|
|
|
))}
|
|
|
@@ -305,7 +392,7 @@ const OrderDetail: React.FC = () => {
|
|
|
</View>
|
|
|
</View>
|
|
|
<View className="space-y-3">
|
|
|
- {videos.map((video) => (
|
|
|
+ {(videos || []).map((video: VideoItem) => (
|
|
|
<View key={video.id} className="flex justify-between items-center border-b border-gray-100 pb-2">
|
|
|
<View className="flex flex-col">
|
|
|
<Text className="font-medium text-gray-800">{video.name}</Text>
|