feat:拼单明细管理加一个撤份额的功能,指定数量

This commit is contained in:
2026-10-25 13:44:34 +08:00
parent a7a8634a96
commit 9c620d39cb
16 changed files with 627 additions and 3 deletions
@@ -72,6 +72,7 @@ import {
markAdminWorkOrderShareProblem,
pinAdminWorkOrder,
publishAdminWorkOrder,
reduceAdminWorkOrderShareQuantity,
reopenAdminCancelledWorkOrder,
resetAdminWorkOrderGiftMaterial,
resolveAdminProblemWorkOrder,
@@ -306,6 +307,7 @@ export default function WorkOrdersPanel() {
const [materialPasteText, setMaterialPasteText] = useState('')
const [sharingOrder, setSharingOrder] = useState<WorkOrder | null>(null)
const [cancelShare, setCancelShare] = useState<WorkOrderShare | null>(null)
const [reduceShare, setReduceShare] = useState<WorkOrderShare | null>(null)
const [problemShare, setProblemShare] = useState<WorkOrderShare | null>(null)
const [disposeShare, setDisposeShare] = useState<WorkOrderShare | null>(null)
const [cancelSharingOrder, setCancelSharingOrder] = useState<WorkOrder | null>(null)
@@ -320,6 +322,7 @@ export default function WorkOrdersPanel() {
const [materialForm] = Form.useForm<MaterialFormValues>()
const [cancelForm] = Form.useForm<CancelOrderFormValues>()
const [cancelShareForm] = Form.useForm<CancelShareFormValues>()
const [reduceShareForm] = Form.useForm<{ reduceQuantity?: number; note?: string }>()
const [problemShareForm] = Form.useForm<{ note?: string }>()
const [disposeShareForm] = Form.useForm<{
action?: 'return_to_worker' | 'reopen' | 'cancel_release' | 'cancel_deduct'
@@ -725,6 +728,32 @@ export default function WorkOrdersPanel() {
cancelShareForm.resetFields()
}
/** 按份数撤销部分份额:减少的份数回到大厅,押金保持冻结。 */
async function submitReduceShare(values: { reduceQuantity?: number; note?: string }) {
if (!sharingOrder || !reduceShare) return
const workOrderId = sharingOrder.workOrderId
const reduceQuantity = Math.floor(Number(values.reduceQuantity || 0))
if (!Number.isFinite(reduceQuantity) || reduceQuantity <= 0) {
message.warning('请填写要撤掉的份数')
return
}
const keepQuantity = Math.max(0, reduceShare.quantity - reduceQuantity)
const succeeded = await runAction(
() =>
reduceAdminWorkOrderShareQuantity(workOrderId, reduceShare.shareId, {
reduceQuantity,
note: String(values.note || '').trim(),
}),
`已撤掉 ${reduceQuantity} 份,保留 ${keepQuantity} 份继续履约`,
)
if (!succeeded) return
await queryClient.invalidateQueries({
queryKey: ['admin-worker-platform-order-sharing', workOrderId],
})
setReduceShare(null)
reduceShareForm.resetFields()
}
/** 按份额标记问题单:只影响该打手,母单状态不变。备注选填。 */
async function submitProblemShare(values: { note?: string }) {
if (!sharingOrder || !problemShare) return
@@ -3083,9 +3112,11 @@ export default function WorkOrdersPanel() {
onCancel={() => {
setSharingOrder(null)
setCancelShare(null)
setReduceShare(null)
setCancelSharingOrder(null)
sharingForm.resetFields()
cancelShareForm.resetFields()
reduceShareForm.resetFields()
cancelSharingForm.resetFields()
}}
onOk={() => sharingForm.submit()}
@@ -3218,7 +3249,7 @@ export default function WorkOrdersPanel() {
loading={sharingQuery.isFetching}
pagination={false}
tableLayout="fixed"
scroll={{ x: 1624 }}
scroll={{ x: 1794 }}
rowClassName={(share) =>
share.problemMarked
? 'admin-share-row-problem'
@@ -3363,6 +3394,27 @@ export default function WorkOrdersPanel() {
)
},
},
{
title: '撤单记录',
width: 170,
render: (_, share) => {
// 份数前缀由展示层拼接:接口只给结构化的份数与原因文本
const cancelledQuantity = Math.max(
0,
Math.floor(Number(share.cancelQuantity || 0)),
)
const note = String(share.cancelNote || '').trim()
if (!cancelledQuantity && !note) return '-'
const text = cancelledQuantity
? `撤 ${cancelledQuantity} 份${note ? ` · ${note}` : ''}`
: note
return (
<Typography.Text style={{ fontSize: 12 }} ellipsis={{ tooltip: text }}>
{text}
</Typography.Text>
)
},
},
{
title: '操作',
width: 300,
@@ -3451,6 +3503,24 @@ export default function WorkOrdersPanel() {
单人撤单
</Button>
) : null}
{(share.status === 'joined' || share.status === 'submitted') &&
share.quantity >= 2 ? (
<Button
danger
size="small"
icon={<UndoOutlined />}
title="按份数撤销部分份额:减少的份数立即回到大厅,押金保持冻结,验收资料保留"
onClick={() => {
setReduceShare(share)
reduceShareForm.setFieldsValue({
reduceQuantity: 1,
note: '',
})
}}
>
撤份额
</Button>
) : null}
{problemAction}
</Space>
)
@@ -3496,6 +3566,75 @@ export default function WorkOrdersPanel() {
) : null}
</Modal>
<Modal
title={`撤份额 · ${reduceShare?.worker?.displayName || reduceShare?.worker?.username || ''}`}
open={Boolean(reduceShare)}
okText="确认撤销"
cancelText="取消"
okButtonProps={{ danger: true }}
onCancel={() => {
setReduceShare(null)
reduceShareForm.resetFields()
}}
onOk={() => reduceShareForm.submit()}
destroyOnHidden
>
{reduceShare ? (
<Form
form={reduceShareForm}
layout="vertical"
initialValues={{ reduceQuantity: 1 }}
onFinish={submitReduceShare}
>
<Alert
showIcon
type="warning"
message={`将从该打手的 ${reduceShare.quantity} 份中撤掉指定份数`}
description="撤掉的份数会立刻回到抢单大厅;押金保持原冻结额不退还;验收资料保留,之后仍可单独验收剩余份数。"
style={{ marginBottom: 16 }}
/>
<Form.Item
label={`撤掉份数(1 ~ ${Math.max(1, reduceShare.quantity - 1)} 份)`}
name="reduceQuantity"
rules={[{ required: true, message: '请填写要撤掉的份数' }]}
>
<InputNumber
min={1}
max={Math.max(1, reduceShare.quantity - 1)}
precision={0}
addonAfter="份"
style={{ width: '100%' }}
/>
</Form.Item>
<Form.Item noStyle shouldUpdate>
{() => {
const reduceQuantity = Math.floor(
Number(reduceShareForm.getFieldValue('reduceQuantity') || 0),
)
const boundedReduce = Math.max(
0,
Math.min(Math.max(0, reduceShare.quantity - 1), reduceQuantity),
)
const keepQuantity = Math.max(0, reduceShare.quantity - boundedReduce)
return (
<Typography.Text type="secondary">
调整后保留 {keepQuantity} 份,回到大厅 {boundedReduce} 份;剩余份额报酬{' '}
{formatMoney(keepQuantity * Number(reduceShare.unitReward || 0))}
</Typography.Text>
)
}}
</Form.Item>
<Form.Item label="撤销原因(选填)" name="note">
<Input.TextArea
rows={3}
maxLength={200}
placeholder="如:打手账号实际只能赠送 5 份"
/>
</Form.Item>
</Form>
) : null}
</Modal>
<Modal
title={`标记份额问题单 · ${
problemShare?.worker?.displayName || problemShare?.worker?.username || ''