修复拼单明细并支持参与者撤单
This commit is contained in:
@@ -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':
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user