统一状态码,优化对应逻辑
This commit is contained in:
@@ -43,6 +43,58 @@ export interface MockWebhookLog {
|
||||
payload: UTSJSONObject
|
||||
}
|
||||
|
||||
/**
|
||||
* 集中管理物流常量与映射
|
||||
*/
|
||||
export const LogisticsConstants = {
|
||||
// 8 大标准配送状态映射
|
||||
STATUS_MAP: {
|
||||
'ORDER_PLACED': '已下单',
|
||||
'SHIPPED': '已发货',
|
||||
'PENDING': '待发货',
|
||||
'IN_TRANSIT': '运输中',
|
||||
'OUT_FOR_DELIVERY': '派送中',
|
||||
'READY_FOR_PICKUP': '待取件',
|
||||
'DELIVERED': '已签收',
|
||||
'EXCEPTION': '异常',
|
||||
'RETURNED': '退回/退件'
|
||||
} as UTSJSONObject,
|
||||
|
||||
// 状态对应图标
|
||||
STATUS_ICONS: {
|
||||
'ORDER_PLACED': '📦',
|
||||
'SHIPPED': '🚚',
|
||||
'IN_TRANSIT': '🛤️',
|
||||
'OUT_FOR_DELIVERY': '🛵',
|
||||
'READY_FOR_PICKUP': '🏪',
|
||||
'DELIVERED': '✅',
|
||||
'EXCEPTION': '❗',
|
||||
'RETURNED': '🔄'
|
||||
} as UTSJSONObject,
|
||||
|
||||
// 时间线简短标签
|
||||
STATUS_LABELS_SHORT: {
|
||||
'ORDER_PLACED': '下单',
|
||||
'SHIPPED': '出库',
|
||||
'IN_TRANSIT': '运输',
|
||||
'OUT_FOR_DELIVERY': '派送',
|
||||
'READY_FOR_PICKUP': '待取',
|
||||
'DELIVERED': '完成',
|
||||
'EXCEPTION': '异常',
|
||||
'RETURNED': '退回'
|
||||
} as UTSJSONObject,
|
||||
|
||||
// 常用快递公司列表
|
||||
CARRIERS: [
|
||||
{ label: '顺丰速运', value: '顺丰速运' },
|
||||
{ label: '圆通速递', value: '圆通速递' },
|
||||
{ label: '中通快递', value: '中通快递' },
|
||||
{ label: '申通快递', value: '申通快递' },
|
||||
{ label: '韵达快递', value: '韵达快递' },
|
||||
{ label: '京东快递', value: '京东快递' }
|
||||
] as UTSJSONObject[]
|
||||
}
|
||||
|
||||
class MockService {
|
||||
// 全局 Mock 配置项
|
||||
public isTestMode: boolean = true
|
||||
@@ -238,32 +290,114 @@ class MockService {
|
||||
const { data: orderData } = await supa.from('ml_orders').select('id,order_no').eq('order_no', orderNo).single().execute()
|
||||
const orderId = (orderData != null) ? orderData['id'] as string : null
|
||||
|
||||
// 2. 创建运单记录
|
||||
const { data: waybill, error: wError } = await supa.from('platform_express_waybills').insert({
|
||||
// 2. 创建或更新运单记录
|
||||
// 先查询是否存在
|
||||
const { data: existingWaybills } = await supa.from('platform_express_waybills').select('id').eq('order_no', orderNo).execute()
|
||||
let waybillIdForEvent: string | null = null
|
||||
|
||||
const waybillPayload = {
|
||||
order_id: orderId,
|
||||
order_no: orderNo,
|
||||
carrier: carrier,
|
||||
tracking_no: trackingNo,
|
||||
current_status_code: 'SHIPPED',
|
||||
current_status_text: '商家已发货',
|
||||
last_synced_at: new Date().toISOString()
|
||||
}).select().single().execute()
|
||||
last_synced_at: new Date().toISOString(),
|
||||
source: 'mock'
|
||||
} as UTSJSONObject
|
||||
|
||||
if (wError != null) {
|
||||
console.error('Bind shipment error:', wError)
|
||||
if (existingWaybills != null && (existingWaybills as Array<any>).length > 0) {
|
||||
// 更新
|
||||
const waybillRow = (existingWaybills as Array<UTSJSONObject>)[0]
|
||||
waybillIdForEvent = waybillRow['id'] as string
|
||||
await supa.from('platform_express_waybills').update(waybillPayload).eq('id', waybillIdForEvent).execute()
|
||||
} else {
|
||||
// 插入
|
||||
const { data: newWaybill, error: insError } = await supa.from('platform_express_waybills').insert(waybillPayload).select().single().execute()
|
||||
if (insError != null) {
|
||||
console.error('Insert waybill error:', insError)
|
||||
return false
|
||||
}
|
||||
if (newWaybill != null) {
|
||||
waybillIdForEvent = (newWaybill as UTSJSONObject)['id'] as string
|
||||
}
|
||||
}
|
||||
|
||||
if (waybillIdForEvent == null) {
|
||||
console.error('Bind shipment error: Failed to get waybill ID')
|
||||
return false
|
||||
}
|
||||
|
||||
// 2.5 更新订单表状态
|
||||
const { error: oError } = await supa.from('ml_orders').update({
|
||||
order_status: 3, // SHIPPED
|
||||
shipping_status: 2, // 已向物流公司提交
|
||||
shipped_at: new Date().toISOString()
|
||||
}).eq('order_no', orderNo).execute()
|
||||
|
||||
if (oError != null) {
|
||||
console.error('Update ml_orders error:', oError)
|
||||
// 继续执行,因为运单记录已经拉起
|
||||
}
|
||||
|
||||
// 3. 产生初始轨迹
|
||||
await supa.from('platform_express_tracking_events').insert({
|
||||
waybill_id: waybill!['id'] as string,
|
||||
waybill_id: waybillIdForEvent,
|
||||
carrier: carrier,
|
||||
tracking_no: trackingNo,
|
||||
event_time: new Date().toISOString(),
|
||||
event_code: 'CREATED',
|
||||
event_text: '商家已发货,等待快递公司揽收',
|
||||
status_code: 'SHIPPED',
|
||||
dedupe_key: 'INIT_' + Date.now()
|
||||
dedupe_key: 'INIT_' + orderNo + '_' + Date.now(),
|
||||
evidence_urls: []
|
||||
}).execute()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 用户确认取件逻辑
|
||||
async confirmReceipt(orderNo: string): Promise<boolean> {
|
||||
// 1. 获取运单信息
|
||||
const { data: waybills } = await supa.from('platform_express_waybills')
|
||||
.select('id,carrier,tracking_no')
|
||||
.eq('order_no', orderNo)
|
||||
.execute()
|
||||
|
||||
if (waybills == null || (waybills as Array<any>).length === 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
const waybill = (waybills as Array<UTSJSONObject>)[0]
|
||||
const waybillId = waybill['id'] as string
|
||||
const carrier = waybill['carrier'] as string
|
||||
const trackingNo = waybill['tracking_no'] as string
|
||||
const now = new Date().toISOString()
|
||||
|
||||
// 2. 更新运单主表状态
|
||||
await supa.from('platform_express_waybills').update({
|
||||
current_status_code: 'DELIVERED',
|
||||
current_status_text: '用户已确认取件',
|
||||
last_synced_at: now
|
||||
}).eq('id', waybillId).execute()
|
||||
|
||||
// 3. 更新订单主表状态 (DEVLIVERED = 4)
|
||||
await supa.from('ml_orders').update({
|
||||
order_status: 4,
|
||||
delivered_at: now
|
||||
}).eq('order_no', orderNo).execute()
|
||||
|
||||
// 4. 插入取件轨迹
|
||||
await supa.from('platform_express_tracking_events').insert({
|
||||
waybill_id: waybillId,
|
||||
carrier: carrier,
|
||||
tracking_no: trackingNo,
|
||||
event_time: now,
|
||||
event_code: 'USER_PICKUP',
|
||||
event_text: '用户已确认取件,感谢使用',
|
||||
status_code: 'DELIVERED',
|
||||
dedupe_key: 'CONFIRM_' + orderNo + '_' + Date.now(),
|
||||
evidence_urls: []
|
||||
}).execute()
|
||||
|
||||
return true
|
||||
@@ -315,12 +449,27 @@ class MockService {
|
||||
|
||||
console.log('Found Waybill ID:', final_id)
|
||||
|
||||
// 状态映射
|
||||
// 状态映射 (根据 状态映射表.md 规范)
|
||||
let status_code = 'IN_TRANSIT'
|
||||
if (yto_status === 'GOT' || yto_status === 'SEND') status_code = 'IN_TRANSIT'
|
||||
else if (yto_status === 'SENT') status_code = 'OUT_FOR_DELIVERY'
|
||||
else if (yto_status === 'SIGNED') status_code = 'DELIVERED'
|
||||
else if (yto_status === 'FAILED') status_code = 'EXCEPTION'
|
||||
if (yto_status === 'GOT' || yto_status === 'SEND' || yto_status === 'TRANSIT') {
|
||||
status_code = 'IN_TRANSIT'
|
||||
} else if (yto_status === 'SENT') {
|
||||
status_code = 'OUT_FOR_DELIVERY'
|
||||
} else if (yto_status === 'PICKUP') {
|
||||
status_code = 'READY_FOR_PICKUP'
|
||||
} else if (yto_status === 'SIGNED' || yto_status === 'DELIVERED') {
|
||||
status_code = 'DELIVERED'
|
||||
} else if (yto_status === 'FAILED' || yto_status === 'EXCEPTION') {
|
||||
status_code = 'EXCEPTION'
|
||||
} else if (yto_status === 'RETURNED') {
|
||||
status_code = 'RETURNED'
|
||||
} else {
|
||||
// 容错:如果是已知的 8 大状态之一,直接使用
|
||||
const validStates = ['ORDER_PLACED', 'SHIPPED', 'IN_TRANSIT', 'OUT_FOR_DELIVERY', 'READY_FOR_PICKUP', 'DELIVERED', 'EXCEPTION', 'RETURNED']
|
||||
if (validStates.indexOf(yto_status) > -1) {
|
||||
status_code = yto_status
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 执行更新 (确保 ID 不为空)
|
||||
const updateRes = await supa.from('platform_express_waybills').update({
|
||||
@@ -334,11 +483,22 @@ class MockService {
|
||||
}
|
||||
|
||||
// 4. 插入轨迹 (确保 ID 不为空)
|
||||
const acceptTimeRaw = payload['acceptTime'] as string
|
||||
let eventTimeToStore = new Date().toISOString()
|
||||
if (acceptTimeRaw != null && acceptTimeRaw != '') {
|
||||
const normalized = (acceptTimeRaw.indexOf('T') > -1) ? acceptTimeRaw : acceptTimeRaw.replace(' ', 'T')
|
||||
const parsed = new Date(normalized)
|
||||
const parsedMs = parsed.getTime()
|
||||
if (parsedMs == parsedMs) {
|
||||
eventTimeToStore = parsed.toISOString()
|
||||
}
|
||||
}
|
||||
|
||||
const eventRes = await supa.from('platform_express_tracking_events').insert({
|
||||
waybill_id: final_id,
|
||||
carrier: carrier,
|
||||
tracking_no: tracking_no,
|
||||
event_time: payload['acceptTime'] as string || new Date().toISOString(),
|
||||
event_time: eventTimeToStore,
|
||||
event_code: yto_status,
|
||||
event_text: event_text,
|
||||
status_code: status_code,
|
||||
@@ -398,6 +558,32 @@ class MockService {
|
||||
const m = d.getMinutes().toString().padStart(2, '0')
|
||||
return `${Y}-${M}-${D} ${h}:${m}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一的状态文本转换工具
|
||||
*/
|
||||
public getStatusText(status: string): string {
|
||||
const text = LogisticsConstants.STATUS_MAP[status] as string | null
|
||||
return (text != null) ? text : status
|
||||
}
|
||||
|
||||
/**
|
||||
* 依照需求文档:展示第三方回传的原始轨迹文案
|
||||
*/
|
||||
public getDisplayMessage(text: string, status: string): string {
|
||||
if (!text) return '暂无动态'
|
||||
|
||||
// 不再进行脱敏/泛化处理,直接返回原始文案
|
||||
return text
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一的状态图标转换工具
|
||||
*/
|
||||
public getStatusIcon(status: string): string {
|
||||
const icon = LogisticsConstants.STATUS_ICONS[status] as string | null
|
||||
return (icon != null) ? icon : '📦'
|
||||
}
|
||||
}
|
||||
|
||||
export const mockService = new MockService()
|
||||
|
||||
Reference in New Issue
Block a user