diff --git a/apps/backend/src/repositories/worker-platform/consignment-repo.ts b/apps/backend/src/repositories/worker-platform/consignment-repo.ts index 481af492..98cb210e 100644 --- a/apps/backend/src/repositories/worker-platform/consignment-repo.ts +++ b/apps/backend/src/repositories/worker-platform/consignment-repo.ts @@ -41,6 +41,8 @@ export type ConsignmentInventoryRow = { gift_evidence_json?: string | Record | null gift_work_order_no?: string | null gift_work_order_status?: string | null + gift_phase?: string | null + gift_friend_added_at?: string | null bound_work_order_material_json?: string | Record | null bound_work_order_requirement_json?: string | Record | null worker_id?: string | number | null @@ -197,6 +199,8 @@ export async function listConsignmentInventories(filters: { wo.acceptance_json AS gift_evidence_json, wo.work_order_no AS gift_work_order_no, wo.status AS gift_work_order_status, + wo.gift_phase AS gift_phase, + wo.friend_added_at AS gift_friend_added_at, wo.material_json AS bound_work_order_material_json, wo.requirement_json AS bound_work_order_requirement_json FROM consignment_inventories ci @@ -314,6 +318,8 @@ export async function getConsignmentInventoryById( wo.acceptance_json AS gift_evidence_json, wo.work_order_no AS gift_work_order_no, wo.status AS gift_work_order_status, + wo.gift_phase AS gift_phase, + wo.friend_added_at AS gift_friend_added_at, wo.material_json AS bound_work_order_material_json, wo.requirement_json AS bound_work_order_requirement_json FROM consignment_inventories ci diff --git a/apps/backend/src/repositories/worker-platform/work-order-query-repo.ts b/apps/backend/src/repositories/worker-platform/work-order-query-repo.ts index 9a08fc8e..1b7eade4 100644 --- a/apps/backend/src/repositories/worker-platform/work-order-query-repo.ts +++ b/apps/backend/src/repositories/worker-platform/work-order-query-repo.ts @@ -3,9 +3,14 @@ import type { ListInput, WorkOrderRow, WorkOrderStatistics } from './types.js' import type { PoolClient } from 'pg' import { normalizeWorkOrderAcceptanceMode, + WORK_ORDER_ACCEPTANCE_MODE, WORK_ORDER_GIFT_PHASE, } from '../../domain/work-order-acceptance-mode.js' -import { isPlatformOrderIdLookupKeyword } from '../../utils/platform-order-id.js' +import { + isPlatformOrderIdLookupKeyword, + isWorkOrderNoLookupKeyword, +} from '../../utils/platform-order-id.js' + export const WORK_ORDER_SELECT = ` SELECT wo.*, @@ -843,6 +848,12 @@ export function buildWorkOrderWhere({ filters.push( `(wo.platform_order_id = ${paramIndex} OR wo.platform_order_id LIKE ${paramIndex} || '%')`, ) + } else if (isWorkOrderNoLookupKeyword(normalizedKeyword)) { + params.push(normalizedKeyword) + const paramIndex = `$${params.length}` + filters.push( + `(wo.work_order_no = ${paramIndex} OR wo.work_order_no ILIKE ${paramIndex} || '%' OR LOWER(wo.work_order_no) = LOWER(${paramIndex}))`, + ) } else { params.push(`%${normalizedKeyword}%`) filters.push(`${workOrderSearchExpression()} LIKE LOWER($${params.length})`) @@ -887,11 +898,37 @@ export function buildWorkOrderWhere({ ) } if (acceptanceMode) { - params.push(normalizeWorkOrderAcceptanceMode(acceptanceMode)) - filters.push(`wo.acceptance_mode = $${params.length}`) + const rawMode = String(acceptanceMode).trim() + if (rawMode === 'internal_consignment') { + filters.push(`( + wo.material_json->'consignment'->>'inventoryId' IS NOT NULL + AND (wo.material_json->'consignment'->>'fulfillmentType' IS NULL OR wo.material_json->'consignment'->>'fulfillmentType' != 'worker_deposit') + AND (wo.material_json->'consignment'->>'workerId' IS NULL OR wo.material_json->'consignment'->>'workerId' = '0') + AND (wo.assigned_worker_id IS NULL OR wo.assigned_worker_id = 0) + )`) + } else if (rawMode === WORK_ORDER_ACCEPTANCE_MODE.FRIEND_GIFT) { + filters.push(`( + wo.acceptance_mode = 'friend_gift' + AND NOT ( + wo.material_json->'consignment'->>'inventoryId' IS NOT NULL + AND (wo.material_json->'consignment'->>'fulfillmentType' IS NULL OR wo.material_json->'consignment'->>'fulfillmentType' != 'worker_deposit') + AND (wo.material_json->'consignment'->>'workerId' IS NULL OR wo.material_json->'consignment'->>'workerId' = '0') + AND (wo.assigned_worker_id IS NULL OR wo.assigned_worker_id = 0) + ) + )`) + } else if (rawMode === WORK_ORDER_ACCEPTANCE_MODE.STANDARD) { + filters.push(`( + wo.acceptance_mode = 'standard' + AND wo.material_json->'consignment'->>'inventoryId' IS NULL + )`) + } else { + params.push(normalizeWorkOrderAcceptanceMode(acceptanceMode)) + filters.push(`wo.acceptance_mode = $${params.length}`) + } } if (giftPhase) { const normalizedGiftPhase = String(giftPhase).trim() + const activeGiftStatusSql = `wo.status NOT IN ('accepted', 'cancelled')` if (normalizedGiftPhase === WORK_ORDER_GIFT_PHASE.GIFT_READY) { // gift_ready 是冷却到点后的实时阶段,由时间条件计算而不是落库状态。 filters.push(`( @@ -899,10 +936,18 @@ export function buildWorkOrderWhere({ AND wo.gift_phase = 'friend_countdown' AND wo.gift_available_at IS NOT NULL AND wo.gift_available_at <= NOW() + AND ${activeGiftStatusSql} + )`) + } else if (normalizedGiftPhase === WORK_ORDER_GIFT_PHASE.FRIEND_COUNTDOWN) { + filters.push(`( + wo.acceptance_mode = 'friend_gift' + AND wo.gift_phase = 'friend_countdown' + AND (wo.gift_available_at IS NULL OR wo.gift_available_at > NOW()) + AND ${activeGiftStatusSql} )`) } else if (Object.values(WORK_ORDER_GIFT_PHASE).includes(normalizedGiftPhase as never)) { params.push(normalizedGiftPhase) - const giftPhaseFilter = `wo.acceptance_mode = 'friend_gift' AND wo.gift_phase = $${params.length}` + const giftPhaseFilter = `wo.acceptance_mode = 'friend_gift' AND wo.gift_phase = $${params.length} AND ${activeGiftStatusSql}` // 待打手提交资料仅代表已接单后的赠送流程;待抢单/未分配模板单不应混入该筛选。 filters.push( normalizedGiftPhase === WORK_ORDER_GIFT_PHASE.MATERIAL_REQUIRED diff --git a/apps/backend/src/services/worker-platform/consignment-admin-service.ts b/apps/backend/src/services/worker-platform/consignment-admin-service.ts index 70ad37fe..8aaa081b 100644 --- a/apps/backend/src/services/worker-platform/consignment-admin-service.ts +++ b/apps/backend/src/services/worker-platform/consignment-admin-service.ts @@ -110,6 +110,8 @@ function mapConsignmentEvidence(source: { gift_evidence_json?: string | Record | null gift_work_order_no?: string | null gift_work_order_status?: string | null + gift_phase?: string | null + gift_friend_added_at?: string | null }) { const acceptance = toRecord(source.gift_evidence_json) const files = Array.isArray(acceptance?.files) ? (acceptance.files as unknown[]) : [] @@ -146,6 +148,8 @@ function mapConsignmentEvidence(source: { giftEvidenceSubmittedAt: String(acceptance?.submittedAt || ''), giftWorkOrderNo: source.gift_work_order_no || '', giftWorkOrderStatus: workOrderStatus, + giftPhase: source.gift_phase || '', + giftFriendAddedAt: source.gift_friend_added_at || '', /** none=还没交 / pending=交了待客服验收 / accepted=客服已验收 / submitted=其他在途状态 */ giftEvidenceReviewStatus: reviewStatus, } diff --git a/apps/backend/src/services/worker-platform/worker-platform-service.test.ts b/apps/backend/src/services/worker-platform/worker-platform-service.test.ts index f0fdfbfe..d75ebe85 100644 --- a/apps/backend/src/services/worker-platform/worker-platform-service.test.ts +++ b/apps/backend/src/services/worker-platform/worker-platform-service.test.ts @@ -1635,6 +1635,25 @@ test('好友赠送待打手提交资料筛选排除待抢单订单', () => { assert.match(whereClause, /wo\.status IN \('in_progress', 'problem'\)/) }) +test('工单筛选支持内部寄售匹配与打手好友赠送隔离,且赠送冷却中排除已验收已取消工单', () => { + const internalQuery = buildWorkOrderWhere({ acceptanceMode: 'internal_consignment' }) + assert.match(internalQuery.whereClause, /wo\.material_json->'consignment'->>'inventoryId' IS NOT NULL/) + assert.match(internalQuery.whereClause, /wo\.assigned_worker_id IS NULL OR wo\.assigned_worker_id = 0/) + + const friendGiftQuery = buildWorkOrderWhere({ acceptanceMode: 'friend_gift' }) + assert.match(friendGiftQuery.whereClause, /wo\.acceptance_mode = 'friend_gift'/) + assert.match(friendGiftQuery.whereClause, /NOT \(/) + + const countdownQuery = buildWorkOrderWhere({ giftPhase: 'friend_countdown' }) + assert.match(countdownQuery.whereClause, /wo\.gift_phase = 'friend_countdown'/) + assert.match(countdownQuery.whereClause, /wo\.gift_available_at > NOW\(\)/) + assert.match(countdownQuery.whereClause, /wo\.status NOT IN \('accepted', 'cancelled'\)/) + + const readyQuery = buildWorkOrderWhere({ giftPhase: 'gift_ready' }) + assert.match(readyQuery.whereClause, /wo\.gift_available_at <= NOW\(\)/) + assert.match(readyQuery.whereClause, /wo\.status NOT IN \('accepted', 'cancelled'\)/) +}) + test('好友赠送冷却中才允许客服手动结束冷却', () => { const cooling = mapWorkOrderAdmin( buildWorkOrderRow({ diff --git a/apps/backend/src/utils/platform-order-id.test.ts b/apps/backend/src/utils/platform-order-id.test.ts index 9a1870e8..4c8b5fdb 100644 --- a/apps/backend/src/utils/platform-order-id.test.ts +++ b/apps/backend/src/utils/platform-order-id.test.ts @@ -1,7 +1,10 @@ import assert from 'node:assert/strict' import test from 'node:test' -import { isPlatformOrderIdLookupKeyword } from './platform-order-id.js' +import { + isPlatformOrderIdLookupKeyword, + isWorkOrderNoLookupKeyword, +} from './platform-order-id.js' test('识别纯数字平台订单号', () => { assert.equal(isPlatformOrderIdLookupKeyword('20247230034021572'), true) @@ -14,9 +17,19 @@ test('识别拼多多带连字符的 order_sn', () => { assert.equal(isPlatformOrderIdLookupKeyword('260912-123456789012345'), true) }) +test('识别统一内部工单号 (WO...)', () => { + assert.equal(isWorkOrderNoLookupKeyword('WOb320ee0b39b9'), true) + assert.equal(isWorkOrderNoLookupKeyword('wob320ee0b39b9'), true) + assert.equal(isWorkOrderNoLookupKeyword('WO26091216358821'), true) + assert.equal(isWorkOrderNoLookupKeyword('WO12'), false) + assert.equal(isWorkOrderNoLookupKeyword('20247230034021572'), false) +}) + test('拒绝普通关键词', () => { assert.equal(isPlatformOrderIdLookupKeyword('皮肤店'), false) assert.equal(isPlatformOrderIdLookupKeyword('安卓怒嚎3钻'), false) assert.equal(isPlatformOrderIdLookupKeyword('DT881aa66294cc'), false) assert.equal(isPlatformOrderIdLookupKeyword(''), false) + assert.equal(isWorkOrderNoLookupKeyword('皮肤店'), false) }) + diff --git a/apps/backend/src/utils/platform-order-id.ts b/apps/backend/src/utils/platform-order-id.ts index 2ca55447..9169bc09 100644 --- a/apps/backend/src/utils/platform-order-id.ts +++ b/apps/backend/src/utils/platform-order-id.ts @@ -6,3 +6,12 @@ export function isPlatformOrderIdLookupKeyword(value: unknown): boolean { const trimmed = String(value || '').trim() return /^\d{6,}(-\d{6,})?$/.test(trimmed) } + +/** + * 识别内部统一工单号 (以 WO 开头且至少 4 位字符,如 WOb320ee0b39b9、WO26091216358821)。 + */ +export function isWorkOrderNoLookupKeyword(value: unknown): boolean { + const trimmed = String(value || '').trim() + return /^WO[0-9a-zA-Z]{4,}$/i.test(trimmed) +} + diff --git a/apps/frontend/src/pages/admin/AdminWorkerPlatformPage.tsx b/apps/frontend/src/pages/admin/AdminWorkerPlatformPage.tsx index ce8f5703..b27364eb 100644 --- a/apps/frontend/src/pages/admin/AdminWorkerPlatformPage.tsx +++ b/apps/frontend/src/pages/admin/AdminWorkerPlatformPage.tsx @@ -1,4 +1,4 @@ -import { useQuery } from '@tanstack/react-query' +import { useQuery, useQueryClient } from '@tanstack/react-query' import { Card, Space, Tabs } from 'antd' import { useEffect, useRef, useState } from 'react' import { useLocation, useSearchParams } from 'react-router' @@ -27,7 +27,30 @@ type AfterSalesLocationState = { createOrder?: WorkOrder } +const TAB_QUERY_KEYS: Record = { + 'consignment-inventory': [['admin-consignment-inventories'], ['admin-consignment-stats']], + 'consignment-submissions': [ + ['admin-consignment-submissions'], + ['admin-consignment-submissions-pending-total'], + ], + orders: [['admin-work-orders'], ['admin-work-orders-stats']], + 'cancel-requests': [['admin-work-order-cancel-requests']], + 'after-sales': [['admin-after-sales-orders'], ['admin-after-sales-stats']], + feedbacks: [['admin-feedbacks']], + rules: [['admin-product-rules']], + 'product-match': [['admin-product-match']], + categories: [['admin-categories']], + workers: [['admin-workers'], ['admin-worker-users']], + leaderboard: [['admin-leaderboard']], + finance: [['admin-finance-settlements'], ['admin-finance-withdrawals']], + levels: [['admin-worker-levels']], + notifications: [['admin-notifications']], + announcement: [['admin-announcements']], + 'hall-config': [['admin-hall-config']], +} + export default function AdminWorkerPlatformPage() { + const queryClient = useQueryClient() const [searchParams, setSearchParams] = useSearchParams() const location = useLocation() const [activeTab, setActiveTab] = useState(() => loadActiveTab(searchParams.get('tab'))) @@ -49,6 +72,18 @@ export default function AdminWorkerPlatformPage() { ? 'orders' : activeTab + // 切换标签页时自动刷新对应标签页的查询数据,确保切入即为最新状态 + useEffect(() => { + if (!visibleActiveTab) return + const queries = TAB_QUERY_KEYS[visibleActiveTab] + if (queries) { + queries.forEach((queryKey) => { + void queryClient.invalidateQueries({ queryKey }) + }) + } + void queryClient.invalidateQueries({ queryKey: ['admin-worker-platform-summary'] }) + }, [visibleActiveTab, queryClient]) + useEffect(() => { const tab = searchParams.get('tab') if (isWorkerPlatformTab(tab)) { diff --git a/apps/frontend/src/pages/admin/panels/ConsignmentInventoryPanel.tsx b/apps/frontend/src/pages/admin/panels/ConsignmentInventoryPanel.tsx index ba3010ae..582bffd6 100644 --- a/apps/frontend/src/pages/admin/panels/ConsignmentInventoryPanel.tsx +++ b/apps/frontend/src/pages/admin/panels/ConsignmentInventoryPanel.tsx @@ -331,6 +331,31 @@ export default function ConsignmentInventoryPanel() { {resolveConsignmentNo(record)} + {record.giftWorkOrderNo ? ( +
+ + + 关联工单 + + + {record.giftWorkOrderNo} + + {record.giftWorkOrderStatus ? ( + + {formatGiftWorkOrderStatus(record.giftWorkOrderStatus)} + + ) : null} + +
+ ) : null}
{record.sourceType === 'worker_portal' ? ( @@ -510,8 +535,18 @@ export default function ConsignmentInventoryPanel() { return ( + {record.giftWorkOrderNo ? ( + + + 工单: + + + {record.giftWorkOrderNo} + + + ) : null} {record.boundPlatformOrderId ? ( - + {record.boundPlatformOrderId} ) : null} @@ -601,6 +636,8 @@ export default function ConsignmentInventoryPanel() { ) : null} {record.status === 'consumed' && canManageConsignment && + !record.giftFriendAddedAt && + (!record.giftPhase || record.giftPhase === 'material_required') && record.giftEvidenceReviewStatus !== 'accepted' && record.giftWorkOrderStatus !== 'accepted' ? (
+ } open={Boolean(approveModalItem)} - width={680} + width={760} + style={{ top: 24 }} + bodyStyle={{ maxHeight: 'calc(86vh - 120px)', overflowY: 'auto', paddingRight: 8 }} onCancel={() => setApproveModalItem(null)} onOk={handleApproveSubmit} confirmLoading={approving} @@ -478,73 +486,186 @@ export default function ConsignmentSubmissionsPanel() { okType="primary" destroyOnClose > -
- - 提报人联系方式:{approveModalItem?.contactInfo} | 游戏ID: - {approveModalItem?.sellerGameId || '-'} | 卖家要价: - - ¥{((approveModalItem?.askingPriceFen || 0) / 100).toFixed(2)} - - + {/* 顶部提报概览卡片 */} +
+
+
+ + + 单号:{approveModalItem?.submissionNo} + + {approveModalItem?.workerName ? ( + 打手提报: {approveModalItem.workerName} + ) : ( + 卖家自主提报 + )} + {approveModalItem?.createdAt ? ( + + 提报于 {formatDateTime(approveModalItem.createdAt)} + + ) : null} + +
+ + 联系方式:{approveModalItem?.contactInfo || '-'} + + + 游戏ID:{approveModalItem?.sellerGameId || '-'} + + {approveModalItem?.sellerPaymentInfo ? ( + + 提报收款:{approveModalItem.sellerPaymentInfo} + + ) : null} +
+
+
+
卖家提报要价
+
+ ¥{((approveModalItem?.askingPriceFen || 0) / 100).toFixed(2)} +
+
+
+ + {/* 提报截图快速直览 */} + {approveModalItem?.screenshotsJson && approveModalItem.screenshotsJson.length > 0 ? ( +
+ + 商品截图 ({approveModalItem.screenshotsJson.length}张): + + +
+ ) : null}
- - + {/* 分组一:物品与规格 */} +
+
+ 物品属性与收购成本 +
+ + + - + - + - + - + - - {/* 审核可修正规格:与打手端发布同一套选项(苹果/安卓;微信/QQ/互通) */} + - - - - - - - + + - + + + + + + - + {/* 分组二:履约与打手 */} +
+
+ 履约模式与打手关联 (选填) +
+ + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - + {/* 分组四:审核备注 */} + + diff --git a/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx b/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx index 14db82af..2a119018 100644 --- a/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx +++ b/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx @@ -415,6 +415,17 @@ export default function WorkOrdersPanel() { }), }) const ordersPagination = ordersQuery.data?.data.pagination + + // 当列表重新拉取最新数据后,若详情抽屉正处于打开状态,自动用最新状态同步更新 detailOrder + useEffect(() => { + if (!detailOrder) return + const items = ordersQuery.data?.data.items || [] + const updated = items.find((item) => item.workOrderId === detailOrder.workOrderId) + if (updated) { + setDetailOrder(updated) + } + }, [ordersQuery.data]) + const categoriesQuery = useQuery({ queryKey: ['admin-worker-platform-categories'], queryFn: () => fetchAdminWorkCategories(), @@ -518,7 +529,9 @@ export default function WorkOrdersPanel() { }, [showWorkerLevelFilter]) useEffect(() => { - if (acceptanceMode !== 'friend_gift') setGiftPhase(undefined) + if (acceptanceMode !== 'friend_gift' && acceptanceMode !== 'internal_consignment') { + setGiftPhase(undefined) + } }, [acceptanceMode]) function openAssignModal(row: WorkOrder) { @@ -680,6 +693,12 @@ export default function WorkOrdersPanel() { queryClient.invalidateQueries({ queryKey: ['admin-worker-platform-summary'], }), + queryClient.invalidateQueries({ + queryKey: ['admin-consignment-inventories'], + }), + queryClient.invalidateQueries({ + queryKey: ['admin-consignment-stats'], + }), ]) } @@ -1008,9 +1027,26 @@ export default function WorkOrdersPanel() { setMaterialScreenshots([]) } + function isExplicitOrderNoSearch(text: string) { + const trimmed = text.trim() + if (!trimmed) return false + return ( + /^WO[0-9a-zA-Z]{4,}$/i.test(trimmed) || + /^\d{6,}(-\d{6,})?$/.test(trimmed) || + /^OD[0-9a-zA-Z]{4,}$/i.test(trimmed) + ) + } + function searchOrders() { - setKeyword(keywordInput.trim()) + const trimmed = keywordInput.trim() + setKeyword(trimmed) setPage(1) + // 管理员精准搜索工单号/平台单号时,自动清除排他的状态与阶段限制,避免状态流转后工单从视野中消失 + if (isExplicitOrderNoSearch(trimmed)) { + if (giftPhase) setGiftPhase(undefined) + if (statuses.length > 0) setStatuses([]) + if (acceptanceMode) setAcceptanceMode(undefined) + } } function clearOrderFilters() { @@ -1395,8 +1431,14 @@ export default function WorkOrdersPanel() { 置顶 ) : null} - {row.acceptanceMode === 'friend_gift' ? 好友赠送 : null} - {row.acceptanceMode === 'friend_gift' && + {isInternalConsignmentOrder(row) ? ( + 内部匹配 + ) : row.acceptanceMode === 'friend_gift' ? ( + 好友赠送 + ) : null} + {row.status !== 'accepted' && + row.status !== 'cancelled' && + row.acceptanceMode === 'friend_gift' && row.gift && (!['pending_material', 'unassigned', 'open'].includes(row.rawStatus || row.status) || isInternalConsignmentOrder(row)) ? ( @@ -1682,9 +1724,16 @@ export default function WorkOrdersPanel() { setKeywordInput(event.target.value)} + onChange={(event) => { + const nextVal = event.target.value + setKeywordInput(nextVal) + if (!nextVal.trim()) { + setKeyword('') + setPage(1) + } + }} onPressEnter={searchOrders} /> ({ value: phase, - label: {formatGiftPhase(phase)}, + label: ( + + {formatGiftPhase(phase, acceptanceMode === 'internal_consignment')} + + ), }))} onChange={(nextPhase) => { setGiftPhase(nextPhase) @@ -2041,11 +2095,17 @@ export default function WorkOrdersPanel() { {detailOrder.acceptanceMode === 'friend_gift' && detailOrder.gift ? ( - {formatAcceptanceMode(detailOrder.acceptanceMode)} + {isInternalConsignmentOrder(detailOrder) ? ( + 内部寄售匹配 + ) : ( + {formatAcceptanceMode(detailOrder.acceptanceMode)} + )} {formatGiftPhase( detailOrder.gift.phase, diff --git a/apps/frontend/src/pages/worker/WorkerConsignmentPage.tsx b/apps/frontend/src/pages/worker/WorkerConsignmentPage.tsx index d03b4957..6b006664 100644 --- a/apps/frontend/src/pages/worker/WorkerConsignmentPage.tsx +++ b/apps/frontend/src/pages/worker/WorkerConsignmentPage.tsx @@ -12,7 +12,7 @@ import { SafetyCertificateOutlined, UserOutlined, } from '@ant-design/icons' -import { useQuery } from '@tanstack/react-query' +import { useQuery, useQueryClient } from '@tanstack/react-query' import { Alert, App, @@ -101,6 +101,8 @@ export default function WorkerConsignmentPage() { const priceFetchTimer = useRef | null>(null) const lastPriceQueryKeyRef = useRef('') + const queryClient = useQueryClient() + const profileQuery = useQuery({ queryKey: ['worker-profile'], queryFn: () => fetchWorkerProfile(), @@ -114,6 +116,14 @@ export default function WorkerConsignmentPage() { queryFn: () => fetchWorkerConsignments(), }) + // 切换标签页时自动刷新最新数据 + useEffect(() => { + if (activeTab === 'records') { + void queryClient.invalidateQueries({ queryKey: ['worker-my-consignments'] }) + } + void queryClient.invalidateQueries({ queryKey: ['worker-profile'] }) + }, [activeTab, queryClient]) + // 后端已按「一件货一行」聚合,前端不再合并提报单与库存 const records = myConsignmentsQuery.data?.data.items || [] const stageCounts = myConsignmentsQuery.data?.data.stageCounts || {} @@ -1104,10 +1114,37 @@ function ConsignmentRecordCard({ ) : null} {shots.length > 0 || giftShots.length > 0 ? ( -
+
{shots.length > 0 ? ( -
- +
+ 商品截图({shots.length}) @@ -1127,8 +1164,28 @@ function ConsignmentRecordCard({
) : null} {giftShots.length > 0 ? ( -
- +
+ 赠送凭证({giftShots.length}) @@ -1146,7 +1203,11 @@ function ConsignmentRecordCard({ {record.giftEvidenceNote ? ( - + {record.giftEvidenceNote} ) : null} diff --git a/apps/frontend/src/types/consignment.ts b/apps/frontend/src/types/consignment.ts index b7f0403a..8092d732 100644 --- a/apps/frontend/src/types/consignment.ts +++ b/apps/frontend/src/types/consignment.ts @@ -26,6 +26,10 @@ export type ConsignmentEvidenceFields = { giftWorkOrderNo?: string /** 关联工单状态:in_progress / pending_acceptance / accepted 等 */ giftWorkOrderStatus?: string + /** 关联工单赠送阶段:material_required / material_submitted / friend_countdown / gift_ready 等 */ + giftPhase?: string + /** 关联工单确认加好友时间(ISO 字符串,为空代表尚未确认加好友) */ + giftFriendAddedAt?: string /** 赠送凭证的客服验收状态 */ giftEvidenceReviewStatus?: GiftEvidenceReviewStatus }