修复拼单明细并支持参与者撤单

This commit is contained in:
yml2213
2026-08-19 14:35:23 +08:00
parent 4b1dcd47ea
commit ab6387759e
9 changed files with 409 additions and 43 deletions
@@ -182,6 +182,15 @@ export function formatWorkOrderEvent(event: WorkOrderEvent): EventNodeStyle {
return { title: '更改了订单信息', color: 'default' }
case 'sharing_config_updated':
return { title: '更新了拼单配置', color: 'default' }
case 'sharing_share_cancelled_by_admin': {
const workerId = readPayload(event, 'workerId')
const quantity = readPayload(event, 'quantity')
return {
title: `撤销拼单参与者${workerId ? `(打手 #${workerId}` : ''}`,
description: `${quantity ? `撤销 ${quantity} 份;` : ''}${note ? `原因:${note}` : '份数已退回接单大厅'}`,
color: 'red',
}
}
case 'pending_deposit_deducted':
return { title: '扣减了待解冻押金', color: 'default' }
case 'voucher_backfilled':
+11 -7
View File
@@ -349,13 +349,17 @@ function applyAdminRealtimeEvent(
})
}
if (
event.type === 'work_order.changed' &&
event.scopes.includes('admin_work_orders') &&
isRecord(event.data)
) {
const data = event.data
patchAdminWorkOrderCaches(queryClient, { ...event, data })
if (event.type === 'work_order.changed' && event.scopes.includes('admin_work_orders')) {
// 拼单明细是独立查询,工单列表快照更新时也要同步刷新当前打开的明细。
void queryClient.invalidateQueries({
queryKey: ['admin-worker-platform-order-sharing', event.entityId],
})
if (isRecord(event.data)) {
const data = event.data
patchAdminWorkOrderCaches(queryClient, { ...event, data })
} else {
void queryClient.invalidateQueries({ queryKey: ['admin-worker-platform-orders'] })
}
}
if (
@@ -49,6 +49,7 @@ import {
acceptAdminWorkOrders,
assignAdminWorkOrderToWorker,
cancelAdminWorkOrder,
cancelAdminWorkOrderShare,
createAdminMockWorkOrder,
deductAdminWorkOrderPendingDeposit,
deleteAdminWorkOrder,
@@ -120,6 +121,10 @@ type CancelOrderFormValues = {
reason?: string
}
type CancelShareFormValues = {
reason?: string
}
export default function WorkOrdersPanel() {
const { message, modal } = App.useApp()
const navigate = useNavigate()
@@ -142,6 +147,7 @@ export default function WorkOrdersPanel() {
const [materialScreenshots, setMaterialScreenshots] = useState<UploadedFile[]>([])
const [materialPasteText, setMaterialPasteText] = useState('')
const [sharingOrder, setSharingOrder] = useState<WorkOrder | null>(null)
const [cancelShare, setCancelShare] = useState<WorkOrderShare | null>(null)
const [assignOrder, setAssignOrder] = useState<WorkOrder | null>(null)
const [assignWorkerId, setAssignWorkerId] = useState<number | undefined>(undefined)
const [editOrder, setEditOrder] = useState<WorkOrder | null>(null)
@@ -151,6 +157,7 @@ export default function WorkOrdersPanel() {
const [resolutionForm] = Form.useForm()
const [materialForm] = Form.useForm<MaterialFormValues>()
const [cancelForm] = Form.useForm<CancelOrderFormValues>()
const [cancelShareForm] = Form.useForm<CancelShareFormValues>()
const [deductForm] = Form.useForm<{ amount?: number; note?: string }>()
const [editForm] = Form.useForm<{
productName?: string
@@ -349,6 +356,24 @@ export default function WorkOrdersPanel() {
sharingForm.resetFields()
}
async function submitCancelShare(values: CancelShareFormValues) {
if (!sharingOrder || !cancelShare) return
const workOrderId = sharingOrder.workOrderId
const succeeded = await runAction(
() =>
cancelAdminWorkOrderShare(workOrderId, cancelShare.shareId, {
reason: String(values.reason || '').trim(),
}),
'该参与者已撤单,押金和拼单份数已恢复',
)
if (!succeeded) return
await queryClient.invalidateQueries({
queryKey: ['admin-worker-platform-order-sharing', workOrderId],
})
setCancelShare(null)
cancelShareForm.resetFields()
}
async function refreshAll() {
await Promise.all([
queryClient.invalidateQueries({
@@ -816,7 +841,9 @@ export default function WorkOrdersPanel() {
) : null}
{row.sharing?.enabled || row.capabilities?.canConfigureSharing ? (
<Button icon={<TeamOutlined />} onClick={() => openSharingConfigModal(row)}>
{row.sharing?.enabled && !row.capabilities?.canConfigureSharing ? '拼单明细' : '拼单配置'}
{row.sharing?.enabled && !row.capabilities?.canConfigureSharing
? '拼单明细'
: '拼单配置'}
</Button>
) : null}
{row.capabilities?.canAssign ? (
@@ -1589,7 +1616,9 @@ export default function WorkOrdersPanel() {
open={Boolean(sharingOrder)}
onCancel={() => {
setSharingOrder(null)
setCancelShare(null)
sharingForm.resetFields()
cancelShareForm.resetFields()
}}
onOk={() => sharingForm.submit()}
footer={sharingOrder?.capabilities?.canConfigureSharing ? undefined : null}
@@ -1679,6 +1708,7 @@ export default function WorkOrdersPanel() {
rowKey="shareId"
size="small"
dataSource={sharingQuery.data?.data.shares || []}
loading={sharingQuery.isFetching}
pagination={false}
columns={[
{
@@ -1709,8 +1739,14 @@ export default function WorkOrdersPanel() {
width: 150,
render: (_, share) => (
<ImagePreviewList
files={Array.isArray(share.acceptance?.files) ? share.acceptance.files : []}
imageUrls={Array.isArray(share.acceptance?.imageUrls) ? share.acceptance.imageUrls : []}
files={
Array.isArray(share.acceptance?.files) ? share.acceptance.files : []
}
imageUrls={
Array.isArray(share.acceptance?.imageUrls)
? share.acceptance.imageUrls
: []
}
size={44}
maxVisible={2}
/>
@@ -1722,35 +1758,55 @@ export default function WorkOrdersPanel() {
},
{
title: '操作',
width: 110,
render: (_, share) =>
share.status === 'submitted' ? (
<Button
type="primary"
size="small"
onClick={() => {
void runAction(
() => acceptAdminWorkOrderShare(sharingOrder.workOrderId, share.shareId),
'该拼单参与者已验收',
).then((succeeded) => {
if (succeeded) {
void queryClient.invalidateQueries({
queryKey: [
'admin-worker-platform-order-sharing',
sharingOrder.workOrderId,
],
width: 190,
render: (_, share) => {
if (share.status === 'accepted') return <Tag color="green"></Tag>
if (share.status === 'cancelled') return <Tag></Tag>
return (
<Space size={6}>
{share.status === 'submitted' ? (
<Button
type="primary"
size="small"
onClick={() => {
void runAction(
() =>
acceptAdminWorkOrderShare(
sharingOrder.workOrderId,
share.shareId,
),
'该拼单参与者已验收',
).then((succeeded) => {
if (succeeded) {
void queryClient.invalidateQueries({
queryKey: [
'admin-worker-platform-order-sharing',
sharingOrder.workOrderId,
],
})
}
})
}
})
}}
>
</Button>
) : share.status === 'accepted' ? (
<Tag color="green"></Tag>
) : (
<Typography.Text type="secondary"></Typography.Text>
),
}}
>
</Button>
) : (
<Typography.Text type="secondary"></Typography.Text>
)}
<Button
danger
size="small"
icon={<UndoOutlined />}
onClick={() => {
setCancelShare(share)
cancelShareForm.setFieldsValue({ reason: '' })
}}
>
</Button>
</Space>
)
},
},
]}
/>
@@ -1759,6 +1815,37 @@ export default function WorkOrdersPanel() {
</Space>
) : null}
</Modal>
<Modal
title={`撤销拼单参与者 · ${
cancelShare?.worker?.displayName || cancelShare?.worker?.username || ''
}`}
open={Boolean(cancelShare)}
okText="确认撤单"
cancelText="取消"
okButtonProps={{ danger: true }}
onCancel={() => {
setCancelShare(null)
cancelShareForm.resetFields()
}}
onOk={() => cancelShareForm.submit()}
destroyOnHidden
>
{cancelShare ? (
<Form form={cancelShareForm} layout="vertical" onFinish={submitCancelShare}>
<Alert
showIcon
type="warning"
message={`将撤销该打手承接的 ${cancelShare.quantity} 份拼单`}
description="撤单后会退还该份额冻结的押金,空出的份数重新回到接单大厅;已提交的验收资料会保留在后台记录中。"
style={{ marginBottom: 16 }}
/>
<Form.Item label="撤单原因" name="reason">
<Input.TextArea rows={3} placeholder="选填,用于后台流转记录" />
</Form.Item>
</Form>
) : null}
</Modal>
</section>
)
}
@@ -470,6 +470,18 @@ export function acceptAdminWorkOrderShare(workOrderId: number, shareId: number)
)
}
export function cancelAdminWorkOrderShare(
workOrderId: number,
shareId: number,
payload: { reason?: string },
) {
return apiPost<{
order: WorkOrder
share: WorkOrderShare
releasedDepositAmount: number
}>(`/api/v1/admin/worker-platform/orders/${workOrderId}/shares/${shareId}/cancel`, payload)
}
export function acceptAdminWorkOrders(workOrderIds: number[]) {
return apiPost<{ orders: WorkOrder[] }>('/api/v1/admin/worker-platform/orders/accept-batch', {
workOrderIds,