diff --git a/apps/backend/src/services/worker-platform/index.ts b/apps/backend/src/services/worker-platform/index.ts index 77924462..24a380c3 100644 --- a/apps/backend/src/services/worker-platform/index.ts +++ b/apps/backend/src/services/worker-platform/index.ts @@ -12,6 +12,7 @@ export * from './worker-profile-service.js' export * from './worker-hall-service.js' export * from './worker-order-timeout-service.js' export * from './worker-order-realtime-service.js' +export * from './worker-collect-service.js' export * from './worker-platform-defaults.js' export * from './work-order-timeout-policy.js' export * from './after-sales-service.js' diff --git a/apps/backend/src/services/worker-platform/worker-collect-service.ts b/apps/backend/src/services/worker-platform/worker-collect-service.ts new file mode 100644 index 00000000..3a5346ee --- /dev/null +++ b/apps/backend/src/services/worker-platform/worker-collect-service.ts @@ -0,0 +1,136 @@ +import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js' +import { + createWorkOrderEvent, + listPendingMaterialWorkOrdersByPlatformOrderId, + updateWorkOrder, + type WorkOrderRow, +} from '../../repositories/worker-platform/index.js' +import type { JsonObject } from '../../types/json.js' +import { createHttpError } from '../../utils/http.js' +import { nowIso } from '../../utils/time.js' +import { safeParseJson } from '../admin/admin-query-utils.js' +import { publishWorkOrderRealtimeChange } from '../realtime/realtime-event-service.js' +import { + mapCollectLookupOrder, + mapWorkOrderPublic, + normalizeOptionalId, + normalizeSubmittedFields, + normalizeUploadedFiles, + resolveRequirementFields, +} from './mappers.js' + +export async function collectLookupWorkOrder(payload: JsonObject = {}) { + const orderNo = String(payload.orderNo || payload.platformOrderId || '').trim() + if (!orderNo) { + throw createHttpError('请填写订单号', { + statusCode: 400, + errorCode: 'collect_order_no_required', + }) + } + const workOrders = await listPendingMaterialWorkOrdersByPlatformOrderId(orderNo) + if (workOrders.length === 0) { + throw createHttpError('未找到待完善订单,请确认订单号是否正确', { + statusCode: 404, + errorCode: 'collect_order_not_found', + }) + } + const [primaryOrder] = workOrders + if (!primaryOrder) { + throw createHttpError('未找到待完善订单,请确认订单号是否正确', { + statusCode: 404, + errorCode: 'collect_order_not_found', + }) + } + return { + order: mapWorkOrderPublic(primaryOrder), + fields: resolveRequirementFields(primaryOrder), + orders: workOrders.map(mapCollectLookupOrder), + pendingCount: workOrders.length, + } +} + +export async function collectSubmitWorkOrder(payload: JsonObject = {}) { + const orderNo = String(payload.orderNo || payload.platformOrderId || '').trim() + if (!orderNo) { + throw createHttpError('请填写订单号', { + statusCode: 400, + errorCode: 'collect_order_no_required', + }) + } + const workOrders = await listPendingMaterialWorkOrdersByPlatformOrderId(orderNo) + if (workOrders.length === 0) { + throw createHttpError('未找到待完善订单,请确认订单号是否正确', { + statusCode: 404, + errorCode: 'collect_order_not_found', + }) + } + const workOrder = resolveCollectSubmitTargetWorkOrder( + orderNo, + workOrders, + payload.workOrderId || payload.work_order_id, + ) + + const fields = resolveRequirementFields(workOrder) + const submittedFields = normalizeSubmittedFields(payload.fields || payload.material || payload) + const complete = fields.every( + (field) => !field.required || String(submittedFields[field.key] || '').trim(), + ) + const now = nowIso() + const screenshots = normalizeUploadedFiles(payload.screenshots || payload.files) + const material = { + ...safeParseJson(workOrder.material_json), + collect: { + fields: submittedFields, + screenshots, + submittedAt: now, + complete, + }, + } + const nextStatus = complete ? WORK_ORDER_STATUS.UNASSIGNED : WORK_ORDER_STATUS.PENDING_MATERIAL + const updated = await updateWorkOrder(workOrder.id, { + status: nextStatus, + material_json: material, + updated_at: now, + }) + await createWorkOrderEvent({ + workOrderId: workOrder.id, + actorType: 'collect', + actorId: orderNo, + eventType: 'material_submitted', + fromStatus: workOrder.status, + toStatus: nextStatus, + payloadJson: JSON.stringify({ fields: submittedFields, complete }), + now, + }) + publishWorkOrderRealtimeChange({ workOrderId: Number(workOrder.id) }) + return { + order: mapWorkOrderPublic(updated || workOrder), + complete, + } +} + +export function resolveCollectSubmitTargetWorkOrder( + orderNo: string, + workOrders: WorkOrderRow[], + requestedWorkOrderId: unknown, +): WorkOrderRow { + const workOrderId = normalizeOptionalId(requestedWorkOrderId) + if (workOrderId) { + const matched = workOrders.find((item) => Number(item.id) === workOrderId) + if (matched) return matched + throw createHttpError('待完善订单不存在或已更新,请刷新后重试', { + statusCode: 404, + errorCode: 'collect_work_order_not_found', + context: { orderNo, workOrderId }, + }) + } + if (workOrders.length === 1) { + const [singleWorkOrder] = workOrders + if (singleWorkOrder) return singleWorkOrder + } + throw createHttpError('该订单存在多个待完善商品,请逐个提交资料', { + statusCode: 409, + errorCode: 'collect_work_order_required', + context: { orderNo, pendingCount: workOrders.length }, + }) +} diff --git a/apps/backend/src/services/worker-platform/worker-service.ts b/apps/backend/src/services/worker-platform/worker-service.ts index 4d5892a0..8ca1b84d 100644 --- a/apps/backend/src/services/worker-platform/worker-service.ts +++ b/apps/backend/src/services/worker-platform/worker-service.ts @@ -26,7 +26,6 @@ import { revokeWorkerSession, touchWorkerSession, joinWorkOrderShare, - listPendingMaterialWorkOrdersByPlatformOrderId, listWorkerCancelRequests, listWorkerOrderFeedbacks, listWorkerSharesByWorker, @@ -73,9 +72,7 @@ import { } from '../realtime/realtime-event-service.js' import { - mapCollectLookupOrder, mapWorkOrderForWorker, - mapWorkOrderPublic, mapWorkOrderEvents, mapWorkOrderShare, mapWorkerCancelRequest, @@ -85,10 +82,8 @@ import { normalizePositiveInteger, normalizeStatuses, normalizeStringArray, - normalizeSubmittedFields, normalizeUploadedFiles, resolveFreezeDepositAmount, - resolveRequirementFields, resolveWorkerPermissions, canWorkerAutoAcceptWholeOrder, throwGrabWorkOrderFailure, @@ -1371,129 +1366,8 @@ async function saveWorkerSharingAcceptanceDraft( return { share: share ? mapWorkOrderShare(share) : mapWorkOrderShare(sharingShare) } } -export async function collectLookupWorkOrder(payload: JsonObject = {}) { - const orderNo = String(payload.orderNo || payload.platformOrderId || '').trim() - if (!orderNo) { - throw createHttpError('请填写订单号', { - statusCode: 400, - errorCode: 'collect_order_no_required', - }) - } - const workOrders = await listPendingMaterialWorkOrdersByPlatformOrderId(orderNo) - if (workOrders.length === 0) { - throw createHttpError('未找到待完善订单,请确认订单号是否正确', { - statusCode: 404, - errorCode: 'collect_order_not_found', - }) - } - const [primaryOrder] = workOrders - if (!primaryOrder) { - throw createHttpError('未找到待完善订单,请确认订单号是否正确', { - statusCode: 404, - errorCode: 'collect_order_not_found', - }) - } - return { - order: mapWorkOrderPublic(primaryOrder), - fields: resolveRequirementFields(primaryOrder), - orders: workOrders.map(mapCollectLookupOrder), - pendingCount: workOrders.length, - } -} - -export async function collectSubmitWorkOrder(payload: JsonObject = {}) { - const orderNo = String(payload.orderNo || payload.platformOrderId || '').trim() - if (!orderNo) { - throw createHttpError('请填写订单号', { - statusCode: 400, - errorCode: 'collect_order_no_required', - }) - } - const workOrders = await listPendingMaterialWorkOrdersByPlatformOrderId(orderNo) - if (workOrders.length === 0) { - throw createHttpError('未找到待完善订单,请确认订单号是否正确', { - statusCode: 404, - errorCode: 'collect_order_not_found', - }) - } - const workOrder = resolveCollectSubmitTargetWorkOrder( - orderNo, - workOrders, - payload.workOrderId || payload.work_order_id, - ) - - const fields = resolveRequirementFields(workOrder) - const submittedFields = normalizeSubmittedFields(payload.fields || payload.material || payload) - const complete = fields.every( - (field) => !field.required || String(submittedFields[field.key] || '').trim(), - ) - const now = nowIso() - const screenshots = normalizeUploadedFiles(payload.screenshots || payload.files) - const material = { - ...safeParseJson(workOrder.material_json), - collect: { - fields: submittedFields, - screenshots, - submittedAt: now, - complete, - }, - } - const nextStatus = complete ? WORK_ORDER_STATUS.UNASSIGNED : WORK_ORDER_STATUS.PENDING_MATERIAL - const updated = await updateWorkOrder(workOrder.id, { - status: nextStatus, - material_json: material, - updated_at: now, - }) - await createWorkOrderEvent({ - workOrderId: workOrder.id, - actorType: 'collect', - actorId: orderNo, - eventType: 'material_submitted', - fromStatus: workOrder.status, - toStatus: nextStatus, - payloadJson: JSON.stringify({ fields: submittedFields, complete }), - now, - }) - publishWorkOrderRealtimeChange({ - workOrderId: Number(workOrder.id), - }) - return { - order: mapWorkOrderPublic(updated || workOrder), - complete, - } -} - -export function resolveCollectSubmitTargetWorkOrder( - orderNo: string, - workOrders: WorkOrderRow[], - requestedWorkOrderId: unknown, -): WorkOrderRow { - const workOrderId = normalizeOptionalId(requestedWorkOrderId) - if (workOrderId) { - const matched = workOrders.find((item) => Number(item.id) === workOrderId) - if (matched) { - return matched - } - throw createHttpError('待完善订单不存在或已更新,请刷新后重试', { - statusCode: 404, - errorCode: 'collect_work_order_not_found', - context: { orderNo, workOrderId }, - }) - } - - if (workOrders.length === 1) { - const [singleWorkOrder] = workOrders - if (singleWorkOrder) { - return singleWorkOrder - } - } - - throw createHttpError('该订单存在多个待完善商品,请逐个提交资料', { - statusCode: 409, - errorCode: 'collect_work_order_required', - context: { - orderNo, - pendingCount: workOrders.length, - }, - }) -} +export { + collectLookupWorkOrder, + collectSubmitWorkOrder, + resolveCollectSubmitTargetWorkOrder, +} from './worker-collect-service.js'