创建数据库表格
This commit is contained in:
@@ -65,4 +65,87 @@
|
|||||||
- 联调/设计参考(不要用于生产直接落库):[express_tracking_mock_platform.sql](express_tracking_mock_platform.sql)
|
- 联调/设计参考(不要用于生产直接落库):[express_tracking_mock_platform.sql](express_tracking_mock_platform.sql)
|
||||||
- 包含平台侧表 + `mock_*` 测试表(故障注入/回放用),仅用于联调与文档说明。
|
- 包含平台侧表 + `mock_*` 测试表(故障注入/回放用),仅用于联调与文档说明。
|
||||||
|
|
||||||
|
测试/预发环境(不使用 mock_* 表也能联调):
|
||||||
|
- 仍然执行 [express_tracking_platform_upgrade.sql](express_tracking_platform_upgrade.sql) 创建“生产同款”三表。
|
||||||
|
- 再执行 [seed_platform_express_test_data.sql](seed_platform_express_test_data.sql) 向 `platform_express_*` 写入少量 TEST_ 前缀示例数据,用于页面联调与排障演示(可随时清理)。
|
||||||
|
|
||||||
|
### Ubuntu 上的 Supabase(测试/预发)怎么执行
|
||||||
|
|
||||||
|
目标:在 Supabase 上只使用“生产同款”三表进行联调,不创建/不依赖任何 `mock_*` 表。
|
||||||
|
|
||||||
|
执行顺序(必须按顺序):
|
||||||
|
1) 执行建表脚本:[express_tracking_platform_upgrade.sql](express_tracking_platform_upgrade.sql)
|
||||||
|
2) 执行种子数据脚本:[seed_platform_express_test_data.sql](seed_platform_express_test_data.sql)
|
||||||
|
|
||||||
|
方式 A:Supabase Dashboard(推荐)
|
||||||
|
- 打开 Supabase 项目 -> SQL Editor
|
||||||
|
- 分别粘贴并执行以上两个 SQL 文件内容(先建表、后种子)
|
||||||
|
- 建议使用具备 DDL 权限的角色执行(通常 SQL Editor 以高权限执行)
|
||||||
|
|
||||||
|
方式 B:Ubuntu 通过 psql 执行(适合自动化/脚本化)
|
||||||
|
1) 安装客户端:`sudo apt-get update && sudo apt-get install -y postgresql-client`
|
||||||
|
2) 从 Supabase 项目设置里复制连接串(Database -> Connection string),导出环境变量(示例):
|
||||||
|
`export DATABASE_URL='postgresql://USER:PASSWORD@HOST:6543/postgres?sslmode=require'`
|
||||||
|
3) 在仓库根目录执行:
|
||||||
|
- `psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f pages/mall/delivery/doc/需求文档/express_tracking_platform_upgrade.sql`
|
||||||
|
- `psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f pages/mall/delivery/doc/需求文档/seed_platform_express_test_data.sql`
|
||||||
|
|
||||||
|
清理测试数据:
|
||||||
|
- 种子脚本底部自带清理 SQL(按 `tracking_no LIKE 'TEST_%'` 删除),需要时复制执行即可。
|
||||||
|
|
||||||
|
### 如何“伪造第三方推送到数据库”(无需后端)
|
||||||
|
|
||||||
|
如果你暂时没有 webhook 接收服务,但希望测试环境表现得像“第三方已经推送了轨迹”,可以直接写数据库:
|
||||||
|
- 使用脚本 [simulate_third_party_to_db.sql](simulate_third_party_to_db.sql)
|
||||||
|
- 会同时写入:
|
||||||
|
- `platform_express_event_raw`(原始请求留痕/验签/排障)
|
||||||
|
- `platform_express_tracking_events`(时间线事件)
|
||||||
|
- `platform_express_waybills`(运单摘要)
|
||||||
|
- 用法:在 Supabase SQL Editor 打开脚本,修改顶部【参数区】后执行整段。
|
||||||
|
- 建议:运单号使用 `TEST_` 前缀,便于按脚本底部清理 SQL 一键删除。
|
||||||
|
|
||||||
|
### 与数据库其他表是否“相通”(关联与校验)
|
||||||
|
|
||||||
|
这套三表与平台业务表的关键“相通点”是:
|
||||||
|
- `public.platform_express_waybills.order_id` 外键引用 `public.ml_orders(id)`(订单主表)。
|
||||||
|
|
||||||
|
因此:
|
||||||
|
- 如果你的 Supabase(测试/预发)数据库里已经部署了完整商城库(包含 `public.ml_orders`),那么这三表可以直接和订单表联查/联动。
|
||||||
|
- 如果你的 Supabase 只是一个“独立的轨迹联调库”,没有 `public.ml_orders`,那么执行建表脚本时会因为外键依赖缺失而失败;此时建议先导入/执行商城主库迁移(让 `ml_orders` 存在),或临时改为仅使用 `order_no` 关联(不建外键),待接入完整主库后再补外键。
|
||||||
|
|
||||||
|
在 Supabase SQL Editor 里可执行以下校验:
|
||||||
|
|
||||||
|
1) 检查订单表是否存在:
|
||||||
|
```sql
|
||||||
|
select to_regclass('public.ml_orders') as ml_orders;
|
||||||
|
```
|
||||||
|
|
||||||
|
2) 检查外键是否创建成功(应该能看到 `platform_express_waybills_order_id_fkey` 或类似名称):
|
||||||
|
```sql
|
||||||
|
select
|
||||||
|
conname as fk_name,
|
||||||
|
pg_get_constraintdef(c.oid) as fk_def
|
||||||
|
from pg_constraint c
|
||||||
|
join pg_class t on t.oid = c.conrelid
|
||||||
|
join pg_namespace n on n.oid = t.relnamespace
|
||||||
|
where c.contype = 'f'
|
||||||
|
and n.nspname = 'public'
|
||||||
|
and t.relname = 'platform_express_waybills';
|
||||||
|
```
|
||||||
|
|
||||||
|
3) 联查示例(有真实订单时):
|
||||||
|
```sql
|
||||||
|
select
|
||||||
|
o.id as order_id,
|
||||||
|
o.order_no,
|
||||||
|
w.carrier,
|
||||||
|
w.tracking_no,
|
||||||
|
w.current_status_code,
|
||||||
|
w.last_synced_at
|
||||||
|
from public.ml_orders o
|
||||||
|
left join public.platform_express_waybills w on w.order_id = o.id
|
||||||
|
order by o.created_at desc
|
||||||
|
limit 20;
|
||||||
|
```
|
||||||
|
|
||||||
建议下一步:在平台侧实现一个可切换的“Mock 数据源”开关(仅测试环境),并在 QA 用例中覆盖重复/乱序/验签失败等注入场景。
|
建议下一步:在平台侧实现一个可切换的“Mock 数据源”开关(仅测试环境),并在 QA 用例中覆盖重复/乱序/验签失败等注入场景。
|
||||||
|
|||||||
@@ -16,20 +16,20 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|||||||
CREATE EXTENSION IF NOT EXISTS "btree_gin";
|
CREATE EXTENSION IF NOT EXISTS "btree_gin";
|
||||||
|
|
||||||
-- updated_at 维护函数:若主库已存在则不重复创建
|
-- updated_at 维护函数:若主库已存在则不重复创建
|
||||||
DO $$
|
DO $do$
|
||||||
BEGIN
|
BEGIN
|
||||||
IF to_regprocedure('public.update_updated_at_column()') IS NULL THEN
|
IF to_regprocedure('public.update_updated_at_column()') IS NULL THEN
|
||||||
CREATE OR REPLACE FUNCTION public.update_updated_at_column()
|
CREATE OR REPLACE FUNCTION public.update_updated_at_column()
|
||||||
RETURNS TRIGGER
|
RETURNS TRIGGER
|
||||||
LANGUAGE plpgsql
|
LANGUAGE plpgsql
|
||||||
AS $$
|
AS $func$
|
||||||
BEGIN
|
BEGIN
|
||||||
NEW.updated_at = NOW();
|
NEW.updated_at = NOW();
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END;
|
END;
|
||||||
$$;
|
$func$;
|
||||||
END IF;
|
END IF;
|
||||||
END $$;
|
END $do$;
|
||||||
|
|
||||||
-- =====================================================================
|
-- =====================================================================
|
||||||
-- A. 平台侧(platform):统一轨迹模型入库与查询
|
-- A. 平台侧(platform):统一轨迹模型入库与查询
|
||||||
|
|||||||
236
pages/mall/delivery/doc/需求文档/seed_platform_express_test_data.sql
Normal file
236
pages/mall/delivery/doc/需求文档/seed_platform_express_test_data.sql
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
-- =====================================================================================
|
||||||
|
-- 测试环境种子数据(仅写入 platform_express_* 三表)
|
||||||
|
--
|
||||||
|
-- 目的:在测试/预发环境使用“生产同款表结构”联调页面与接口,避免创建 mock_* 表。
|
||||||
|
-- 适用:已执行 express_tracking_platform_upgrade.sql 后。
|
||||||
|
--
|
||||||
|
-- 注意:
|
||||||
|
-- - 本文件会插入 tracking_no 以 TEST_ 前缀开头的示例数据。
|
||||||
|
-- - 如需清理,可执行文末的清理 SQL。
|
||||||
|
-- =====================================================================================
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- 1) 创建/更新示例运单(若已存在则跳过)
|
||||||
|
INSERT INTO public.platform_express_waybills (
|
||||||
|
order_id,
|
||||||
|
order_no,
|
||||||
|
carrier,
|
||||||
|
tracking_no,
|
||||||
|
source,
|
||||||
|
current_status_code,
|
||||||
|
current_status_text,
|
||||||
|
eta,
|
||||||
|
last_synced_at
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(NULL, 'ORD_TEST_20260206001', 'YUNDA', 'TEST_YD_20260206_0001', 'mock', 'IN_TRANSIT', '运输中', NULL, NOW()),
|
||||||
|
(NULL, 'ORD_TEST_20260206002', 'YTO', 'TEST_YT_20260206_0002', 'mock', 'OUT_FOR_DELIVERY', '派送中', NULL, NOW()),
|
||||||
|
(NULL, 'ORD_TEST_20260206003', 'ZTO', 'TEST_ZT_20260206_0003', 'mock', 'DELIVERED', '已签收', NULL, NOW())
|
||||||
|
ON CONFLICT (carrier, tracking_no) DO NOTHING;
|
||||||
|
|
||||||
|
|
||||||
|
-- 2) 插入轨迹事件(幂等:按 (waybill_id, dedupe_key) 去重)
|
||||||
|
WITH w AS (
|
||||||
|
SELECT id, carrier, tracking_no
|
||||||
|
FROM public.platform_express_waybills
|
||||||
|
WHERE tracking_no IN ('TEST_YD_20260206_0001', 'TEST_YT_20260206_0002', 'TEST_ZT_20260206_0003')
|
||||||
|
)
|
||||||
|
INSERT INTO public.platform_express_tracking_events (
|
||||||
|
waybill_id,
|
||||||
|
carrier,
|
||||||
|
tracking_no,
|
||||||
|
event_id,
|
||||||
|
event_time,
|
||||||
|
event_code,
|
||||||
|
event_text,
|
||||||
|
status_code,
|
||||||
|
node_name,
|
||||||
|
location,
|
||||||
|
description,
|
||||||
|
evidence_urls,
|
||||||
|
raw_payload,
|
||||||
|
received_at,
|
||||||
|
source,
|
||||||
|
dedupe_key
|
||||||
|
)
|
||||||
|
SELECT * FROM (
|
||||||
|
-- 运单 1:运输中
|
||||||
|
SELECT
|
||||||
|
(SELECT id FROM w WHERE tracking_no = 'TEST_YD_20260206_0001') AS waybill_id,
|
||||||
|
'YUNDA' AS carrier,
|
||||||
|
'TEST_YD_20260206_0001' AS tracking_no,
|
||||||
|
'test_e_1001' AS event_id,
|
||||||
|
NOW() - INTERVAL '12 hours' AS event_time,
|
||||||
|
'PICKED' AS event_code,
|
||||||
|
'包裹已揽收' AS event_text,
|
||||||
|
'ARRIVED_HUB' AS status_code,
|
||||||
|
'上海浦东集散中心' AS node_name,
|
||||||
|
'上海市 浦东新区' AS location,
|
||||||
|
NULL AS description,
|
||||||
|
'[]'::jsonb AS evidence_urls,
|
||||||
|
NULL::jsonb AS raw_payload,
|
||||||
|
NOW() AS received_at,
|
||||||
|
'poll' AS source,
|
||||||
|
'test_e_1001' AS dedupe_key
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
(SELECT id FROM w WHERE tracking_no = 'TEST_YD_20260206_0001'),
|
||||||
|
'YUNDA',
|
||||||
|
'TEST_YD_20260206_0001',
|
||||||
|
'test_e_1002',
|
||||||
|
NOW() - INTERVAL '6 hours',
|
||||||
|
'TRANSIT',
|
||||||
|
'快件离开【上海浦东集散中心】,已发往【杭州转运中心】',
|
||||||
|
'IN_TRANSIT',
|
||||||
|
'上海浦东集散中心',
|
||||||
|
'上海市 浦东新区',
|
||||||
|
NULL,
|
||||||
|
'[]'::jsonb,
|
||||||
|
NULL::jsonb,
|
||||||
|
NOW(),
|
||||||
|
'poll',
|
||||||
|
'test_e_1002'
|
||||||
|
|
||||||
|
-- 运单 2:派送中
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
(SELECT id FROM w WHERE tracking_no = 'TEST_YT_20260206_0002'),
|
||||||
|
'YTO',
|
||||||
|
'TEST_YT_20260206_0002',
|
||||||
|
'test_e_2001',
|
||||||
|
NOW() - INTERVAL '8 hours',
|
||||||
|
'ARRIVAL',
|
||||||
|
'快件已到达【广州天河网点】',
|
||||||
|
'IN_TRANSIT',
|
||||||
|
'广州天河网点',
|
||||||
|
'广州市 天河区',
|
||||||
|
NULL,
|
||||||
|
'[]'::jsonb,
|
||||||
|
NULL::jsonb,
|
||||||
|
NOW(),
|
||||||
|
'webhook',
|
||||||
|
'test_e_2001'
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
(SELECT id FROM w WHERE tracking_no = 'TEST_YT_20260206_0002'),
|
||||||
|
'YTO',
|
||||||
|
'TEST_YT_20260206_0002',
|
||||||
|
'test_e_2002',
|
||||||
|
NOW() - INTERVAL '1 hours',
|
||||||
|
'OUT_FOR_DELIVERY',
|
||||||
|
'派送员正在派件(测试数据)',
|
||||||
|
'OUT_FOR_DELIVERY',
|
||||||
|
'广州天河网点',
|
||||||
|
'广州市 天河区',
|
||||||
|
NULL,
|
||||||
|
'[]'::jsonb,
|
||||||
|
NULL::jsonb,
|
||||||
|
NOW(),
|
||||||
|
'webhook',
|
||||||
|
'test_e_2002'
|
||||||
|
|
||||||
|
-- 运单 3:已签收
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
(SELECT id FROM w WHERE tracking_no = 'TEST_ZT_20260206_0003'),
|
||||||
|
'ZTO',
|
||||||
|
'TEST_ZT_20260206_0003',
|
||||||
|
'test_e_3001',
|
||||||
|
NOW() - INTERVAL '2 days',
|
||||||
|
'PICKED',
|
||||||
|
'包裹已揽收',
|
||||||
|
'ARRIVED_HUB',
|
||||||
|
'北京朝阳网点',
|
||||||
|
'北京市 朝阳区',
|
||||||
|
NULL,
|
||||||
|
'[]'::jsonb,
|
||||||
|
NULL::jsonb,
|
||||||
|
NOW(),
|
||||||
|
'poll',
|
||||||
|
'test_e_3001'
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
(SELECT id FROM w WHERE tracking_no = 'TEST_ZT_20260206_0003'),
|
||||||
|
'ZTO',
|
||||||
|
'TEST_ZT_20260206_0003',
|
||||||
|
'test_e_3002',
|
||||||
|
NOW() - INTERVAL '1 days',
|
||||||
|
'TRANSIT',
|
||||||
|
'快件运输中',
|
||||||
|
'IN_TRANSIT',
|
||||||
|
'北京朝阳网点',
|
||||||
|
'北京市 朝阳区',
|
||||||
|
NULL,
|
||||||
|
'[]'::jsonb,
|
||||||
|
NULL::jsonb,
|
||||||
|
NOW(),
|
||||||
|
'poll',
|
||||||
|
'test_e_3002'
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
(SELECT id FROM w WHERE tracking_no = 'TEST_ZT_20260206_0003'),
|
||||||
|
'ZTO',
|
||||||
|
'TEST_ZT_20260206_0003',
|
||||||
|
'test_e_3003',
|
||||||
|
NOW() - INTERVAL '12 hours',
|
||||||
|
'DELIVERED',
|
||||||
|
'您的快件已签收(测试数据)',
|
||||||
|
'DELIVERED',
|
||||||
|
'北京朝阳网点',
|
||||||
|
'北京市 朝阳区',
|
||||||
|
NULL,
|
||||||
|
'["https://img-shop.gmugmu.com/mock/pod_sample.png"]'::jsonb,
|
||||||
|
NULL::jsonb,
|
||||||
|
NOW(),
|
||||||
|
'webhook',
|
||||||
|
'test_e_3003'
|
||||||
|
) AS rows_to_insert
|
||||||
|
WHERE rows_to_insert.waybill_id IS NOT NULL
|
||||||
|
ON CONFLICT (waybill_id, dedupe_key) DO NOTHING;
|
||||||
|
|
||||||
|
|
||||||
|
-- 3) 可选:插入原始接收留痕(用于演示验签/排障界面)
|
||||||
|
INSERT INTO public.platform_express_event_raw (
|
||||||
|
received_at,
|
||||||
|
source,
|
||||||
|
client_id,
|
||||||
|
carrier,
|
||||||
|
tracking_no,
|
||||||
|
signature_valid,
|
||||||
|
signature,
|
||||||
|
ts_header,
|
||||||
|
request_id,
|
||||||
|
remote_ip,
|
||||||
|
headers,
|
||||||
|
body,
|
||||||
|
parse_error,
|
||||||
|
dedupe_key
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
NOW(),
|
||||||
|
'webhook',
|
||||||
|
'test_client',
|
||||||
|
'YTO',
|
||||||
|
'TEST_YT_20260206_0002',
|
||||||
|
TRUE,
|
||||||
|
'test-signature',
|
||||||
|
EXTRACT(EPOCH FROM NOW())::text,
|
||||||
|
'req_test_0001',
|
||||||
|
'127.0.0.1',
|
||||||
|
'{"content-type":"application/json"}'::jsonb,
|
||||||
|
'{"tracking_no":"TEST_YT_20260206_0002","status_code":"OUT_FOR_DELIVERY","event_text":"派送员正在派件(测试数据)"}'::jsonb,
|
||||||
|
NULL,
|
||||||
|
'raw_test_0001'
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- =====================================================================================
|
||||||
|
-- 清理(需要时手工执行)
|
||||||
|
-- =====================================================================================
|
||||||
|
-- BEGIN;
|
||||||
|
-- DELETE FROM public.platform_express_event_raw WHERE tracking_no LIKE 'TEST_%';
|
||||||
|
-- DELETE FROM public.platform_express_tracking_events WHERE tracking_no LIKE 'TEST_%';
|
||||||
|
-- DELETE FROM public.platform_express_waybills WHERE tracking_no LIKE 'TEST_%';
|
||||||
|
-- COMMIT;
|
||||||
191
pages/mall/delivery/doc/需求文档/simulate_third_party_to_db.sql
Normal file
191
pages/mall/delivery/doc/需求文档/simulate_third_party_to_db.sql
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
-- =====================================================================================
|
||||||
|
-- 模拟第三方“推送到平台”的数据(直接写入数据库)
|
||||||
|
--
|
||||||
|
-- 适用场景:
|
||||||
|
-- - 你暂时没有后端 webhook 接收服务,但希望在测试/预发环境快速伪造第三方推送效果。
|
||||||
|
-- - 通过写入:
|
||||||
|
-- 1) platform_express_event_raw (原始请求留痕/验签结果/排障信息)
|
||||||
|
-- 2) platform_express_tracking_events(解析后的轨迹事件,用于时间线展示)
|
||||||
|
-- 3) platform_express_waybills(运单摘要)
|
||||||
|
--
|
||||||
|
-- 注意:
|
||||||
|
-- - 这是“绕过后端解析与验签”的直写方案,仅用于测试/演示。
|
||||||
|
-- - 生产环境不建议这样做。
|
||||||
|
-- - 执行前请确保已跑过 express_tracking_platform_upgrade.sql 创建三表。
|
||||||
|
--
|
||||||
|
-- 使用方式:
|
||||||
|
-- - Supabase SQL Editor:把下面的【参数区】内容改成你要的值,然后整段执行。
|
||||||
|
-- =====================================================================================
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- =========================
|
||||||
|
-- 参数区(手工修改这里)
|
||||||
|
-- =========================
|
||||||
|
-- 承运商编码:建议与平台枚举一致(YTO/YUNDA/ZTO/STO...)
|
||||||
|
-- 运单号:建议用 TEST_ 前缀,便于清理
|
||||||
|
-- 事件码/状态码:按你的平台约定(IN_TRANSIT/OUT_FOR_DELIVERY/DELIVERED/EXCEPTION...)
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
DECLARE
|
||||||
|
v_order_no TEXT := 'ORD_TEST_20260206099';
|
||||||
|
v_carrier TEXT := 'YTO';
|
||||||
|
v_tracking_no TEXT := 'TEST_YT_20260206_0099';
|
||||||
|
|
||||||
|
v_event_id TEXT := NULL; -- 可为空
|
||||||
|
v_event_time TIMESTAMPTZ := NOW();
|
||||||
|
v_event_code TEXT := 'OUT_FOR_DELIVERY';
|
||||||
|
v_event_text TEXT := '派送员正在派件(伪造推送,直写数据库)';
|
||||||
|
v_status_code TEXT := 'OUT_FOR_DELIVERY';
|
||||||
|
v_node_name TEXT := '广州天河网点';
|
||||||
|
v_location TEXT := '广州市 天河区';
|
||||||
|
|
||||||
|
v_source TEXT := 'webhook'; -- webhook/poll/manual
|
||||||
|
v_client_id TEXT := 'test_client';
|
||||||
|
v_signature_valid BOOLEAN := TRUE;
|
||||||
|
v_signature TEXT := 'fake-signature';
|
||||||
|
v_remote_ip INET := '127.0.0.1';
|
||||||
|
|
||||||
|
v_waybill_id UUID;
|
||||||
|
v_dedupe_key TEXT;
|
||||||
|
BEGIN
|
||||||
|
-- 1) Upsert 运单主表(保证 waybill 存在)
|
||||||
|
INSERT INTO public.platform_express_waybills (
|
||||||
|
order_id,
|
||||||
|
order_no,
|
||||||
|
carrier,
|
||||||
|
tracking_no,
|
||||||
|
source,
|
||||||
|
current_status_code,
|
||||||
|
current_status_text,
|
||||||
|
last_synced_at
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
NULL,
|
||||||
|
v_order_no,
|
||||||
|
v_carrier,
|
||||||
|
v_tracking_no,
|
||||||
|
'mock',
|
||||||
|
v_status_code,
|
||||||
|
CASE
|
||||||
|
WHEN v_status_code = 'PENDING' THEN '待发货'
|
||||||
|
WHEN v_status_code = 'SHIPPED' THEN '已发货'
|
||||||
|
WHEN v_status_code = 'IN_TRANSIT' THEN '运输中'
|
||||||
|
WHEN v_status_code = 'ARRIVED_HUB' THEN '到达网点'
|
||||||
|
WHEN v_status_code = 'OUT_FOR_DELIVERY' THEN '派送中'
|
||||||
|
WHEN v_status_code = 'DELIVERED' THEN '已签收'
|
||||||
|
WHEN v_status_code = 'EXCEPTION' THEN '异常'
|
||||||
|
ELSE v_status_code
|
||||||
|
END,
|
||||||
|
NOW()
|
||||||
|
)
|
||||||
|
ON CONFLICT (carrier, tracking_no)
|
||||||
|
DO UPDATE SET
|
||||||
|
order_no = COALESCE(EXCLUDED.order_no, public.platform_express_waybills.order_no),
|
||||||
|
current_status_code = EXCLUDED.current_status_code,
|
||||||
|
current_status_text = EXCLUDED.current_status_text,
|
||||||
|
last_synced_at = EXCLUDED.last_synced_at
|
||||||
|
RETURNING id INTO v_waybill_id;
|
||||||
|
|
||||||
|
-- 2) 计算幂等键(优先 event_id;否则用运单+事件码+事件时间)
|
||||||
|
v_dedupe_key := COALESCE(
|
||||||
|
v_event_id,
|
||||||
|
v_tracking_no || '|' || v_event_code || '|' || to_char(v_event_time, 'YYYY-MM-DD"T"HH24:MI:SSOF')
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 3) 写入原始接收留痕(模拟第三方请求)
|
||||||
|
INSERT INTO public.platform_express_event_raw (
|
||||||
|
received_at,
|
||||||
|
source,
|
||||||
|
client_id,
|
||||||
|
carrier,
|
||||||
|
tracking_no,
|
||||||
|
signature_valid,
|
||||||
|
signature,
|
||||||
|
ts_header,
|
||||||
|
request_id,
|
||||||
|
remote_ip,
|
||||||
|
headers,
|
||||||
|
body,
|
||||||
|
parse_error,
|
||||||
|
dedupe_key
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
NOW(),
|
||||||
|
v_source,
|
||||||
|
v_client_id,
|
||||||
|
v_carrier,
|
||||||
|
v_tracking_no,
|
||||||
|
v_signature_valid,
|
||||||
|
v_signature,
|
||||||
|
EXTRACT(EPOCH FROM NOW())::text,
|
||||||
|
'req_fake_' || replace(v_dedupe_key, '|', '_'),
|
||||||
|
v_remote_ip,
|
||||||
|
'{"content-type":"application/json"}'::jsonb,
|
||||||
|
jsonb_build_object(
|
||||||
|
'order_no', v_order_no,
|
||||||
|
'carrier', v_carrier,
|
||||||
|
'tracking_no', v_tracking_no,
|
||||||
|
'event_id', v_event_id,
|
||||||
|
'event_time', v_event_time,
|
||||||
|
'event_code', v_event_code,
|
||||||
|
'event_text', v_event_text,
|
||||||
|
'status_code', v_status_code,
|
||||||
|
'node_name', v_node_name,
|
||||||
|
'location', v_location
|
||||||
|
),
|
||||||
|
NULL,
|
||||||
|
'raw|' || v_dedupe_key
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 4) 写入解析后的轨迹事件(用于时间线展示)
|
||||||
|
INSERT INTO public.platform_express_tracking_events (
|
||||||
|
waybill_id,
|
||||||
|
carrier,
|
||||||
|
tracking_no,
|
||||||
|
event_id,
|
||||||
|
event_time,
|
||||||
|
event_code,
|
||||||
|
event_text,
|
||||||
|
status_code,
|
||||||
|
node_name,
|
||||||
|
location,
|
||||||
|
description,
|
||||||
|
evidence_urls,
|
||||||
|
raw_payload,
|
||||||
|
received_at,
|
||||||
|
source,
|
||||||
|
dedupe_key
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
v_waybill_id,
|
||||||
|
v_carrier,
|
||||||
|
v_tracking_no,
|
||||||
|
v_event_id,
|
||||||
|
v_event_time,
|
||||||
|
v_event_code,
|
||||||
|
v_event_text,
|
||||||
|
v_status_code,
|
||||||
|
v_node_name,
|
||||||
|
v_location,
|
||||||
|
NULL,
|
||||||
|
'[]'::jsonb,
|
||||||
|
NULL,
|
||||||
|
NOW(),
|
||||||
|
v_source,
|
||||||
|
v_dedupe_key
|
||||||
|
)
|
||||||
|
ON CONFLICT (waybill_id, dedupe_key) DO NOTHING;
|
||||||
|
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- =====================================================================================
|
||||||
|
-- 清理示例(需要时手工执行)
|
||||||
|
-- =====================================================================================
|
||||||
|
-- BEGIN;
|
||||||
|
-- DELETE FROM public.platform_express_event_raw WHERE tracking_no LIKE 'TEST_%';
|
||||||
|
-- DELETE FROM public.platform_express_tracking_events WHERE tracking_no LIKE 'TEST_%';
|
||||||
|
-- DELETE FROM public.platform_express_waybills WHERE tracking_no LIKE 'TEST_%';
|
||||||
|
-- COMMIT;
|
||||||
@@ -18,24 +18,24 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="section">
|
<view class="section">
|
||||||
<text class="section-title">2. 构造回调数据 (JSON Payload)</text>
|
<text class="section-title">2. 构造圆通协议数据 (YTO Protocol)</text>
|
||||||
<view class="form-group">
|
<view class="form-group">
|
||||||
<text class="label">运单号:</text>
|
<text class="label">物流单号 (mailNo):</text>
|
||||||
<input class="input" v-model="form.tracking_no" placeholder="请输入运单号" />
|
<input class="input" v-model="form.mailNo" placeholder="请输入运单号" />
|
||||||
</view>
|
</view>
|
||||||
<view class="form-group">
|
<view class="form-group">
|
||||||
<text class="label">快递公司:</text>
|
<text class="label">订单号 (txLogisticId):</text>
|
||||||
<input class="input" v-model="form.carrier" placeholder="请输入快递公司" />
|
<input class="input" v-model="form.txLogisticId" placeholder="请输入关联订单号" />
|
||||||
</view>
|
</view>
|
||||||
<view class="form-group">
|
<view class="form-group">
|
||||||
<text class="label">物流状态:</text>
|
<text class="label">事件状态 (infoContent):</text>
|
||||||
<picker :range="statusOptions" range-key="label" @change="onStatusChange">
|
<picker :range="statusOptions" range-key="label" @change="onStatusChange">
|
||||||
<view class="picker-val">{{ currentStatusLabel }}</view>
|
<view class="picker-val">{{ currentStatusLabel }}</view>
|
||||||
</picker>
|
</picker>
|
||||||
</view>
|
</view>
|
||||||
<view class="form-group">
|
<view class="form-group">
|
||||||
<text class="label">轨迹描述文字:</text>
|
<text class="label">轨迹描述 (remark):</text>
|
||||||
<textarea class="textarea" v-model="form.event_text" placeholder="描述当前的物流位置或状态..." />
|
<textarea class="textarea" v-model="form.remark" placeholder="描述当前的物流位置或状态..." />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -64,61 +64,77 @@
|
|||||||
const selectedOrderIndex = ref(-1)
|
const selectedOrderIndex = ref(-1)
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
tracking_no: '',
|
mailNo: '',
|
||||||
carrier: '',
|
txLogisticId: '',
|
||||||
status_code: 'IN_TRANSIT',
|
infoContent: 'SEND',
|
||||||
event_text: '快件已到达【XX转运中心】,准备发往下一站'
|
remark: '快件已到达【XX分拨中心】,准备发往下一站',
|
||||||
|
acceptTime: '',
|
||||||
|
carrier: '圆通速递'
|
||||||
})
|
})
|
||||||
|
|
||||||
const statusOptions = [
|
const statusOptions = [
|
||||||
{ label: '在途中 (IN_TRANSIT)', value: 'IN_TRANSIT' },
|
{ label: '揽收 (GOT)', value: 'GOT' },
|
||||||
{ label: '派送中 (OUT_FOR_DELIVERY)', value: 'OUT_FOR_DELIVERY' },
|
{ label: '运输中 (SEND)', value: 'SEND' },
|
||||||
{ label: '已签收 (DELIVERED)', value: 'DELIVERED' },
|
{ label: '派送中 (SENT)', value: 'SENT' },
|
||||||
{ label: '异常 (EXCEPTION)', value: 'EXCEPTION' }
|
{ label: '已签收 (SIGNED)', value: 'SIGNED' },
|
||||||
|
{ label: '异常 (FAILED)', value: 'FAILED' }
|
||||||
]
|
]
|
||||||
|
|
||||||
const currentStatusLabel = computed(() => {
|
const currentStatusLabel = computed((): string => {
|
||||||
const opt = statusOptions.find(o => o.value === form.status_code)
|
const opt = statusOptions.find((o: UTSJSONObject): boolean => o['value'] === form.infoContent)
|
||||||
return opt ? opt.label : '请选择'
|
return (opt != null) ? opt['label'] as string : '请选择'
|
||||||
})
|
})
|
||||||
|
|
||||||
const jsonString = computed(() => {
|
const jsonString = computed((): string => {
|
||||||
return JSON.stringify(form, null, 2)
|
return JSON.stringify(form, null, 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
function selectOrder(index: number) {
|
function selectOrder(index: number) {
|
||||||
selectedOrderIndex.value = index
|
selectedOrderIndex.value = index
|
||||||
const order = shippedOrders.value[index]
|
const order = shippedOrders.value[index]
|
||||||
form.tracking_no = order.tracking_no
|
form.mailNo = order.tracking_no
|
||||||
form.carrier = order.carrier
|
form.txLogisticId = order.order_no
|
||||||
|
form.carrier = order.carrier + '速递'
|
||||||
|
|
||||||
// 根据订单当前状态智能预设
|
// 根据订单当前状态智能预设
|
||||||
if (order.status === 'SHIPPED') {
|
if (order.status === 'SHIPPED') {
|
||||||
form.status_code = 'IN_TRANSIT'
|
form.infoContent = 'SEND'
|
||||||
form.event_text = '快件已揽收,正发往城市中心'
|
form.remark = '快件已到达北京分拨中心'
|
||||||
} else if (order.status === 'IN_TRANSIT') {
|
} else if (order.status === 'IN_TRANSIT') {
|
||||||
form.status_code = 'OUT_FOR_DELIVERY'
|
form.infoContent = 'SENT'
|
||||||
form.event_text = '派送员王师傅(13700008888)正在派件'
|
form.remark = '派送员王师傅(13700008888)正在派件'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStatusChange(e: UniPickerChangeEvent) {
|
function onStatusChange(e: UniPickerChangeEvent) {
|
||||||
const idx = e.detail.value as number
|
const idx = e.detail.value as number
|
||||||
form.status_code = statusOptions[idx].value as string
|
form.infoContent = statusOptions[idx].value
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendWebhook() {
|
function sendWebhook() {
|
||||||
if (!form.tracking_no) {
|
if (!form.mailNo) {
|
||||||
uni.showToast({ title: '请先填写运单号', icon: 'none' })
|
uni.showToast({ title: '请先填写运单号', icon: 'none' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取当前时间戳作为圆通要求的 acceptTime
|
||||||
|
const now = new Date()
|
||||||
|
const Y = now.getFullYear()
|
||||||
|
const M = (now.getMonth() + 1).toString().padStart(2, '0')
|
||||||
|
const D = now.getDate().toString().padStart(2, '0')
|
||||||
|
const h = now.getHours().toString().padStart(2, '0')
|
||||||
|
const m = now.getMinutes().toString().padStart(2, '0')
|
||||||
|
const s = now.getSeconds().toString().padStart(2, '0')
|
||||||
|
form.acceptTime = `${Y}-${M}-${D} ${h}:${m}:${s}`
|
||||||
|
|
||||||
// 执行模拟推送 (转换为普通对象以兼容 UTS)
|
// 执行模拟推送 (转换为普通对象以兼容 UTS)
|
||||||
const payload = {
|
const payload = {
|
||||||
tracking_no: form.tracking_no,
|
mailNo: form.mailNo,
|
||||||
carrier: form.carrier,
|
txLogisticId: form.txLogisticId,
|
||||||
status_code: form.status_code,
|
infoContent: form.infoContent,
|
||||||
event_text: form.event_text
|
remark: form.remark,
|
||||||
|
acceptTime: form.acceptTime,
|
||||||
|
carrier: form.carrier
|
||||||
} as UTSJSONObject
|
} as UTSJSONObject
|
||||||
|
|
||||||
const success = mockService.pushWebhookData(payload)
|
const success = mockService.pushWebhookData(payload)
|
||||||
|
|||||||
@@ -135,7 +135,8 @@
|
|||||||
},
|
},
|
||||||
getStatusText(status: string): string {
|
getStatusText(status: string): string {
|
||||||
const maps = {
|
const maps = {
|
||||||
'SHIPPED': '运输中',
|
'SHIPPED': '已发货',
|
||||||
|
'IN_TRANSIT': '运输中',
|
||||||
'DELIVERED': '已签收',
|
'DELIVERED': '已签收',
|
||||||
'OUT_FOR_DELIVERY': '派送中',
|
'OUT_FOR_DELIVERY': '派送中',
|
||||||
'PENDING': '待揽收',
|
'PENDING': '待揽收',
|
||||||
|
|||||||
@@ -71,7 +71,8 @@
|
|||||||
},
|
},
|
||||||
getStatusText(status: string): string {
|
getStatusText(status: string): string {
|
||||||
const maps = {
|
const maps = {
|
||||||
'SHIPPED': '运输中',
|
'SHIPPED': '已发货',
|
||||||
|
'IN_TRANSIT': '运输中',
|
||||||
'DELIVERED': '已签收',
|
'DELIVERED': '已签收',
|
||||||
'OUT_FOR_DELIVERY': '派送中',
|
'OUT_FOR_DELIVERY': '派送中',
|
||||||
'PENDING': '待揽收',
|
'PENDING': '待揽收',
|
||||||
|
|||||||
@@ -113,7 +113,14 @@
|
|||||||
this.statusHistory = mockService.getMockTracking(this.orderNo)
|
this.statusHistory = mockService.getMockTracking(this.orderNo)
|
||||||
},
|
},
|
||||||
getStatusText(status: string) : string {
|
getStatusText(status: string) : string {
|
||||||
const maps = { 'PENDING': '待发货', 'SHIPPED': '待签收', 'DELIVERED': '已签收', 'EXCEPTION': '异常' }
|
const maps = {
|
||||||
|
'PENDING': '待发货',
|
||||||
|
'SHIPPED': '已发货',
|
||||||
|
'IN_TRANSIT': '运输中',
|
||||||
|
'DELIVERED': '已签收',
|
||||||
|
'OUT_FOR_DELIVERY': '派送中',
|
||||||
|
'EXCEPTION': '异常'
|
||||||
|
}
|
||||||
return (maps[status] != null) ? maps[status] : status
|
return (maps[status] != null) ? maps[status] : status
|
||||||
},
|
},
|
||||||
async refreshLogistics() {
|
async refreshLogistics() {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
<view class="modal-body">
|
<view class="modal-body">
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<text class="label">选择承运商</text>
|
<text class="label">选择承运商</text>
|
||||||
<picker :range="carriers" @change="onCarrierChange">
|
<picker :range="carriers" range-key="label" @change="onCarrierChange">
|
||||||
<view class="picker-val">{{ currentCarrier || '请选择' }}</view>
|
<view class="picker-val">{{ currentCarrier || '请选择' }}</view>
|
||||||
</picker>
|
</picker>
|
||||||
</view>
|
</view>
|
||||||
@@ -83,8 +83,14 @@
|
|||||||
orders: [] as MockOrder[],
|
orders: [] as MockOrder[],
|
||||||
showShipModal: false,
|
showShipModal: false,
|
||||||
selectedOrder: null as MockOrder | null,
|
selectedOrder: null as MockOrder | null,
|
||||||
carriers: ['YUNDA', 'YTO', 'ZTO', 'STO', 'SF'],
|
carriers: [
|
||||||
currentCarrier: '',
|
{ label: '韵达快递', value: '韵达' },
|
||||||
|
{ label: '圆通速递', value: '圆通' },
|
||||||
|
{ label: '中通快递', value: '中通' },
|
||||||
|
{ label: '申通快递', value: '申通' },
|
||||||
|
{ label: '顺丰速运', value: '顺丰' }
|
||||||
|
],
|
||||||
|
currentCarrier: '韵达',
|
||||||
trackingNo: ''
|
trackingNo: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -117,6 +123,7 @@
|
|||||||
const maps = {
|
const maps = {
|
||||||
'PENDING': '待发货',
|
'PENDING': '待发货',
|
||||||
'SHIPPED': '已发货',
|
'SHIPPED': '已发货',
|
||||||
|
'IN_TRANSIT': '运输中',
|
||||||
'DELIVERED': '已签收',
|
'DELIVERED': '已签收',
|
||||||
'OUT_FOR_DELIVERY': '派送中',
|
'OUT_FOR_DELIVERY': '派送中',
|
||||||
'EXCEPTION': '包裹异常'
|
'EXCEPTION': '包裹异常'
|
||||||
@@ -131,7 +138,7 @@
|
|||||||
},
|
},
|
||||||
onCarrierChange(e: any) {
|
onCarrierChange(e: any) {
|
||||||
const index = e.detail.value as number
|
const index = e.detail.value as number
|
||||||
this.currentCarrier = this.carriers[index]
|
this.currentCarrier = this.carriers[index].value
|
||||||
},
|
},
|
||||||
async confirmShip() {
|
async confirmShip() {
|
||||||
if (!this.trackingNo) {
|
if (!this.trackingNo) {
|
||||||
|
|||||||
@@ -436,14 +436,24 @@ class MockService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 核心功能:模拟第三方回调接口
|
* 核心功能:模拟第三方回调接口 (适配圆通推送协议)
|
||||||
* 模拟外部物流平台向本系统发送轨迹更新 API
|
* 对应字段: txLogisticId(订单号), mailNo(票号), infoContent(状态), remark(描述)
|
||||||
*/
|
*/
|
||||||
pushWebhookData(payload: UTSJSONObject): boolean {
|
pushWebhookData(payload: UTSJSONObject): boolean {
|
||||||
const tracking_no = payload['tracking_no'] as string
|
// 兼容圆通协议字段
|
||||||
const status_code = payload['status_code'] as string
|
const tracking_no = (payload['mailNo'] != null) ? payload['mailNo'] as string : (payload['tracking_no'] as string)
|
||||||
const event_text = payload['event_text'] as string
|
const yto_status = (payload['infoContent'] != null) ? payload['infoContent'] as string : (payload['status_code'] as string)
|
||||||
const carrier = payload['carrier'] 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 carrier = payload['carrier'] as string || '圆通速递'
|
||||||
|
|
||||||
|
// 状态映射:圆通状态 -> 本系统状态
|
||||||
|
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. 记录原始日志
|
// 1. 记录原始日志
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
@@ -451,7 +461,7 @@ class MockService {
|
|||||||
time: this.formatDate(now).split(' ')[1],
|
time: this.formatDate(now).split(' ')[1],
|
||||||
carrier: carrier,
|
carrier: carrier,
|
||||||
tracking_no: tracking_no,
|
tracking_no: tracking_no,
|
||||||
event_code: status_code,
|
event_code: yto_status, // 保留圆通原始代码
|
||||||
success: true,
|
success: true,
|
||||||
result_text: '接收成功',
|
result_text: '接收成功',
|
||||||
payload: payload
|
payload: payload
|
||||||
@@ -459,16 +469,16 @@ class MockService {
|
|||||||
this.webhookLogs.unshift(log)
|
this.webhookLogs.unshift(log)
|
||||||
|
|
||||||
// 2. 更新系统内部轨迹
|
// 2. 更新系统内部轨迹
|
||||||
const order = this.orders.find(o => o.tracking_no === tracking_no)
|
const order = this.orders.find(o => o.tracking_no === tracking_no || o.order_no === order_id)
|
||||||
if (order != null) {
|
if (order != null) {
|
||||||
if (!this.trackingHistory.has(order.order_no)) {
|
if (!this.trackingHistory.has(order.order_no)) {
|
||||||
this.trackingHistory.set(order.order_no, [])
|
this.trackingHistory.set(order.order_no, [])
|
||||||
}
|
}
|
||||||
const history = this.trackingHistory.get(order.order_no)!
|
const history = this.trackingHistory.get(order.order_no)!
|
||||||
history.unshift({
|
history.unshift({
|
||||||
event_id: 'wb_' + Date.now(),
|
event_id: 'yto_' + Date.now(),
|
||||||
event_time: this.formatDate(now),
|
event_time: payload['acceptTime'] as string || this.formatDate(now),
|
||||||
event_code: status_code,
|
event_code: yto_status,
|
||||||
event_text: event_text,
|
event_text: event_text,
|
||||||
status_code: status_code,
|
status_code: status_code,
|
||||||
evidence_urls: []
|
evidence_urls: []
|
||||||
@@ -479,7 +489,7 @@ class MockService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.success = false
|
log.success = false
|
||||||
log.result_text = '未找到对应的运单号'
|
log.result_text = '未找到对应的运单或订单号'
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="info-item">
|
<view class="info-item">
|
||||||
<text class="label">当前状态:</text>
|
<text class="label">当前状态:</text>
|
||||||
<text class="value">{{ waybillInfo.status }}</text>
|
<text class="value">{{ getStatusText(waybillInfo.status) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -44,8 +44,8 @@
|
|||||||
<view class="event-main-col">
|
<view class="event-main-col">
|
||||||
<text class="event-text">{{ event.event_text }}</text>
|
<text class="event-text">{{ event.event_text }}</text>
|
||||||
<view class="event-meta">
|
<view class="event-meta">
|
||||||
<text class="meta-tag blue">CODE: {{ event.event_code }}</text>
|
<text class="meta-tag blue">代码: {{ event.event_code }}</text>
|
||||||
<text class="meta-tag orange">MAP: {{ event.status_code }}</text>
|
<text class="meta-tag orange">映射状态: {{ getStatusMapping(event.status_code) }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="raw-box" v-if="showRaw[index]">
|
<view class="raw-box" v-if="showRaw[index]">
|
||||||
<text class="raw-text">{{ JSON.stringify(event.raw_payload, null, 2) }}</text>
|
<text class="raw-text">{{ JSON.stringify(event.raw_payload, null, 2) }}</text>
|
||||||
@@ -116,6 +116,28 @@
|
|||||||
const current = this.showRaw[index]
|
const current = this.showRaw[index]
|
||||||
this.showRaw[index] = !current
|
this.showRaw[index] = !current
|
||||||
},
|
},
|
||||||
|
getStatusText(status: string) : string {
|
||||||
|
const maps = {
|
||||||
|
'PENDING': '待发货',
|
||||||
|
'SHIPPED': '已发货',
|
||||||
|
'IN_TRANSIT': '运输中',
|
||||||
|
'DELIVERED': '已签收',
|
||||||
|
'OUT_FOR_DELIVERY': '派送中',
|
||||||
|
'EXCEPTION': '异常'
|
||||||
|
}
|
||||||
|
return (maps[status] != null) ? maps[status] : status
|
||||||
|
},
|
||||||
|
getStatusMapping(code: string) : string {
|
||||||
|
const maps = {
|
||||||
|
'SHIPPED': '已揽收',
|
||||||
|
'IN_TRANSIT': '运输中',
|
||||||
|
'ARRIVED_HUB': '到达分拨中心',
|
||||||
|
'OUT_FOR_DELIVERY': '正在派送',
|
||||||
|
'DELIVERED': '已签收',
|
||||||
|
'EXCEPTION': '包裹异常'
|
||||||
|
}
|
||||||
|
return (maps[code] != null) ? maps[code] : code
|
||||||
|
},
|
||||||
runScenario(type: string) {
|
runScenario(type: string) {
|
||||||
if (this.waybillInfo == null) return
|
if (this.waybillInfo == null) return
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="log-row">
|
<view class="log-row">
|
||||||
<text class="log-label">事件:</text>
|
<text class="log-label">事件:</text>
|
||||||
<text class="log-value">{{ log.event_code }}</text>
|
<text class="log-value">{{ getEventText(log.event_code) }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="log-row">
|
<view class="log-row">
|
||||||
<text class="log-label">状态:</text>
|
<text class="log-label">状态:</text>
|
||||||
@@ -84,6 +84,18 @@
|
|||||||
showPayload.value = true
|
showPayload.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getEventText(code: string) : string {
|
||||||
|
const maps = {
|
||||||
|
'SHIPPED': '发货揽收',
|
||||||
|
'IN_TRANSIT': '运输中',
|
||||||
|
'ARRIVED_HUB': '中转入库',
|
||||||
|
'OUT_FOR_DELIVERY': '派件中',
|
||||||
|
'DELIVERED': '确认签收',
|
||||||
|
'EXCEPTION': '异常上报'
|
||||||
|
}
|
||||||
|
return (maps[code] != null) ? maps[code] : code
|
||||||
|
}
|
||||||
|
|
||||||
function reProcess(log: MockWebhookLog) {
|
function reProcess(log: MockWebhookLog) {
|
||||||
uni.showLoading({ title: '重送中...' })
|
uni.showLoading({ title: '重送中...' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user