From 18057d0eea4cef3f1fa8f2c0b790748a9aec630e Mon Sep 17 00:00:00 2001 From: yml Date: Thu, 21 May 2026 17:22:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E8=BF=81=E7=A7=BB=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E8=AF=BB=E4=BE=A7=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/{audit-logs.js => audit-logs.ts} | 4 +- apps/backend/src/routes/admin/inventory.js | 118 ------------------ apps/backend/src/routes/admin/inventory.ts | 117 +++++++++++++++++ ...ge-deliveries.js => message-deliveries.ts} | 7 +- .../src/routes/admin/{orders.js => orders.ts} | 13 +- .../{webhook-events.js => webhook-events.ts} | 33 +++-- docs/backend-typescript-migration-plan.md | 11 ++ 7 files changed, 155 insertions(+), 148 deletions(-) rename apps/backend/src/routes/admin/{audit-logs.js => audit-logs.ts} (79%) delete mode 100644 apps/backend/src/routes/admin/inventory.js create mode 100644 apps/backend/src/routes/admin/inventory.ts rename apps/backend/src/routes/admin/{message-deliveries.js => message-deliveries.ts} (63%) rename apps/backend/src/routes/admin/{orders.js => orders.ts} (58%) rename apps/backend/src/routes/admin/{webhook-events.js => webhook-events.ts} (52%) diff --git a/apps/backend/src/routes/admin/audit-logs.js b/apps/backend/src/routes/admin/audit-logs.ts similarity index 79% rename from apps/backend/src/routes/admin/audit-logs.js rename to apps/backend/src/routes/admin/audit-logs.ts index 6719a487..1e9b7076 100644 --- a/apps/backend/src/routes/admin/audit-logs.js +++ b/apps/backend/src/routes/admin/audit-logs.ts @@ -3,12 +3,14 @@ import { Router } from 'express' import { getAdminAuditLogs } from '../../services/admin/admin-audit-service.js' import { createJsonHandler, requireAdminRoles } from './shared.js' +type AdminAuditLogRouteQuery = Record + const router = Router() router.use('/audit-logs', requireAdminRoles(['admin'])) router.get('/audit-logs', createJsonHandler( - (req) => getAdminAuditLogs(req.query), + (req) => getAdminAuditLogs(req.query as AdminAuditLogRouteQuery), { successMessage: 'ok', errorMessage: '读取操作审计日志失败', diff --git a/apps/backend/src/routes/admin/inventory.js b/apps/backend/src/routes/admin/inventory.js deleted file mode 100644 index 1643447d..00000000 --- a/apps/backend/src/routes/admin/inventory.js +++ /dev/null @@ -1,118 +0,0 @@ -// @ts-check - -import { Router } from 'express' - -import { - createAdminInventoryItem, - importAdminInventoryItems, - invalidateAdminInventoryItem, - releaseAdminInventoryItem, -} from '../../services/admin/admin-write-service.js' -import { - getAdminInventoryItems, - getAdminInventorySkuSuggestions, -} from '../../services/admin/admin-read-service.js' -import { createJsonHandler, requireAdminRoles } from './shared.js' - -/** @typedef {import('../../types/admin-route-inputs.js').AdminInventoryCreateRouteBody} AdminInventoryCreateRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminInventoryImportRouteBody} AdminInventoryImportRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminInventoryInvalidateRouteBody} AdminInventoryInvalidateRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminInventoryRouteParams} AdminInventoryRouteParams */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminInventoryRouteQuery} AdminInventoryRouteQuery */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminInventorySkuSuggestionRouteQuery} AdminInventorySkuSuggestionRouteQuery */ -/** @typedef {import('../../types/admin-write-models.js').AdminInventoryMutationResponse} AdminInventoryMutationResponse */ - -const router = Router() - -router.use('/inventory', requireAdminRoles(['admin', 'operator'])) - -router.get('/inventory', createJsonHandler( - (req) => getAdminInventoryItems( - /** @type {AdminInventoryRouteQuery} */ (req.query), - req.adminSession || null, - ), - { - successMessage: 'ok', - errorMessage: '读取库存列表失败', - scope: '[admin/inventory]', - }, -)) - -router.get('/inventory/sku-suggestions', createJsonHandler( - (req) => getAdminInventorySkuSuggestions( - /** @type {AdminInventorySkuSuggestionRouteQuery} */ (req.query), - req.adminSession || null, - ), - { - successMessage: 'ok', - errorMessage: '读取内部 SKU 建议失败', - scope: '[admin/inventory/sku-suggestions]', - }, -)) - -router.post('/inventory', createJsonHandler( - (req) => createAdminInventoryItem(/** @type {AdminInventoryCreateRouteBody} */ (req.body)), - { - successMessage: '库存项已新增', - errorMessage: '新增库存项失败', - scope: '[admin/inventory]', - }, -)) - -router.post('/inventory/import', createJsonHandler( - (req) => importAdminInventoryItems(/** @type {AdminInventoryImportRouteBody} */ (req.body)), - { - successMessage: '导入完成', - errorMessage: '导入库存凭据失败', - scope: '[admin/inventory/import]', - }, -)) - -router.post('/inventory/:inventoryItemId/release', requireAdminRoles(['admin']), createJsonHandler( - (req) => releaseAdminInventoryItem((/** @type {AdminInventoryRouteParams} */ (req.params)).inventoryItemId), - { - successMessage: '库存项已释放', - errorMessage: '释放库存项失败', - scope: '[admin/inventory/:inventoryItemId/release]', - audit: (req, data) => { - const result = /** @type {AdminInventoryMutationResponse} */ (data) - return { - action: 'inventory_item_released', - targetType: 'inventory_item', - targetId: String((/** @type {AdminInventoryRouteParams} */ (req.params)).inventoryItemId), - data: { - inventoryItemId: result.inventoryItem?.inventoryItemId, - skuCode: result.inventoryItem?.skuCode, - displayValue: result.inventoryItem?.displayValue, - }, - } - }, - }, -)) - -router.post('/inventory/:inventoryItemId/invalidate', requireAdminRoles(['admin']), createJsonHandler( - (req) => invalidateAdminInventoryItem( - (/** @type {AdminInventoryRouteParams} */ (req.params)).inventoryItemId, - /** @type {AdminInventoryInvalidateRouteBody} */ (req.body), - ), - { - successMessage: '库存项已作废', - errorMessage: '作废库存项失败', - scope: '[admin/inventory/:inventoryItemId/invalidate]', - audit: (req, data) => { - const result = /** @type {AdminInventoryMutationResponse} */ (data) - return { - action: 'inventory_item_invalidated', - targetType: 'inventory_item', - targetId: String((/** @type {AdminInventoryRouteParams} */ (req.params)).inventoryItemId), - data: { - inventoryItemId: result.inventoryItem?.inventoryItemId, - skuCode: result.inventoryItem?.skuCode, - invalidReason: result.inventoryItem?.invalidReason, - }, - } - }, - }, -)) - -export default router diff --git a/apps/backend/src/routes/admin/inventory.ts b/apps/backend/src/routes/admin/inventory.ts new file mode 100644 index 00000000..8f135c02 --- /dev/null +++ b/apps/backend/src/routes/admin/inventory.ts @@ -0,0 +1,117 @@ +import { Router } from 'express' + +import { + createAdminInventoryItem, + importAdminInventoryItems, + invalidateAdminInventoryItem, + releaseAdminInventoryItem, +} from '../../services/admin/admin-write-service.js' +import { + getAdminInventoryItems, + getAdminInventorySkuSuggestions, +} from '../../services/admin/admin-read-service.js' +import { createJsonHandler, requireAdminRoles } from './shared.js' +import type { + AdminInventoryCreateRouteBody, + AdminInventoryImportRouteBody, + AdminInventoryInvalidateRouteBody, + AdminInventoryRouteParams, + AdminInventoryRouteQuery, + AdminInventorySkuSuggestionRouteQuery, +} from '../../types/admin-route-inputs.js' +import type { AdminInventoryMutationResponse } from '../../types/admin-write-models.js' + +const router = Router() + +router.use('/inventory', requireAdminRoles(['admin', 'operator'])) + +router.get('/inventory', createJsonHandler( + (req) => getAdminInventoryItems( + req.query as AdminInventoryRouteQuery, + req.adminSession || null, + ), + { + successMessage: 'ok', + errorMessage: '读取库存列表失败', + scope: '[admin/inventory]', + }, +)) + +router.get('/inventory/sku-suggestions', createJsonHandler( + (req) => getAdminInventorySkuSuggestions( + req.query as AdminInventorySkuSuggestionRouteQuery, + req.adminSession || null, + ), + { + successMessage: 'ok', + errorMessage: '读取内部 SKU 建议失败', + scope: '[admin/inventory/sku-suggestions]', + }, +)) + +router.post('/inventory', createJsonHandler( + (req) => createAdminInventoryItem(req.body as AdminInventoryCreateRouteBody), + { + successMessage: '库存项已新增', + errorMessage: '新增库存项失败', + scope: '[admin/inventory]', + }, +)) + +router.post('/inventory/import', createJsonHandler( + (req) => importAdminInventoryItems(req.body as AdminInventoryImportRouteBody), + { + successMessage: '导入完成', + errorMessage: '导入库存凭据失败', + scope: '[admin/inventory/import]', + }, +)) + +router.post('/inventory/:inventoryItemId/release', requireAdminRoles(['admin']), createJsonHandler( + (req) => releaseAdminInventoryItem((req.params as AdminInventoryRouteParams).inventoryItemId), + { + successMessage: '库存项已释放', + errorMessage: '释放库存项失败', + scope: '[admin/inventory/:inventoryItemId/release]', + audit: (req, data) => { + const result = data as AdminInventoryMutationResponse + return { + action: 'inventory_item_released', + targetType: 'inventory_item', + targetId: String((req.params as AdminInventoryRouteParams).inventoryItemId), + data: { + inventoryItemId: result.inventoryItem?.inventoryItemId, + skuCode: result.inventoryItem?.skuCode, + displayValue: result.inventoryItem?.displayValue, + }, + } + }, + }, +)) + +router.post('/inventory/:inventoryItemId/invalidate', requireAdminRoles(['admin']), createJsonHandler( + (req) => invalidateAdminInventoryItem( + (req.params as AdminInventoryRouteParams).inventoryItemId, + req.body as AdminInventoryInvalidateRouteBody, + ), + { + successMessage: '库存项已作废', + errorMessage: '作废库存项失败', + scope: '[admin/inventory/:inventoryItemId/invalidate]', + audit: (req, data) => { + const result = data as AdminInventoryMutationResponse + return { + action: 'inventory_item_invalidated', + targetType: 'inventory_item', + targetId: String((req.params as AdminInventoryRouteParams).inventoryItemId), + data: { + inventoryItemId: result.inventoryItem?.inventoryItemId, + skuCode: result.inventoryItem?.skuCode, + invalidReason: result.inventoryItem?.invalidReason, + }, + } + }, + }, +)) + +export default router diff --git a/apps/backend/src/routes/admin/message-deliveries.js b/apps/backend/src/routes/admin/message-deliveries.ts similarity index 63% rename from apps/backend/src/routes/admin/message-deliveries.js rename to apps/backend/src/routes/admin/message-deliveries.ts index a9c031d7..e818e906 100644 --- a/apps/backend/src/routes/admin/message-deliveries.js +++ b/apps/backend/src/routes/admin/message-deliveries.ts @@ -1,16 +1,13 @@ -// @ts-check - import { Router } from 'express' import { getAdminMessageDeliveries } from '../../services/admin/admin-message-delivery-service.js' import { createJsonHandler } from './shared.js' - -/** @typedef {import('../../types/admin-route-inputs.js').AdminMessageDeliveryRouteQuery} AdminMessageDeliveryRouteQuery */ +import type { AdminMessageDeliveryRouteQuery } from '../../types/admin-route-inputs.js' const router = Router() router.get('/message-deliveries', createJsonHandler( - (req) => getAdminMessageDeliveries(/** @type {AdminMessageDeliveryRouteQuery} */ (req.query)), + (req) => getAdminMessageDeliveries(req.query as AdminMessageDeliveryRouteQuery), { successMessage: 'ok', errorMessage: '读取消息发送记录失败', diff --git a/apps/backend/src/routes/admin/orders.js b/apps/backend/src/routes/admin/orders.ts similarity index 58% rename from apps/backend/src/routes/admin/orders.js rename to apps/backend/src/routes/admin/orders.ts index 9447ebb1..bbdbc471 100644 --- a/apps/backend/src/routes/admin/orders.js +++ b/apps/backend/src/routes/admin/orders.ts @@ -1,17 +1,16 @@ -// @ts-check - import { Router } from 'express' import { getAdminOrderDetail, getAdminOrders } from '../../services/admin/admin-read-service.js' import { createJsonHandler } from './shared.js' - -/** @typedef {import('../../types/admin-route-inputs.js').AdminOrderRouteParams} AdminOrderRouteParams */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminOrderRouteQuery} AdminOrderRouteQuery */ +import type { + AdminOrderRouteParams, + AdminOrderRouteQuery, +} from '../../types/admin-route-inputs.js' const router = Router() router.get('/orders', createJsonHandler( - (req) => getAdminOrders(/** @type {AdminOrderRouteQuery} */ (req.query)), + (req) => getAdminOrders(req.query as AdminOrderRouteQuery), { successMessage: 'ok', errorMessage: '读取订单列表失败', @@ -20,7 +19,7 @@ router.get('/orders', createJsonHandler( )) router.get('/orders/:orderId', createJsonHandler( - (req) => getAdminOrderDetail((/** @type {AdminOrderRouteParams} */ (req.params)).orderId), + (req) => getAdminOrderDetail((req.params as AdminOrderRouteParams).orderId), { successMessage: 'ok', errorMessage: '读取订单详情失败', diff --git a/apps/backend/src/routes/admin/webhook-events.js b/apps/backend/src/routes/admin/webhook-events.ts similarity index 52% rename from apps/backend/src/routes/admin/webhook-events.js rename to apps/backend/src/routes/admin/webhook-events.ts index b609d933..212b6aee 100644 --- a/apps/backend/src/routes/admin/webhook-events.js +++ b/apps/backend/src/routes/admin/webhook-events.ts @@ -1,5 +1,3 @@ -// @ts-check - import { Router } from 'express' import { @@ -10,17 +8,18 @@ import { getAdminWebhookEvents, } from '../../services/admin/admin-read-service.js' import { createJsonHandler, requireAdminRoles } from './shared.js' - -/** @typedef {import('../../types/admin-route-inputs.js').AdminWebhookEventRouteParams} AdminWebhookEventRouteParams */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminWebhookEventRouteQuery} AdminWebhookEventRouteQuery */ -/** @typedef {import('../../types/admin-write-models.js').AdminWebhookReplayResponse} AdminWebhookReplayResponse */ +import type { + AdminWebhookEventRouteParams, + AdminWebhookEventRouteQuery, +} from '../../types/admin-route-inputs.js' +import type { AdminWebhookReplayResponse } from '../../types/admin-write-models.js' const router = Router() router.use('/webhook-events', requireAdminRoles(['admin', 'operator'])) router.get('/webhook-events', createJsonHandler( - (req) => getAdminWebhookEvents(/** @type {AdminWebhookEventRouteQuery} */ (req.query)), + (req) => getAdminWebhookEvents(req.query as AdminWebhookEventRouteQuery), { successMessage: 'ok', errorMessage: '读取 webhook 列表失败', @@ -29,7 +28,7 @@ router.get('/webhook-events', createJsonHandler( )) router.get('/webhook-events/:eventId', createJsonHandler( - (req) => getAdminWebhookEventDetail((/** @type {AdminWebhookEventRouteParams} */ (req.params)).eventId), + (req) => getAdminWebhookEventDetail((req.params as AdminWebhookEventRouteParams).eventId), { successMessage: 'ok', errorMessage: '读取 webhook 详情失败', @@ -38,21 +37,21 @@ router.get('/webhook-events/:eventId', createJsonHandler( )) router.post('/webhook-events/:eventId/replay', requireAdminRoles(['admin']), createJsonHandler( - (req) => replayAdminWebhookEvent((/** @type {AdminWebhookEventRouteParams} */ (req.params)).eventId), + (req) => replayAdminWebhookEvent((req.params as AdminWebhookEventRouteParams).eventId), { successMessage: 'Webhook 已重放', errorMessage: '重放 webhook 失败', scope: '[admin/webhook-events/:eventId/replay]', audit: (req, data) => { - const result = /** @type {AdminWebhookReplayResponse} */ (data) + const result = data as AdminWebhookReplayResponse return { - action: 'webhook_replayed', - targetType: 'webhook_event', - targetId: String((/** @type {AdminWebhookEventRouteParams} */ (req.params)).eventId), - data: { - eventId: result.eventId, - replayed: result.replayed, - }, + action: 'webhook_replayed', + targetType: 'webhook_event', + targetId: String((req.params as AdminWebhookEventRouteParams).eventId), + data: { + eventId: result.eventId, + replayed: result.replayed, + }, } }, }, diff --git a/docs/backend-typescript-migration-plan.md b/docs/backend-typescript-migration-plan.md index c043964e..87d9368c 100644 --- a/docs/backend-typescript-migration-plan.md +++ b/docs/backend-typescript-migration-plan.md @@ -818,6 +818,17 @@ - `npm run typecheck` - `npm run build` - `npm test` 共 139 个用例通过 +212. 第二批后台 Admin 读侧 / 库存路由迁移到 `.ts`: + - `src/routes/admin/orders.ts` + - `src/routes/admin/inventory.ts` + - `src/routes/admin/message-deliveries.ts` + - `src/routes/admin/webhook-events.ts` + - `src/routes/admin/audit-logs.ts` +213. 后台订单列表 / 详情、库存列表 / SKU 建议 / 写操作、消息发送记录、Webhook 事件列表 / 详情 / 重放、审计日志路由已进入 TS 编译链路;route query、params、body、库存 mutation response 与 webhook replay response 补齐类型,审计 payload 缩进同步整理 +214. Docker 内验证通过: + - `npm run typecheck` + - `npm run build` + - `npm test` 共 139 个用例通过 ## 下一步建议