收紧后端 TypeScript:统一 Json 类型与 TaskContext 契约

关闭 allowJs;集中 JsonObject 定义并替换分散 any 别名;parseTaskContext 返回 TaskContext;任务详情 API 标注 AdminTaskDetailView;测试减少 as any。
This commit is contained in:
yml2213
2026-07-10 15:52:05 +08:00
parent e7244eaa5e
commit 8bcd9bbd81
79 changed files with 415 additions and 259 deletions
@@ -1,3 +1,4 @@
import type { JsonObject } from '../../types/json.js'
import {
listCloudtentaclesSources,
} from '../platforms/cloudtentacles/source-config-service.js'
@@ -17,8 +18,6 @@ import {
} from './cloudtentacles-override-rule-service.js'
import { normalizeCloudtentaclesMatchName } from './cloudtentacles-match-utils.js'
type JsonObject = Record<string, any>
type CloudtentaclesSource = {
key?: string
label?: string
@@ -1,4 +1,5 @@
import path from 'node:path'
import type { JsonObject } from '../../types/json.js'
import { APP_CONFIG_KEYS } from '../../config/app-config-keys.js'
import { PROJECT_ROOT } from '../../config/runtime.js'
@@ -14,8 +15,6 @@ const CLOUDTENTACLES_OVERRIDE_RULE_FILE_PATH = path.join(
'cloudtentacles-override-rules.json',
)
type JsonObject = Record<string, any>
export type CloudtentaclesOverrideDeliveryItem = {
cloudSkuId: number
cloudSkuName: string
@@ -2,22 +2,111 @@ import assert from 'node:assert/strict'
import test from 'node:test'
import { syncDeliveryTasksForOrderWithDeps } from './delivery-task-service.js'
import type { OrderItemRow, OrderRow, TaskRow } from '../../types/repository/rows.js'
import type { JsonObject } from '../../types/json.js'
type CreatedTaskInput = {
orderItemId?: number
contextJson?: string
taskStatus?: string
executorKey?: string
[key: string]: unknown
}
function stubOrder(patch: Partial<OrderRow> & Pick<OrderRow, 'id' | 'platform_order_id'>): OrderRow {
return {
id: patch.id,
order_id: patch.id,
provider: patch.provider || 'open_91',
platform: patch.platform || 'kuaishou',
shop_id: patch.shop_id || 'shop-1',
shop_name: patch.shop_name || '测试店铺',
platform_order_id: patch.platform_order_id,
order_status: patch.order_status || 'created',
pay_status: patch.pay_status || 'pending_payment',
buyer_id: '',
buyer_name: '',
receiver_contact: '',
total_amount: 0,
currency: 'CNY',
raw_payload_json: '{}',
paid_at: null,
created_at: '2026-05-29T00:00:00.000Z',
updated_at: '2026-05-29T00:00:00.000Z',
...patch,
} as OrderRow
}
function stubOrderItem(
patch: Partial<OrderItemRow> & Pick<OrderItemRow, 'id' | 'order_id' | 'sku_code'>,
): OrderItemRow {
return {
id: patch.id,
order_id: patch.order_id,
sku_code: patch.sku_code,
sku_name: patch.sku_name || patch.sku_code,
quantity: patch.quantity || 1,
spec_json: '{}',
item_snapshot_json: patch.item_snapshot_json || {},
created_at: '2026-05-29T00:00:00.000Z',
updated_at: '2026-05-29T00:00:00.000Z',
...patch,
} as OrderItemRow
}
function stubCreatedTask(id: number, input: CreatedTaskInput): TaskRow {
return {
id,
order_id: 0,
order_item_id: Number(input.orderItemId || 0),
unit_index: 1,
platform_order_id: '',
profile_id: 0,
task_no: 'DT-test',
executor_key: String(input.executorKey || ''),
task_status: String(input.taskStatus || 'pending'),
delivery_status: 'pending',
result_code: '',
result_message: '',
automation_mode: 'manual',
requires_claim: true,
user_action_status: 'pending_claim',
attempt_count: 0,
runtime_session_id: '',
login_type: '',
nickname: '',
role_name: '',
role_id: '',
area: '',
partition_name: '',
claim_token: '',
primary_claim_token: '',
primary_claim_token_id: null,
primary_claim_token_status: '',
artifacts_json: '{}',
context_json: String(input.contextJson || '{}'),
screenshot_path: '',
last_error: '',
retry_count: 0,
created_at: '2026-05-29T00:00:00.000Z',
updated_at: '2026-05-29T00:00:00.000Z',
claimed_at: null,
role_confirmed_at: null,
redeemed_at: null,
} as TaskRow
}
test('syncDeliveryTasksForOrder 多账号候选时不提前固定 cloudtentacles 账号', async () => {
const createdInputs: any[] = []
const createdInputs: CreatedTaskInput[] = []
await syncDeliveryTasksForOrderWithDeps(
{
stubOrder({
id: 1,
pay_status: 'pending_payment',
provider: 'open_91',
platform: 'kuaishou',
shop_id: 'shop-1',
shop_name: '测试店铺',
platform_order_id: '2614900602069169',
} as any,
}),
[
{
stubOrderItem({
id: 10,
order_id: 1,
sku_code: 'SKU-1',
@@ -37,9 +126,9 @@ test('syncDeliveryTasksForOrder 多账号候选时不提前固定 cloudtentacles
},
],
},
},
},
] as any,
} as JsonObject,
}),
],
{
listTasksByOrderId: async () => [],
getFulfillmentProfileByKey: async () => ({
@@ -48,44 +137,33 @@ test('syncDeliveryTasksForOrder 多账号候选时不提前固定 cloudtentacles
profile_name: 'kuaishou-lewan 履约',
executor_key: 'kuaishou_ct_assisted',
}),
createTask: async (input: any) => {
createdInputs.push(input)
return {
id: 100,
order_item_id: input.orderItemId,
context_json: input.contextJson,
task_status: input.taskStatus,
executor_key: input.executorKey,
} as any
createTask: async (input) => {
createdInputs.push(input as CreatedTaskInput)
return stubCreatedTask(100, input as CreatedTaskInput)
},
nowIso: () => '2026-05-29T09:05:46.658Z',
randomId: () => 'DT-test',
},
)
const context = JSON.parse(createdInputs[0].contextJson)
assert.deepEqual(context.kuaishouCloudFulfillment.binding.cloudSourceKeys, [
'account-a',
'account-b',
])
assert.equal(context.kuaishouCloudFulfillment.binding.resolvedSourceKey, '')
const context = JSON.parse(String(createdInputs[0]?.contextJson || '{}')) as JsonObject
const fulfillment = context.kuaishouCloudFulfillment as JsonObject
const binding = fulfillment.binding as JsonObject
assert.deepEqual(binding.cloudSourceKeys, ['account-a', 'account-b'])
assert.equal(binding.resolvedSourceKey, '')
})
test('syncDeliveryTasksForOrder 单账号候选时保留固定 cloudtentacles 账号', async () => {
const createdInputs: any[] = []
const createdInputs: CreatedTaskInput[] = []
await syncDeliveryTasksForOrderWithDeps(
{
stubOrder({
id: 2,
pay_status: 'pending_payment',
provider: 'open_91',
platform: 'kuaishou',
shop_id: 'shop-1',
shop_name: '测试店铺',
platform_order_id: '2614900602069170',
} as any,
}),
[
{
stubOrderItem({
id: 11,
order_id: 2,
sku_code: 'SKU-1',
@@ -97,9 +175,9 @@ test('syncDeliveryTasksForOrder 单账号候选时保留固定 cloudtentacles
cloudSkuId: 74,
cloudSkuName: '荣耀勋章礼包(30个)',
},
},
},
] as any,
} as JsonObject,
}),
],
{
listTasksByOrderId: async () => [],
getFulfillmentProfileByKey: async () => ({
@@ -108,22 +186,18 @@ test('syncDeliveryTasksForOrder 单账号候选时保留固定 cloudtentacles
profile_name: 'kuaishou-lewan 履约',
executor_key: 'kuaishou_ct_assisted',
}),
createTask: async (input: any) => {
createdInputs.push(input)
return {
id: 101,
order_item_id: input.orderItemId,
context_json: input.contextJson,
task_status: input.taskStatus,
executor_key: input.executorKey,
} as any
createTask: async (input) => {
createdInputs.push(input as CreatedTaskInput)
return stubCreatedTask(101, input as CreatedTaskInput)
},
nowIso: () => '2026-05-29T09:05:46.658Z',
randomId: () => 'DT-test',
},
)
const context = JSON.parse(createdInputs[0].contextJson)
assert.deepEqual(context.kuaishouCloudFulfillment.binding.cloudSourceKeys, ['account-a'])
assert.equal(context.kuaishouCloudFulfillment.binding.resolvedSourceKey, 'account-a')
const context = JSON.parse(String(createdInputs[0]?.contextJson || '{}')) as JsonObject
const fulfillment = context.kuaishouCloudFulfillment as JsonObject
const binding = fulfillment.binding as JsonObject
assert.deepEqual(binding.cloudSourceKeys, ['account-a'])
assert.equal(binding.resolvedSourceKey, 'account-a')
})