import { Descriptions, Space, Tag, Typography } from 'antd' import ImagePreviewList from '@/components/files/ImagePreviewList' import { DeadlineCountdown, formatTimeoutPolicyLabel } from '@/components/DeadlineCountdown' import type { CollectField, UploadedFile, WorkOrder } from '@/types/worker-platform' export { DeadlineCountdown, formatTimeoutPolicyLabel } type MappedRequirementField = { key: string label: string required: boolean type: 'text' | 'select' options: string[] } export function getRequirementFields(order: WorkOrder | null): CollectField[] { if (!order) return [] const rawFields = Array.isArray(order.requirement?.fields) ? order.requirement.fields : [] return rawFields .map((item) => { const source = asRecord(item) const key = String(source.key || '').trim() if (!key) return null return { key, label: String(source.label || key).trim(), required: source.required !== false, type: source.type === 'select' ? ('select' as const) : ('text' as const), options: Array.isArray(source.options) ? source.options.map((option) => String(option || '').trim()).filter(Boolean) : [], } }) .filter((item): item is MappedRequirementField => Boolean(item)) } export type DetailFieldItem = { key: string label: string required: boolean value: string } export function getMaterialFields(order: WorkOrder): Record { const material = asRecord(order.material) const collect = asRecord(material.collect) const fields = asRecord(collect.fields || material.fields) return Object.fromEntries( Object.entries(fields).map(([key, value]) => [key, String(value || '')]), ) } export function getMaterialDetailItems(order: WorkOrder): DetailFieldItem[] { const values = getMaterialFields(order) const requiredFields = getRequirementFields(order) const usedKeys = new Set() const items = requiredFields.map((field) => { usedKeys.add(field.key) return { key: field.key, label: field.label, required: field.required, value: String(values[field.key] || ''), } }) Object.entries(values).forEach(([key, value]) => { if (usedKeys.has(key)) return items.push({ key, label: key, required: false, value: String(value || ''), }) }) return items } export function renderDetailFieldValues(items: DetailFieldItem[], emptyText: string) { if (items.length === 0) { return {emptyText} } return ( {items.map((item) => ( {item.label} {item.required ? 必填 : null} } > {String(item.value || '').trim() || '-'} ))} ) } export function renderRequirementFieldValues(order: WorkOrder) { const fields = getRequirementFields(order) if (fields.length === 0) { return 当前工单未配置资料要求 } return ( {fields.map((field) => ( {field.key} {field.required ? '必填' : '选填'} ))} ) } export function renderMaterialSummary(order: WorkOrder) { const fieldLabelMap = new Map( getRequirementFields(order).map((field) => [field.key, field.label]), ) const fields = getMaterialFields(order) const entries = Object.entries(fields).filter(([, value]) => String(value || '').trim()) const screenshots = getMaterialScreenshots(order) if (entries.length === 0 && screenshots.length === 0) { return - } return (
{entries.map(([key, value]) => ( {fieldLabelMap.get(key) || key}: {value} ))} {screenshots.length > 0 ? : null}
) } export function getAcceptanceFiles(row: WorkOrder): UploadedFile[] { return Array.isArray(row.acceptance?.files) ? row.acceptance.files : [] } export function getAcceptanceImageUrls(row: WorkOrder): string[] { return Array.isArray(row.acceptance?.imageUrls) ? row.acceptance.imageUrls.map((item) => String(item || '').trim()).filter(Boolean) : [] } export function getAcceptanceSubmittedAt(order: WorkOrder): string | null { const acceptanceSubmittedAt = typeof order.acceptance?.submittedAt === 'string' ? order.acceptance.submittedAt : null return order.submittedAt || acceptanceSubmittedAt || null } export function getMaterialScreenshots(order: WorkOrder): UploadedFile[] { const material = asRecord(order.material) const collect = asRecord(material.collect) const screenshots = Array.isArray(collect.screenshots) ? collect.screenshots : [] return screenshots .map((item) => { const file = asRecord(item) const url = String(file.url || '').trim() if (!url) return null return { objectKey: String(file.objectKey || file.object_key || '').trim(), filename: String(file.originalFilename || file.filename || '').trim(), url, mediumUrl: String(file.mediumUrl || file.medium_url || '').trim(), thumbnailUrl: String(file.thumbnailUrl || file.thumbnail_url || '').trim(), } as UploadedFile }) .filter((item): item is UploadedFile => Boolean(item)) } export function asRecord(value: unknown): Record { return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record) : {} } export function formatMoney(value: number | undefined) { return `¥${((Number(value || 0) || 0) / 100).toFixed(2)}` } export function formatStatus(status: string) { const labels: Record = { pending_material: '待完善', unassigned: '未分配', open: '待抢单', in_progress: '代练中', pending_acceptance: '待验收', problem: '问题单', vip_evidence_pending: '待补图', accepted: '已验收', cancelled: '已取消', } return labels[status] || status } export function resolveStatusColor(status: string) { const colors: Record = { pending_material: 'orange', unassigned: 'cyan', open: 'blue', in_progress: 'geekblue', pending_acceptance: 'purple', problem: 'red', vip_evidence_pending: 'gold', accepted: 'green', cancelled: 'default', } return colors[status] || 'default' } export function formatWorkerStatus(status: string) { const labels: Record = { pending_review: '待处理', active: '已启用', rejected: '已冻结', disabled: '已停用', } return labels[status] || status } export function formatSharingShareStatus(status: string) { const labels: Record = { joined: '已参与', submitted: '已提交验收', accepted: '已验收', cancelled: '已取消', } return labels[status] || status } export function resolveSharingShareStatusColor(status: string) { if (status === 'accepted') return 'green' if (status === 'submitted') return 'gold' if (status === 'cancelled') return 'default' return 'purple' }