diff --git a/apps/backend/src/config/env-documentation.test.ts b/apps/backend/src/config/env-documentation.test.ts index 0d1510ae..f79a4e8a 100644 --- a/apps/backend/src/config/env-documentation.test.ts +++ b/apps/backend/src/config/env-documentation.test.ts @@ -8,7 +8,7 @@ import { ENV_OVERRIDES } from './env-overrides.js' const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url)) const BACKEND_ROOT = path.resolve(CURRENT_DIR, '../..') -const WORKSPACE_ROOT = path.resolve(BACKEND_ROOT, '../..') +const WORKSPACE_ROOT = process.env.WORKSPACE_ROOT || path.resolve(BACKEND_ROOT, '../..') const SPECIAL_RUNTIME_ENV_NAMES = ['APP_BASE_URL', 'CLAIM_BASE_URL'] @@ -31,6 +31,7 @@ const DEPLOYMENT_ONLY_ENV_NAMES = [ 'VITE_API_TARGET', 'VITE_ALLOWED_HOSTS', 'VITE_WORKER_SITE_URL', + 'WORKSPACE_ROOT', 'WORKER_SITE_ADDR', ] 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 0f5d4a87..ab4709ca 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 @@ -10,6 +10,7 @@ import type { WorkerUserRow, } from '../../repositories/worker-platform/index.js' import { + buildWorkOrderWhere, resolveWorkOrderShareCancellationStatus, resolveWorkOrderShareJoinQuantity, resolveOpenSharingSyncReward, @@ -36,6 +37,7 @@ import { resolveSkuNameQuantity, resolveWorkOrderRulePricing, resolveWorkOrderTemplateSyncPrice, + resolveWorkerShareStatus, resolveWorkOrderSharingEnabled, validateWorkerPassword, } from './index.js' @@ -817,6 +819,29 @@ test('mapWorkOrderForWorker 使用个人拼单份数、金额、状态和接单 assert.equal(mapped.assignedAt, '2026-08-18T09:09:08.000Z') }) +test('打手拼单状态以个人份额为准,母工单终态优先', () => { + assert.equal(resolveWorkerShareStatus('open', 'joined'), 'in_progress') + assert.equal(resolveWorkerShareStatus('open', 'submitted'), 'pending_acceptance') + assert.equal(resolveWorkerShareStatus('open', 'accepted'), 'accepted') + assert.equal(resolveWorkerShareStatus('open', 'cancelled'), 'cancelled') + assert.equal(resolveWorkerShareStatus('problem', 'joined'), 'problem') +}) + +test('打手订单状态筛选使用个人拼单份额状态', () => { + const { joins, whereClause, params } = buildWorkOrderWhere({ + workerSharingId: 42, + statuses: ['in_progress', 'pending_acceptance'], + }) + + assert.deepEqual(params, [42, ['in_progress', 'pending_acceptance']]) + assert.match(joins, /work_order_shares share_source/) + assert.match(joins, /worker_share\.worker_id = \$1/) + assert.match(whereClause, /WHEN 'joined' THEN 'in_progress'/) + assert.match(whereClause, /WHEN 'submitted' THEN 'pending_acceptance'/) + assert.match(whereClause, /worker_share\.status/) + assert.match(whereClause, /= ANY\(\$2::text\[\]\)/) +}) + test('后台拼单聚合状态同时收敛筛选语义和操作能力', () => { const waitingForClaim = mapWorkOrderAdmin(buildWorkOrderRow({ status: 'open' })) assert.equal(waitingForClaim.status, 'open') diff --git a/apps/frontend/src/pages/worker/WorkerOrdersPage.tsx b/apps/frontend/src/pages/worker/WorkerOrdersPage.tsx index 8206fbcc..152d6ce8 100644 --- a/apps/frontend/src/pages/worker/WorkerOrdersPage.tsx +++ b/apps/frontend/src/pages/worker/WorkerOrdersPage.tsx @@ -58,6 +58,7 @@ import type { import { formatDateTime } from '@/utils/date-time' import { getImageIdentity } from '@/utils/image-identity' import { useIsMobile } from '@/utils/use-is-mobile' +import { buildWorkerOrderQuery } from '@/utils/worker-order-query' const STATUS_OPTIONS = [ { value: 'in_progress', label: '代练中' }, @@ -86,15 +87,6 @@ type FeedbackFormValues = { content?: string } -function buildWorkerOrderQuery(status: string, keyword: string, page: number, pageSize: number) { - return { - keyword, - page, - pageSize, - ...(status === 'vip_evidence_pending' ? { vipEvidencePending: true } : { status }), - } -} - type NoteTheme = 'success' | 'processing' | 'danger' | 'warning' | 'purple' | 'default' const PRESET_NOTE_TAGS: Array<{ label: string; theme: NoteTheme }> = [ diff --git a/apps/frontend/src/utils/worker-order-query.ts b/apps/frontend/src/utils/worker-order-query.ts new file mode 100644 index 00000000..b6202071 --- /dev/null +++ b/apps/frontend/src/utils/worker-order-query.ts @@ -0,0 +1,13 @@ +export function buildWorkerOrderQuery( + status: string, + keyword: string, + page: number, + pageSize: number, +) { + return { + keyword, + page, + pageSize, + ...(status === 'vip_evidence_pending' ? { vipEvidencePending: true } : { status }), + } +} diff --git a/apps/frontend/tests/worker-order-query.test.ts b/apps/frontend/tests/worker-order-query.test.ts new file mode 100644 index 00000000..6d09a8d1 --- /dev/null +++ b/apps/frontend/tests/worker-order-query.test.ts @@ -0,0 +1,31 @@ +import assert from 'node:assert/strict' +import test from 'node:test' + +import { buildWorkerOrderQuery } from '../src/utils/worker-order-query.ts' + +test('打手订单页按普通状态筛选并保留分页参数', () => { + assert.deepEqual(buildWorkerOrderQuery('in_progress', '王者荣耀', 2, 20), { + status: 'in_progress', + keyword: '王者荣耀', + page: 2, + pageSize: 20, + }) +}) + +test('打手订单页待补图筛选使用独立标记', () => { + assert.deepEqual(buildWorkerOrderQuery('vip_evidence_pending', '', 1, 20), { + vipEvidencePending: true, + keyword: '', + page: 1, + pageSize: 20, + }) +}) + +test('打手订单页选择全部订单时不附加状态筛选值', () => { + assert.deepEqual(buildWorkerOrderQuery('', '', 1, 20), { + status: '', + keyword: '', + page: 1, + pageSize: 20, + }) +}) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 850cf437..14f6c1cb 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -82,6 +82,7 @@ services: STORAGE_SECRET_ACCESS_KEY: ${STORAGE_SECRET_ACCESS_KEY:-minioadmin} STORAGE_REGION: ${STORAGE_REGION:-us-east-1} STORAGE_MAX_UPLOAD_SIZE_MB: ${STORAGE_MAX_UPLOAD_SIZE_MB:-10} + WORKSPACE_ROOT: /workspace # ADMIN_* 仅走 env_file,避免 JSON 经 ${} 注入时被 YAML 破坏 KUASHOU_INDUSTRY_RATE_LIMIT_MAX: ${KUASHOU_INDUSTRY_RATE_LIMIT_MAX:-120} logging: *json-log-rotation @@ -89,6 +90,10 @@ services: - ./apps/backend:/app - ./.prettierrc.json:/.prettierrc.json:ro - ./.prettierignore:/.prettierignore:ro + - ./.env.server.example:/workspace/.env.server.example:ro + - ./.env.mac-docker.example:/workspace/.env.mac-docker.example:ro + - ./docker-compose.yml:/workspace/docker-compose.yml:ro + - ./docker-compose.dev.yml:/workspace/docker-compose.dev.yml:ro - backend_node_modules:/app/node_modules - ./apps/backend/data:/app/data