新增好友赠送验收模式支持打手资料提交加好友冷却与模板配置
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||
import {
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
import { createWorkOrder, createWorkOrderEvent } from '../../repositories/worker-platform/index.js'
|
||||
import type { JsonObject } from '../../types/json.js'
|
||||
import { createHttpError } from '../../utils/http.js'
|
||||
@@ -78,6 +82,8 @@ export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
|
||||
depositThresholdAmount,
|
||||
timeoutMinutes: Math.max(0, normalizeInteger(payload.timeoutMinutes, 0)),
|
||||
timeoutPolicy: normalizeWorkOrderTimeoutPolicy(payload.timeoutPolicy),
|
||||
acceptanceMode: normalizeWorkOrderAcceptanceMode(payload.acceptanceMode),
|
||||
giftCooldownHours: normalizeWorkOrderGiftCooldownHours(payload.giftCooldownHours),
|
||||
materialJson: JSON.stringify(material),
|
||||
requirementJson: JSON.stringify({ fields }),
|
||||
now,
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import {
|
||||
confirmWorkOrderFriendAdded,
|
||||
resetWorkOrderGiftMaterial,
|
||||
} from '../../repositories/worker-platform/index.js'
|
||||
import { publishWorkOrderRealtimeChange } from '../realtime/realtime-event-service.js'
|
||||
import { mapWorkOrderAdmin } from './mappers.js'
|
||||
import { getRequiredWorkOrder } from './worker-session-context-service.js'
|
||||
import { nowIso } from '../../utils/time.js'
|
||||
import { createHttpError } from '../../utils/http.js'
|
||||
|
||||
/** 后台核对打手资料并添加游戏好友后确认,开始 N 小时赠送冷却。 */
|
||||
export async function confirmAdminWorkOrderFriendAdded(
|
||||
workOrderId: number | string,
|
||||
actorName = '',
|
||||
) {
|
||||
const workOrder = await getRequiredWorkOrder(workOrderId)
|
||||
const { order, failureReason } = await confirmWorkOrderFriendAdded({
|
||||
workOrderId: Number(workOrder.id),
|
||||
actorName,
|
||||
now: nowIso(),
|
||||
})
|
||||
if (failureReason === 'work_order_gift_phase_invalid') {
|
||||
throw createHttpError('当前阶段不能确认加好友,请刷新后重试', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_friend_confirm_phase_invalid',
|
||||
})
|
||||
}
|
||||
if (!order) {
|
||||
throw createHttpError('确认加好友失败,订单可能已变化', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_friend_confirm_failed',
|
||||
})
|
||||
}
|
||||
const workerId = Number(order.assigned_worker_id || 0)
|
||||
publishWorkOrderRealtimeChange({
|
||||
workOrderId: Number(order.id),
|
||||
workerIds: workerId > 0 ? [workerId] : [],
|
||||
})
|
||||
return { order: mapWorkOrderAdmin(order) }
|
||||
}
|
||||
|
||||
/** 打手资料有误或误确认好友时,重置资料让打手重新提交(冷却与好友时间清零)。 */
|
||||
export async function resetAdminWorkOrderGiftMaterial(
|
||||
workOrderId: number | string,
|
||||
payload: { note?: unknown } = {},
|
||||
actorName = '',
|
||||
) {
|
||||
const workOrder = await getRequiredWorkOrder(workOrderId)
|
||||
const note = String(payload.note || '').trim()
|
||||
const { order, failureReason } = await resetWorkOrderGiftMaterial({
|
||||
workOrderId: Number(workOrder.id),
|
||||
note,
|
||||
actorName,
|
||||
now: nowIso(),
|
||||
})
|
||||
if (failureReason === 'work_order_gift_phase_invalid') {
|
||||
throw createHttpError('当前阶段没有可重置的打手资料', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_gift_reset_phase_invalid',
|
||||
})
|
||||
}
|
||||
if (failureReason === 'work_order_status_invalid') {
|
||||
throw createHttpError('当前订单状态不能重置资料', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_gift_reset_status_invalid',
|
||||
})
|
||||
}
|
||||
if (!order) {
|
||||
throw createHttpError('重置打手资料失败,订单可能已变化', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_gift_reset_failed',
|
||||
})
|
||||
}
|
||||
const workerId = Number(order.assigned_worker_id || 0)
|
||||
publishWorkOrderRealtimeChange({
|
||||
workOrderId: Number(order.id),
|
||||
workerIds: workerId > 0 ? [workerId] : [],
|
||||
})
|
||||
return { order: mapWorkOrderAdmin(order) }
|
||||
}
|
||||
@@ -38,6 +38,8 @@ export async function listAdminWorkOrders(query: JsonObject = {}) {
|
||||
const vipEvidencePending = normalizeBoolean(query.vipEvidencePending, false)
|
||||
const createdFrom = normalizeDateString(query.createdFrom)
|
||||
const createdTo = normalizeDateString(query.createdTo)
|
||||
const acceptanceMode = String(query.acceptanceMode || '').trim()
|
||||
const giftPhase = String(query.giftPhase || '').trim()
|
||||
const filters = {
|
||||
statuses,
|
||||
workOrderId,
|
||||
@@ -45,6 +47,8 @@ export async function listAdminWorkOrders(query: JsonObject = {}) {
|
||||
workerSharingId: workerId,
|
||||
workerLevelIds,
|
||||
vipEvidencePending,
|
||||
...(acceptanceMode ? { acceptanceMode } : {}),
|
||||
...(giftPhase ? { giftPhase } : {}),
|
||||
useOperationalStatus: true,
|
||||
...(createdFrom ? { createdFrom } : {}),
|
||||
...(createdTo ? { createdTo } : {}),
|
||||
|
||||
@@ -23,6 +23,11 @@ import {
|
||||
upsertWorkProductRule,
|
||||
} from '../../repositories/worker-platform/work-product-rule-repo.js'
|
||||
import type { WorkOrderRow, WorkProductRuleRow } from '../../repositories/worker-platform/types.js'
|
||||
import {
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
WORK_ORDER_ACCEPTANCE_MODE,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
import type { JsonObject } from '../../types/json.js'
|
||||
import { createHttpError } from '../../utils/http.js'
|
||||
import { randomId } from '../../utils/random.js'
|
||||
@@ -257,6 +262,17 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
|
||||
? 0
|
||||
: normalizeAmountFen(payload.unitPrice ?? payload.unitPriceYuan, 0)
|
||||
const sharingEnabled = normalizeBoolean(payload.sharingEnabled ?? payload.sharing_enabled, false)
|
||||
const acceptanceMode = normalizeWorkOrderAcceptanceMode(
|
||||
hasOwnPayload(payload, 'acceptanceMode') || hasOwnPayload(payload, 'acceptance_mode')
|
||||
? payload.acceptanceMode || payload.acceptance_mode
|
||||
: existingRule?.acceptance_mode,
|
||||
)
|
||||
if (acceptanceMode === WORK_ORDER_ACCEPTANCE_MODE.FRIEND_GIFT && sharingEnabled) {
|
||||
throw createHttpError('好友赠送验收模式不支持拼单,请先关闭拼单', {
|
||||
statusCode: 400,
|
||||
errorCode: 'work_product_rule_gift_sharing_conflict',
|
||||
})
|
||||
}
|
||||
const hasManualSharingConfig =
|
||||
hasConfiguredSharingValue(payload.sharingTotalQuantity ?? payload.sharing_total_quantity) ||
|
||||
hasConfiguredSharingValue(payload.sharingUnitReward ?? payload.sharingUnitRewardYuan) ||
|
||||
@@ -351,6 +367,13 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
|
||||
sharingAutoFromOrder,
|
||||
timeoutMinutes: Math.max(0, normalizeInteger(payload.timeoutMinutes, 0)),
|
||||
timeoutPolicy: normalizeWorkOrderTimeoutPolicy(payload.timeoutPolicy),
|
||||
acceptanceMode,
|
||||
giftCooldownHours:
|
||||
hasOwnPayload(payload, 'giftCooldownHours') || hasOwnPayload(payload, 'gift_cooldown_hours')
|
||||
? normalizeWorkOrderGiftCooldownHours(
|
||||
payload.giftCooldownHours ?? payload.gift_cooldown_hours,
|
||||
)
|
||||
: normalizeWorkOrderGiftCooldownHours(existingRule?.gift_cooldown_hours),
|
||||
requirementJson: JSON.stringify({ fields }),
|
||||
matchJson: JSON.stringify(match),
|
||||
sortOrder: normalizeInteger(payload.sortOrder, 100),
|
||||
|
||||
@@ -15,6 +15,7 @@ export * from './worker-order-timeout-service.js'
|
||||
export * from './worker-order-realtime-service.js'
|
||||
export * from './worker-collect-service.js'
|
||||
export * from './worker-acceptance-service.js'
|
||||
export * from './worker-gift-material-service.js'
|
||||
export * from './worker-my-order-service.js'
|
||||
export * from './worker-hall-action-service.js'
|
||||
export * from './worker-platform-defaults.js'
|
||||
@@ -33,6 +34,7 @@ export * from './admin-worker-cancel-service.js'
|
||||
export * from './admin-work-order-sharing-service.js'
|
||||
export * from './admin-work-order-realtime-service.js'
|
||||
export * from './admin-work-order-material-service.js'
|
||||
export * from './admin-work-order-gift-service.js'
|
||||
export * from './admin-mock-work-order-service.js'
|
||||
export * from './admin-work-order-management-service.js'
|
||||
export * from './admin-worker-platform-summary-service.js'
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||
import {
|
||||
isFriendGiftAcceptanceMode,
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
import {
|
||||
createWorkProductMatchLog,
|
||||
createWorkOrder,
|
||||
@@ -95,10 +100,9 @@ export async function syncWorkerOrdersForSourceOrder(
|
||||
sharingTotalQuantity: Number(rule.sharing_total_quantity || 1),
|
||||
sharingUnitReward: Number(rule.sharing_unit_reward || 0),
|
||||
})
|
||||
const sharingEnabled = resolveWorkOrderSharingEnabled(
|
||||
rule.sharing_enabled === true,
|
||||
sharingTotalQuantity,
|
||||
)
|
||||
const sharingEnabled = isFriendGiftAcceptanceMode(rule.acceptance_mode)
|
||||
? false
|
||||
: resolveWorkOrderSharingEnabled(rule.sharing_enabled === true, sharingTotalQuantity)
|
||||
const now = nowIso()
|
||||
const materialComplete = fields.every((field) => !field.required)
|
||||
const workOrder = await createWorkOrder({
|
||||
@@ -119,6 +123,8 @@ export async function syncWorkerOrdersForSourceOrder(
|
||||
sharingUnitReward,
|
||||
timeoutMinutes: Number(rule.timeout_minutes || 0),
|
||||
timeoutPolicy: String(rule.timeout_policy || 'reopen').trim(),
|
||||
acceptanceMode: normalizeWorkOrderAcceptanceMode(rule.acceptance_mode),
|
||||
giftCooldownHours: normalizeWorkOrderGiftCooldownHours(rule.gift_cooldown_hours),
|
||||
materialJson: JSON.stringify({
|
||||
source: {
|
||||
orderId: Number(order.id),
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||
import {
|
||||
isFriendGiftAcceptanceMode,
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
resolveWorkOrderGiftPhase,
|
||||
WORK_ORDER_ACCEPTANCE_MODE,
|
||||
WORK_ORDER_GIFT_PHASE,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
import {
|
||||
type WorkCategoryRow,
|
||||
type WorkOrderCapabilities,
|
||||
@@ -49,6 +57,20 @@ export function mapWorkOrderMaterial(value: unknown) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 读取好友赠送模式的打手本人资料;主页截图访问链接需要读取时重签。 */
|
||||
export function mapWorkOrderBoosterMaterial(value: unknown) {
|
||||
const material = safeParseJson(value)
|
||||
return {
|
||||
fields:
|
||||
material.fields && typeof material.fields === 'object' && !Array.isArray(material.fields)
|
||||
? (material.fields as Record<string, string>)
|
||||
: {},
|
||||
screenshots: normalizeUploadedFiles(material.screenshots).map(refreshUploadedFileUrls),
|
||||
note: String(material.note || ''),
|
||||
submittedAt: String(material.submittedAt || ''),
|
||||
}
|
||||
}
|
||||
|
||||
/** 统一计算后台使用的工单业务状态,避免拼单订单继续直接暴露母工单 open。 */
|
||||
export function resolveWorkOrderOperationalStatus(workOrder: WorkOrderRow): string {
|
||||
const activeShareQuantity = Math.max(0, Number(workOrder.active_share_quantity || 0))
|
||||
@@ -100,6 +122,9 @@ export function mapWorkOrderAdmin(workOrder: WorkOrderRow, shares?: WorkOrderSha
|
||||
const sharingFilled =
|
||||
workOrder.sharing_enabled === true && activeShareQuantity >= sharingTotalQuantity
|
||||
const status = resolveWorkOrderOperationalStatus(workOrder)
|
||||
const acceptanceMode = normalizeWorkOrderAcceptanceMode(workOrder.acceptance_mode)
|
||||
const isFriendGift = acceptanceMode === WORK_ORDER_ACCEPTANCE_MODE.FRIEND_GIFT
|
||||
const giftPhase = String(workOrder.gift_phase || '').trim()
|
||||
const hallAvailable =
|
||||
workOrder.status === WORK_ORDER_STATUS.OPEN &&
|
||||
(!workOrder.sharing_enabled || activeShareQuantity < sharingTotalQuantity)
|
||||
@@ -142,6 +167,18 @@ export function mapWorkOrderAdmin(workOrder: WorkOrderRow, shares?: WorkOrderSha
|
||||
canCancel: status === WORK_ORDER_STATUS.IN_PROGRESS && Boolean(workOrder.assigned_worker_id),
|
||||
canResolveProblem: workOrder.status === WORK_ORDER_STATUS.PROBLEM,
|
||||
canDeduct: workOrder.status === WORK_ORDER_STATUS.ACCEPTED,
|
||||
canConfirmFriend:
|
||||
isFriendGift &&
|
||||
workOrder.status === WORK_ORDER_STATUS.IN_PROGRESS &&
|
||||
giftPhase === WORK_ORDER_GIFT_PHASE.MATERIAL_SUBMITTED,
|
||||
canResetGiftFlow:
|
||||
isFriendGift &&
|
||||
[WORK_ORDER_STATUS.IN_PROGRESS, WORK_ORDER_STATUS.PROBLEM].includes(
|
||||
workOrder.status as never,
|
||||
) &&
|
||||
[WORK_ORDER_GIFT_PHASE.MATERIAL_SUBMITTED, WORK_ORDER_GIFT_PHASE.FRIEND_COUNTDOWN].includes(
|
||||
giftPhase as never,
|
||||
),
|
||||
}
|
||||
return {
|
||||
workOrderId: Number(workOrder.id),
|
||||
@@ -155,6 +192,19 @@ export function mapWorkOrderAdmin(workOrder: WorkOrderRow, shares?: WorkOrderSha
|
||||
status,
|
||||
rawStatus: workOrder.status,
|
||||
hallAvailable,
|
||||
acceptanceMode,
|
||||
...(isFriendGift
|
||||
? {
|
||||
gift: {
|
||||
phase: resolveWorkOrderGiftPhase(workOrder),
|
||||
rawPhase: giftPhase,
|
||||
cooldownHours: normalizeWorkOrderGiftCooldownHours(workOrder.gift_cooldown_hours),
|
||||
friendAddedAt: workOrder.friend_added_at,
|
||||
giftAvailableAt: workOrder.gift_available_at,
|
||||
boosterMaterial: mapWorkOrderBoosterMaterial(workOrder.booster_material_json),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
sharingProgress: {
|
||||
joinedQuantity: activeShareQuantity,
|
||||
pendingSubmissionCount: pendingShareCount,
|
||||
|
||||
@@ -2,6 +2,10 @@ import {
|
||||
type WorkProductRuleMappingRow,
|
||||
type WorkProductRuleRow,
|
||||
} from '../../repositories/worker-platform/index.js'
|
||||
import {
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
import type { JsonObject } from '../../types/json.js'
|
||||
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
|
||||
import { safeParseJson } from '../admin/admin-query-utils.js'
|
||||
@@ -45,6 +49,8 @@ export function mapWorkProductRule(rule: WorkProductRuleRow | null | undefined)
|
||||
},
|
||||
timeoutMinutes: Number(rule.timeout_minutes || 0),
|
||||
timeoutPolicy: String(rule.timeout_policy || 'reopen').trim(),
|
||||
acceptanceMode: normalizeWorkOrderAcceptanceMode(rule.acceptance_mode),
|
||||
giftCooldownHours: normalizeWorkOrderGiftCooldownHours(rule.gift_cooldown_hours),
|
||||
requirement: {
|
||||
fields: normalizeRequirementFields(requirement.fields),
|
||||
},
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||
import {
|
||||
isFriendGiftAcceptanceMode,
|
||||
isWorkOrderGiftAvailable,
|
||||
WORK_ORDER_GIFT_PHASE,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
import {
|
||||
acceptWorkOrderAndSettle,
|
||||
acceptWorkOrderShareAndSettle,
|
||||
@@ -61,13 +66,20 @@ export async function submitWorkerOrderAcceptance(
|
||||
if (sharingShare) {
|
||||
return submitWorkerSharingAcceptance(workOrder, sharingShare, payload, session)
|
||||
}
|
||||
const canAutoAcceptWithoutEvidence = canWorkerAutoAcceptWholeOrder({
|
||||
worker,
|
||||
hasPersonalSharingShare: false,
|
||||
})
|
||||
const canAutoAcceptWithoutEvidence = isFriendGiftAcceptanceMode(workOrder.acceptance_mode)
|
||||
? false
|
||||
: canWorkerAutoAcceptWholeOrder({
|
||||
worker,
|
||||
hasPersonalSharingShare: false,
|
||||
})
|
||||
const now = nowIso()
|
||||
// 好友赠送单在“待确认好友”阶段是等后台操作,等待期不计打手超时。
|
||||
const awaitingFriendConfirm =
|
||||
isFriendGiftAcceptanceMode(workOrder.acceptance_mode) &&
|
||||
workOrder.gift_phase === WORK_ORDER_GIFT_PHASE.MATERIAL_SUBMITTED
|
||||
if (
|
||||
workOrder.status === WORK_ORDER_STATUS.IN_PROGRESS &&
|
||||
!awaitingFriendConfirm &&
|
||||
workOrder.deadline_at &&
|
||||
new Date(workOrder.deadline_at).getTime() <= Date.now()
|
||||
) {
|
||||
@@ -95,6 +107,18 @@ export async function submitWorkerOrderAcceptance(
|
||||
errorCode: 'work_order_submit_status_invalid',
|
||||
})
|
||||
}
|
||||
// 好友赠送模式:必须等后台确认加好友且冷却结束后,才能提交赠送凭证。
|
||||
if (isFriendGiftAcceptanceMode(workOrder.acceptance_mode)) {
|
||||
if (
|
||||
workOrder.gift_phase !== WORK_ORDER_GIFT_PHASE.FRIEND_COUNTDOWN ||
|
||||
!isWorkOrderGiftAvailable(workOrder)
|
||||
) {
|
||||
throw createHttpError('好友赠送冷却未结束,暂不能提交验收', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_gift_cooldown_active',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const { files, imageUrls, note } = resolveAcceptanceImages(
|
||||
payload,
|
||||
@@ -141,7 +165,11 @@ export async function submitWorkerOrderAcceptance(
|
||||
}),
|
||||
now,
|
||||
})
|
||||
if (worker.worker_type === 'internal' || canAutoAcceptWithoutEvidence) {
|
||||
// 好友赠送模式必须由后台人工验收赠送凭证,内部打手与 VIP 免审核直通均不适用。
|
||||
if (
|
||||
!isFriendGiftAcceptanceMode(workOrder.acceptance_mode) &&
|
||||
(worker.worker_type === 'internal' || canAutoAcceptWithoutEvidence)
|
||||
) {
|
||||
const { order: acceptedOrder, failureReason } = await acceptWorkOrderAndSettle({
|
||||
workOrderId: workOrder.id,
|
||||
unfreezeDays: getWorkerFinanceConfig().depositUnfreezeDays,
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
import { isFriendGiftAcceptanceMode } from '../../domain/work-order-acceptance-mode.js'
|
||||
import { submitWorkOrderGiftMaterial } 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 {
|
||||
mapWorkOrderForWorker,
|
||||
normalizeUploadedFiles,
|
||||
resolveWorkerPermissions,
|
||||
} from './mappers.js'
|
||||
import { publishWorkOrderParticipantChange } from './worker-order-realtime-service.js'
|
||||
import {
|
||||
getRequiredWorkOrder,
|
||||
getRequiredWorker,
|
||||
requireActiveWorkerSession,
|
||||
type WorkerSession,
|
||||
} from './worker-session-context-service.js'
|
||||
|
||||
/** 打手本人资料的固定字段:昵称/ID/区服必填,系统选填(安卓/苹果)。 */
|
||||
const BOOSTER_MATERIAL_REQUIRED_FIELDS = [
|
||||
{ key: 'gameNickname', label: '游戏昵称' },
|
||||
{ key: 'gameId', label: '游戏ID' },
|
||||
{ key: 'serverZone', label: '区服' },
|
||||
] as const
|
||||
|
||||
/** 好友赠送模式:打手接单后提交本人游戏资料与主页截图,等待后台核对并添加好友。 */
|
||||
export async function submitWorkerOrderGiftMaterial(
|
||||
workOrderId: number | string,
|
||||
payload: JsonObject = {},
|
||||
session: WorkerSession,
|
||||
) {
|
||||
requireActiveWorkerSession(session)
|
||||
const workOrder = await getRequiredWorkOrder(workOrderId)
|
||||
const worker = await getRequiredWorker(session.workerId)
|
||||
if (!isFriendGiftAcceptanceMode(workOrder.acceptance_mode)) {
|
||||
throw createHttpError('该订单不需要提交好友赠送资料', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_gift_mode_invalid',
|
||||
})
|
||||
}
|
||||
if (Number(workOrder.assigned_worker_id || 0) !== Number(session.workerId)) {
|
||||
throw createHttpError('只能操作自己的订单', {
|
||||
statusCode: 403,
|
||||
errorCode: 'work_order_owner_required',
|
||||
})
|
||||
}
|
||||
|
||||
const now = nowIso()
|
||||
const fieldsPayload =
|
||||
payload.fields && typeof payload.fields === 'object' && !Array.isArray(payload.fields)
|
||||
? (payload.fields as Record<string, unknown>)
|
||||
: {}
|
||||
const fields: Record<string, string> = {}
|
||||
for (const field of BOOSTER_MATERIAL_REQUIRED_FIELDS) {
|
||||
const value = String(fieldsPayload[field.key] ?? '').trim()
|
||||
if (!value) {
|
||||
throw createHttpError(`请填写${field.label}`, {
|
||||
statusCode: 400,
|
||||
errorCode: 'work_order_gift_material_field_required',
|
||||
})
|
||||
}
|
||||
fields[field.key] = value
|
||||
}
|
||||
const system = String(fieldsPayload.system ?? '').trim()
|
||||
if (system) fields.system = system
|
||||
|
||||
const note = String(payload.note || '').trim()
|
||||
if (note.length > 200) {
|
||||
throw createHttpError('备注不能超过 200 个字符', {
|
||||
statusCode: 400,
|
||||
errorCode: 'work_order_gift_material_note_too_long',
|
||||
})
|
||||
}
|
||||
const screenshots = normalizeUploadedFiles(payload.screenshots)
|
||||
if (screenshots.length === 0) {
|
||||
throw createHttpError('请上传主页截图', {
|
||||
statusCode: 400,
|
||||
errorCode: 'work_order_gift_material_screenshot_required',
|
||||
})
|
||||
}
|
||||
|
||||
const { order, failureReason } = await submitWorkOrderGiftMaterial({
|
||||
workOrderId: Number(workOrder.id),
|
||||
workerId: Number(session.workerId),
|
||||
boosterMaterialJson: JSON.stringify({
|
||||
fields,
|
||||
screenshots,
|
||||
note,
|
||||
submittedAt: now,
|
||||
}),
|
||||
now,
|
||||
})
|
||||
if (failureReason === 'work_order_gift_phase_invalid') {
|
||||
throw createHttpError('当前阶段不能提交资料,请刷新后重试', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_gift_phase_invalid',
|
||||
})
|
||||
}
|
||||
if (failureReason === 'work_order_status_invalid') {
|
||||
throw createHttpError('当前订单状态不能提交资料', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_gift_status_invalid',
|
||||
})
|
||||
}
|
||||
if (failureReason === 'work_order_owner_required') {
|
||||
throw createHttpError('只能操作自己的订单', {
|
||||
statusCode: 403,
|
||||
errorCode: 'work_order_owner_required',
|
||||
})
|
||||
}
|
||||
if (!order) {
|
||||
throw createHttpError('提交好友赠送资料失败,请稍后重试', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_gift_material_submit_failed',
|
||||
})
|
||||
}
|
||||
await publishWorkOrderParticipantChange(Number(workOrder.id), {
|
||||
workerIds: [Number(session.workerId)],
|
||||
})
|
||||
return {
|
||||
order: mapWorkOrderForWorker(order, resolveWorkerPermissions(worker)),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user