feat(order-service): 优化客户订单状态与验收展示

This commit is contained in:
yml2213
2026-11-04 16:36:29 +08:00
parent c31fa7db76
commit e3a66309a0
5 changed files with 517 additions and 74 deletions
@@ -4,6 +4,7 @@ import test from 'node:test'
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
import {
resolveOrderServiceAcceptanceImageUrls,
resolveOrderServiceAcceptanceVideo,
resolveOrderServiceStatusLabel,
resolveOrderServiceStatusMessage,
} from './order-service-public-service.js'
@@ -42,6 +43,43 @@ test('客户页验收图片:仅交付相关状态展示图片,并按文件
)
})
test('客户页验收视频:交付相关状态返回视频地址,未交付状态不返回', () => {
const acceptanceJson = {
video: {
url: '/api/v1/files/object?key=worker-acceptance-video%2Fdemo.webm',
thumbnailUrl: '',
filename: 'acceptance.webm',
contentType: 'video/webm',
durationSeconds: 8.8,
width: 808,
height: 720,
objectKey: 'worker-acceptance-video/demo.webm',
},
}
assert.deepEqual(
resolveOrderServiceAcceptanceVideo({
status: WORK_ORDER_STATUS.ACCEPTED,
acceptanceJson,
}),
{
url: '/api/v1/files/object?key=worker-acceptance-video%2Fdemo.webm',
thumbnailUrl: '',
filename: 'acceptance.webm',
contentType: 'video/webm',
durationSeconds: 8.8,
width: 808,
height: 720,
},
)
assert.equal(
resolveOrderServiceAcceptanceVideo({
status: WORK_ORDER_STATUS.IN_PROGRESS,
acceptanceJson,
}),
null,
)
})
test('订单服务状态文案:待抢单提示高峰期等待', () => {
const message = resolveOrderServiceStatusMessage({
status: WORK_ORDER_STATUS.OPEN,
@@ -94,6 +94,7 @@ export type OrderServicePublicItem = {
screenshotsRule?: OrderServiceProfileConfig['screenshots']
guideImage?: Record<string, unknown>
acceptanceImageUrls?: string[]
acceptanceVideo?: OrderServiceAcceptanceVideo
submittedAt?: string
acceptanceSubmittedAt?: string
acceptedAt?: string
@@ -163,6 +164,55 @@ export function resolveOrderServiceAcceptanceImageUrls(input: {
return urls
}
export type OrderServiceAcceptanceVideo = {
url: string
thumbnailUrl: string
filename: string
contentType: string
durationSeconds: number | null
width: number | null
height: number | null
}
export function resolveOrderServiceAcceptanceVideo(input: {
status: string
acceptanceJson: unknown
}): OrderServiceAcceptanceVideo | null {
if (!PUBLIC_ACCEPTANCE_IMAGE_STATUSES.has(String(input.status || '').trim())) return null
const rawAcceptance = safeParseJson(input.acceptanceJson)
const acceptance = mapAcceptanceForResponse(input.acceptanceJson)
const candidates = [
rawAcceptance.video,
...(Array.isArray(acceptance.files) ? acceptance.files : []),
]
for (const candidate of candidates) {
if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) continue
const source = candidate as Record<string, unknown>
const contentType = String(source.contentType || '')
.trim()
.toLowerCase()
const objectKey = String(
source.objectKey || extractObjectKeyFromFileUrl(String(source.url || '')) || '',
).trim()
const videoLike = contentType.startsWith('video/') || /\.(?:mp4|webm|mov|m4v)$/i.test(objectKey)
if (!videoLike) continue
const url = refreshStoredFileUrl(String(source.url || '').trim())
if (!url) continue
return {
url,
thumbnailUrl: refreshStoredFileUrl(String(source.thumbnailUrl || '').trim()),
filename: String(source.filename || '').trim(),
contentType,
durationSeconds: normalizeFiniteNumber(source.durationSeconds),
width: normalizeFiniteNumber(source.width),
height: normalizeFiniteNumber(source.height),
}
}
return null
}
export async function getOrderServiceByPlatformOrderId(platformOrderIdInput: unknown) {
const platformOrderId = normalizeOrderNo(platformOrderIdInput)
const orders = await listWorkOrdersByPlatformOrderId(platformOrderId)
@@ -428,6 +478,10 @@ async function mapPublicOrderItem(order: WorkOrderRow): Promise<OrderServicePubl
status: order.status,
acceptanceJson: order.acceptance_json,
})
const acceptanceVideo = resolveOrderServiceAcceptanceVideo({
status: order.status,
acceptanceJson: order.acceptance_json,
})
const screenshots = normalizeUploadedFiles(collect.screenshots || [])
.map(refreshUploadedFileUrls)
.filter(Boolean)
@@ -457,21 +511,11 @@ async function mapPublicOrderItem(order: WorkOrderRow): Promise<OrderServicePubl
...(acceptanceSubmittedAt ? { acceptanceSubmittedAt } : {}),
...(order.accepted_at ? { acceptedAt: String(order.accepted_at) } : {}),
...(acceptanceImageUrls.length > 0 ? { acceptanceImageUrls } : {}),
...(acceptanceVideo ? { acceptanceVideo } : {}),
...(profile?.materialConfirmation
? { materialConfirmation: profile.materialConfirmation }
: {}),
statusSteps:
currentPresentationProfile?.config.statusSteps ||
profile?.statusSteps ||
DEFAULT_ORDER_SERVICE_STATUS_STEPS,
}
if (!state.canSubmit) return base
const fields = profile?.fields || []
return {
...base,
fields,
fields: profile?.fields || [],
values,
screenshots,
screenshotsRule: profile?.screenshots || {
@@ -482,6 +526,16 @@ async function mapPublicOrderItem(order: WorkOrderRow): Promise<OrderServicePubl
label: '买家主页截图',
helpText: '',
},
statusSteps:
currentPresentationProfile?.config.statusSteps ||
profile?.statusSteps ||
DEFAULT_ORDER_SERVICE_STATUS_STEPS,
}
if (!state.canSubmit) return base
return {
...base,
guideImage: profile?.guideImage || {},
}
}
@@ -585,6 +639,11 @@ function normalizeOrderNo(value: unknown) {
return normalized
}
function normalizeFiniteNumber(value: unknown): number | null {
const parsed = Number(value)
return Number.isFinite(parsed) && parsed >= 0 ? parsed : null
}
function notFound() {
return createHttpError('订单号无效,请确认订单号是否正确', {
statusCode: 404,