feat(接单): 支持客服手动结束赠送冷却
This commit is contained in:
@@ -479,6 +479,7 @@ export type WorkOrderCapabilities = {
|
||||
canResolveProblem: boolean
|
||||
canDeduct: boolean
|
||||
canConfirmFriend: boolean
|
||||
canCompleteGiftCooldown: boolean
|
||||
canResetGiftFlow: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -162,6 +162,82 @@ export async function confirmWorkOrderFriendAdded(input: {
|
||||
})
|
||||
}
|
||||
|
||||
/** 后台人工确认赠送冷却已完成:立即开放打手提交赠送凭证,并从当前重新计算任务时限。 */
|
||||
export async function completeWorkOrderGiftCooldown(input: {
|
||||
workOrderId: number
|
||||
note?: string
|
||||
actorName?: string
|
||||
now: string
|
||||
}): Promise<{
|
||||
order: WorkOrderRow | null
|
||||
failureReason:
|
||||
| 'work_order_not_found'
|
||||
| 'work_order_mode_invalid'
|
||||
| 'work_order_status_invalid'
|
||||
| 'work_order_gift_phase_invalid'
|
||||
| 'work_order_gift_cooldown_completed'
|
||||
| null
|
||||
}> {
|
||||
return withTransaction(async (client) => {
|
||||
const currentResult = await client.query<WorkOrderRow>(
|
||||
'SELECT * FROM work_orders WHERE id = $1 FOR UPDATE',
|
||||
[input.workOrderId],
|
||||
)
|
||||
const workOrder = currentResult.rows[0] || null
|
||||
if (!workOrder) return { order: null, failureReason: 'work_order_not_found' }
|
||||
if (
|
||||
normalizeWorkOrderAcceptanceMode(workOrder.acceptance_mode) !==
|
||||
WORK_ORDER_ACCEPTANCE_MODE.FRIEND_GIFT
|
||||
) {
|
||||
return { order: null, failureReason: 'work_order_mode_invalid' }
|
||||
}
|
||||
if (!['in_progress', 'problem'].includes(workOrder.status)) {
|
||||
return { order: null, failureReason: 'work_order_status_invalid' }
|
||||
}
|
||||
if (workOrder.gift_phase !== WORK_ORDER_GIFT_PHASE.FRIEND_COUNTDOWN) {
|
||||
return { order: null, failureReason: 'work_order_gift_phase_invalid' }
|
||||
}
|
||||
const availableAt = Date.parse(String(workOrder.gift_available_at || ''))
|
||||
if (Number.isFinite(availableAt) && availableAt <= Date.parse(input.now)) {
|
||||
return { order: null, failureReason: 'work_order_gift_cooldown_completed' }
|
||||
}
|
||||
|
||||
await client.query(
|
||||
`
|
||||
UPDATE work_orders
|
||||
SET
|
||||
gift_available_at = $1::timestamptz,
|
||||
deadline_at = CASE
|
||||
WHEN timeout_minutes > 0
|
||||
THEN $1::timestamptz + (timeout_minutes * INTERVAL '1 minute')
|
||||
ELSE NULL
|
||||
END,
|
||||
updated_at = $1::timestamptz
|
||||
WHERE id = $2
|
||||
`,
|
||||
[input.now, input.workOrderId],
|
||||
)
|
||||
await createWorkOrderEventWithClient(client, {
|
||||
workOrderId: input.workOrderId,
|
||||
actorType: 'admin',
|
||||
actorId: input.actorName || '',
|
||||
eventType: 'gift_cooldown_completed_by_admin',
|
||||
fromStatus: workOrder.status,
|
||||
toStatus: workOrder.status,
|
||||
payloadJson: JSON.stringify({
|
||||
previousGiftAvailableAt: workOrder.gift_available_at,
|
||||
completedAt: input.now,
|
||||
note: String(input.note || '').trim(),
|
||||
}),
|
||||
now: input.now,
|
||||
})
|
||||
return {
|
||||
order: await getWorkOrderByIdWithClient(client, input.workOrderId),
|
||||
failureReason: null,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 后台重置打手资料(资料有误或误确认好友):清空好友状态并让打手重新提交。 */
|
||||
export async function resetWorkOrderGiftMaterial(input: {
|
||||
workOrderId: number
|
||||
|
||||
@@ -841,7 +841,13 @@ export function buildWorkOrderWhere({
|
||||
)`)
|
||||
} else if (Object.values(WORK_ORDER_GIFT_PHASE).includes(normalizedGiftPhase as never)) {
|
||||
params.push(normalizedGiftPhase)
|
||||
filters.push(`wo.acceptance_mode = 'friend_gift' AND wo.gift_phase = $${params.length}`)
|
||||
const giftPhaseFilter = `wo.acceptance_mode = 'friend_gift' AND wo.gift_phase = $${params.length}`
|
||||
// 待打手提交资料仅代表已接单后的赠送流程;待抢单/未分配模板单不应混入该筛选。
|
||||
filters.push(
|
||||
normalizedGiftPhase === WORK_ORDER_GIFT_PHASE.MATERIAL_REQUIRED
|
||||
? `(${giftPhaseFilter} AND wo.assigned_worker_id IS NOT NULL AND wo.status IN ('in_progress', 'problem'))`
|
||||
: giftPhaseFilter,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (hallCandidateLimit > 0) {
|
||||
|
||||
Reference in New Issue
Block a user