diff --git a/apps/backend/src/routes/admin/platform-config.js b/apps/backend/src/routes/admin/platform-config.ts similarity index 72% rename from apps/backend/src/routes/admin/platform-config.js rename to apps/backend/src/routes/admin/platform-config.ts index 6d95ee83..dcf7492d 100644 --- a/apps/backend/src/routes/admin/platform-config.js +++ b/apps/backend/src/routes/admin/platform-config.ts @@ -1,5 +1,3 @@ -// @ts-check - import { Router } from "express"; import { @@ -46,32 +44,35 @@ import { validateAdminCloudtentaclesSession, } from "../../services/admin/platform-config/service.js"; import { createJsonHandler, requireAdminRoles } from "./shared.js"; - -/** @typedef {import('../../types/admin-route-inputs.js').AdminAgisoShopConfigRouteBody} AdminAgisoShopConfigRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminFulfillmentBindingConfigRouteBody} AdminFulfillmentBindingConfigRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminFulfillmentBindingLookupRouteBody} AdminFulfillmentBindingLookupRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminEntityRouteParams} AdminEntityRouteParams */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminKuaishouEticketSourceConfigRouteBody} AdminKuaishouEticketSourceConfigRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminNotificationConfigRouteBody} AdminNotificationConfigRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminNotificationTestRouteBody} AdminNotificationTestRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminScheduledJobsConfigRouteBody} AdminScheduledJobsConfigRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminKuaishouEticketDetailQueryRouteBody} AdminKuaishouEticketDetailQueryRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminKuaishouEticketConsumeRouteBody} AdminKuaishouEticketConsumeRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminKuaishouEticketShopInfoRouteBody} AdminKuaishouEticketShopInfoRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesSourceConfigRouteBody} AdminCloudtentaclesSourceConfigRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminKuaishouCloudFulfillmentConfigRouteBody} AdminKuaishouCloudFulfillmentConfigRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesSendSmsCodeRouteBody} AdminCloudtentaclesSendSmsCodeRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesTestLoginRouteBody} AdminCloudtentaclesTestLoginRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesValidateSessionRouteBody} AdminCloudtentaclesValidateSessionRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesCatalogQueryRouteBody} AdminCloudtentaclesCatalogQueryRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesSkuBuyRouteBody} AdminCloudtentaclesSkuBuyRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesSkuUseRouteBody} AdminCloudtentaclesSkuUseRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesVirtualNumberRouteBody} AdminCloudtentaclesVirtualNumberRouteBody */ -/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesFullFlowRouteBody} AdminCloudtentaclesFullFlowRouteBody */ -/** @typedef {import('../../types/admin-write-models.js').AdminAgisoShopConfigSaveResponse} AdminAgisoShopConfigSaveResponse */ +import type { AdminAgisoShopConfigSaveResponse } from "../../types/admin-write-models.js"; +import type { + AdminAgisoShopConfigRouteBody, + AdminCloudtentaclesCatalogQueryRouteBody, + AdminCloudtentaclesFullFlowRouteBody, + AdminCloudtentaclesSendSmsCodeRouteBody, + AdminCloudtentaclesSkuBuyRouteBody, + AdminCloudtentaclesSkuUseRouteBody, + AdminCloudtentaclesSourceConfigRouteBody, + AdminCloudtentaclesTestLoginRouteBody, + AdminCloudtentaclesValidateSessionRouteBody, + AdminCloudtentaclesVirtualNumberRouteBody, + AdminEntityRouteParams, + AdminFulfillmentBindingConfigRouteBody, + AdminFulfillmentBindingLookupRouteBody, + AdminKuaishouCloudFulfillmentConfigRouteBody, + AdminKuaishouEticketConsumeRouteBody, + AdminKuaishouEticketDetailQueryRouteBody, + AdminKuaishouEticketShopInfoRouteBody, + AdminKuaishouEticketSourceConfigRouteBody, + AdminNotificationConfigRouteBody, + AdminNotificationTestRouteBody, + AdminScheduledJobsConfigRouteBody, +} from "../../types/admin-route-inputs.js"; const router = Router(); +type JsonRecord = Record; + router.use("/platform-config", requireAdminRoles(["admin"])); router.get( @@ -88,14 +89,14 @@ router.post( createJsonHandler( (req) => updateAdminAgisoShopConfigs( - /** @type {AdminAgisoShopConfigRouteBody} */ (req.body) + req.body as AdminAgisoShopConfigRouteBody ), { successMessage: "Agiso 店铺配置已保存", errorMessage: "保存 Agiso 店铺配置失败", scope: "[admin/platform-config/agiso-shops]", audit: (_req, data) => { - const result = /** @type {AdminAgisoShopConfigSaveResponse} */ (data); + const result = data as AdminAgisoShopConfigSaveResponse; return { action: "platform_shop_config_updated", targetType: "platform_config", @@ -124,17 +125,14 @@ router.post( createJsonHandler( (req) => updateAdminNotificationConfig( - /** @type {AdminNotificationConfigRouteBody} */ (req.body) + req.body as AdminNotificationConfigRouteBody ), { successMessage: "内部通知配置已保存", errorMessage: "保存内部通知配置失败", scope: "[admin/platform-config/notifications]", audit: (_req, data) => { - const result = - /** @type {{ filePath?: string, source?: { enabled?: boolean, channels?: { bark?: { recipients?: unknown[] } } } }} */ ( - data - ); + const result = data as JsonRecord; return { action: "platform_notification_config_updated", targetType: "platform_config", @@ -159,17 +157,14 @@ router.post( createJsonHandler( (req) => testAdminNotification( - /** @type {AdminNotificationTestRouteBody} */ (req.body) + req.body as AdminNotificationTestRouteBody ), { successMessage: "内部通知测试已执行", errorMessage: "内部通知测试失败", scope: "[admin/platform-config/notifications/test]", audit: (_req, data) => { - const result = - /** @type {{ successCount?: number, failedCount?: number, channel?: string }} */ ( - data - ); + const result = data as JsonRecord; return { action: "platform_notification_test_sent", targetType: "platform_config", @@ -199,17 +194,14 @@ router.post( createJsonHandler( (req) => updateAdminScheduledJobsConfig( - /** @type {AdminScheduledJobsConfigRouteBody} */ (req.body) + req.body as AdminScheduledJobsConfigRouteBody ), { successMessage: "定时任务配置已保存", errorMessage: "保存定时任务配置失败", scope: "[admin/platform-config/scheduled-jobs]", audit: (_req, data) => { - const result = - /** @type {{ filePath?: string, source?: { enabled?: boolean, jobs?: unknown[] } }} */ ( - data - ); + const result = data as JsonRecord; return { action: "platform_scheduled_jobs_updated", targetType: "platform_config", @@ -232,22 +224,19 @@ router.post( createJsonHandler( (req) => runAdminScheduledJobNow( - /** @type {AdminEntityRouteParams} */ (req.params).id + (req.params as AdminEntityRouteParams).id ), { successMessage: "定时任务已执行", errorMessage: "执行定时任务失败", scope: "[admin/platform-config/scheduled-jobs/:id/run]", audit: (req, data) => { - const result = - /** @type {{ result?: { status?: string, message?: string } }} */ ( - data - ); + const result = data as JsonRecord; return { action: "platform_scheduled_job_run", targetType: "platform_config", targetId: String( - /** @type {AdminEntityRouteParams} */ (req.params).id || "" + (req.params as AdminEntityRouteParams).id || "" ).trim(), data: { status: String(result.result?.status || "").trim(), @@ -273,17 +262,14 @@ router.post( createJsonHandler( (req) => updateAdminKuaishouEticketSourceConfig( - /** @type {AdminKuaishouEticketSourceConfigRouteBody} */ (req.body) + req.body as AdminKuaishouEticketSourceConfigRouteBody ), { successMessage: "快手小店核销配置已保存", errorMessage: "保存快手小店核销配置失败", scope: "[admin/platform-config/kuaishou-eticket-source]", audit: (_req, data) => { - const result = - /** @type {{ filePath?: string, source?: { enabled?: boolean, shops?: unknown[] } }} */ ( - data - ); + const result = data as JsonRecord; return { action: "platform_kuaishou_eticket_source_updated", targetType: "platform_config", @@ -315,17 +301,14 @@ router.post( createJsonHandler( (req) => retryAdminNinetyoneOrder( - /** @type {AdminEntityRouteParams} */ (req.params).id + (req.params as AdminEntityRouteParams).id ), { successMessage: "91卡券订单已重试", errorMessage: "重试 91卡券订单失败", scope: "[admin/platform-config/ninetyone/orders/:id/retry]", audit: (_req, data) => { - const result = - /** @type {{ orderId?: number, orderNo?: string, taskCount?: number }} */ ( - data - ); + const result = data as JsonRecord; return { action: "platform_ninetyone_order_retried", targetType: "order", @@ -345,17 +328,15 @@ router.post( createJsonHandler( (req) => failAdminNinetyoneOrder( - /** @type {AdminEntityRouteParams} */ (req.params).id, - /** @type {{ reason?: string }} */ (req.body) + (req.params as AdminEntityRouteParams).id, + req.body as { reason?: string } ), { successMessage: "91卡券订单已标记失败", errorMessage: "标记 91卡券订单失败", scope: "[admin/platform-config/ninetyone/orders/:id/fail]", audit: (req, data) => { - const result = /** @type {{ orderId?: number, orderNo?: string }} */ ( - data - ); + const result = data as JsonRecord; return { action: "platform_ninetyone_order_failed", targetType: "order", @@ -363,7 +344,7 @@ router.post( data: { orderNo: String(result.orderNo || "").trim(), reason: String( - /** @type {{ reason?: string }} */ (req.body).reason || "" + (req.body as { reason?: string }).reason || "" ).trim(), }, }; @@ -377,20 +358,15 @@ router.post( createJsonHandler( (req) => queryAdminKuaishouEticketDetail( - /** @type {AdminKuaishouEticketDetailQueryRouteBody} */ (req.body) + req.body as AdminKuaishouEticketDetailQueryRouteBody ), { successMessage: "快手小店核销信息查询成功", errorMessage: "查询快手小店核销信息失败", scope: "[admin/platform-config/kuaishou-eticket/query-detail]", audit: (req, data) => { - const body = /** @type {AdminKuaishouEticketDetailQueryRouteBody} */ ( - req.body - ); - const result = - /** @type {{ eTicketId?: string, result?: number, ok?: boolean, alreadyConsumed?: boolean }} */ ( - data - ); + const body = req.body as AdminKuaishouEticketDetailQueryRouteBody; + const result = data as JsonRecord; return { action: "platform_kuaishou_eticket_query_detail", targetType: "platform_config", @@ -413,20 +389,15 @@ router.post( createJsonHandler( (req) => queryAdminKuaishouEticketShopInfo( - /** @type {AdminKuaishouEticketShopInfoRouteBody} */ (req.body) + req.body as AdminKuaishouEticketShopInfoRouteBody ), { successMessage: "快手小店店铺信息查询成功", errorMessage: "查询快手小店店铺信息失败", scope: "[admin/platform-config/kuaishou-eticket/query-shop-info]", audit: (req, data) => { - const body = /** @type {AdminKuaishouEticketShopInfoRouteBody} */ ( - req.body - ); - const result = - /** @type {{ shop?: { shopId?: string, kshopName?: string }, result?: number, ok?: boolean }} */ ( - data - ); + const body = req.body as AdminKuaishouEticketShopInfoRouteBody; + const result = data as JsonRecord; return { action: "platform_kuaishou_eticket_query_shop_info", targetType: "platform_config", @@ -449,20 +420,15 @@ router.post( createJsonHandler( (req) => consumeAdminKuaishouEticket( - /** @type {AdminKuaishouEticketConsumeRouteBody} */ (req.body) + req.body as AdminKuaishouEticketConsumeRouteBody ), { successMessage: "快手小店核销请求已执行", errorMessage: "执行快手小店核销失败", scope: "[admin/platform-config/kuaishou-eticket/consume]", audit: (req, data) => { - const body = /** @type {AdminKuaishouEticketConsumeRouteBody} */ ( - req.body - ); - const result = - /** @type {{ eTicketId?: string, result?: number, consumed?: boolean, alreadyConsumed?: boolean }} */ ( - data - ); + const body = req.body as AdminKuaishouEticketConsumeRouteBody; + const result = data as JsonRecord; return { action: "platform_kuaishou_eticket_consume", targetType: "platform_config", @@ -515,17 +481,14 @@ router.post( createJsonHandler( (req) => updateAdminCloudtentaclesSourceConfig( - /** @type {AdminCloudtentaclesSourceConfigRouteBody} */ (req.body) + req.body as AdminCloudtentaclesSourceConfigRouteBody ), { successMessage: "cloudtentacles 履约平台配置已保存", errorMessage: "保存 cloudtentacles 履约平台配置失败", scope: "[admin/platform-config/cloudtentacles-source]", audit: (_req, data) => { - const result = - /** @type {{ filePath?: string, source?: { username?: string, enabled?: boolean } }} */ ( - data - ); + const result = data as JsonRecord; return { action: "platform_cloudtentacles_source_updated", targetType: "platform_config", @@ -546,20 +509,15 @@ router.post( createJsonHandler( (req) => sendAdminCloudtentaclesSmsCode( - /** @type {AdminCloudtentaclesSendSmsCodeRouteBody} */ (req.body) + req.body as AdminCloudtentaclesSendSmsCodeRouteBody ), { successMessage: "cloudtentacles 短信验证码已发送", errorMessage: "cloudtentacles 发送短信验证码失败", scope: "[admin/platform-config/cloudtentacles/send-sms-code]", audit: (req, data) => { - const body = /** @type {AdminCloudtentaclesSendSmsCodeRouteBody} */ ( - req.body - ); - const result = - /** @type {{ username?: string, phoneMasked?: string, baseUrl?: string }} */ ( - data - ); + const body = req.body as AdminCloudtentaclesSendSmsCodeRouteBody; + const result = data as JsonRecord; return { action: "platform_cloudtentacles_send_sms_code", targetType: "platform_config", @@ -581,20 +539,15 @@ router.post( createJsonHandler( (req) => testAdminCloudtentaclesLogin( - /** @type {AdminCloudtentaclesTestLoginRouteBody} */ (req.body) + req.body as AdminCloudtentaclesTestLoginRouteBody ), { successMessage: "cloudtentacles 登录测试成功", errorMessage: "cloudtentacles 登录测试失败", scope: "[admin/platform-config/cloudtentacles/test-login]", audit: (req, data) => { - const body = /** @type {AdminCloudtentaclesTestLoginRouteBody} */ ( - req.body - ); - const result = - /** @type {{ baseUrl?: string, username?: string, session?: { permissionCount?: number } }} */ ( - data - ); + const body = req.body as AdminCloudtentaclesTestLoginRouteBody; + const result = data as JsonRecord; return { action: "platform_cloudtentacles_test_login", targetType: "platform_config", @@ -616,17 +569,14 @@ router.post( createJsonHandler( (req) => validateAdminCloudtentaclesSession( - /** @type {AdminCloudtentaclesValidateSessionRouteBody} */ (req.body) + req.body as AdminCloudtentaclesValidateSessionRouteBody ), { successMessage: "cloudtentacles 会话校验成功", errorMessage: "cloudtentacles 会话校验失败", scope: "[admin/platform-config/cloudtentacles/validate-session]", audit: (_req, data) => { - const result = - /** @type {{ baseUrl?: string, session?: { permissionCount?: number } }} */ ( - data - ); + const result = data as JsonRecord; return { action: "platform_cloudtentacles_validate_session", targetType: "platform_config", @@ -646,7 +596,7 @@ router.post( createJsonHandler( (req) => getAdminCloudtentaclesAsset( - /** @type {AdminCloudtentaclesCatalogQueryRouteBody} */ (req.body) + req.body as AdminCloudtentaclesCatalogQueryRouteBody ), { successMessage: "cloudtentacles 余额查询成功", @@ -661,7 +611,7 @@ router.post( createJsonHandler( (req) => getAdminCloudtentaclesCategories( - /** @type {AdminCloudtentaclesCatalogQueryRouteBody} */ (req.body) + req.body as AdminCloudtentaclesCatalogQueryRouteBody ), { successMessage: "cloudtentacles 分类查询成功", @@ -676,7 +626,7 @@ router.post( createJsonHandler( (req) => getAdminCloudtentaclesSkuList( - /** @type {AdminCloudtentaclesCatalogQueryRouteBody} */ (req.body) + req.body as AdminCloudtentaclesCatalogQueryRouteBody ), { successMessage: "cloudtentacles SKU 列表查询成功", @@ -691,7 +641,7 @@ router.post( createJsonHandler( (req) => buyAdminCloudtentaclesSku( - /** @type {AdminCloudtentaclesSkuBuyRouteBody} */ (req.body) + req.body as AdminCloudtentaclesSkuBuyRouteBody ), { successMessage: "cloudtentacles SKU 购买成功", @@ -706,7 +656,7 @@ router.post( createJsonHandler( (req) => useAdminCloudtentaclesSku( - /** @type {AdminCloudtentaclesSkuUseRouteBody} */ (req.body) + req.body as AdminCloudtentaclesSkuUseRouteBody ), { successMessage: "cloudtentacles 发货成功", @@ -721,7 +671,7 @@ router.post( createJsonHandler( (req) => getAdminCloudtentaclesKnapsack( - /** @type {AdminCloudtentaclesCatalogQueryRouteBody} */ (req.body) + req.body as AdminCloudtentaclesCatalogQueryRouteBody ), { successMessage: "cloudtentacles 背包查询成功", @@ -736,7 +686,7 @@ router.post( createJsonHandler( (req) => listAdminCloudtentaclesVirtualNumbers( - /** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body) + req.body as AdminCloudtentaclesVirtualNumberRouteBody ), { successMessage: "cloudtentacles 虚拟号列表查询成功", @@ -751,7 +701,7 @@ router.post( createJsonHandler( (req) => appointAdminCloudtentaclesVirtualNumber( - /** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body) + req.body as AdminCloudtentaclesVirtualNumberRouteBody ), { successMessage: "cloudtentacles 虚拟号申请成功", @@ -766,7 +716,7 @@ router.post( createJsonHandler( (req) => generateAdminCloudtentaclesLoginCode( - /** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body) + req.body as AdminCloudtentaclesVirtualNumberRouteBody ), { successMessage: "cloudtentacles 登录码生成成功", @@ -781,7 +731,7 @@ router.post( createJsonHandler( (req) => fetchAdminCloudtentaclesVirtualNumberCode( - /** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body) + req.body as AdminCloudtentaclesVirtualNumberRouteBody ), { successMessage: "cloudtentacles 验证码获取成功", @@ -796,7 +746,7 @@ router.post( createJsonHandler( (req) => verifyAdminCloudtentaclesLoginCode( - /** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body) + req.body as AdminCloudtentaclesVirtualNumberRouteBody ), { successMessage: "cloudtentacles 登录码校验成功", @@ -811,7 +761,7 @@ router.post( createJsonHandler( (req) => getAdminCloudtentaclesBindUrl( - /** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body) + req.body as AdminCloudtentaclesVirtualNumberRouteBody ), { successMessage: "cloudtentacles 兑换链接获取成功", @@ -826,7 +776,7 @@ router.post( createJsonHandler( (req) => backAdminCloudtentaclesVirtualNumber( - /** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body) + req.body as AdminCloudtentaclesVirtualNumberRouteBody ), { successMessage: "cloudtentacles 号码退还成功", @@ -841,7 +791,7 @@ router.post( createJsonHandler( (req) => runAdminCloudtentaclesFullFlow( - /** @type {AdminCloudtentaclesFullFlowRouteBody} */ (req.body) + req.body as AdminCloudtentaclesFullFlowRouteBody ), { successMessage: "cloudtentacles 完整调试流程执行成功", @@ -865,17 +815,14 @@ router.post( createJsonHandler( (req) => lookupAdminFulfillmentBindingOrder( - /** @type {AdminFulfillmentBindingLookupRouteBody} */ (req.body) + req.body as AdminFulfillmentBindingLookupRouteBody ), { successMessage: "订单商品查询成功", errorMessage: "手动查询订单商品失败", scope: "[admin/platform-config/fulfillment-bindings/lookup-order]", audit: (req, data) => { - const result = - /** @type {{ order?: { provider?: string, platform?: string, shopId?: string, platformOrderId?: string }, items?: unknown[] }} */ ( - data - ); + const result = data as JsonRecord; return { action: "platform_fulfillment_order_lookup", targetType: "platform_config", @@ -890,13 +837,12 @@ router.post( shopId: result.order?.shopId || String( - /** @type {AdminFulfillmentBindingLookupRouteBody} */ (req.body) - ?.shopId || "" + (req.body as AdminFulfillmentBindingLookupRouteBody)?.shopId || "" ).trim(), platformOrderId: result.order?.platformOrderId || String( - /** @type {AdminFulfillmentBindingLookupRouteBody} */ (req.body) + (req.body as AdminFulfillmentBindingLookupRouteBody) ?.platformOrderId || "" ).trim(), }, @@ -911,15 +857,14 @@ router.post( createJsonHandler( (req) => updateAdminFulfillmentBindingConfigs( - /** @type {AdminFulfillmentBindingConfigRouteBody} */ (req.body) + req.body as AdminFulfillmentBindingConfigRouteBody ), { successMessage: "履约配置已保存", errorMessage: "保存履约配置失败", scope: "[admin/platform-config/fulfillment-bindings]", audit: (_req, data) => { - const result = - /** @type {{ bindings?: unknown[], filePath?: string }} */ (data); + const result = data as JsonRecord; return { action: "platform_fulfillment_config_updated", targetType: "platform_config", @@ -950,17 +895,14 @@ router.post( createJsonHandler( (req) => updateAdminKuaishouCloudFulfillmentConfig( - /** @type {AdminKuaishouCloudFulfillmentConfigRouteBody} */ (req.body) + req.body as AdminKuaishouCloudFulfillmentConfigRouteBody ), { successMessage: "新履约配置已保存", errorMessage: "保存新履约配置失败", scope: "[admin/platform-config/kuaishou-cloud-fulfillment]", audit: (_req, data) => { - const result = - /** @type {{ filePath?: string, source?: { items?: unknown[] } }} */ ( - data - ); + const result = data as JsonRecord; return { action: "platform_kuaishou_cloud_fulfillment_updated", targetType: "platform_config", diff --git a/docs/backend-typescript-migration-plan.md b/docs/backend-typescript-migration-plan.md index db88a461..0f3d7c45 100644 --- a/docs/backend-typescript-migration-plan.md +++ b/docs/backend-typescript-migration-plan.md @@ -843,6 +843,14 @@ - `npm run typecheck` - `npm run build` - `npm test` 共 139 个用例通过 +221. 后台平台配置路由迁移到 `.ts`: + - `src/routes/admin/platform-config.ts` +222. Agiso 店铺、通知、定时任务、快手电子券、91 卡券订单、cloudtentacles 来源 / 登录 / 商品 / 背包 / 虚拟号 / debug flow、履约绑定和快手 Cloud 履约配置路由已进入 TS 编译链路;route body / params、Agiso 保存响应和审计动态结果补齐类型,并移除旧 JSDoc cast +223. Docker 内验证通过: + - `npm run typecheck` + - `npm run build` + - `npm test` 共 139 个用例通过 +224. `src/routes/admin` 目录下非测试 `.js` 路由文件已全部迁移为 `.ts` ## 下一步建议