接单工单支持任务时限,超时自动判定失败并处置
This commit is contained in:
@@ -113,6 +113,8 @@ export default function ProductRulesPanel() {
|
||||
sharingTotalQuantity?: number
|
||||
sharingUnitReward?: number
|
||||
sharingTotalAmount?: number
|
||||
timeoutMinutes?: number
|
||||
timeoutPolicy?: string
|
||||
fieldsText?: string
|
||||
enabled?: boolean
|
||||
autoCreate?: boolean
|
||||
@@ -389,6 +391,27 @@ export default function ProductRulesPanel() {
|
||||
>
|
||||
<Input.TextArea rows={4} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="默认任务时限"
|
||||
name="timeoutMinutes"
|
||||
tooltip="自动创建的工单继承该时限,打手抢单后开始计时;0 表示不限时"
|
||||
>
|
||||
<InputNumber min={0} step={5} addonAfter="分钟" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="默认超时策略"
|
||||
name="timeoutPolicy"
|
||||
tooltip="reopen:释放押金退回大厅;cancel_release:取消退押金;cancel_deduct:取消扣押金"
|
||||
>
|
||||
<Select
|
||||
style={{ width: 260 }}
|
||||
options={[
|
||||
{ value: 'reopen', label: '释放押金退回大厅' },
|
||||
{ value: 'cancel_release', label: '取消订单并退还押金' },
|
||||
{ value: 'cancel_deduct', label: '取消订单并扣除押金' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Button type="primary" htmlType="submit">
|
||||
保存规则
|
||||
</Button>
|
||||
|
||||
@@ -87,6 +87,8 @@ import {
|
||||
} from '@/utils/admin-pagination'
|
||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
||||
import {
|
||||
DeadlineCountdown,
|
||||
formatTimeoutPolicyLabel,
|
||||
getAcceptanceFiles,
|
||||
getAcceptanceImageUrls,
|
||||
getAcceptanceSubmittedAt,
|
||||
@@ -129,6 +131,8 @@ export default function WorkOrdersPanel() {
|
||||
rewardAmount?: number
|
||||
requiredDepositAmount?: number
|
||||
fieldsText?: string
|
||||
timeoutMinutes?: number
|
||||
timeoutPolicy?: string
|
||||
}>()
|
||||
const [sharingForm] = Form.useForm<{
|
||||
enabled?: boolean
|
||||
@@ -320,6 +324,8 @@ export default function WorkOrdersPanel() {
|
||||
requiredDepositAmount:
|
||||
Math.round(Number(row.requiredDepositAmount || 0)) / 100,
|
||||
fieldsText: formatRequirementFieldsText(getRequirementFields(row)),
|
||||
timeoutMinutes: Number(row.timeoutMinutes || 0),
|
||||
timeoutPolicy: row.timeoutPolicy || 'reopen',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -330,6 +336,8 @@ export default function WorkOrdersPanel() {
|
||||
rewardAmount?: number
|
||||
requiredDepositAmount?: number
|
||||
fieldsText?: string
|
||||
timeoutMinutes?: number
|
||||
timeoutPolicy?: string
|
||||
}) {
|
||||
if (!editOrder) return
|
||||
const succeeded = await runAction(
|
||||
@@ -341,6 +349,8 @@ export default function WorkOrdersPanel() {
|
||||
rewardAmount: Number(values.rewardAmount || 0),
|
||||
requiredDepositAmount: Number(values.requiredDepositAmount || 0),
|
||||
fieldsText: String(values.fieldsText || ''),
|
||||
timeoutMinutes: Math.max(0, Number(values.timeoutMinutes || 0)),
|
||||
timeoutPolicy: values.timeoutPolicy || 'reopen',
|
||||
}),
|
||||
'工单信息已保存',
|
||||
)
|
||||
@@ -398,6 +408,34 @@ export default function WorkOrdersPanel() {
|
||||
width: 110,
|
||||
render: (_, row) => formatMoney(row.requiredDepositAmount),
|
||||
},
|
||||
{
|
||||
title: '时限',
|
||||
width: 190,
|
||||
render: (_, row) => {
|
||||
const minutes = Number(row.timeoutMinutes || 0)
|
||||
if (minutes <= 0) {
|
||||
return <Typography.Text type="secondary">不限时</Typography.Text>
|
||||
}
|
||||
return (
|
||||
<div className="cell-stack">
|
||||
<Space wrap size={6}>
|
||||
<Tag color="blue">{minutes} 分钟</Tag>
|
||||
<Typography.Text type="secondary">
|
||||
{formatTimeoutPolicyLabel(row.timeoutPolicy)}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
{row.status === 'in_progress' && row.deadlineAt ? (
|
||||
<DeadlineCountdown deadlineAt={row.deadlineAt} showExpired />
|
||||
) : null}
|
||||
{row.deadlineAt ? (
|
||||
<Typography.Text type="secondary">
|
||||
截止 {formatAdminDateTime(row.deadlineAt)}
|
||||
</Typography.Text>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '拼单',
|
||||
width: 190,
|
||||
@@ -699,6 +737,29 @@ export default function WorkOrdersPanel() {
|
||||
<Descriptions.Item label="押金">
|
||||
{formatMoney(detailOrder.requiredDepositAmount)}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="任务时限">
|
||||
{Number(detailOrder.timeoutMinutes || 0) > 0
|
||||
? `${detailOrder.timeoutMinutes} 分钟`
|
||||
: '不限时'}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="超时策略">
|
||||
{formatTimeoutPolicyLabel(detailOrder.timeoutPolicy)}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="超时截止">
|
||||
{detailOrder.deadlineAt ? (
|
||||
<Space wrap size={8}>
|
||||
<DeadlineCountdown
|
||||
deadlineAt={detailOrder.deadlineAt}
|
||||
showExpired
|
||||
/>
|
||||
<Typography.Text type="secondary">
|
||||
{formatAdminDateTime(detailOrder.deadlineAt)}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="发布时间">
|
||||
{formatAdminDateTime(detailOrder.publishedAt)}
|
||||
</Descriptions.Item>
|
||||
@@ -857,6 +918,32 @@ export default function WorkOrdersPanel() {
|
||||
>
|
||||
<Input.TextArea rows={5} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="任务时限"
|
||||
name="timeoutMinutes"
|
||||
tooltip="打手抢单后开始计时,超时由系统自动按策略处置;0 表示不限时"
|
||||
>
|
||||
<InputNumber
|
||||
min={0}
|
||||
step={5}
|
||||
addonAfter="分钟"
|
||||
style={{ width: 160 }}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="超时策略"
|
||||
name="timeoutPolicy"
|
||||
tooltip="reopen:释放押金退回大厅继续可抢;cancel_release:取消订单并退还押金;cancel_deduct:取消订单并扣除押金"
|
||||
>
|
||||
<Select
|
||||
style={{ width: 320 }}
|
||||
options={[
|
||||
{ value: 'reopen', label: '释放押金退回大厅' },
|
||||
{ value: 'cancel_release', label: '取消订单并退还押金' },
|
||||
{ value: 'cancel_deduct', label: '取消订单并扣除押金' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
) : null}
|
||||
</Modal>
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import { Descriptions, Space, Tag, Typography } from 'antd'
|
||||
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
||||
import {
|
||||
DeadlineCountdown,
|
||||
formatTimeoutPolicyLabel,
|
||||
} from '@/components/DeadlineCountdown'
|
||||
import type { CollectField, UploadedFile, WorkOrder, WorkOrderShare } from '@/types/worker-platform'
|
||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
||||
|
||||
export { DeadlineCountdown, formatTimeoutPolicyLabel }
|
||||
|
||||
export function getRequirementFields(order: WorkOrder | null): CollectField[] {
|
||||
if (!order) return []
|
||||
const rawFields = Array.isArray(order.requirement?.fields)
|
||||
|
||||
Reference in New Issue
Block a user