修改页面逻辑
This commit is contained in:
51
pages/mall/delivery/doc/all.md
Normal file
51
pages/mall/delivery/doc/all.md
Normal file
@@ -0,0 +1,51 @@
|
||||
|
||||
## 1. 功能概述
|
||||
`all.uvue` 是为配送端设计的全量订单抓取页面。当首页待接订单超过 5 个时,用户可通过此页面查看并抢单。
|
||||
|
||||
## 2. 核心设计说明
|
||||
根据最新 UI 指标,该页面采用了**现代垂直流布局**:
|
||||
- **中心费用展示**:订单金额在卡片顶部居中加粗显示,强化利益点。
|
||||
- **垂直路径流**:采用垂直排布的取货(📍)与送达(🏠)地址,中间以箭头连接,更符合手机屏阅读习惯。
|
||||
- **全宽操作按钮**:底部采用 100% 宽度的按钮,提高抢单操作的触达率。
|
||||
- **实时空态处理**:当订单被他人抢先接走时,列表会自动更新。
|
||||
|
||||
## 3. 技术实现要点
|
||||
|
||||
### 3.1 数据安全与并发控制
|
||||
在执行 `acceptOrder`(抢单)时,通过数据库约束确保操作的原子性:
|
||||
```uts
|
||||
// 增加 driver_id 为空的前提条件,防止已被他人接单
|
||||
const res = await supa.from('ml_delivery_tasks')
|
||||
.update({
|
||||
driver_id: driverId,
|
||||
status: 2,
|
||||
accepted_at: new Date().toISOString()
|
||||
})
|
||||
.eq('id', taskId)
|
||||
.is('driver_id', 'null') // 关键:确保单子还没被接
|
||||
.execute();
|
||||
```
|
||||
|
||||
### 3.2 数据结构转换 (`_transformTask`)
|
||||
为了兼容数据库存储的 JSON 字符串格式与 UI 组件所需的 Object 格式,页面内置了转换逻辑:
|
||||
- 自动解析 `pickup_address` 和 `delivery_address` JSON 字符串。
|
||||
- 格式化 `delivery_fee` 为保留两位小数。
|
||||
- 映射状态码到对应的 UI 标签。
|
||||
|
||||
### 3.3 路由与交互
|
||||
- **路由路径**:`pages/mall/delivery/all`
|
||||
- **导航栏**:配置了 `navigationBarTitleText: "待接订单"`,并开启了原生的回退功能。
|
||||
- **动态跳转**:支持从详情页返回后自动刷新列表(通过 `onShow` 触发)。
|
||||
|
||||
## 4. 样式规范
|
||||
- 布局:Flexbox (Column)
|
||||
- 配色:
|
||||
- 取货点:Pink (`#ff4d94`)
|
||||
- 送达点:Blue (`#2196F3`)
|
||||
- 主按钮:Green (`#4CAF50`)
|
||||
- 间距:标准 30rpx 外边距,卡片内 40rpx 内边距。
|
||||
|
||||
## 5. 开发历史
|
||||
- **2026-02-03**: 页面初版创建。
|
||||
- **2026-02-03**: 完成从水平卡片到垂直流卡片的 UI 重构。
|
||||
- **2026-02-03**: 接入 Supabase 实现秒级抢单逻辑与状态同步。
|
||||
@@ -1,205 +0,0 @@
|
||||
## 测试数据生成与验证记录
|
||||
|
||||
本文档记录了在本项目中为配送端页面生成并验证测试数据库数据的全过程,包含关键表结构要点、执行的幂等 SQL、遇到的问题及解决办法,以及前端验证步骤,便于回溯和复现。
|
||||
|
||||
---
|
||||
|
||||
**概述**
|
||||
|
||||
- 目标:让配送端页面 `pages/mall/delivery/index.uvue` 能读取真实 DB 中的配送任务(`ml_delivery_tasks`)并在附近订单 / 当前任务中展示;为此需要在 DB 中创建或复用 `ak_users`、`ml_delivery_drivers`、`ml_orders`、`ml_delivery_tasks` 的测试数据。
|
||||
- 环境:Supabase(Postgres)。建议在 Supabase SQL Editor 中以 `Role = postgres` 执行 SQL 以避免 RLS/触发器引起的权限问题。
|
||||
|
||||
**关键表与约束摘要**
|
||||
|
||||
- `public.ak_users`:项目用户表,`id` 为主键,`auth_id` 对应 `auth.users.id`。
|
||||
- `public.ml_delivery_drivers`:配送员表,重要列:`id`、`user_id` (引用 `ak_users.id`,UNIQUE NOT NULL)、`real_name`、`id_card`。注意:此表没有 `phone` 列(以前曾误以为存在)。
|
||||
- `public.ml_orders`:订单表,重要列:`id`、`order_no`(UNIQUE NOT NULL)、`user_id`、`merchant_id`、`shipping_address` (JSONB NOT NULL)、`order_status`。
|
||||
- `public.ml_delivery_tasks`:配送任务表,重要列:`id`、`order_id` (UNIQUE NOT NULL,引用 `ml_orders.id`)、`driver_id` (引用 `ml_delivery_drivers.id`)、`pickup_address`/`delivery_address` (JSONB)、`status` (CHECK in (1..6))。注意:联系人信息应内嵌到地址 JSON 中(没有单独 `pickup_contact` 字段)。
|
||||
|
||||
---
|
||||
|
||||
**我执行的主要步骤(已实现的幂等脚本)**
|
||||
|
||||
1. 查找或创建 `ak_users`(按 `auth_id` 唯一):避免重复插入,若已存在则复用其 `id`。
|
||||
2. 查找或创建 `ml_delivery_drivers`(以 `ak_users.id` 为 `user_id`):注意去掉对不存在列的引用(例如 `phone`)。
|
||||
3. 插入两个测试订单(使用唯一 `order_no` 标识,若已存在则跳过),`shipping_address` 使用 JSONB 格式且包含 `contact`/`phone`/`province`/`city`/`detail` 等字段。
|
||||
4. 为每个订单创建对应的 `ml_delivery_tasks`:一个保持 `status = 1`(可接单,`driver_id = NULL`),另一个设置 `status = 4` 并分配上步骤创建或找到的 `driver_id`。
|
||||
|
||||
下面是我实际使用的幂等 SQL(已去除不存在列并兼容 schema)。在 Supabase SQL Editor 中以 `Role = postgres` 运行整段脚本即可。
|
||||
|
||||
```sql
|
||||
-- 替换 auth_id 为你的 auth.users.id(示例值可替换)
|
||||
WITH
|
||||
found_user AS (
|
||||
SELECT id FROM public.ak_users WHERE auth_id = 'dae9f45b-3955-43ae-992f-a3e24beaa520'
|
||||
),
|
||||
ins_user AS (
|
||||
INSERT INTO public.ak_users (id, auth_id, email, username, created_at)
|
||||
SELECT uuid_generate_v4(), 'dae9f45b-3955-43ae-992f-a3e24beaa520', 'test+delivery@example.com', 'test_delivery_user', NOW()
|
||||
WHERE NOT EXISTS (SELECT 1 FROM found_user)
|
||||
RETURNING id
|
||||
),
|
||||
user_id AS (
|
||||
SELECT id FROM ins_user
|
||||
UNION ALL
|
||||
SELECT id FROM found_user
|
||||
LIMIT 1
|
||||
),
|
||||
|
||||
found_driver AS (
|
||||
SELECT id, user_id FROM public.ml_delivery_drivers WHERE user_id = (SELECT id FROM user_id) LIMIT 1
|
||||
),
|
||||
ins_driver AS (
|
||||
INSERT INTO public.ml_delivery_drivers (id, user_id, real_name, id_card, created_at)
|
||||
SELECT uuid_generate_v4(), (SELECT id FROM user_id), '张师傅', 'ID-TEST-0001', NOW()
|
||||
WHERE NOT EXISTS (SELECT 1 FROM found_driver)
|
||||
RETURNING id, user_id
|
||||
),
|
||||
driver_row AS (
|
||||
SELECT id, user_id FROM ins_driver
|
||||
UNION ALL
|
||||
SELECT id, user_id FROM found_driver
|
||||
LIMIT 1
|
||||
),
|
||||
|
||||
ins_order_1 AS (
|
||||
INSERT INTO public.ml_orders (
|
||||
order_no, user_id, merchant_id,
|
||||
product_amount, shipping_fee, total_amount,
|
||||
shipping_address, created_at, updated_at
|
||||
)
|
||||
SELECT
|
||||
'TEST-DELIV-20260202-001',
|
||||
(SELECT id FROM user_id),
|
||||
(SELECT id FROM user_id),
|
||||
88.00, 12.00, 100.00,
|
||||
('{"contact":"李小明","phone":"13800000002","province":"上海市","city":"上海市","district":"浦东新区","street":"测试路100号","detail":"5楼502室","lat":31.2000,"lng":121.5000}')::jsonb,
|
||||
NOW(), NOW()
|
||||
WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no = 'TEST-DELIV-20260202-001')
|
||||
RETURNING id, order_no, order_status
|
||||
),
|
||||
sel_order_1 AS (
|
||||
SELECT id, order_no FROM ins_order_1
|
||||
UNION ALL
|
||||
SELECT id, order_no FROM public.ml_orders WHERE order_no = 'TEST-DELIV-20260202-001'
|
||||
LIMIT 1
|
||||
),
|
||||
|
||||
ins_task_1 AS (
|
||||
INSERT INTO public.ml_delivery_tasks (
|
||||
order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at
|
||||
)
|
||||
SELECT
|
||||
(SELECT id FROM sel_order_1),
|
||||
('{"contact":"商家小二","phone":"13900000002","street":"商家路1號","city":"上海市","detail":"商家门店A"}')::jsonb,
|
||||
('{"contact":"李小明","phone":"13800000002","street":"测试路100号","city":"上海市","detail":"5楼502室"}')::jsonb,
|
||||
12.00,
|
||||
1,
|
||||
NOW(), NOW()
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM public.ml_delivery_tasks dt WHERE dt.order_id = (SELECT id FROM sel_order_1)
|
||||
)
|
||||
RETURNING id, order_id, status, driver_id
|
||||
),
|
||||
|
||||
ins_order_2 AS (
|
||||
INSERT INTO public.ml_orders (
|
||||
order_no, user_id, merchant_id,
|
||||
product_amount, shipping_fee, total_amount,
|
||||
shipping_address, created_at, updated_at
|
||||
)
|
||||
SELECT
|
||||
'TEST-DELIV-20260202-002',
|
||||
(SELECT id FROM user_id),
|
||||
(SELECT id FROM user_id),
|
||||
59.00, 8.00, 67.00,
|
||||
('{"contact":"王小红","phone":"13800000003","province":"上海市","city":"上海市","district":"闵行区","street":"示例街20号","detail":"2幢101室","lat":31.1000,"lng":121.4000}')::jsonb,
|
||||
NOW(), NOW()
|
||||
WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no = 'TEST-DELIV-20260202-002')
|
||||
RETURNING id, order_no, order_status
|
||||
),
|
||||
sel_order_2 AS (
|
||||
SELECT id, order_no FROM ins_order_2
|
||||
UNION ALL
|
||||
SELECT id, order_no FROM public.ml_orders WHERE order_no = 'TEST-DELIV-20260202-002'
|
||||
LIMIT 1
|
||||
),
|
||||
|
||||
ins_task_2 AS (
|
||||
INSERT INTO public.ml_delivery_tasks (
|
||||
order_id, driver_id, pickup_address, delivery_address,
|
||||
delivery_fee, status, assigned_at, picked_at, created_at, updated_at
|
||||
)
|
||||
SELECT
|
||||
(SELECT id FROM sel_order_2),
|
||||
(SELECT id FROM driver_row),
|
||||
('{"contact":"商家B","phone":"13900000003","street":"商家街2號","city":"上海市","detail":"商家门店B"}')::jsonb,
|
||||
('{"contact":"王小红","phone":"13800000003","street":"示例街20号","city":"上海市","detail":"2幢101室"}')::jsonb,
|
||||
8.00,
|
||||
4,
|
||||
NOW(), NOW(), NOW(), NOW()
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM public.ml_delivery_tasks dt WHERE dt.order_id = (SELECT id FROM sel_order_2)
|
||||
)
|
||||
RETURNING id, order_id, status, driver_id
|
||||
)
|
||||
|
||||
SELECT
|
||||
(SELECT id FROM user_id) AS ak_user_id,
|
||||
(SELECT id FROM driver_row) AS delivery_driver_id,
|
||||
(SELECT id FROM sel_order_1) AS order1_id,
|
||||
(SELECT order_no FROM sel_order_1) AS order1_no,
|
||||
(SELECT id FROM sel_order_2) AS order2_id,
|
||||
(SELECT order_no FROM sel_order_2) AS order2_no,
|
||||
(SELECT id FROM ins_task_1) AS task1_id,
|
||||
(SELECT id FROM ins_task_2) AS task2_id;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**常见错误与处理**
|
||||
|
||||
- 错误:列不存在(例如 `address` / `phone` / `pickup_contact`)。处理:核对 `complete_mall_database.sql` 中的表结构,确认应使用 `shipping_address`、并将联系人内嵌到 JSON 中。
|
||||
- 错误:插入触发 FK 或 NOT NULL 违规(23503 / 23502)。处理:按顺序插入依赖表或使用已存在的 FK 值(例如先查找 `ak_users` 再插入 driver)。
|
||||
- 错误:唯一约束冲突(23505,例如 `ml_delivery_tasks.order_id` 唯一)。处理:脚本使用 `WHERE NOT EXISTS` 与 `ORDER_NO` 检查以避免重复插入。
|
||||
- 无行返回(UPDATE/SELECT 返回 “Success. No rows returned”):可能因为复制 id 时包含不可见字符,或 WHERE 条件不匹配。建议先用 `SELECT` 按 `order_no` 查找 task,再用 `UPDATE ... FROM public.ml_orders WHERE order_no = '...' RETURNING ...` 更新并检查返回值。
|
||||
|
||||
---
|
||||
|
||||
**前端验证(我在 `pages/mall/delivery/index.uvue` 已加入日志)**
|
||||
|
||||
1. 刷新配送端页面(或重新打开),观察控制台日志:
|
||||
- `loadDriverInfo` 日志:应输出 `driverInfo`,例如打印 `loadDriverInfo: try user_id=... res=...`。
|
||||
- `loadCurrentTask` 日志:输出查询结果 `loadCurrentTask: driverId=... res=...`,若 driver 有未完成任务(status < 5),`currentTask` 会被设置。
|
||||
- `loadAvailableOrders` 日志:输出 `loadAvailableOrders: query result=...`,用于验证 `status = 1` 且 `driver_id IS NULL` 的任务是否列出。
|
||||
|
||||
2. 若需要把某条 `ml_delivery_tasks` 的 `status` 改为 4(分配给司机),可运行:
|
||||
|
||||
```sql
|
||||
UPDATE public.ml_delivery_tasks dt
|
||||
SET status = 4,
|
||||
driver_id = '<DRIVER_ID>',
|
||||
assigned_at = NOW(),
|
||||
updated_at = NOW()
|
||||
FROM public.ml_orders o
|
||||
WHERE dt.order_id = o.id
|
||||
AND o.order_no = 'TEST-DELIV-20260202-001'
|
||||
RETURNING dt.id, dt.order_id, dt.status, dt.driver_id, dt.assigned_at, dt.updated_at;
|
||||
```
|
||||
|
||||
执行后刷新前端并贴回 `loadCurrentTask` / `loadAvailableOrders` 的日志,以便确认页面行为。
|
||||
|
||||
---
|
||||
|
||||
**附:运行建议与注意事项**
|
||||
|
||||
- 优先在 Supabase SQL Editor 中以 `Role = postgres` 执行插入与更新脚本,能避免 RLS 导致的“无行返回”。
|
||||
- 若需要创建 `ml_order_items`,需先确保 `ml_products` 存在或用最小 mock 产品插入,否则会触发 FK 约束错误。为减少依赖,我先仅创建 `ml_orders` 与 `ml_delivery_tasks`。
|
||||
- 保持 `order_no` 的唯一性(测试用的 `order_no` 推荐加时间戳或前缀 `TEST-`)。
|
||||
|
||||
如需我把脚本扩展为同时创建 `ml_products` / `ml_order_items`(以便测试完整订单页),或希望我直接在 repo 中加入一个可执行的 SQL 脚本文件,请回复我想要的范围,我来补充。
|
||||
|
||||
---
|
||||
|
||||
作者:自动化助手(配合用户执行并记录)
|
||||
日期:2026-02-02
|
||||
@@ -58,6 +58,8 @@ const result = Array.from(orderMap.values())
|
||||
## 数据源更新:包含已接订单(Accepted)
|
||||
- 需求说明:为了与“历史订单”页面保持一致,收入统计应包含配送员已接取(accepted/assigned)的订单,不仅限于已完成订单。也就是说,只要 `ml_delivery_tasks` 中 `driver_id` = 当前司机且 `status >= 2`(已接取或进行中),其对应的订单都应计入收入统计范围。
|
||||
|
||||
- 需求说明(已采纳):收入统计以 `ml_delivery_tasks` 为数据源之一:只要任务记录显示 `driver_id` = 当前司机且 `status >= 2`(已接取或进行中),其对应订单即应计入统计范围。注意:部分 `ml_delivery_tasks` 可能没有可匹配的 `ml_orders`(`order_id` 为空或在 `ml_orders` 中找不到),页面/后端应对缺失 `order_no` 做回退显示并记录供核查。
|
||||
|
||||
- 推荐 Supabase 查询示例(后端或前端按需实现):
|
||||
|
||||
```
|
||||
@@ -78,6 +80,7 @@ LIMIT :size OFFSET :offset;
|
||||
```js
|
||||
const taskRes = await supa.from('ml_delivery_tasks').select('order_id').eq('driver_id', uid).gte('status', 2).execute()
|
||||
const orderIds = taskRes.data.map(r => r.order_id)
|
||||
// 对于 order_id 为空或找不到的情况,server 端应记录这些 id 以便排查
|
||||
const ordersRes = await supa.from('ml_orders').select('*,ml_delivery_tips(*)').in('id', orderIds).order('created_at',{ascending:false}).limit(size).execute()
|
||||
```
|
||||
|
||||
|
||||
@@ -46,6 +46,16 @@ await supa.from('ml_delivery_tasks')
|
||||
- `toggleWorkStatus()`:切换 `isOnline` 并调用 `startWork()` / `stopWork()`。上线时会刷新可接订单列表。
|
||||
- 接单/开始取货/确认取货/开始配送/确认送达等均通过对 `ml_delivery_tasks` 的 `update` 操作变更 `status`,并在成功后更新本地 `currentTask`。
|
||||
|
||||
## UI 行为变动(已生效)
|
||||
- 当页面检测到存在 `currentTask`(来自 `ml_delivery_tasks`)时,页面不会再弹出“附近可接订单”列表。即:配送端以 `ml_delivery_tasks` 为状态真源,主页面的订单展示不再依赖或回退展示 `ml_orders.order_status`,以避免两表不同步导致的显示冲突。
|
||||
- 为了减少页面闪烁与重复刷新,`enableAutoRefresh` 在默认实现中已可被关闭(`false`),且 `loadAvailableOrders()` 在检测到 `currentTask` 时会跳过可接订单的渲染。
|
||||
|
||||
## 会话与加载保护
|
||||
- `supaReady` 的会话恢复在某些环境中会较慢,页面中已对其使用 `Promise.race(..., 1500)` 超时包装:超时后页面会打警告并继续渲染以避免长时间阻塞用户界面。依赖用户 id 的查询在超时情况下可能为空,请参照 `order-history.md` 的“已实现的防护”部分进行排查。
|
||||
|
||||
## 前端同步尝试(临时)
|
||||
- 在接单/确认送达流程中前端会尝试向 `ml_orders` 发送更新(将 `order_status` 同步到任务的状态)并记录返回结果用于诊断。但该同步并不保证在所有权限或网络错误下成功,因此更稳妥的方案仍是后端触发器同步或可信服务端接口。
|
||||
|
||||
## 注意事项
|
||||
- 高并发接单场景需后端保证原子性(乐观锁或 DB 事务)以防止竞单冲突。
|
||||
- `loadAvailableOrders()` 最好按司机服务区域与距离筛选,并使用分页/实时推送代替频繁轮询。
|
||||
|
||||
@@ -22,30 +22,26 @@
|
||||
- 解析 `options.id` 与 `options.status`,调用 `loadOrderDetail(id)`。
|
||||
|
||||
- `loadOrderDetail(id)`
|
||||
- 判断 ID 类型(UUID / 数字 / 非数字)以决定查询字段(`id`、`cid`、`order_no`)。
|
||||
- 并行查询 `ml_orders`, `ml_order_items`, `ml_shops`, `ml_delivery_tasks` 并合并到页面状态。
|
||||
- **加载保护**:对 `supaReady` 采用 1.5s 超时策略包装,防止会话刷新阻塞页面加载。
|
||||
- **智能 ID 回查**:优先从 `ml_orders` (UUID/cid/order_no) 查找。若未找到,则尝试从未分配任务表 `ml_delivery_tasks` 中根据 ID 查找,再反查关联订单。
|
||||
- **降级机制(Fallback)**:当 `ml_orders` 行缺失时,自动回退到从 `ml_delivery_tasks` 提取地址、手机号、配送费及距离等基础信息进行展示,并在 UI 上显示回退加载提示。
|
||||
- **清理加载状态**:在 `finally` 块中统一切除加载动画 (`uni.hideLoading`),防止界面挂起。
|
||||
|
||||
- `acceptOrder()` / `rejectOrder(reason)`
|
||||
- accept: 尝试对 `ml_delivery_tasks` 执行 `update driver_id` 操作并设置 `status=2`(处理中),需要后端并发保护。
|
||||
- reject: 增加拒单原因到 `ml_delivery_tasks` 或 `order_notes` 并回滚本地 UI 状态。
|
||||
## 交互与样式优化(2026-02-03 更新)
|
||||
- **联系人信息解析**:地址栏(取货/送货)现在仅在“联系人姓名”存在时显示分隔点 `·`。若无姓名,则仅显示手机号,避免显示为 `. 手机号`。
|
||||
- **联系方式布局优化**:为了防止手机号在不同屏幕宽度下被图标遮挡,联系人区域采用**垂直居中布局**(图标在上,姓名电话在下),显著拉高了边框高度 (`min-height: 180rpx`) 并增加了垂直间距。
|
||||
- **文本显示优化**:
|
||||
- 商品区域的“**订单号**”增加了加粗显示 (`bold`),提升核对便利性。
|
||||
- 展示给配送员的联系手机号调大了字号并加粗,确保清晰可见。
|
||||
- 修复了在 Uni-app x 下由于类型推断导致的手机号无法通过点语法访问的问题(改用索引访问)。
|
||||
|
||||
- `confirmPickup()` / `confirmDelivery()`
|
||||
- 根据 `task.id` 更新相应时间戳字段(`picked_at`/`delivered_at`)并设置状态(例如 `status=3/4`)。
|
||||
|
||||
## 示例:按 id 类型查询(伪代码)
|
||||
```
|
||||
let q = supa.from('ml_orders').select('*')
|
||||
if (isUUID(id)) q = q.eq('id', id)
|
||||
else if (isNumeric(id)) q = q.eq('cid', id)
|
||||
else q = q.eq('order_no', id)
|
||||
const { data: order } = await q.limit(1).execute()
|
||||
## 示例:地址兼容解析逻辑
|
||||
```typescript
|
||||
// 兼容 JSON 字符串及对象格式的地址字段
|
||||
let shipping = {}
|
||||
if (typeof raw == 'string') {
|
||||
try { shipping = JSON.parse(raw) } catch (e) { shipping = { detail: raw } }
|
||||
} else { shipping = raw || {} }
|
||||
// 访问方式:(address as UTSJSONObject)['phone']
|
||||
```
|
||||
|
||||
## 事务与并发注意
|
||||
- 接单场景应使用后端原子性检查(数据库事务或行级乐观锁)以避免多司机同时接单。
|
||||
- 前端接单流程:先尝试 update(带 where driver_id IS NULL),若返回 0 row affected 则提示已被接单。
|
||||
|
||||
## 错误处理与回退
|
||||
- 捕获所有 supa 调用错误并将友好错误展示给用户(例如:'网络错误,请稍后重试')。
|
||||
- 对可能缺失的字段(地址为字符串或对象)使用 `_transformAddress()` 做兼容处理。
|
||||
|
||||
|
||||
@@ -1,3 +1,78 @@
|
||||
# 历史订单 页面说明(order-history.uvue)
|
||||
|
||||
## 概要
|
||||
`order-history.uvue` 用于配送员查看历史订单与近期任务。页面会展示:
|
||||
- 以 `ml_delivery_tasks` 为配送端“状态真源”的任务记录(只要 `driver_id = 当前司机` 且 `status >= 2`,均会包含在统计/列表中);
|
||||
- 页面会批量回填对应 `ml_orders.order_no` 以补全显示(若 `order_no` 缺失会显示回退文本),避免直接以 `ml_orders.order_status` 作为展示依据而导致与配送端不一致。
|
||||
|
||||
页面关键点:
|
||||
- 首次加载时通过 `loadOrderHistory()` 拉取数据;页面每次显示时会检查本地存储 `completed_order_for_history`,并把刚完成订单插入列表表头。
|
||||
- 使用 Supabase 客户端 `supa` 读取 `ml_delivery_tasks` 与 `ml_orders` 表,并通过 `getCurrentUser()` / `getCurrentUserId()` 获取当前用户/司机 id。
|
||||
|
||||
## 行为细节
|
||||
- 当前实现优先以 `ml_delivery_tasks`(status >= 2)作为数据源,页面会:
|
||||
- 查询 `ml_delivery_tasks` 中与 `driver_id` 相关的任务,按时间排序并映射为页面项;
|
||||
- 对获取到的 `order_id` 列表做一次批量查询 `ml_orders` 以回填 `order_no` 和订单详情;
|
||||
- 对没有匹配到 `ml_orders` 的 `order_id`,页面会用短 id 回退显示并在控制台打印缺失 id 列表,便于后台核查数据不一致的原因。
|
||||
- 为避免重复展示,页面在将“当前任务对应订单”插入顶部时,会先检查 `orderList` 是否已有相同 `id`。
|
||||
|
||||
## 依赖 & 相关文件
|
||||
- 页面文件:`pages/mall/delivery/order-history.uvue`(当前)
|
||||
- Supabase 实例:`components/supadb/aksupainstance.uts`(导出 `supa` 与 `supaReady`)
|
||||
- 用户/会话工具:`utils/store.uts`(`getCurrentUser()`、`getCurrentUserId()`)
|
||||
- 相关文档:
|
||||
- `pages/mall/delivery/doc/earnings.md`(收入聚合与 DB 建议)
|
||||
- `pages/mall/delivery/doc/test-user-1_at_123.com.md`(测试用户与 SQL 示例)
|
||||
|
||||
## 已实现的防护与诊断信息
|
||||
- `supaReady` 在会话恢复时可能会进行网络刷新(refreshSession),该步骤可能较慢。为避免页面长时间阻塞,页面中对 `supaReady` 使用了 `Promise.race` 的 1.5s 超时包装:如果超时会打印警告并继续执行(某些依赖用户 id 的查询可能因此为空)。
|
||||
- 如果 `getCurrentUserId()` 返回空,页面会尝试从 `supa.getSession()` 获取 auth id 并在 `ak_users` 表中查找对应的 `ak_users.id` 作为回退,这能修复 `driver_id` 在数据库中为 `ak_users.id` 的常见映射问题。
|
||||
|
||||
## 常见不一致现象说明
|
||||
- 我们观察到的常见情况:`ml_delivery_tasks` 中的任务显示为“已完成”(配送端),但对应 `ml_orders.order_status` 仍为“已取消”或其它状态,导致不同页面显示冲突。原因通常为:
|
||||
- `ml_delivery_tasks.order_id` 为空或格式不一致(UUID vs string);
|
||||
- `ml_orders` 没有相应行(数据尚未同步或被删除);
|
||||
- RLS/权限导致前端不能读取或更新 `ml_orders`。
|
||||
|
||||
建议排查 SQL(例):
|
||||
```
|
||||
SELECT t.id AS task_id, t.order_id, t.status AS task_status, o.order_status
|
||||
FROM public.ml_delivery_tasks t
|
||||
LEFT JOIN public.ml_orders o ON o.id = t.order_id
|
||||
WHERE t.status >= 2
|
||||
ORDER BY t.created_at DESC
|
||||
LIMIT 200;
|
||||
```
|
||||
|
||||
如需我为你生成触发器或前端重试队列示例,我可以继续实现。
|
||||
|
||||
## 常见问题与排查步骤
|
||||
1. 问题:页面没有显示当前已接订单(即使首页显示有当前任务)。
|
||||
- 检查控制台日志:页面会打印 `loadOrderHistory: currentUserId=`、`loadOrderHistory: session id fallback=`、`loadOrderHistory: delivery_tasks dtRes=`、`loadOrderHistory: ordersRes=`。把这些日志逐项核对:
|
||||
- `currentUserId` 应为 `ak_users.id`(或系统实际使用的 driver id)。
|
||||
- `dtRes`(delivery_tasks 查询)应包含对象数组,且数组项含 `order_id`。
|
||||
- `ordersRes` 应包含对应的 `ml_orders` 行。
|
||||
- 若 `dtRes` 为空且 `session id fallback` 有值,说明 `ak_users` 表中可能没有把 auth id 映射到 `ak_users.id`,需要把 `ak_users.auth_id` 填入或同步。
|
||||
- 若 `ordersRes` 为空,但 `dtRes` 非空,请检查 `ml_orders.id` 与 `ml_delivery_tasks.order_id` 的数据类型(例如 UUID vs string)以及 RLS 策略。
|
||||
|
||||
2. 问题:页面加载慢或时不时刷新。
|
||||
- 原因:多个页面在 `onShow`/`onLoad` 时发起多次 supa 查询,且 `supaReady` 恢复会话有时较慢,导致累积延迟。已在 `index.uvue` 增加了防抖与 `enableAutoRefresh` 开关来禁止自动刷新。
|
||||
- 排查:查看控制台是否有 `supaReady timeout/failed` 警告(若有,则说明会话恢复慢或失败)。
|
||||
|
||||
## 性能与安全建议
|
||||
- 若数据量大,请在后端做分页与聚合(只返回必要字段);避免一次性查询大量 `ml_orders` 字段。参见 `earnings.md` 中的后端接口建议。
|
||||
- 长期建议:修改 `components/supadb/aksupainstance.uts` 中会话恢复逻辑,让刷新在后台异步进行或提供可配置的超时策略,避免阻塞页面加载。
|
||||
|
||||
## 测试步骤(快速)
|
||||
1. 使用测试用户(参见 `test-user-1_at_123.com.md`)创建一个 `ml_delivery_tasks` 记录,`driver_id` 对应当前司机,且 `status >= 2`。
|
||||
2. 在首页确认当前任务显示;然后打开“历史订单”页面,观察顶部是否显示该订单。若未显示,贴上控制台中 `loadOrderHistory:` 的相关日志给开发者排查。
|
||||
|
||||
## 变更历史
|
||||
- 2026-02-02:添加回退 mapping(session -> ak_users.id)、supaReady 超时保护的说明、调试日志建议及性能建议。
|
||||
|
||||
---
|
||||
|
||||
如需我把文档翻译为英文或生成 README 风格的一页说明,我可以继续补充。
|
||||
# order-history.uvue — 历史订单
|
||||
|
||||
## 概要
|
||||
|
||||
Reference in New Issue
Block a user