add:新增同一个工单同一人可以多次拼单
This commit is contained in:
@@ -3,9 +3,13 @@ import type { Response } from 'express'
|
||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||
|
||||
import {
|
||||
getLatestMaterialEventAtByOrderIds,
|
||||
getPendingCancelRequestOrderIds,
|
||||
getPendingFeedbackOrderIds,
|
||||
getWorkerFinanceRequestById,
|
||||
getWorkerUserById,
|
||||
getWorkOrderById,
|
||||
listWorkerTimeoutEventsByOrderIds,
|
||||
listWorkerWorkOrderNotes,
|
||||
listWorkerWorkOrderViews,
|
||||
listWorkOrderShares,
|
||||
@@ -23,10 +27,13 @@ import { mapAdminOrderListItem } from '../admin/admin-order-read-helpers.js'
|
||||
import { mapAdminTaskListItem } from '../admin/admin-task-read-helpers.js'
|
||||
import {
|
||||
isWorkOrderSharingFilled,
|
||||
isWorkerOrderVipEvidencePending,
|
||||
mapFinanceRequest,
|
||||
mapWorkOrderAdmin,
|
||||
mapWorkOrderForWorker,
|
||||
mapWorkerUser,
|
||||
pickWorkerRepresentativeShare,
|
||||
resolveWorkerOrderStatusTabs,
|
||||
resolveWorkerPermissions,
|
||||
} from '../worker-platform/mappers.js'
|
||||
import { invalidateWorkerMyOrderCaches } from '../worker-platform/worker-my-order-cache.js'
|
||||
@@ -336,33 +343,121 @@ async function publishWorkOrderSnapshots(input: {
|
||||
})
|
||||
}
|
||||
|
||||
// 资料更新时间只与工单有关,提到循环外只查一次(参与人数多时省掉 N 次查询)。
|
||||
const materialEventAt =
|
||||
(await getLatestMaterialEventAtByOrderIds([workOrderId])).get(workOrderId) || ''
|
||||
|
||||
for (const workerId of new Set(
|
||||
(input.workerIds || []).map((item) => Number(item)).filter(Boolean),
|
||||
)) {
|
||||
const worker = await getWorkerUserById(workerId)
|
||||
if (!worker) continue
|
||||
const [notes, views] = await Promise.all([
|
||||
listWorkerWorkOrderNotes(workerId, [workOrderId]),
|
||||
listWorkerWorkOrderViews(workerId, [workOrderId]),
|
||||
])
|
||||
const note = notes.find((item) => Number(item.work_order_id) === workOrderId)?.note || ''
|
||||
const viewedAt =
|
||||
views.find((item) => Number(item.work_order_id) === workOrderId)?.viewed_at || null
|
||||
const share = shares.find((item) => Number(item.worker_id) === workerId)
|
||||
|
||||
// 同一打手在同一工单可能有多份份额(多次拼单),必须按「全部份额」还原这一行:
|
||||
// 旧实现用 shares.find(...) 只取最早一条,多份额时会把可见性、个人状态、金额都算错,
|
||||
// 还会让实时补丁把行从错误的页签删掉(打手端偶发「页签里没有数据」)。
|
||||
const isAssignedWorker = Number(workOrder.assigned_worker_id || 0) === workerId
|
||||
const workerOrderVisible = isAssignedWorker || Boolean(share && share.status !== 'cancelled')
|
||||
const workerShares = shares.filter((item) => Number(item.worker_id) === workerId)
|
||||
const activeWorkerShares = workerShares.filter((item) => item.status !== 'cancelled')
|
||||
const representativeShare = pickWorkerRepresentativeShare(
|
||||
activeWorkerShares.length > 0 ? activeWorkerShares : workerShares,
|
||||
)
|
||||
const cancelledShare = workerShares
|
||||
.filter((item) => item.status === 'cancelled')
|
||||
.sort((left, right) => Number(right.id) - Number(left.id))[0]
|
||||
const isOwnerCurrently = isAssignedWorker || activeWorkerShares.length > 0
|
||||
const workerOrderVisible = isOwnerCurrently
|
||||
|
||||
// 只有「已不持有该单」时才需要判断超时归属,避免给正常在办的单多打一次查询。
|
||||
const needsTimeoutCheck = !isOwnerCurrently
|
||||
const [notes, views, pendingCancelOrderIds, pendingFeedbackOrderIds, timeoutEventsByOrderId] =
|
||||
await Promise.all([
|
||||
listWorkerWorkOrderNotes(workerId, [workOrderId]),
|
||||
listWorkerWorkOrderViews(workerId, [workOrderId]),
|
||||
getPendingCancelRequestOrderIds(workerId, [workOrderId]),
|
||||
getPendingFeedbackOrderIds(workerId, [workOrderId]),
|
||||
needsTimeoutCheck
|
||||
? listWorkerTimeoutEventsByOrderIds(workerId, [workOrderId])
|
||||
: Promise.resolve(new Map<number, { createdAt: string }>()),
|
||||
])
|
||||
const note = notes.find((item) => Number(item.work_order_id) === workOrderId)?.note || ''
|
||||
const view = views.find((item) => Number(item.work_order_id) === workOrderId)
|
||||
const viewedAt = view?.viewed_at || null
|
||||
const timeoutEvent = timeoutEventsByOrderId.get(workOrderId)
|
||||
const isTimedOutForMe =
|
||||
!isOwnerCurrently && Boolean(timeoutEvent || (cancelledShare && workOrder.sharing_enabled))
|
||||
|
||||
const timeoutNotice = isTimedOutForMe
|
||||
? {
|
||||
isTimedOut: true,
|
||||
timedOutAt:
|
||||
timeoutEvent?.createdAt ||
|
||||
(workOrder.deadline_at ? String(workOrder.deadline_at) : null) ||
|
||||
workOrder.updated_at,
|
||||
warningMessage:
|
||||
(workOrder.assigned_worker_id != null &&
|
||||
Number(workOrder.assigned_worker_id) !== workerId) ||
|
||||
['in_progress', 'submitted', 'pending_acceptance', 'accepted'].includes(
|
||||
workOrder.status,
|
||||
)
|
||||
? '该订单已超时返回大厅并被其他打手接手,请勿继续在游戏内赠送!若私自继续赠送,造成的财产损失平台概不负责。'
|
||||
: '该订单已超时退回抢单大厅,您已失去接单资格,请勿在游戏内赠送!若私自继续赠送,造成的财产损失平台概不负责。',
|
||||
isTakenByOther:
|
||||
(workOrder.assigned_worker_id != null &&
|
||||
Number(workOrder.assigned_worker_id) !== workerId) ||
|
||||
['in_progress', 'submitted', 'pending_acceptance', 'accepted'].includes(
|
||||
workOrder.status,
|
||||
),
|
||||
}
|
||||
: undefined
|
||||
|
||||
const hasPendingHandling =
|
||||
pendingCancelOrderIds.has(workOrderId) || pendingFeedbackOrderIds.has(workOrderId)
|
||||
const materialSeenAt = view?.material_seen_at || ''
|
||||
const vipEvidencePending = isWorkerOrderVipEvidencePending(workOrder)
|
||||
|
||||
publishRealtimeEvent({
|
||||
type: 'work_order.changed',
|
||||
entityId: workOrderId,
|
||||
scopes: ['worker_my_orders'],
|
||||
operation: workerOrderVisible ? 'upsert' : 'remove',
|
||||
data: mapWorkOrderForWorker(
|
||||
workOrder,
|
||||
resolveWorkerPermissions(worker),
|
||||
share,
|
||||
note,
|
||||
viewedAt,
|
||||
),
|
||||
data: {
|
||||
...mapWorkOrderForWorker(
|
||||
workOrder,
|
||||
resolveWorkerPermissions(worker),
|
||||
representativeShare,
|
||||
note,
|
||||
viewedAt,
|
||||
{
|
||||
isTimedOutForMe,
|
||||
...(timeoutNotice ? { timeoutNotice } : {}),
|
||||
// 与列表一致:只带未取消份额,按 id DESC(参与先后倒序)
|
||||
myShares: [...activeWorkerShares].sort(
|
||||
(left, right) => Number(right.id) - Number(left.id),
|
||||
),
|
||||
},
|
||||
),
|
||||
/**
|
||||
* 这张单在该打手「我的订单」里属于哪些状态页签。
|
||||
* 多份额工单可同时属于代练中/待验收,单个 status 字段表达不了,前端据此判归属。
|
||||
*/
|
||||
workerStatuses: resolveWorkerOrderStatusTabs({
|
||||
workOrderStatus: workOrder.status,
|
||||
isAssignedWorker,
|
||||
shares: workerShares,
|
||||
hasPendingHandling,
|
||||
hasTimeoutForMe: Boolean(timeoutEvent),
|
||||
vipEvidencePending,
|
||||
}),
|
||||
problemMarked: !isTimedOutForMe && workOrder.status === WORK_ORDER_STATUS.PROBLEM,
|
||||
pendingCancelRequest: !isTimedOutForMe && pendingCancelOrderIds.has(workOrderId),
|
||||
pendingFeedback: !isTimedOutForMe && pendingFeedbackOrderIds.has(workOrderId),
|
||||
materialUpdated:
|
||||
!isTimedOutForMe &&
|
||||
Boolean(materialEventAt) &&
|
||||
(!materialSeenAt ||
|
||||
new Date(materialEventAt).getTime() > new Date(materialSeenAt).getTime()),
|
||||
},
|
||||
workerIds: [workerId],
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user