import { ReloadOutlined } from '@ant-design/icons' import { useQuery, useQueryClient } from '@tanstack/react-query' import { App, Button, Card, Form, Input, Modal, Space, Table, Tag, Typography } from 'antd' import type { TableColumnsType } from 'antd' import { useEffect, useState } from 'react' import { useSearchParams } from 'react-router' import { fetchAdminWorkerCancelRequests, reviewAdminWorkerCancelRequest } from '@/services/admin' import type { WorkerCancelRequest } from '@/types/worker-platform' import { formatAdminDateTime } from '@/utils/admin-time' type ReviewFormValues = { reviewNote?: string } export default function CancelRequestsPanel() { const { message } = App.useApp() const queryClient = useQueryClient() const [searchParams, setSearchParams] = useSearchParams() const [reviewTarget, setReviewTarget] = useState<{ request: WorkerCancelRequest approved: boolean } | null>(null) const [form] = Form.useForm() const requestsQuery = useQuery({ queryKey: ['admin-worker-cancel-requests', 'pending'], queryFn: () => fetchAdminWorkerCancelRequests('pending'), }) useEffect(() => { const requestId = Number(searchParams.get('cancelRequestId') || 0) if (!Number.isInteger(requestId) || requestId <= 0) return const request = (requestsQuery.data?.data.items || []).find( (item) => item.requestId === requestId, ) if (!request) return setReviewTarget({ request, approved: true }) form.resetFields() setSearchParams( (current) => { current.delete('cancelRequestId') return current }, { replace: true }, ) }, [form, requestsQuery.data, searchParams, setSearchParams]) async function refreshAll() { await Promise.all([ queryClient.invalidateQueries({ queryKey: ['admin-worker-cancel-requests'] }), queryClient.invalidateQueries({ queryKey: ['admin-worker-platform-orders'] }), queryClient.invalidateQueries({ queryKey: ['admin-worker-platform-summary'] }), ]) } function openReview(request: WorkerCancelRequest, approved: boolean) { setReviewTarget({ request, approved }) form.resetFields() } async function submitReview(values: ReviewFormValues) { if (!reviewTarget) return try { const response = await reviewAdminWorkerCancelRequest(reviewTarget.request.requestId, { approved: reviewTarget.approved, reviewNote: String(values.reviewNote || '').trim(), }) const result = response.data const resultText = result.accountDisabled ? ',该打手已封禁' : result.levelChanged ? ',该打手已降一级 VIP' : '' message.success(`${result.approved ? '已同意' : '已驳回'}撤单申请${resultText}`) setReviewTarget(null) form.resetFields() await refreshAll() } catch (error) { message.error(error instanceof Error ? error.message : '审核撤单申请失败') } } const columns: TableColumnsType = [ { title: '订单号 / 店铺', width: 260, render: (_, request) => (
{request.platformOrderId || '-'} {request.shopName || '-'}
), }, { title: '打手 / 份数', width: 180, render: (_, request) => (
{request.workerName || `打手 #${request.workerId}`} {request.shareQuantity ? ( 拼单 {request.shareQuantity} 份 ) : ( 整单 )}
), }, { title: '申请原因', render: (_, request) => ( {request.reason} ), }, { title: '申请时间', width: 180, render: (_, request) => formatAdminDateTime(request.createdAt), }, { title: '操作', width: 180, render: (_, request) => ( ), }, ] return ( <> } loading={requestsQuery.isFetching} onClick={() => requestsQuery.refetch()} > 刷新 } bordered={false} > rowKey="requestId" size="small" loading={requestsQuery.isLoading} dataSource={requestsQuery.data?.data.items || []} columns={columns} pagination={false} locale={{ emptyText: '暂无待审核撤单申请' }} scroll={{ x: 900 }} /> { setReviewTarget(null) form.resetFields() }} onOk={() => form.submit()} okText={reviewTarget?.approved ? '确认同意' : '确认驳回'} okButtonProps={reviewTarget?.approved ? undefined : { danger: true }} destroyOnHidden > {reviewTarget ? ( {reviewTarget.request.workerName || `打手 #${reviewTarget.request.workerId}`}: {reviewTarget.request.reason} {reviewTarget.approved ? '同意后将退还冻结押金,并将整单或对应拼单份额回到大厅;该申请会计入撤单处罚次数。' : '驳回后不会计入累计次数,且会释放本次申请的当天额度。'}
) : null}
) }