feat(order-service): 客户页展示验收图片与订单进度
This commit is contained in:
@@ -3,10 +3,45 @@ import test from 'node:test'
|
||||
|
||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||
import {
|
||||
resolveOrderServiceAcceptanceImageUrls,
|
||||
resolveOrderServiceStatusLabel,
|
||||
resolveOrderServiceStatusMessage,
|
||||
} from './order-service-public-service.js'
|
||||
|
||||
test('客户页验收图片:仅交付相关状态展示图片,并按文件对象去重', () => {
|
||||
const acceptanceJson = {
|
||||
files: [
|
||||
{
|
||||
objectKey: 'worker-acceptance/a.webp',
|
||||
url: '/api/v1/files/object?key=worker-acceptance%2Fa.webp',
|
||||
thumbnailUrl: '/api/v1/files/object?key=worker-acceptance%2Fa.thumb.jpg',
|
||||
mediumUrl: '/api/v1/files/object?key=worker-acceptance%2Fa.medium.jpg',
|
||||
contentType: 'image/webp',
|
||||
},
|
||||
{
|
||||
objectKey: 'worker-acceptance/a-video.mp4',
|
||||
url: 'https://example.com/a-video.mp4',
|
||||
contentType: 'video/mp4',
|
||||
},
|
||||
],
|
||||
imageUrls: ['/api/v1/files/object?key=worker-acceptance%2Fa.webp'],
|
||||
}
|
||||
assert.deepEqual(
|
||||
resolveOrderServiceAcceptanceImageUrls({
|
||||
status: WORK_ORDER_STATUS.ACCEPTED,
|
||||
acceptanceJson,
|
||||
}),
|
||||
['/api/v1/files/object?key=worker-acceptance%2Fa.medium.jpg'],
|
||||
)
|
||||
assert.deepEqual(
|
||||
resolveOrderServiceAcceptanceImageUrls({
|
||||
status: WORK_ORDER_STATUS.IN_PROGRESS,
|
||||
acceptanceJson,
|
||||
}),
|
||||
[],
|
||||
)
|
||||
})
|
||||
|
||||
test('订单服务状态文案:待抢单提示高峰期等待', () => {
|
||||
const message = resolveOrderServiceStatusMessage({
|
||||
status: WORK_ORDER_STATUS.OPEN,
|
||||
|
||||
@@ -21,7 +21,9 @@ import { normalizeSubmittedFields, normalizeUploadedFiles } from './worker-input
|
||||
import {
|
||||
ORDER_SERVICE_SCREENSHOT_CONTENT_TYPES,
|
||||
buildFileUrl,
|
||||
extractObjectKeyFromFileUrl,
|
||||
refreshUploadedFileUrls,
|
||||
refreshStoredFileUrl,
|
||||
type UploadedFileDto,
|
||||
} from '../file-storage/file-storage-service.js'
|
||||
import { enqueueCustomerOrderNotification } from '../notification/customer-order-notification-service.js'
|
||||
@@ -43,6 +45,7 @@ import {
|
||||
enqueueOrderServiceAutoPublish,
|
||||
processDueOrderServiceAutoPublishJobs,
|
||||
} from './order-service-auto-publish-service.js'
|
||||
import { mapAcceptanceForResponse } from './work-order-material-mappers.js'
|
||||
|
||||
const PUBLIC_STATUS_MESSAGES: Record<string, string> = {
|
||||
[WORK_ORDER_STATUS.PENDING_MATERIAL]: '请补充订单资料。',
|
||||
@@ -87,8 +90,18 @@ export type OrderServicePublicItem = {
|
||||
screenshots?: Array<Record<string, unknown>>
|
||||
screenshotsRule?: OrderServiceProfileConfig['screenshots']
|
||||
guideImage?: Record<string, unknown>
|
||||
acceptanceImageUrls?: string[]
|
||||
submittedAt?: string
|
||||
acceptanceSubmittedAt?: string
|
||||
acceptedAt?: string
|
||||
}
|
||||
|
||||
const PUBLIC_ACCEPTANCE_IMAGE_STATUSES = new Set<string>([
|
||||
WORK_ORDER_STATUS.PENDING_ACCEPTANCE,
|
||||
WORK_ORDER_STATUS.ACCEPTED,
|
||||
WORK_ORDER_STATUS.PROBLEM,
|
||||
])
|
||||
|
||||
export function resolveOrderServiceStatusLabel(status: string, fallback = '处理中') {
|
||||
return PUBLIC_STATUS_LABELS[String(status || '').trim()] || fallback
|
||||
}
|
||||
@@ -106,6 +119,47 @@ export function resolveOrderServiceStatusMessage(input: {
|
||||
)
|
||||
}
|
||||
|
||||
export function resolveOrderServiceAcceptanceImageUrls(input: {
|
||||
status: string
|
||||
acceptanceJson: unknown
|
||||
}) {
|
||||
if (!PUBLIC_ACCEPTANCE_IMAGE_STATUSES.has(String(input.status || '').trim())) return []
|
||||
const acceptance = mapAcceptanceForResponse(input.acceptanceJson)
|
||||
const files = Array.isArray(acceptance.files) ? acceptance.files : []
|
||||
const imageUrls = Array.isArray(acceptance.imageUrls) ? acceptance.imageUrls : []
|
||||
const seenObjects = new Set<string>()
|
||||
const urls: string[] = []
|
||||
|
||||
for (const file of files) {
|
||||
const source =
|
||||
file && typeof file === 'object' && !Array.isArray(file)
|
||||
? (file as Record<string, unknown>)
|
||||
: {}
|
||||
const objectKey = String(source.objectKey || '').trim()
|
||||
const url = String(source.url || '').trim()
|
||||
const contentType = String(source.contentType || '').trim()
|
||||
const imageLike =
|
||||
contentType.startsWith('image/') ||
|
||||
/\.(?:jpe?g|png|webp|gif)$/i.test(objectKey || extractObjectKeyFromFileUrl(url))
|
||||
if (!imageLike) continue
|
||||
const identity = objectKey || extractObjectKeyFromFileUrl(url) || url
|
||||
if (!identity || seenObjects.has(identity)) continue
|
||||
seenObjects.add(identity)
|
||||
const displayUrl = String(source.mediumUrl || source.thumbnailUrl || url).trim()
|
||||
if (displayUrl) urls.push(displayUrl)
|
||||
}
|
||||
|
||||
for (const rawUrl of imageUrls) {
|
||||
const url = refreshStoredFileUrl(String(rawUrl || '').trim())
|
||||
if (!url) continue
|
||||
const identity = extractObjectKeyFromFileUrl(url) || url
|
||||
if (seenObjects.has(identity)) continue
|
||||
seenObjects.add(identity)
|
||||
urls.push(url)
|
||||
}
|
||||
return urls
|
||||
}
|
||||
|
||||
export async function getOrderServiceByPlatformOrderId(platformOrderIdInput: unknown) {
|
||||
const platformOrderId = normalizeOrderNo(platformOrderIdInput)
|
||||
const orders = await listWorkOrdersByPlatformOrderId(platformOrderId)
|
||||
@@ -361,6 +415,13 @@ async function mapPublicOrderItem(order: WorkOrderRow): Promise<OrderServicePubl
|
||||
const material = safeParseJson(order.material_json)
|
||||
const collect = material.collect && typeof material.collect === 'object' ? material.collect : {}
|
||||
const values = normalizeSubmittedFields(collect.fields || {})
|
||||
const rawAcceptance = safeParseJson(order.acceptance_json)
|
||||
const submittedAt = String(collect.submittedAt || '').trim()
|
||||
const acceptanceSubmittedAt = String(rawAcceptance.submittedAt || '').trim()
|
||||
const acceptanceImageUrls = resolveOrderServiceAcceptanceImageUrls({
|
||||
status: order.status,
|
||||
acceptanceJson: order.acceptance_json,
|
||||
})
|
||||
const screenshots = normalizeUploadedFiles(collect.screenshots || [])
|
||||
.map(refreshUploadedFileUrls)
|
||||
.filter(Boolean)
|
||||
@@ -383,6 +444,10 @@ async function mapPublicOrderItem(order: WorkOrderRow): Promise<OrderServicePubl
|
||||
}),
|
||||
canSubmit: state.canSubmit,
|
||||
blockedReason: state.blockedReason,
|
||||
...(submittedAt ? { submittedAt } : {}),
|
||||
...(acceptanceSubmittedAt ? { acceptanceSubmittedAt } : {}),
|
||||
...(order.accepted_at ? { acceptedAt: String(order.accepted_at) } : {}),
|
||||
...(acceptanceImageUrls.length > 0 ? { acceptanceImageUrls } : {}),
|
||||
...(profile?.materialConfirmation
|
||||
? { materialConfirmation: profile.materialConfirmation }
|
||||
: {}),
|
||||
|
||||
Reference in New Issue
Block a user