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 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 export type PendingWorkOrderRetryResult = { scanned: number createdWorkOrders: number assigned: number remaining: number carrierFailed: number skipReasons: Record } 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('/api/v1/admin/fulfillment/pending', params) } export function fetchChannelExceptions( params: { reason?: string status?: string page?: number pageSize?: number } = {}, ) { return apiGet('/api/v1/admin/fulfillment/exceptions', params) } export function retryPendingWorkOrderRouting( payload: { internalSku?: string; limit?: number } = {}, ) { return apiPost( '/api/v1/admin/fulfillment/pending/retry-work-orders', payload, ) } export function deletePendingChannelGroup(payload: { internalSku: string }) { return apiPost( '/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('/api/v1/admin/fulfillment/rules', params) } export function fetchInternalSkuMappings( params: { keyword?: string provider?: string shopId?: string matchType?: string page?: number pageSize?: number } = {}, ) { return apiGet( '/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(`/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('/api/v1/admin/fulfillment/pipeline/status') } export function runFinancePipeline(payload: { days?: number; pipeline?: string } = {}) { return apiPost('/api/v1/admin/fulfillment/pipeline/run', payload, { timeout: 300_000, }) }