对接数据库,模拟第三方接入信息

This commit is contained in:
not-like-juvenile
2026-02-09 08:54:26 +08:00
parent a5e7afacec
commit 3ea0f008b5
14 changed files with 882 additions and 502 deletions

View File

@@ -1,10 +1,13 @@
import supa from '@/components/supadb/aksupainstance.uts'
/**
* 配送模块模拟数据服务 (Mock Service)
* 配送模块数据服务 (Express Service)
* 依据: pages/mall/delivery/doc/需求文档/
* 涵盖: 商家端订单、平台端轨迹、Webhook 日志与场景模拟
* 功能: 对接 Supabase 生产表 (platform_express_*)
*/
export interface MockOrder {
id?: string
order_no: string
status: string
created_at: string
@@ -15,6 +18,7 @@ export interface MockOrder {
carrier: string
tracking_no: string
last_synced_at?: string
current_status_text?: string
}
export interface MockTrackingEvent {
@@ -39,466 +43,359 @@ export interface MockWebhookLog {
payload: UTSJSONObject
}
export interface MockCarrierOption {
code: string
name: string
}
class MockService {
private orders: MockOrder[] = [
{
order_no: 'ORD20260205001',
status: 'PENDING',
created_at: '2026-02-05 10:00',
receiver_name: '张三',
receiver_masked_phone: '138****8000',
address: '北京市朝阳区某某街道100号',
amount: '299.00',
tracking_no: '',
carrier: ''
},
{
order_no: 'ORD20260205002',
status: 'DELIVERED',
created_at: '2026-02-05 09:30',
receiver_name: '李四',
receiver_masked_phone: '139****1234',
address: '上海市浦东新区某某路200号',
amount: '158.50',
tracking_no: 'YD987654321',
carrier: '韵达',
last_synced_at: '2026-02-05 14:35'
},
{
order_no: 'ORD20260205003',
status: 'SHIPPED',
created_at: '2026-02-04 15:00',
receiver_name: '王五',
receiver_masked_phone: '137****5566',
address: '广州市天河区某某大厦15楼',
amount: '88.00',
tracking_no: 'ZT123456789',
carrier: '中通',
last_synced_at: '2026-02-05 10:00'
},
{
order_no: 'ORD20260205004',
status: 'OUT_FOR_DELIVERY',
created_at: '2026-02-05 08:00',
receiver_name: '赵六',
receiver_masked_phone: '135****0011',
address: '杭州市西湖区某某创意园',
amount: '450.00',
tracking_no: 'SF666888999',
carrier: '顺丰',
last_synced_at: '2026-02-06 09:00'
},
{
order_no: 'ORD20260205005',
status: 'EXCEPTION',
created_at: '2026-02-03 12:00',
receiver_name: '孙七',
receiver_masked_phone: '136****9988',
address: '成都市武侯区某某软件园',
amount: '120.00',
tracking_no: 'YT555444333',
carrier: '圆通',
last_synced_at: '2026-02-04 18:00'
}
]
// 全局 Mock 配置项,支持页面间同步
// 全局 Mock 配置项
public isTestMode: boolean = true
public autoPush: boolean = true
public mockUrl: string = 'http://192.168.1.100:3000/mock/v1'
// 持久化存储轨迹:按订单号存储
private trackingHistory: Map<string, MockTrackingEvent[]> = new Map()
private webhookLogs: MockWebhookLog[] = []
constructor() {}
constructor() {
this.initDefaultHistory()
this.initDefaultLogs()
}
async getMockOrders(): Promise<MockOrder[]> {
const { data, error } = await supa.from('platform_express_waybills')
.select('*,ml_orders(*)')
.order('created_at', { ascending: false })
.execute()
private initDefaultLogs() {
this.webhookLogs = [
{
time: '14:35:22', carrier: '韵达', tracking_no: 'YD987654321',
event_code: 'DELIVERED', success: true, result_text: '成功入库',
payload: {
trackingNo: 'YD987654321',
status: 'DELIVERED',
msg: '您的快件已由本人签收'
} as UTSJSONObject
}
]
}
private initDefaultHistory() {
const tip = "【物流问题无需找商家或平台请致电95338专属热线400-811-1111更快解决】"
// 已签收订单轨迹
this.trackingHistory.set('ORD20260205002', [
{
event_id: 'e210',
event_time: '2026-02-05 18:30',
event_code: 'DELIVERED',
event_text: '您的快件已由本人签收。感谢使用韵达快递,期待再次为您服务!',
status_code: 'DELIVERED',
evidence_urls: ['https://img-shop.gmugmu.com/mock/pod_sample.png']
},
{
event_id: 'e209',
event_time: '2026-02-05 15:25',
event_code: 'OUT_FOR_DELIVERY',
event_text: '派送员张师傅(13800138000)正在派件(事先呼我,勿找商家)',
status_code: 'OUT_FOR_DELIVERY',
evidence_urls: []
},
{
event_id: 'e208',
event_time: '2026-02-05 15:24',
event_code: 'ARRIVED_HUB',
event_text: '【朝阳分部】已收入',
status_code: 'ARRIVED_HUB',
evidence_urls: []
},
{
event_id: 'e207',
event_time: '2026-02-05 15:23',
event_code: 'ARRIVED',
event_text: '您的快件已经到达【朝阳区】' + tip,
status_code: 'IN_TRANSIT',
evidence_urls: []
},
{
event_id: 'e200',
event_time: '2026-02-05 09:46',
event_code: 'SHIPPED',
event_text: '包裹正在等待揽收',
status_code: 'SHIPPED',
evidence_urls: []
}
])
// 运输中订单轨迹
this.trackingHistory.set('ORD20260205003', [
{
event_id: 'e305',
event_time: '2026-02-05 10:00',
event_code: 'TRANSIT',
event_text: '快件离开【广州分拣中心】,已发往【天河分部】',
status_code: 'IN_TRANSIT',
evidence_urls: []
},
{
event_id: 'e301',
event_time: '2026-02-04 15:30',
event_code: 'PICKED',
event_text: '包裹已揽收',
status_code: 'ARRIVED_HUB',
evidence_urls: []
}
])
// 派送中订单轨迹
this.trackingHistory.set('ORD20260205004', [
{
event_id: 'e405',
event_time: '2026-02-06 09:00',
event_code: 'OUT_FOR_DELIVERY',
event_text: '派送员王师傅(13700137000)正在派件',
status_code: 'OUT_FOR_DELIVERY',
evidence_urls: []
},
{
event_id: 'e401',
event_time: '2026-02-05 18:00',
event_code: 'ARRIVED',
event_text: '快件到达【杭州西湖分拨中心】',
status_code: 'IN_TRANSIT',
evidence_urls: []
}
])
// 异常订单轨迹
this.trackingHistory.set('ORD20260205005', [
{
event_id: 'e505',
event_time: '2026-02-04 18:00',
event_code: 'EXCEPTION',
event_text: '【包裹异常】由于天气原因,快件将在分拨中心稍作停留',
status_code: 'EXCEPTION',
evidence_urls: []
},
{
event_id: 'e501',
event_time: '2026-02-03 14:00',
event_code: 'PICKED',
event_text: '包裹已揽收',
status_code: 'ARRIVED_HUB',
evidence_urls: []
}
])
}
getAvailableCarriers(): MockCarrierOption[] {
return [
{ code: 'YUNDA', name: '韵达' },
{ code: 'YTO', name: '圆通' },
{ code: 'ZTO', name: '中通' },
{ code: 'STO', name: '申通' }
]
}
getMockOrders(): MockOrder[] {
return this.orders
}
bindShipment(orderNo: string, carrier: string, trackingNo: string): MockOrder | null {
const order = this.orders.find(o => o.order_no === orderNo)
if (!order) return null
order.carrier = carrier
order.tracking_no = trackingNo
order.status = 'SHIPPED'
order.last_synced_at = this.formatDate(new Date())
// 初始化轨迹
this.trackingHistory.set(orderNo, [
{
event_id: 'init_' + Date.now(),
event_time: order.last_synced_at,
event_code: 'CREATED',
event_text: '商家已发货,等待快递公司揽收',
status_code: '已发货',
evidence_urls: []
}
])
return order
}
getMockTracking(id: string): MockTrackingEvent[] {
const order = this.orders.find(o => o.order_no === id || o.tracking_no === id)
if (order != null && this.trackingHistory.has(order.order_no)) {
return this.trackingHistory.get(order.order_no)!
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 []
}
/**
* 生成符合消费者端高保真展示的物流轨迹
* 模拟各种物流场景 (生成生产测试数据)
*/
generateFullProcess(id: string) {
const order = this.orders.find(o => o.order_no === id || o.tracking_no === id)
if (!order) return
const now = new Date()
const getPastTime = (days: number, hours: number): string => {
const d = new Date(now.getTime() - (days * 24 + hours) * 3600 * 1000)
const YY = d.getFullYear()
const M = (d.getMonth() + 1).toString().padStart(2, '0')
const DD = d.getDate().toString().padStart(2, '0')
const h = d.getHours().toString().padStart(2, '0')
const m = d.getMinutes().toString().padStart(2, '0')
return `${YY}-${M}-${DD} ${h}:${m}`
}
const tip = "【物流问题无需找商家或平台请致电95338专属热线400-811-1111更快解决】"
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()
const fullProcess: MockTrackingEvent[] = [
{
event_id: 'f7',
event_time: getPastTime(0, 1),
event_code: 'OUT_FOR_DELIVERY',
event_text: '派送员张师傅(13800138000)正在派件(事先呼我,勿找商家)',
status_code: 'OUT_FOR_DELIVERY',
evidence_urls: []
},
{
event_id: 'f6',
event_time: getPastTime(0, 4),
event_code: 'TRANSIT',
event_text: '【朝阳分部】已收入',
status_code: 'ARRIVED_HUB',
evidence_urls: []
},
{
event_id: 'f5',
event_time: getPastTime(0, 12),
event_code: 'ARRIVED',
event_text: '您的快件已经到达【北京朝阳区】' + tip,
status_code: 'IN_TRANSIT',
evidence_urls: []
},
{
event_id: 'f4',
event_time: getPastTime(1, 2),
event_code: 'DEPARTED',
event_text: '您的快件离开【顺义转运中心】,已发往【北京朝阳区】',
status_code: 'IN_TRANSIT',
evidence_urls: []
},
{
event_id: 'f3',
event_time: getPastTime(1, 10),
event_code: 'ARRIVED_HUB',
event_text: '您的快件已经到达【顺义转运中心】' + tip,
status_code: 'ARRIVED_HUB',
evidence_urls: []
},
{
event_id: 'f2',
event_time: getPastTime(1, 20),
event_code: 'PICKED',
event_text: '您的快件在【北京海淀区】已揽收,揽收人:李师傅(13911112222)' + tip,
status_code: 'ARRIVED_HUB',
evidence_urls: []
},
{
event_id: 'f1',
event_time: getPastTime(2, 1),
event_code: 'SHIPPED',
event_text: '包裹正在等待揽收',
status_code: 'SHIPPED',
evidence_urls: []
}
]
this.trackingHistory.set(order.order_no, fullProcess)
order.status = 'OUT_FOR_DELIVERY'
order.last_synced_at = this.formatDate(now)
}
runScenario(waybillNo: string, scenario: string) {
// 兼容逻辑:优先按运单号搜,搜不到按订单号搜
let order = this.orders.find(o => o.tracking_no === waybillNo)
if (!order) {
order = this.orders.find(o => o.order_no === waybillNo)
if (waybills == null || (waybills as Array<any>).length === 0) {
console.error('Scenario Error: Waybill not found', trackingNo)
return
}
if (!order) return
if (scenario === 'full') {
this.generateFullProcess(order.order_no)
} else if (scenario === 'exception') {
const history = this.getMockTracking(order.order_no)
history.unshift({
event_id: 'ex_' + Date.now(),
event_time: this.formatDate(new Date()),
event_code: 'EXCEPTION',
event_text: '【包裹异常】由于天气原因,快件将在分拨中心稍作停留',
status_code: 'EXCEPTION',
evidence_urls: []
})
order.status = 'EXCEPTION'
} else {
// 默认:模拟一个新的在途节点
let history = this.getMockTracking(order.order_no)
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()
// 如果该订单还没轨迹(比如刚发货),先初始化数组
if (!this.trackingHistory.has(order.order_no)) {
this.trackingHistory.set(order.order_no, [])
history = this.trackingHistory.get(order.order_no)!
}
const now = new Date()
history.unshift({
event_id: 'st_' + Date.now(),
event_time: this.formatDate(now),
event_code: 'TRANS_UPDATE',
event_text: '快件已到达新的中转场进行分拣,准备发往目的地',
status_code: 'IN_TRANSIT',
evidence_urls: []
})
order.last_synced_at = this.formatDate(now)
// 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()
}
}
/**
* 模拟从云端同步最新轨迹(使刷新按钮生效)
*/
async syncFromCloud(orderNo: string): Promise<boolean> {
const order = this.orders.find(o => o.order_no === orderNo)
if (!order || order.status === 'DELIVERED') return false
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 new Promise((resolve) => {
setTimeout(() => {
this.runScenario(order.tracking_no, 'step')
resolve(true)
}, 800)
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
})
}
getMockWebhookLogs(): MockWebhookLog[] {
return this.webhookLogs
// 绑定发货逻辑:写库
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: waybill, error: wError } = await supa.from('platform_express_waybills').insert({
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()
if (wError != null) {
console.error('Bind shipment error:', wError)
return false
}
// 3. 产生初始轨迹
await supa.from('platform_express_tracking_events').insert({
waybill_id: waybill!['id'] as string,
carrier: carrier,
tracking_no: trackingNo,
event_time: new Date().toISOString(),
event_code: 'CREATED',
event_text: '商家已发货,等待快递公司揽收',
status_code: 'SHIPPED',
dedupe_key: 'INIT_' + Date.now()
}).execute()
return true
}
/**
* 核心功能:模拟第三方回调接口 (适配圆通推送协议)
* 对应字段: txLogisticId(订单号), mailNo(票号), infoContent(状态), remark(描述)
* 核心功能:模拟第三方回调接口 (写库版)
*/
pushWebhookData(payload: UTSJSONObject): boolean {
// 兼容圆通协议字段
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_id = payload['txLogisticId'] 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)
// 状态映射
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'
else status_code = yto_status
// 1. 记录原始日志
const now = new Date()
const log: MockWebhookLog = {
time: this.formatDate(now).split(' ')[1],
// 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 eventRes = await supa.from('platform_express_tracking_events').insert({
waybill_id: final_id,
carrier: carrier,
tracking_no: tracking_no,
event_code: yto_status, // 保留圆通原始代码
success: true,
result_text: '接收成功',
payload: payload
}
this.webhookLogs.unshift(log)
event_time: payload['acceptTime'] as string || new Date().toISOString(),
event_code: yto_status,
event_text: event_text,
status_code: status_code,
raw_payload: payload,
dedupe_key: 'WEBHOOK_' + Date.now()
}).execute()
// 2. 更新系统内部轨迹
const order = this.orders.find(o => o.tracking_no === tracking_no || o.order_no === order_id)
if (order != null) {
if (!this.trackingHistory.has(order.order_no)) {
this.trackingHistory.set(order.order_no, [])
}
const history = this.trackingHistory.get(order.order_no)!
history.unshift({
event_id: 'yto_' + Date.now(),
event_time: payload['acceptTime'] as string || this.formatDate(now),
event_code: yto_status,
event_text: event_text,
status_code: status_code,
evidence_urls: []
})
order.status = status_code
order.last_synced_at = this.formatDate(now)
return true
if (eventRes.error != null) {
console.error('Insert Event Error:', eventRes.error)
}
log.success = false
log.result_text = '未找到对应的运单或订单号'
return false
return true
}
private formatDate(date: Date): string {
const Y = date.getFullYear()
const M = (date.getMonth() + 1).toString().padStart(2, '0')
const D = date.getDate().toString().padStart(2, '0')
const h = date.getHours().toString().padStart(2, '0')
const m = date.getMinutes().toString().padStart(2, '0')
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}`
}
}