diff --git a/apps/frontend/src/components/files/ImagePreviewList.tsx b/apps/frontend/src/components/files/ImagePreviewList.tsx index 72ccacda..87422453 100644 --- a/apps/frontend/src/components/files/ImagePreviewList.tsx +++ b/apps/frontend/src/components/files/ImagePreviewList.tsx @@ -1,6 +1,7 @@ import { Image, Typography } from 'antd' import type { UploadedFile } from '@/types/worker-platform' +import { getImageIdentityFromUrl } from '@/utils/image-identity' type ImagePreviewListProps = { files?: UploadedFile[] @@ -44,15 +45,10 @@ function normalizePreviewItems(files: UploadedFile[], imageUrls: string[]) { mediumUrl: file.mediumUrl || file.url, })) .filter((item) => Boolean(item.url)) - const fileUrlSet = new Set(normalizedFiles.map((item) => getImageIdentity(item.url))) + const fileUrlSet = new Set(normalizedFiles.map((item) => getImageIdentityFromUrl(item.url))) const normalizedUrls = imageUrls .map((url) => String(url || '').trim()) - .filter((url) => url && !fileUrlSet.has(getImageIdentity(url))) + .filter((url) => url && !fileUrlSet.has(getImageIdentityFromUrl(url))) .map((url) => ({ url, thumbnailUrl: url, mediumUrl: url })) return [...normalizedFiles, ...normalizedUrls] } - -/** 忽略临时签名参数,避免同一存储对象重复显示。 */ -function getImageIdentity(value: string) { - return String(value || '').trim().split(/[?#]/, 1)[0] -} diff --git a/apps/frontend/src/components/files/ImageUpload.tsx b/apps/frontend/src/components/files/ImageUpload.tsx index fc9b0f10..0e4039dd 100644 --- a/apps/frontend/src/components/files/ImageUpload.tsx +++ b/apps/frontend/src/components/files/ImageUpload.tsx @@ -89,7 +89,10 @@ export default function ImageUpload({ message.error(error instanceof Error ? error.message : '上传失败') } } - if (next.length > valueRef.current.length) onChange?.(next) + if (next.length > valueRef.current.length) { + valueRef.current = next + onChange?.(next) + } } async function uploadFiles(files: File[]) { @@ -141,7 +144,10 @@ export default function ImageUpload({ const customRequest: UploadProps['customRequest'] = async (options) => { try { const uploaded = await uploadFile(options.file as File, scene, scope) - onChange?.([...value, uploaded].slice(-maxCount)) + // 多文件选择会并发执行 customRequest,必须以 ref 中的最新列表累加,避免后完成的上传覆盖前面的图片。 + const next = [...valueRef.current, uploaded].slice(0, maxCount) + valueRef.current = next + onChange?.(next) options.onSuccess?.(uploaded) } catch (error) { message.error(error instanceof Error ? error.message : '上传失败') @@ -160,14 +166,17 @@ export default function ImageUpload({ > { - onChange?.( - value.filter((item) => (item.objectKey || item.url) !== file.uid), + const next = valueRef.current.filter( + (item) => (item.objectKey || item.url) !== file.uid, ) + valueRef.current = next + onChange?.(next) return true }} showUploadList={{ showPreviewIcon: false }} diff --git a/apps/frontend/src/pages/worker/WorkerOrdersPage.tsx b/apps/frontend/src/pages/worker/WorkerOrdersPage.tsx index fb45a88d..63c35909 100644 --- a/apps/frontend/src/pages/worker/WorkerOrdersPage.tsx +++ b/apps/frontend/src/pages/worker/WorkerOrdersPage.tsx @@ -45,6 +45,7 @@ import type { WorkerAcceptance, } from '@/types/worker-platform' import { formatDateTime } from '@/utils/date-time' +import { getImageIdentity } from '@/utils/image-identity' const STATUS_OPTIONS = [ { value: '', label: '全部订单' }, @@ -169,7 +170,7 @@ export default function WorkerOrdersPage() { ? getWorkerAcceptance(order) : getWorkerDraft(order) setAcceptanceFiles(getUniqueAcceptanceFiles(source)) - form.setFieldsValue({ note: String(source.note || '') }) + form.setFieldsValue({ note: String(source?.note || '') }) setDetailOrder(null) } @@ -263,38 +264,43 @@ export default function WorkerOrdersPage() { const columns: TableColumnsType = [ { title: '订单信息', - minWidth: 280, + width: 270, render: (_, row) => (
- setDetailOrder(row)}> + setDetailOrder(row)} + title={row.productName || row.workOrderNo} + ellipsis + > {row.productName || row.workOrderNo} - - {row.categoryName ? {row.categoryName} : null} + + {row.categoryName ? {row.categoryName} : null} {row.myShare ? 拼单 : null} - - {row.workOrderNo} · {row.platformOrderId || '-'} + + {row.workOrderNo} - - 接单时间:{formatDateTime(row.assignedAt)} + + 接单:{formatDateTime(row.assignedAt)}
), }, { title: '状态', - width: 170, + width: 130, render: (_, row) => (
- + {formatStatus(row.status)} {row.status === 'in_progress' && row.deadlineAt ? ( ) : null} {row.status === 'problem' && String(row.problemNote || '').trim() ? ( - + {row.problemNote} ) : null} @@ -303,16 +309,18 @@ export default function WorkerOrdersPage() { }, { title: '奖励 / 押金', - width: 150, + width: 140, render: (_, row) => (
- {formatMoney(row.rewardAmount)} - - 冻结押金:{formatMoney(row.freezeDepositAmount)} + + {formatMoney(row.rewardAmount)} + + + 押金:{formatMoney(row.freezeDepositAmount)} {row.myShare ? ( - - {row.myShare.quantity} 份 · 份额 {formatMoney(row.myShare.shareReward)} + + {row.myShare.quantity} 份 · {formatMoney(row.myShare.shareReward)} ) : null}
@@ -320,40 +328,38 @@ export default function WorkerOrdersPage() { }, { title: '验收信息', - minWidth: 200, + width: 220, render: (_, row) => { const submittedAt = getAcceptanceSubmittedAt(row) - const hasAcceptance = - getAcceptanceFiles(row).length > 0 || getAcceptanceImageUrls(row).length > 0 - const draftFiles = getDraftFiles(row) - const draftUrls = getDraftImageUrls(row) - const draftCount = draftFiles.length + draftUrls.length + const acceptanceFiles = getUniqueAcceptanceFiles(getWorkerAcceptance(row)) + const hasAcceptance = acceptanceFiles.length > 0 + const draftFiles = getUniqueAcceptanceFiles(getWorkerDraft(row)) + const draftCount = draftFiles.length + if (!hasAcceptance && !submittedAt && draftCount === 0) { - return 未提交 + return 未提交 } return (
{hasAcceptance ? ( - + ) : null} {submittedAt ? ( - - 提交时间:{formatDateTime(submittedAt)} + + 提交:{formatDateTime(submittedAt)} ) : null} {draftCount > 0 && !hasSubmittedAcceptance(row) ? ( - <> - 已暂存 {draftCount} 张图片 - - +
+ }> + 已暂存 {draftCount} 张图片 + + +
) : null} - {getWorkerAcceptance(row).note ? ( - - {getWorkerAcceptance(row).note} + {getWorkerAcceptance(row)?.note ? ( + + {getWorkerAcceptance(row)?.note} ) : null}
@@ -362,7 +368,7 @@ export default function WorkerOrdersPage() { }, { title: '快捷复制', - width: 280, + width: 250, render: (_, row) => { const items = getMaterialDetailItems(row).filter((item) => String(item.value || '').trim(), @@ -372,7 +378,7 @@ export default function WorkerOrdersPage() {
{items.length > 0 ? ( items.map((item) => ( - + {item.label}: {item.value} )) @@ -382,9 +388,9 @@ export default function WorkerOrdersPage() { )} {screenshots.length > 0 ? ( - + ) : null} - + -
- ), + width: 180, + render: (_, row) => { + const note = String(row.workerNote || '').trim() + return ( +
+ {note ? ( +
openNoteModal(row)}> + + {note} + + +
+ ) : ( + + )} +
+ ) + }, }, { title: '操作', - width: 190, + width: 150, render: (_, row) => (
- +