289 lines
6.4 KiB
TypeScript
289 lines
6.4 KiB
TypeScript
import { apiDelete, apiGet, apiPost } from '@/lib/http'
|
|
|
|
/** 待分类队列(按内部 SKU 聚合)。 */
|
|
export type PendingChannelGroup = {
|
|
internal_sku: string
|
|
sku_name: string
|
|
providers: string[]
|
|
shop_ids: string[]
|
|
shops: Array<{ id: string; name: string }>
|
|
sku_codes: string[]
|
|
pending_reasons: string[]
|
|
item_count: number
|
|
revenue_fen: number
|
|
first_seen_at: string
|
|
last_seen_at: string
|
|
}
|
|
|
|
export type PendingChannelGroupListResult = {
|
|
items: PendingChannelGroup[]
|
|
total: number
|
|
page: number
|
|
pageSize: number
|
|
}
|
|
|
|
/** 渠道规则(L1)。 */
|
|
export type ChannelRule = {
|
|
id: number
|
|
match_key_type: 'internal_sku'
|
|
match_key: string
|
|
channel: 'work_order' | 'affiliate_dash' | 'third_party_voucher' | 'manual'
|
|
priority: number
|
|
enabled: boolean
|
|
is_fallback: boolean
|
|
source: string
|
|
config_json: Record<string, unknown>
|
|
note: string
|
|
}
|
|
|
|
export type ChannelRuleListResult = {
|
|
items: ChannelRule[]
|
|
total: number
|
|
page: number
|
|
pageSize: number
|
|
}
|
|
|
|
export type InternalSkuMappingMatchType =
|
|
| 'sku_code'
|
|
| 'sku_nick'
|
|
| 'out_sku_sn'
|
|
| 'spec'
|
|
| 'sku_name'
|
|
|
|
export type InternalSkuMapping = {
|
|
id: number
|
|
provider: string
|
|
shop_id: string
|
|
match_type: InternalSkuMappingMatchType
|
|
match_value: string
|
|
internal_sku: string
|
|
priority: number
|
|
enabled: boolean
|
|
source: string
|
|
note: string
|
|
updated_at: string
|
|
}
|
|
|
|
export type InternalSkuMappingListResult = {
|
|
items: InternalSkuMapping[]
|
|
total: number
|
|
page: number
|
|
pageSize: number
|
|
}
|
|
|
|
export type ChannelException = {
|
|
id: number
|
|
reason: string
|
|
status: string
|
|
scope_key: string
|
|
item_count: number
|
|
first_seen_at: string
|
|
last_seen_at: string
|
|
detail_json: unknown
|
|
}
|
|
|
|
export type ChannelExceptionListResult = {
|
|
items: ChannelException[]
|
|
total: number
|
|
page: number
|
|
pageSize: number
|
|
}
|
|
|
|
export type PipelineRunResult = Record<string, unknown>
|
|
|
|
export type PendingWorkOrderRetryResult = {
|
|
scanned: number
|
|
createdWorkOrders: number
|
|
assigned: number
|
|
remaining: number
|
|
carrierFailed: number
|
|
skipReasons: Record<string, number>
|
|
}
|
|
|
|
export type DeletePendingChannelGroupResult = {
|
|
archivedItems: number
|
|
preservedOrders: number
|
|
deletedCostSnapshots: number
|
|
resolvedExceptions: number
|
|
refreshedDays: number
|
|
skippedClosedDays: number
|
|
}
|
|
|
|
export type FinancePipelineStatus = {
|
|
pipeline: string
|
|
label: string
|
|
lastItemId: number
|
|
lastStatDate: string | null
|
|
lastSuccessAt: string | null
|
|
lastError: string
|
|
jobId: string
|
|
scheduler: {
|
|
running: boolean
|
|
enabled: boolean
|
|
lastRunAt: string
|
|
lastFinishedAt: string
|
|
nextRunAt: string
|
|
lastStatus: string
|
|
lastMessage: string
|
|
} | null
|
|
}
|
|
|
|
export function fetchPendingChannelGroups(
|
|
params: {
|
|
page?: number
|
|
pageSize?: number
|
|
keyword?: string
|
|
} = {},
|
|
) {
|
|
return apiGet<PendingChannelGroupListResult>('/api/v1/admin/fulfillment/pending', params)
|
|
}
|
|
|
|
export function fetchChannelExceptions(
|
|
params: {
|
|
reason?: string
|
|
status?: string
|
|
page?: number
|
|
pageSize?: number
|
|
} = {},
|
|
) {
|
|
return apiGet<ChannelExceptionListResult>('/api/v1/admin/fulfillment/exceptions', params)
|
|
}
|
|
|
|
export function retryPendingWorkOrderRouting(
|
|
payload: { internalSku?: string; limit?: number } = {},
|
|
) {
|
|
return apiPost<PendingWorkOrderRetryResult>(
|
|
'/api/v1/admin/fulfillment/pending/retry-work-orders',
|
|
payload,
|
|
)
|
|
}
|
|
|
|
export function deletePendingChannelGroup(payload: { internalSku: string }) {
|
|
return apiPost<DeletePendingChannelGroupResult>(
|
|
'/api/v1/admin/fulfillment/pending/delete',
|
|
payload,
|
|
)
|
|
}
|
|
|
|
export function assignChannelByInternalSku(payload: {
|
|
internalSku: string
|
|
channel: string
|
|
note?: string
|
|
}) {
|
|
return apiPost<{ updated: number; carrierFailed: number; ruleCreated: boolean }>(
|
|
'/api/v1/admin/fulfillment/assign',
|
|
payload,
|
|
)
|
|
}
|
|
|
|
export function assignChannelToItems(payload: {
|
|
orderItemIds: number[]
|
|
channel: string
|
|
note?: string
|
|
}) {
|
|
return apiPost<{ updated: number; carrierFailed: number }>(
|
|
'/api/v1/admin/fulfillment/assign',
|
|
payload,
|
|
)
|
|
}
|
|
|
|
export function switchChannelForItems(payload: {
|
|
orderItemIds: number[]
|
|
channel: string
|
|
note?: string
|
|
}) {
|
|
return apiPost<{
|
|
switched: number
|
|
failed: number
|
|
errors: Array<{ orderItemId: number; reason: string }>
|
|
}>('/api/v1/admin/fulfillment/switch', payload)
|
|
}
|
|
|
|
export function fetchChannelRules(
|
|
params: {
|
|
channel?: string
|
|
source?: string
|
|
keyword?: string
|
|
enabled?: boolean
|
|
page?: number
|
|
pageSize?: number
|
|
} = {},
|
|
) {
|
|
return apiGet<ChannelRuleListResult>('/api/v1/admin/fulfillment/rules', params)
|
|
}
|
|
|
|
export function fetchInternalSkuMappings(
|
|
params: {
|
|
keyword?: string
|
|
provider?: string
|
|
shopId?: string
|
|
matchType?: string
|
|
page?: number
|
|
pageSize?: number
|
|
} = {},
|
|
) {
|
|
return apiGet<InternalSkuMappingListResult>(
|
|
'/api/v1/admin/fulfillment/internal-sku-mappings',
|
|
params,
|
|
)
|
|
}
|
|
|
|
export function saveInternalSkuMapping(payload: {
|
|
provider?: string
|
|
shopId?: string
|
|
matchType: InternalSkuMappingMatchType
|
|
matchValue: string
|
|
internalSku: string
|
|
priority?: number
|
|
note?: string
|
|
enabled?: boolean
|
|
}) {
|
|
return apiPost<{ id: number }>('/api/v1/admin/fulfillment/internal-sku-mappings', payload)
|
|
}
|
|
|
|
export function deleteInternalSkuMapping(id: number) {
|
|
return apiDelete<boolean>(`/api/v1/admin/fulfillment/internal-sku-mappings/${id}`)
|
|
}
|
|
|
|
export function saveChannelRule(payload: {
|
|
id?: number
|
|
matchKeyType: string
|
|
matchKey: string
|
|
channel: string
|
|
priority?: number
|
|
enabled?: boolean
|
|
note?: string
|
|
}) {
|
|
return apiPost<{ id: number }>('/api/v1/admin/fulfillment/rules', payload)
|
|
}
|
|
|
|
export function deleteChannelRule(ruleId: number) {
|
|
return apiDelete<{ deleted: boolean }>(`/api/v1/admin/fulfillment/rules/${ruleId}`)
|
|
}
|
|
|
|
export function deleteChannelRules(ids: number[]) {
|
|
return apiPost<{
|
|
deletedCount: number
|
|
deletedIds: number[]
|
|
missingIds: number[]
|
|
}>('/api/v1/admin/fulfillment/rules/batch-delete', { ids })
|
|
}
|
|
|
|
export function forceDeleteChannelRules(ids: number[]) {
|
|
return apiPost<{
|
|
deletedCount: number
|
|
deletedIds: number[]
|
|
missingIds: number[]
|
|
}>('/api/v1/admin/fulfillment/rules/force-delete', { ids })
|
|
}
|
|
|
|
export function fetchPipelineStatus() {
|
|
return apiGet<FinancePipelineStatus[]>('/api/v1/admin/fulfillment/pipeline/status')
|
|
}
|
|
|
|
export function runFinancePipeline(payload: { days?: number; pipeline?: string } = {}) {
|
|
return apiPost<PipelineRunResult>('/api/v1/admin/fulfillment/pipeline/run', payload, {
|
|
timeout: 300_000,
|
|
})
|
|
}
|