import { CheckCircleOutlined, CloseCircleOutlined, EyeOutlined, ReloadOutlined, } from '@ant-design/icons' import { useQuery } from '@tanstack/react-query' import { Alert, Badge, Button, Card, Col, Descriptions, Form, Image, Input, InputNumber, Modal, Radio, Row, Select, Space, Table, Tag, Typography, App, } from 'antd' import type { TableColumnsType } from 'antd' import { useState } from 'react' import { approveAdminConsignmentSubmission, fetchAdminConsignmentSubmissions, rejectAdminConsignmentSubmission, } from '@/services/admin/consignment' import { fetchAdminSession } from '@/services/admin/auth' import { fetchAdminWorkerUsers } from '@/services/admin/worker-platform' import type { ConsignmentSubmission } from '@/types/consignment' import { resolveAdminPermission } from '@/utils/admin-auth' const { Text } = Typography export default function ConsignmentSubmissionsPanel() { const { message } = App.useApp() const [submissionStatus, setSubmissionStatus] = useState('pending_review') const [submissionKeyword, setSubmissionKeyword] = useState('') const [submissionPage, setSubmissionPage] = useState(1) const [submissionPageSize, setSubmissionPageSize] = useState(20) const [approveModalItem, setApproveModalItem] = useState(null) const [rejectModalItem, setRejectModalItem] = useState(null) const [viewingSubmission, setViewingSubmission] = useState(null) const [rejectNote, setRejectNote] = useState('') const [approveForm] = Form.useForm() const [approving, setApproving] = useState(false) const [rejecting, setRejecting] = useState(false) // 通过/驳回要 consignment.review:后端接口已挂权限,前端不隐藏会让人点了必 403 const adminSessionQuery = useQuery({ queryKey: ['admin-session'], queryFn: fetchAdminSession, retry: false, }) const sessionPermissions = adminSessionQuery.data?.data.user.permissions const canReviewConsignment = resolveAdminPermission(sessionPermissions, 'consignment.review') const workersQuery = useQuery({ queryKey: ['admin-worker-users-consignment-options'], queryFn: () => fetchAdminWorkerUsers({ page: 1, pageSize: 200, status: 'active' }), }) const workerOptions = (workersQuery.data?.data.items || []).map((w) => ({ label: `${w.displayName || w.username} (${w.phone || '无手机号'}) [ID:${w.workerId}]`, value: w.workerId, phone: w.phone, name: w.displayName || w.username, })) const submissionsQuery = useQuery({ queryKey: [ 'admin-consignment-submissions', submissionStatus, submissionKeyword, submissionPage, submissionPageSize, ], queryFn: () => fetchAdminConsignmentSubmissions({ status: submissionStatus === 'all' ? undefined : submissionStatus, keyword: submissionKeyword || undefined, page: submissionPage, pageSize: submissionPageSize, }), }) const submissions = submissionsQuery.data?.data.items || [] const submissionTotal = submissionsQuery.data?.data.total || 0 // 待审徽标必须用后端总数:原来只统计当前页(pageSize=20 时最多显示 20,且翻页就变)。 const pendingTotalQuery = useQuery({ queryKey: ['admin-consignment-submissions-pending-total'], queryFn: () => fetchAdminConsignmentSubmissions({ status: 'pending_review', page: 1, pageSize: 1, }), refetchInterval: 60_000, }) const pendingCount = pendingTotalQuery.data?.data.total || 0 async function handleApproveSubmit() { if (!approveModalItem || approving) return setApproving(true) try { const values = await approveForm.validateFields() const costPriceFen = Math.round(Number(values.costPrice || 0) * 100) const depositAmountFen = values.depositAmount ? Math.round(Number(values.depositAmount) * 100) : undefined const selectedWorker = workerOptions.find((w) => w.value === values.workerId) await approveAdminConsignmentSubmission(approveModalItem.id, { costPriceFen, buyerName: values.buyerName, shopName: values.shopName, inboundBatch: values.inboundBatch, itemName: values.itemName, system: values.system, serverZone: values.serverZone, series: values.series, diamondLevel: Number(values.diamondLevel || 1), brillianceCount: Number(values.brillianceCount || 0), sellerContact: values.sellerContact, sellerGameId: values.sellerGameId, sellerPaymentInfo: values.sellerPaymentInfo, sellerPhone: values.sellerPhone, workerId: values.workerId || undefined, workerName: selectedWorker?.name || approveModalItem.workerName || undefined, workerPhone: selectedWorker?.phone || approveModalItem.workerPhone || undefined, depositAmountFen, reviewNote: values.reviewNote, }) message.success('审核通过!已正式存入寄售库存待匹配!') setApproveModalItem(null) await Promise.all([submissionsQuery.refetch(), pendingTotalQuery.refetch()]) } catch (err: any) { if (err.errorFields) return message.error(err.message || '审核入库失败') } finally { setApproving(false) } } async function handleRejectConfirm() { if (!rejectModalItem || rejecting) return setRejecting(true) try { await rejectAdminConsignmentSubmission(rejectModalItem.id, { reviewNote: rejectNote }) message.success('已驳回该提报申请') setRejectModalItem(null) setRejectNote('') await Promise.all([submissionsQuery.refetch(), pendingTotalQuery.refetch()]) } catch (err: any) { message.error(err.message || '驳回失败') } finally { setRejecting(false) } } function resolveSubmissionSource(record: ConsignmentSubmission) { const channel = (record.contentJson as { channel?: string } | undefined)?.channel if (channel === 'worker_portal' || record.workerId) return '打手端提报' return '其他渠道' } const submissionColumns: TableColumnsType = [ { title: '提报单号', key: 'submissionNo', width: 180, render: (_, record) => (
{record.submissionNo}
{resolveSubmissionSource(record)}
), }, { title: '提报物品规格', key: 'specs', width: 210, render: (_, record) => (
{record.itemName}
{record.system} {record.serverZone} {record.series} {record.diamondLevel} 钻 {record.brillianceCount > 0 ? ( {record.brillianceCount} 璀璨 ) : null}
), }, { title: '卖家报价', key: 'price', width: 110, render: (_, record) => ( ¥{(record.askingPriceFen / 100).toFixed(2)} ), }, { title: '卖家与关联打手', key: 'contact', width: 200, render: (_, record) => (
联系: {record.contactInfo}
{record.sellerGameId ?
游戏ID: {record.sellerGameId}
: null} {record.sellerPhone ?
电话: {record.sellerPhone}
: null} {record.workerId ? (
打手: {record.workerName || `ID:${record.workerId}`} {record.depositAmountFen ? ` (押¥${(record.depositAmountFen / 100).toFixed(0)})` : ''}
) : null}
), }, { title: '凭据截图', key: 'screens', width: 110, render: (_, record) => { const screens = Array.isArray(record.screenshotsJson) ? record.screenshotsJson : [] if (screens.length === 0) return 无截图 return ( ) }, }, { title: '状态', key: 'status', width: 100, render: (_, record) => { if (record.status === 'pending_review') return 待客服审核 if (record.status === 'approved') return 已入库 return 已驳回 }, }, { title: '提报时间', dataIndex: 'createdAt', width: 150, render: (v) => {v}, }, { title: '操作', key: 'actions', width: 200, render: (_, record) => ( {record.status === 'pending_review' && canReviewConsignment ? ( <> ) : null} ), }, ] return (
{ setSubmissionStatus(e.target.value) setSubmissionPage(1) }} buttonStyle="solid" > 待客服审核 {pendingCount > 0 ? ( ) : null} 已审核入库 已驳回 全部 { setSubmissionKeyword(v) setSubmissionPage(1) }} /> {submissionsQuery.isError ? ( void submissionsQuery.refetch()}> 重试 } /> ) : null} `共 ${t} 条提报记录`, onChange: (p, ps) => { setSubmissionPage(p) setSubmissionPageSize(ps) }, }} /> setApproveModalItem(null)} onOk={handleApproveSubmit} confirmLoading={approving} okText="审核通过并正式入库" okType="primary" destroyOnClose >
提报人联系方式:{approveModalItem?.contactInfo} | 游戏ID: {approveModalItem?.sellerGameId || '-'} | 卖家要价: ¥{((approveModalItem?.askingPriceFen || 0) / 100).toFixed(2)}
setRejectModalItem(null)} onOk={handleRejectConfirm} confirmLoading={rejecting} okText="确认驳回" okType="danger" >
确认驳回 [{rejectModalItem?.submissionNo}] 的寄卖申请吗?
setRejectNote(e.target.value)} placeholder="如:要价过高、物品规格不符、账号存在实名绑定限制等" />
setViewingSubmission(null)}> 关闭 , ]} onCancel={() => setViewingSubmission(null)} > {viewingSubmission ? ( {viewingSubmission.submissionNo} {resolveSubmissionSource(viewingSubmission)} {viewingSubmission.itemName} {viewingSubmission.system} / {viewingSubmission.serverZone} /{' '} {viewingSubmission.series} / {viewingSubmission.diamondLevel}钻 ( {viewingSubmission.brillianceCount}璀璨) ¥{(viewingSubmission.askingPriceFen / 100).toFixed(2)} {viewingSubmission.contactInfo} {viewingSubmission.sellerPhone || '-'} {viewingSubmission.sellerGameId || '-'} {viewingSubmission.workerId ? ( {viewingSubmission.workerName || `ID:${viewingSubmission.workerId}`} ( {viewingSubmission.workerPhone || '无手机号'}) ) : ( 未关联打手账号 )} {viewingSubmission.depositAmountFen ? ( ¥{(viewingSubmission.depositAmountFen / 100).toFixed(0)} ) : ( 按平台默认规则 )} {viewingSubmission.sellerPaymentInfo || '-'} {Array.isArray(viewingSubmission.screenshotsJson) && viewingSubmission.screenshotsJson.length > 0 ? ( {viewingSubmission.screenshotsJson.map((src, i) => ( ))} ) : ( 无截图 )} {viewingSubmission.status === 'pending_review' ? ( 待审核 ) : viewingSubmission.status === 'approved' ? ( 已入库 ) : ( 已驳回 )} {viewingSubmission.reviewerName || '-'} {viewingSubmission.reviewNote || '-'} ) : null} ) }