590 lines
20 KiB
Plaintext
590 lines
20 KiB
Plaintext
import supa from '@/components/supadb/aksupainstance.uts'
|
|
|
|
/**
|
|
* 配送模块数据服务 (Express Service)
|
|
* 依据: pages/mall/delivery/doc/需求文档/
|
|
* 功能: 对接 Supabase 生产表 (platform_express_*)
|
|
*/
|
|
|
|
export interface MockOrder {
|
|
id?: string
|
|
order_no: string
|
|
status: string
|
|
created_at: string
|
|
receiver_name: string
|
|
receiver_masked_phone: string
|
|
address: string
|
|
amount: string
|
|
carrier: string
|
|
tracking_no: string
|
|
last_synced_at?: string
|
|
current_status_text?: string
|
|
}
|
|
|
|
export interface MockTrackingEvent {
|
|
event_id: string
|
|
event_time: string
|
|
event_code: string
|
|
event_text: string
|
|
status_code: string
|
|
node_name?: string
|
|
location?: string
|
|
evidence_urls: string[]
|
|
raw_payload?: string
|
|
}
|
|
|
|
export interface MockWebhookLog {
|
|
time: string
|
|
carrier: string
|
|
tracking_no: string
|
|
event_code: string
|
|
success: boolean
|
|
result_text: string
|
|
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
|
|
public autoPush: boolean = true
|
|
public mockUrl: string = 'http://192.168.1.100:3000/mock/v1'
|
|
|
|
constructor() {}
|
|
|
|
async getMockOrders(): Promise<MockOrder[]> {
|
|
const { data, error } = await supa.from('platform_express_waybills')
|
|
.select('*,ml_orders(*)')
|
|
.order('created_at', { ascending: false })
|
|
.execute()
|
|
|
|
if (error != null) {
|
|
console.error('Fetch orders error:', error)
|
|
return []
|
|
}
|
|
|
|
const list = data as Array<UTSJSONObject>
|
|
return list.map((item: UTSJSONObject): MockOrder => {
|
|
// 兼容 Supabase 关联查询返回对象或数组的情况
|
|
let ml: UTSJSONObject | null = null
|
|
const mlData = item['ml_orders']
|
|
if (mlData != null) {
|
|
if (mlData instanceof Array && (mlData as Array<any>).length > 0) {
|
|
ml = (mlData as Array<UTSJSONObject>)[0]
|
|
} else if (!(mlData instanceof Array)) {
|
|
ml = mlData as UTSJSONObject
|
|
}
|
|
}
|
|
|
|
return {
|
|
id: item['id'] as string,
|
|
order_no: item['order_no'] as string || (ml != null ? ml['order_no'] as string : ''),
|
|
status: item['current_status_code'] as string,
|
|
created_at: this.formatDBTime(item['created_at'] as string),
|
|
receiver_name: (ml != null ? ml['receiver_name'] as string : '测试用户'),
|
|
receiver_masked_phone: this.maskPhone(ml != null ? ml['receiver_phone'] as string : '138****0000'),
|
|
address: (ml != null ? ml['address'] as string : '系统模拟地址'),
|
|
amount: (ml != null ? ml['amount'] as string : '0.00'),
|
|
carrier: item['carrier'] as string,
|
|
tracking_no: item['tracking_no'] as string,
|
|
last_synced_at: this.formatDBTime(item['last_synced_at'] as string),
|
|
current_status_text: item['current_status_text'] as string
|
|
} as MockOrder
|
|
})
|
|
}
|
|
|
|
async getMockTracking(id: string): Promise<MockTrackingEvent[]> {
|
|
if (!id || id == '') return []
|
|
|
|
// 1. 穿透式查询:先寻找运单 ID
|
|
let waybillId: string | null = null
|
|
let trackingNo: string | null = null
|
|
|
|
// 尝试按订单号找
|
|
const { data: b1 } = await supa.from('platform_express_waybills').select('id,tracking_no').eq('order_no', id).execute()
|
|
if (b1 != null && (b1 as Array<any>).length > 0) {
|
|
const row = (b1 as Array<UTSJSONObject>)[0]
|
|
waybillId = row['id'] as string
|
|
trackingNo = row['tracking_no'] as string
|
|
} else {
|
|
// 尝试按运单号找
|
|
const { data: b2 } = await supa.from('platform_express_waybills').select('id,tracking_no').eq('tracking_no', id).execute()
|
|
if (b2 != null && (b2 as Array<any>).length > 0) {
|
|
const row = (b2 as Array<UTSJSONObject>)[0]
|
|
waybillId = row['id'] as string
|
|
trackingNo = row['tracking_no'] as string
|
|
}
|
|
}
|
|
|
|
if (waybillId != null) {
|
|
// 2. 查该运单聚合的所有轨迹
|
|
// 同样为了稳定,分两次查或使用简单的 or (如果 or 有效)
|
|
let allEvents = [] as MockTrackingEvent[]
|
|
|
|
const { data: events, error } = await supa.from('platform_express_tracking_events')
|
|
.select('*')
|
|
.eq('waybill_id', waybillId!)
|
|
.order('event_time', { ascending: false })
|
|
.execute()
|
|
|
|
if (events != null) {
|
|
allEvents = this.mapToEvents(events as Array<UTSJSONObject>)
|
|
}
|
|
|
|
// 如果按 UUID 没查到,尝试按单号补查
|
|
if (allEvents.length == 0 && trackingNo != null) {
|
|
const { data: events2 } = await supa.from('platform_express_tracking_events')
|
|
.select('*')
|
|
.eq('tracking_no', trackingNo!)
|
|
.order('event_time', { ascending: false })
|
|
.execute()
|
|
if (events2 != null) {
|
|
allEvents = this.mapToEvents(events2 as Array<UTSJSONObject>)
|
|
}
|
|
}
|
|
return allEvents
|
|
}
|
|
|
|
// 3. 最后的保底:直接尝试在轨迹表中匹配 (单号直接搜索)
|
|
const { data: directEvents } = await supa.from('platform_express_tracking_events')
|
|
.select('*')
|
|
.eq('tracking_no', id)
|
|
.order('event_time', { ascending: false })
|
|
.execute()
|
|
|
|
if (directEvents != null && (directEvents as Array<any>).length > 0) {
|
|
return this.mapToEvents(directEvents as Array<UTSJSONObject>)
|
|
}
|
|
|
|
return []
|
|
}
|
|
|
|
/**
|
|
* 模拟各种物流场景 (生成生产测试数据)
|
|
*/
|
|
async runScenario(trackingNo: string, type: string) {
|
|
// 查找运单 (使用通用的单号查询逻辑)
|
|
const { data: waybills } = await supa.from('platform_express_waybills')
|
|
.select('id,carrier,tracking_no')
|
|
.eq('tracking_no', trackingNo)
|
|
.execute()
|
|
|
|
if (waybills == null || (waybills as Array<any>).length === 0) {
|
|
console.error('Scenario Error: Waybill not found', trackingNo)
|
|
return
|
|
}
|
|
|
|
const waybill = (waybills as Array<UTSJSONObject>)[0]
|
|
const waybillId = waybill['id'] as string
|
|
const carrier = waybill['carrier'] as string
|
|
|
|
if (waybillId == null || waybillId == "") {
|
|
console.error('Scenario Error: Waybill ID is null')
|
|
return
|
|
}
|
|
|
|
// 模拟不同步长的数据注入
|
|
const now = new Date().toISOString()
|
|
const events = [] as any[]
|
|
|
|
if (type === 'full') {
|
|
events.push({ waybill_id: waybillId, carrier, tracking_no: trackingNo, event_time: now, event_code: 'SIGNED', event_text: '用户已签收', status_code: 'DELIVERED', dedupe_key: 'SCENARIO_SIG_'+Date.now() })
|
|
events.push({ waybill_id: waybillId, carrier, tracking_no: trackingNo, event_time: now, event_code: 'SENT', event_text: '派送中', status_code: 'OUT_FOR_DELIVERY', dedupe_key: 'SCENARIO_SEN_'+Date.now() })
|
|
} else if (type === 'standard') {
|
|
events.push({ waybill_id: waybillId, carrier, tracking_no: trackingNo, event_time: now, event_code: 'ARRIVED_HUB', event_text: '快件已到达中转站', status_code: 'IN_TRANSIT', dedupe_key: 'SCENARIO_HUB_'+Date.now() })
|
|
} else if (type === 'exception') {
|
|
events.push({ waybill_id: waybillId, carrier, tracking_no: trackingNo, event_time: now, event_code: 'FAILED', event_text: '包裹由于地址不详正在退回', status_code: 'EXCEPTION', dedupe_key: 'SCENARIO_ERR_'+Date.now() })
|
|
}
|
|
|
|
if (events.length > 0) {
|
|
// 1. 插入轨迹节点
|
|
await supa.from('platform_express_tracking_events').insert(events).execute()
|
|
|
|
// 2. 同步更新主表状态 (以最新一个节点为准)
|
|
const latest = events[0] as UTSJSONObject
|
|
await supa.from('platform_express_waybills').update({
|
|
current_status_code: latest['status_code'] as string,
|
|
current_status_text: latest['event_text'] as string,
|
|
last_synced_at: now
|
|
}).eq('id', waybillId).execute()
|
|
}
|
|
}
|
|
|
|
private mapToEvents(list: Array<UTSJSONObject>): MockTrackingEvent[] {
|
|
return list.map((e: UTSJSONObject): MockTrackingEvent => {
|
|
// 解析 evidence_urls (JSONB)
|
|
let urls = [] as string[]
|
|
const rawUrls = e['evidence_urls']
|
|
if (rawUrls instanceof Array) {
|
|
urls = rawUrls as string[]
|
|
}
|
|
|
|
return {
|
|
event_id: e['id'] as string,
|
|
event_time: this.formatDBTime(e['event_time'] as string),
|
|
event_code: e['event_code'] as string || '',
|
|
event_text: e['event_text'] as string || '',
|
|
status_code: e['status_code'] as string || '',
|
|
node_name: e['node_name'] as string || '',
|
|
location: e['location'] as string || '',
|
|
evidence_urls: urls,
|
|
raw_payload: JSON.stringify(e['raw_payload'] || {})
|
|
} as MockTrackingEvent
|
|
})
|
|
}
|
|
|
|
// 绑定发货逻辑:写库
|
|
async bindShipment(orderNo: string, carrier: string, trackingNo: string): Promise<boolean> {
|
|
// 1. 先查找订单主体
|
|
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: 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(),
|
|
source: 'mock'
|
|
} as UTSJSONObject
|
|
|
|
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: waybillIdForEvent,
|
|
carrier: carrier,
|
|
tracking_no: trackingNo,
|
|
event_time: new Date().toISOString(),
|
|
event_code: 'CREATED',
|
|
event_text: '商家已发货,等待快递公司揽收',
|
|
status_code: 'SHIPPED',
|
|
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
|
|
}
|
|
|
|
/**
|
|
* 核心功能:模拟第三方回调接口 (写库版)
|
|
*/
|
|
async pushWebhookData(payload: UTSJSONObject): Promise<boolean> {
|
|
const tracking_no = (payload['mailNo'] != null) ? payload['mailNo'] as string : (payload['tracking_no'] as string)
|
|
const yto_status = (payload['infoContent'] != null) ? payload['infoContent'] as string : (payload['status_code'] as string)
|
|
const event_text = (payload['remark'] != null) ? payload['remark'] as string : (payload['event_text'] as string)
|
|
const order_no = payload['txLogisticId'] as string || ''
|
|
const carrier = payload['carrier'] as string || '圆通速递'
|
|
|
|
console.log('--- Webhook Push Start ---')
|
|
console.log('Target:', tracking_no, order_no)
|
|
|
|
// 1. 记录原始日志 (Raw)
|
|
await supa.from('platform_express_event_raw').insert({
|
|
carrier: carrier,
|
|
tracking_no: tracking_no,
|
|
body: payload,
|
|
received_at: new Date().toISOString(),
|
|
signature_valid: true
|
|
}).execute()
|
|
|
|
// 2. 查找运单 ID (手动分步查询)
|
|
let final_id: string = ""
|
|
|
|
// 尝试按单号
|
|
const res1 = await supa.from('platform_express_waybills').select('id').eq('tracking_no', tracking_no).execute()
|
|
const list1 = res1.data as Array<UTSJSONObject> | null
|
|
if (list1 != null && list1.length > 0) {
|
|
final_id = list1[0]['id'] as string
|
|
} else {
|
|
// 尝试按订单号
|
|
const res2 = await supa.from('platform_express_waybills').select('id').eq('order_no', order_no).execute()
|
|
const list2 = res2.data as Array<UTSJSONObject> | null
|
|
if (list2 != null && list2.length > 0) {
|
|
final_id = list2[0]['id'] as string
|
|
}
|
|
}
|
|
|
|
if (final_id == "") {
|
|
console.error('CRITICAL: Waybill NOT found in DB')
|
|
return false
|
|
}
|
|
|
|
console.log('Found Waybill ID:', final_id)
|
|
|
|
// 状态映射 (根据 状态映射表.md 规范)
|
|
let status_code = 'IN_TRANSIT'
|
|
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({
|
|
current_status_code: status_code,
|
|
current_status_text: event_text,
|
|
last_synced_at: new Date().toISOString()
|
|
}).eq('id', final_id).execute()
|
|
|
|
if (updateRes.error != null) {
|
|
console.error('Update Waybill Error:', updateRes.error)
|
|
}
|
|
|
|
// 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: eventTimeToStore,
|
|
event_code: yto_status,
|
|
event_text: event_text,
|
|
status_code: status_code,
|
|
raw_payload: payload,
|
|
dedupe_key: 'WEBHOOK_' + Date.now()
|
|
}).execute()
|
|
|
|
if (eventRes.error != null) {
|
|
console.error('Insert Event Error:', eventRes.error)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
async getMockWebhookLogs(): Promise<MockWebhookLog[]> {
|
|
const { data } = await supa.from('platform_express_event_raw')
|
|
.select('*')
|
|
.order('received_at', { ascending: false })
|
|
.limit(20)
|
|
.execute()
|
|
|
|
if (data == null) return []
|
|
const list = data as Array<UTSJSONObject>
|
|
return list.map((item: UTSJSONObject): MockWebhookLog => {
|
|
const body = item['body'] as UTSJSONObject
|
|
return {
|
|
time: this.formatDBTime(item['received_at'] as string).split(' ')[1],
|
|
carrier: item['carrier'] as string || 'Unknown',
|
|
tracking_no: item['tracking_no'] as string || '-',
|
|
event_code: body['infoContent'] as string || 'Raw',
|
|
success: true,
|
|
result_text: '接收成功',
|
|
payload: body
|
|
} as MockWebhookLog
|
|
})
|
|
}
|
|
|
|
async syncFromCloud(id: string): Promise<boolean> {
|
|
return new Promise((resolve) => {
|
|
setTimeout(() => resolve(true), 500)
|
|
})
|
|
}
|
|
|
|
private maskPhone(phone: string): string {
|
|
if (!phone) return ''
|
|
if (phone.length < 7) return phone
|
|
return phone.substring(0, 3) + "****" + phone.substring(phone.length - 4)
|
|
}
|
|
|
|
private formatDBTime(iso: string): string {
|
|
if (!iso) return ''
|
|
const d = new Date(iso)
|
|
const Y = d.getFullYear()
|
|
const M = (d.getMonth() + 1).toString().padStart(2, '0')
|
|
const D = d.getDate().toString().padStart(2, '0')
|
|
const h = d.getHours().toString().padStart(2, '0')
|
|
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()
|