修复接单平台并发、分页与补资料

This commit is contained in:
yml2213
2026-07-28 10:15:44 +08:00
parent a2587eda01
commit f0ba0fe17f
22 changed files with 1096 additions and 145 deletions
@@ -42,6 +42,7 @@ import {
fetchAdminWorkOrders,
markAdminWorkOrderProblem,
publishAdminWorkOrder,
resolveAdminProblemWorkOrder,
reviewAdminWorkerUser,
saveAdminWorkCategory,
saveAdminWorkProductRule,
@@ -58,13 +59,17 @@ import type {
WorkerLevel,
WorkerUser,
} from '@/types/worker-platform'
import {
ADMIN_DEFAULT_PAGE_SIZE,
buildAdminTablePagination,
} from '@/utils/admin-pagination'
export default function AdminWorkerPlatformPage() {
return (
<section className="page-stack">
<PageHeader
title="接单平台"
description="管理接单员、接单工单、等级权限和本地 Mock 工单。"
description="管理打手、接单工单、等级权限和本地 Mock 工单。"
/>
<SummaryCards />
<Tabs
@@ -73,7 +78,7 @@ export default function AdminWorkerPlatformPage() {
{ key: 'orders', label: '接单工单', children: <WorkOrdersPanel /> },
{ key: 'rules', label: '物品规则', children: <ProductRulesPanel /> },
{ key: 'categories', label: '分类', children: <CategoriesPanel /> },
{ key: 'workers', label: '接单员', children: <WorkersPanel /> },
{ key: 'workers', label: '打手', children: <WorkersPanel /> },
{ key: 'levels', label: '等级权限', children: <LevelsPanel /> },
]}
/>
@@ -92,7 +97,7 @@ function SummaryCards() {
<div className="metric-grid four">
<Card>
<Statistic
title="待审核接单员"
title="待审核打手"
value={summary?.pendingWorkerCount || 0}
/>
</Card>
@@ -116,15 +121,20 @@ function WorkOrdersPanel() {
const { message } = App.useApp()
const queryClient = useQueryClient()
const [status, setStatus] = useState('')
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
const [problemOrder, setProblemOrder] = useState<WorkOrder | null>(null)
const [resolutionOrder, setResolutionOrder] = useState<WorkOrder | null>(null)
const [materialOrder, setMaterialOrder] = useState<WorkOrder | null>(null)
const [problemForm] = Form.useForm()
const [resolutionForm] = Form.useForm()
const [materialForm] = Form.useForm()
const ordersQuery = useQuery({
queryKey: ['admin-worker-platform-orders', status],
queryFn: () => fetchAdminWorkOrders({ status }),
queryKey: ['admin-worker-platform-orders', status, page, pageSize],
queryFn: () => fetchAdminWorkOrders({ status, page, pageSize }),
})
const ordersPagination = ordersQuery.data?.data.pagination
async function refreshAll() {
await Promise.all([
@@ -145,25 +155,47 @@ function WorkOrdersPanel() {
await action()
message.success(successMessage)
await refreshAll()
return true
} catch (error) {
message.error(error instanceof Error ? error.message : '操作失败')
return false
}
}
async function submitProblem(values: { note?: string }) {
if (!problemOrder) return
await runAction(
const succeeded = await runAction(
() =>
markAdminWorkOrderProblem(problemOrder.workOrderId, values.note || ''),
'已标记问题单',
)
if (!succeeded) return
setProblemOrder(null)
problemForm.resetFields()
}
async function submitResolution(values: {
action?: 'return_to_worker' | 'reopen' | 'cancel_release' | 'cancel_deduct'
note?: string
}) {
if (!resolutionOrder || !values.action) return
const action = values.action
const succeeded = await runAction(
() =>
resolveAdminProblemWorkOrder(resolutionOrder.workOrderId, {
action,
note: values.note || '',
}),
'问题单已处置',
)
if (!succeeded) return
setResolutionOrder(null)
resolutionForm.resetFields()
}
async function submitMaterial(values: { fields?: Record<string, string> }) {
if (!materialOrder) return
await runAction(
const succeeded = await runAction(
() =>
submitAdminWorkOrderMaterial(
materialOrder.workOrderId,
@@ -171,6 +203,7 @@ function WorkOrdersPanel() {
),
'订单资料已保存',
)
if (!succeeded) return
setMaterialOrder(null)
materialForm.resetFields()
}
@@ -227,7 +260,7 @@ function WorkOrdersPanel() {
),
},
{
title: '接单员',
title: '打手',
width: 140,
render: (_, row) =>
row.worker?.displayName || row.worker?.username || '-',
@@ -297,6 +330,11 @@ function WorkOrdersPanel() {
</Button>
) : null}
{row.status === 'problem' ? (
<Button icon={<FormOutlined />} onClick={() => setResolutionOrder(row)}>
</Button>
) : null}
</Space>
),
},
@@ -342,8 +380,12 @@ function WorkOrdersPanel() {
{ value: 'pending_acceptance', label: '待验收' },
{ value: 'problem', label: '问题单' },
{ value: 'accepted', label: '已验收' },
{ value: 'cancelled', label: '已取消' },
]}
onChange={setStatus}
onChange={(nextStatus) => {
setStatus(nextStatus)
setPage(1)
}}
/>
<Button
icon={<ReloadOutlined />}
@@ -361,7 +403,15 @@ function WorkOrdersPanel() {
loading={ordersQuery.isLoading}
dataSource={ordersQuery.data?.data.items || []}
columns={columns}
pagination={false}
pagination={buildAdminTablePagination({
current: ordersPagination?.page || page,
pageSize: ordersPagination?.pageSize || pageSize,
total: ordersPagination?.total || 0,
onChange: (nextPage, nextPageSize) => {
setPage(nextPage)
setPageSize(nextPageSize)
},
})}
scroll={{ x: 1100 }}
/>
</Card>
@@ -369,7 +419,10 @@ function WorkOrdersPanel() {
<Modal
title="标记问题单"
open={Boolean(problemOrder)}
onCancel={() => setProblemOrder(null)}
onCancel={() => {
setProblemOrder(null)
problemForm.resetFields()
}}
onOk={() => problemForm.submit()}
destroyOnHidden
>
@@ -384,10 +437,53 @@ function WorkOrdersPanel() {
</Form>
</Modal>
<Modal
title="处置问题单"
open={Boolean(resolutionOrder)}
onCancel={() => {
setResolutionOrder(null)
resolutionForm.resetFields()
}}
onOk={() => resolutionForm.submit()}
destroyOnHidden
>
<Form
form={resolutionForm}
layout="vertical"
initialValues={{ action: 'return_to_worker' }}
onFinish={submitResolution}
>
<Form.Item
label="处置方式"
name="action"
rules={[{ required: true, message: '请选择处置方式' }]}
>
<Select
options={[
{ value: 'return_to_worker', label: '退回打手继续代练' },
{ value: 'reopen', label: '释放押金并重新放回大厅' },
{ value: 'cancel_release', label: '取消订单并退还押金' },
{ value: 'cancel_deduct', label: '取消订单并扣除押金' },
]}
/>
</Form.Item>
<Form.Item
label="处置备注"
name="note"
rules={[{ required: true, message: '请填写处置备注' }]}
>
<Input.TextArea rows={4} />
</Form.Item>
</Form>
</Modal>
<Modal
title="人工补充资料"
open={Boolean(materialOrder)}
onCancel={() => setMaterialOrder(null)}
onCancel={() => {
setMaterialOrder(null)
materialForm.resetFields()
}}
onOk={() => materialForm.submit()}
destroyOnHidden
>
@@ -804,13 +900,16 @@ function WorkersPanel() {
const { message } = App.useApp()
const queryClient = useQueryClient()
const [status, setStatus] = useState('')
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
const [creditWorker, setCreditWorker] = useState<WorkerUser | null>(null)
const [creditForm] = Form.useForm()
const workersQuery = useQuery({
queryKey: ['admin-worker-platform-workers', status],
queryFn: () => fetchAdminWorkerUsers({ status }),
queryKey: ['admin-worker-platform-workers', status, page, pageSize],
queryFn: () => fetchAdminWorkerUsers({ status, page, pageSize }),
})
const workersPagination = workersQuery.data?.data.pagination
async function refreshWorkers() {
await Promise.all([
@@ -826,7 +925,7 @@ function WorkersPanel() {
async function review(worker: WorkerUser, nextStatus: string) {
try {
await reviewAdminWorkerUser(worker.workerId, { status: nextStatus })
message.success('接单员状态已更新')
message.success('打手状态已更新')
await refreshWorkers()
} catch (error) {
message.error(error instanceof Error ? error.message : '操作失败')
@@ -851,7 +950,7 @@ function WorkersPanel() {
const columns: TableColumnsType<WorkerUser> = [
{
title: '接单员',
title: '打手',
minWidth: 220,
render: (_, row) => (
<div className="cell-stack">
@@ -901,7 +1000,7 @@ function WorkersPanel() {
return (
<Card
title="接单员"
title="打手"
extra={
<Space>
<Select
@@ -914,7 +1013,10 @@ function WorkersPanel() {
{ value: 'rejected', label: '已拒绝' },
{ value: 'disabled', label: '已停用' },
]}
onChange={setStatus}
onChange={(nextStatus) => {
setStatus(nextStatus)
setPage(1)
}}
/>
<Button
icon={<ReloadOutlined />}
@@ -932,14 +1034,25 @@ function WorkersPanel() {
loading={workersQuery.isLoading}
dataSource={workersQuery.data?.data.items || []}
columns={columns}
pagination={false}
pagination={buildAdminTablePagination({
current: workersPagination?.page || page,
pageSize: workersPagination?.pageSize || pageSize,
total: workersPagination?.total || 0,
onChange: (nextPage, nextPageSize) => {
setPage(nextPage)
setPageSize(nextPageSize)
},
})}
scroll={{ x: 1000 }}
/>
<Modal
title="人工增加余额"
open={Boolean(creditWorker)}
onCancel={() => setCreditWorker(null)}
onCancel={() => {
setCreditWorker(null)
creditForm.resetFields()
}}
onOk={() => creditForm.submit()}
destroyOnHidden
>
@@ -1010,7 +1123,7 @@ function LevelsPanel() {
layout="inline"
initialValues={{
levelKey: 'regular',
name: '普通接单员',
name: '普通打手',
depositFreeAmount: 0,
maxActiveOrders: 3,
}}