## 测试数据生成与验证记录 本文档记录了在本项目中为配送端页面生成并验证测试数据库数据的全过程,包含关键表结构要点、执行的幂等 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 = '', 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