diff --git a/apps/backend/src/services/admin/platform-config/fulfillment.js b/apps/backend/src/services/admin/platform-config/fulfillment.ts similarity index 89% rename from apps/backend/src/services/admin/platform-config/fulfillment.js rename to apps/backend/src/services/admin/platform-config/fulfillment.ts index 28f905b2..76806ae7 100644 --- a/apps/backend/src/services/admin/platform-config/fulfillment.js +++ b/apps/backend/src/services/admin/platform-config/fulfillment.ts @@ -1,11 +1,11 @@ -// @ts-check - import { createHttpError } from '../../../utils/http.js' import { formatFenToAmount } from '../../../utils/money.js' import { isPlainObject, pickFirstNonEmpty } from './context.js' import { mapAdminObservedProductItem } from './domain.js' -export function normalizeFulfillmentLookupPayload(payload = {}) { +type JsonObject = Record + +export function normalizeFulfillmentLookupPayload(payload: JsonObject = {}) { const provider = String(payload.provider || 'agiso').trim() || 'agiso' const platform = String(payload.platform || 'xianyu').trim() || 'xianyu' const shopId = String(payload.shopId || '').trim() @@ -35,7 +35,7 @@ export function normalizeFulfillmentLookupPayload(payload = {}) { return { provider, platform, shopId, platformOrderId } } -export function resolveFulfillmentLookupDetail(detailResult, platformOrderId) { +export function resolveFulfillmentLookupDetail(detailResult: JsonObject, platformOrderId: unknown) { const detail = isPlainObject(detailResult?.parsed) ? detailResult.parsed : {} const items = Array.isArray(detail.items) ? detail.items : [] @@ -66,10 +66,19 @@ export function buildFulfillmentLookupResult({ platform = '', shopId = '', platformOrderId = '', - detail = /** @type {Record} */ ({}), - detailResult = /** @type {Record} */ ({}), + detail = {}, + detailResult = {}, bindings = [], fallbackShopName = '', +}: { + provider?: string + platform?: string + shopId?: string + platformOrderId?: string + detail?: JsonObject + detailResult?: JsonObject + bindings?: JsonObject[] + fallbackShopName?: string } = {}) { const resolvedShopName = pickFirstNonEmpty([detail.shopName, fallbackShopName]) const items = Array.isArray(detail.items) ? detail.items : [] diff --git a/apps/backend/src/services/admin/platform-config/observed-products.js b/apps/backend/src/services/admin/platform-config/observed-products.ts similarity index 85% rename from apps/backend/src/services/admin/platform-config/observed-products.js rename to apps/backend/src/services/admin/platform-config/observed-products.ts index 0c66b338..295dcdc2 100644 --- a/apps/backend/src/services/admin/platform-config/observed-products.js +++ b/apps/backend/src/services/admin/platform-config/observed-products.ts @@ -1,8 +1,8 @@ -// @ts-check - import { query } from '../../../db/client.js' import { mapAdminObservedProductItem } from './domain.js' +type JsonObject = Record + export const ADMIN_OBSERVED_PRODUCTS_QUERY = ` SELECT o.provider, @@ -31,7 +31,7 @@ export const ADMIN_OBSERVED_PRODUCTS_QUERY = ` LIMIT 200 ` -export function mapAdminObservedProductRow(row = {}) { +export function mapAdminObservedProductRow(row: JsonObject = {}) { return { provider: String(row.provider || '').trim(), platform: String(row.platform || '').trim(), @@ -45,10 +45,8 @@ export function mapAdminObservedProductRow(row = {}) { } } -export async function listAdminObservedProducts(bindings = [], options = {}) { - const queryImpl = /** @type {(sql: string) => Promise<{ rows: Array> }>} */ ( - options.query || query - ) +export async function listAdminObservedProducts(bindings: JsonObject[] = [], options: JsonObject = {}) { + const queryImpl = (options.query || query) as (sql: string) => Promise<{ rows: JsonObject[] }> const rowsResult = await queryImpl(ADMIN_OBSERVED_PRODUCTS_QUERY) return rowsResult.rows.map((row) => mapAdminObservedProductItem(mapAdminObservedProductRow(row), bindings)) } diff --git a/apps/backend/src/services/admin/platform-config/writes.js b/apps/backend/src/services/admin/platform-config/writes.ts similarity index 83% rename from apps/backend/src/services/admin/platform-config/writes.js rename to apps/backend/src/services/admin/platform-config/writes.ts index bb8782c3..8886455d 100644 --- a/apps/backend/src/services/admin/platform-config/writes.js +++ b/apps/backend/src/services/admin/platform-config/writes.ts @@ -1,14 +1,14 @@ -// @ts-check - import { applyOptionalStringField } from "./domain.js"; -export function buildAdminAgisoShopConfigUpdate(item, current = {}) { +type JsonObject = Record + +export function buildAdminAgisoShopConfigUpdate(item: JsonObject, current: JsonObject = {}) { const shopId = String(item?.shopId || "").trim(); if (!shopId) { return null; } - const next = /** @type {Record} */ ({ ...current }); + const next: JsonObject = { ...current }; const shopName = String(item?.shopName || "").trim(); const accessToken = String(item?.accessToken || "").trim(); const messageTemplate = String(item?.messageTemplate || "").trim(); @@ -58,20 +58,16 @@ export function buildAdminAgisoShopConfigUpdate(item, current = {}) { } export function buildAdminAgisoMessagingSavePayload( - payload = {}, - options = {} + payload: JsonObject = {}, + options: JsonObject = {} ) { const rawItems = Array.isArray(payload.shops) ? payload.shops : []; - const currentDefaults = /** @type {Record} */ ( - options.currentDefaults || {} - ); - const currentMap = /** @type {Record>} */ ( - options.currentMap || {} - ); - const nextDefaults = /** @type {Record} */ ({ + const currentDefaults: JsonObject = options.currentDefaults || {}; + const currentMap: Record = options.currentMap || {}; + const nextDefaults: JsonObject = { ...currentDefaults, - }); - const nextMap = /** @type {Record>} */ ({}); + }; + const nextMap: Record = {}; applyOptionalStringField(nextDefaults, "messageTemplate", payload.defaults); applyOptionalStringField( @@ -103,7 +99,7 @@ export function buildAdminAgisoMessagingSavePayload( }; } -export function normalizeAdminCloudtentaclesSourceConfigPayload(payload = {}) { +export function normalizeAdminCloudtentaclesSourceConfigPayload(payload: JsonObject = {}) { const sourceKey = String(payload.sourceKey || payload.key || "").trim() || "default"; return { diff --git a/docs/backend-typescript-migration-plan.md b/docs/backend-typescript-migration-plan.md index 49ebaebb..3106e569 100644 --- a/docs/backend-typescript-migration-plan.md +++ b/docs/backend-typescript-migration-plan.md @@ -589,6 +589,16 @@ - `npm run typecheck` - `npm run build` - `npm test` 共 139 个用例通过 +138. 后台平台配置观察 / 查询 / 写入辅助模块迁移到 `.ts`: + - `src/services/admin/platform-config/observed-products.ts` + - `src/services/admin/platform-config/fulfillment.ts` + - `src/services/admin/platform-config/writes.ts` +139. 后台观察商品列表、履约手动查询结果组装、Agiso 店铺消息配置写入与 Cloudtentacles 来源配置归一化已进入 TS 编译链路;查询依赖、payload 与配置 map 补齐动态对象类型 +140. Docker 内验证通过: + - `src/services/admin/platform-config/observed-products.test.js`、`fulfillment.test.js`、`writes.test.js` 共 8 个用例通过 + - `npm run typecheck` + - `npm run build` + - `npm test` 共 139 个用例通过 ## 下一步建议