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 feaf44f4..45f96eda 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 @@ -1,8 +1,71 @@ import assert from 'node:assert/strict' import test from 'node:test' -import type { WorkOrderRow } from '../../repositories/worker-platform/index.js' -import { resolveCollectSubmitTargetWorkOrder } from './index.js' +import type { WorkOrderRow, WorkerUserRow } from '../../repositories/worker-platform/index.js' +import { assertWorkerLoginAllowed, resolveCollectSubmitTargetWorkOrder } from './index.js' + +function buildWorkerUserRow(overrides: Partial = {}): WorkerUserRow { + return { + id: 1, + username: 'jd01', + password_hash: 'scrypt$salt$hash', + display_name: '测试打手', + phone: '', + level_id: 1, + status: 'active', + review_note: '', + session_version: 1, + created_at: '2026-07-28T00:00:00.000Z', + updated_at: '2026-07-28T00:00:00.000Z', + reviewed_at: null, + inviter_id: null, + invite_code: 'TEST0001', + ...overrides, + } +} + +test('assertWorkerLoginAllowed allows active workers', () => { + assert.doesNotThrow(() => assertWorkerLoginAllowed(buildWorkerUserRow())) +}) + +test('assertWorkerLoginAllowed blocks rejected (frozen) workers with worker_rejected', () => { + assert.throws( + () => assertWorkerLoginAllowed(buildWorkerUserRow({ status: 'rejected' })), + (error: unknown) => + Boolean( + error && + typeof error === 'object' && + (error as { statusCode?: number }).statusCode === 403 && + (error as { errorCode?: string }).errorCode === 'worker_rejected', + ), + ) +}) + +test('assertWorkerLoginAllowed blocks pending review workers with worker_pending_review', () => { + assert.throws( + () => assertWorkerLoginAllowed(buildWorkerUserRow({ status: 'pending_review' })), + (error: unknown) => + Boolean( + error && + typeof error === 'object' && + (error as { statusCode?: number }).statusCode === 403 && + (error as { errorCode?: string }).errorCode === 'worker_pending_review', + ), + ) +}) + +test('assertWorkerLoginAllowed blocks disabled workers with worker_disabled', () => { + assert.throws( + () => assertWorkerLoginAllowed(buildWorkerUserRow({ status: 'disabled' })), + (error: unknown) => + Boolean( + error && + typeof error === 'object' && + (error as { statusCode?: number }).statusCode === 403 && + (error as { errorCode?: string }).errorCode === 'worker_disabled', + ), + ) +}) function buildWorkOrderRow( overrides: Partial = {}, diff --git a/apps/backend/src/services/worker-platform/worker-service.ts b/apps/backend/src/services/worker-platform/worker-service.ts index ff65df88..fd44bf73 100644 --- a/apps/backend/src/services/worker-platform/worker-service.ts +++ b/apps/backend/src/services/worker-platform/worker-service.ts @@ -335,14 +335,34 @@ export async function loginWorker(username: unknown, password: unknown) { }) } - if (worker.status === 'disabled') { - throw createHttpError('接单账号已停用', { + assertWorkerLoginAllowed(worker) + + return createWorkerSession(worker) +} + +export function assertWorkerLoginAllowed(worker: WorkerUserRow) { + if (worker.status === 'active') { + return + } + + if (worker.status === 'rejected') { + throw createHttpError('接单账号已被冻结,无法登录', { statusCode: 403, - errorCode: 'worker_disabled', + errorCode: 'worker_rejected', }) } - return createWorkerSession(worker) + if (worker.status === 'pending_review') { + throw createHttpError('接单账号待审核,暂无法登录', { + statusCode: 403, + errorCode: 'worker_pending_review', + }) + } + + throw createHttpError('接单账号已停用', { + statusCode: 403, + errorCode: 'worker_disabled', + }) } export async function logoutWorkerSession(token: unknown) { @@ -411,7 +431,7 @@ export async function verifyWorkerSessionToken(token: unknown): Promise