feat(consignment): 客服端凭证链可视化(提报凭证 + 赠送凭证)

问题:一件寄卖有两类凭证,客服界面只看得见第一类,还是 48x48 一张缩略图,
看不出是主页还是物品;第二类(证明"这件货真送出去了"的赠送完成截图)只在工单验收界面,
客服要证明赠送是否完成得自己跨模块翻,没有任何地方把两类凭证并排呈现。

- 两类凭证分别在哪里:
  提报凭证 = 提报表 screenshots_json(卖家提报时的游戏主页截图,含物品/仓库详情)
  赠送凭证 = 绑定工单的验收资料 work_orders.acceptance_json(冷却结束后上传、客服凭此验收)
- 后端把凭证链从客服两个列表/详情接口一起下发:提报表/库存 → 结果库存 → 绑定工单,
  新增 submissionScreenshots / giftEvidenceImages / giftEvidenceNote / giftEvidenceSubmittedAt /
  giftWorkOrderNo / giftWorkOrderStatus / giftEvidenceReviewStatus(none|pending|accepted|submitted);
  赠送凭证图从 imageUrls 与 files[].url|mediumUrl|thumbnailUrl 两处取并去重
- 提报凭证口径统一:有来源提报单用提报单主页截图,客服手工入库现货回退库存自身截图,
  前端只看 submissionScreenshots 一个字段,不会拿错
- 前端新增共享组件 ConsignmentEvidenceGallery(缩略图 + 大图预览 + 共 N 张,
  预览用 Image.PreviewGroup items,被折叠的图在大图里仍能翻看);审核面板把「凭据截图」
  拆成「提报凭证(游戏主页截图)」与「赠送凭证」(带待验收/已验收 Tag + 关联工单 Tooltip),
  仓库面板新增「凭证」列并分组展示,两个详情弹窗同口径(含备注/提交时间/工单号/一句话说明)

真实库验证:赠送凭证解析在构造的工单验收资料上取到 3 张图(imageUrls 1 + files 2)并识别
pending_acceptance → 待客服验收;提报凭证在真实数据上取到 1 张。临时数据已清理。
This commit is contained in:
yml2213
2026-09-17 11:22:59 +08:00
parent 44de11a3a7
commit ca04e09deb
10 changed files with 849 additions and 41 deletions
@@ -35,6 +35,12 @@ export type ConsignmentInventoryRow = {
source_submission_id: string | number | null
/** 唯一锚点:来源提报单号(客服手工入库的现货没有) */
source_submission_no?: string | null
/** 提报凭证(卖家提报时上传的物品/主页截图) */
submission_screenshots_json?: string | unknown[] | null
/** 赠送凭证:冷却结束后上传的赠送完成截图(存在绑定工单的验收资料里) */
gift_evidence_json?: string | Record<string, unknown> | null
gift_work_order_no?: string | null
gift_work_order_status?: string | null
worker_id?: string | number | null
worker_name?: string
worker_phone?: string
@@ -74,6 +80,10 @@ export type ConsignmentSubmissionRow = {
reviewer_name: string
reviewed_at: string | null
result_inventory_id: string | number | null
/** 赠送凭证:履约方冷却结束后上传的赠送完成截图(存在绑定工单的验收资料里) */
gift_evidence_json?: string | Record<string, unknown> | null
gift_work_order_no?: string | null
gift_work_order_status?: string | null
created_at: string
updated_at: string
category_name?: string
@@ -180,10 +190,15 @@ export async function listConsignmentInventories(filters: {
SELECT
ci.*,
wc.name AS category_name,
cs.submission_no AS source_submission_no
cs.submission_no AS source_submission_no,
cs.screenshots_json AS submission_screenshots_json,
wo.acceptance_json AS gift_evidence_json,
wo.work_order_no AS gift_work_order_no,
wo.status AS gift_work_order_status
FROM consignment_inventories ci
LEFT JOIN work_categories wc ON wc.id = ci.category_id
LEFT JOIN consignment_submissions cs ON cs.id = ci.source_submission_id
LEFT JOIN work_orders wo ON wo.id = ci.bound_work_order_id
${whereClause}
ORDER BY ci.id DESC
LIMIT $${values.length - 1} OFFSET $${values.length}
@@ -290,10 +305,15 @@ export async function getConsignmentInventoryById(
SELECT
ci.*,
wc.name AS category_name,
cs.submission_no AS source_submission_no
cs.submission_no AS source_submission_no,
cs.screenshots_json AS submission_screenshots_json,
wo.acceptance_json AS gift_evidence_json,
wo.work_order_no AS gift_work_order_no,
wo.status AS gift_work_order_status
FROM consignment_inventories ci
LEFT JOIN work_categories wc ON wc.id = ci.category_id
LEFT JOIN consignment_submissions cs ON cs.id = ci.source_submission_id
LEFT JOIN work_orders wo ON wo.id = ci.bound_work_order_id
WHERE ci.id = $1
LIMIT 1
`
@@ -941,12 +961,18 @@ export async function listConsignmentSubmissions(filters: {
const offset = (page - 1) * pageSize
values.push(pageSize, offset)
// 赠送凭证存在绑定工单的验收资料里:提报行 → 结果库存 → 绑定工单
const listSql = `
SELECT
cs.*,
wc.name AS category_name
wc.name AS category_name,
wo.acceptance_json AS gift_evidence_json,
wo.work_order_no AS gift_work_order_no,
wo.status AS gift_work_order_status
FROM consignment_submissions cs
LEFT JOIN work_categories wc ON wc.id = cs.category_id
LEFT JOIN consignment_inventories rinv ON rinv.id = cs.result_inventory_id
LEFT JOIN work_orders wo ON wo.id = rinv.bound_work_order_id
${whereClause}
ORDER BY cs.id DESC
LIMIT $${values.length - 1} OFFSET $${values.length}