data-model.md 6.7 KB

Data Model: 用户端统一订单列表

Date: 2026-09-20 | Spec: spec.md

本功能无新表、无视图、无字段变更。本文定义组合视图结构、游标格式与 tab 归类谓词的权威规则。

1. 统一列表项 UnifiedOrderListItem(DTO,无落库)

公共字段

字段 类型 说明
sourceType String takeaway / flash
role String 仅闪送有意义:sender 寄件 / receiver 收件;外卖恒 sender
orderId Long 源表主键(两表自增 ID 数值可能重叠,必须与 sourceType 联用)
orderNo String 外卖=业务单号 ddId;闪送=orderNo(FD 前缀)——详情跳转键
unifiedStatus String 归属 tab 同款枚举(unpaid/active/completed/cancelled/refund;all 查询下返回该单实际归属的 tab 值)
createTime Long 下单时间毫秒时间戳(排序与游标基准)
amount Long 订单金额(外卖取现有列表展示金额字段,实现时对齐;闪送 amount)
currency String 币种(闪送 VND;外卖按现有返回,可为空)
hasAfterSale Boolean 外卖售后标记(afterSaleStatus>0);闪送恒 false

外卖渲染块(takeaway,前端复用现有外卖卡片)

type(0外送/1自取/2堂食)、state(0-4)、deliveryStatus(0-3,仅外送)、payStatus(0/1/2)、payType(1-6)、afterSaleStatus(0-6)、storeName(按 mdId 批量查 pos_store.posName,店铺已删回退订单快照 posName)、storeAvatar(pos_store.logo,同回退)、goodsCount(food 快照数组 number 求和)、collectPayment(到付标记)——数值原值透传,文案由前端渲染。

闪送渲染块(flash,对齐 FlashDeliveryUserOrderListView 字段子集)

status(六态枚举原值)、orderVersion(乐观锁版本,编辑待接单订单须回传)、serviceTypedeliveryTypevehicleTypedeliveryMode+scheduledPickupStartAt/scheduledPickupEndAtpickupAddress/pickupDetailAddressdeliveryAddress/deliveryDetailAddresspackageTypequantitytipAmountamount

2. 游标 UnifiedCursor

  • 格式{createTimeMillis}_{sourceType}_{orderId},如 1726812345000_flash_1024。服务端生成,前端视为不透明字符串透传。
  • 排序全序(归并与游标推进的同一规则):
    1. createTime DESC
    2. 同刻:sourceType 字典序 ASC(dinein < flash < pickup < takeaway
    3. 同刻同源:orderId DESC
  • 来源编码:混排查询(source=all)的行与游标只有 takeaway/flashdinein/pickup 仅在来源单选查询的游标中出现(堂食/自取是 pos_order.type 子集,单选时同源翻页同秒 id 决胜照常生效)。
  • 推进条件(每源 SQL):本源取 (t < T) OR (t = T AND 本源序 > cursor源序) OR (t = T AND 本源 = cursor源 AND id < cursorId),其中"本源序 > cursor 源序"在单源 SQL 中退化为常量布尔(实现封装在 UnifiedCursor,禁止散落拼接)。
  • 校验:格式非法/数值越界 → 参数错误(消息 key),不静默当首页。
  • 有效期:游标仅是位置标记,无过期概念;源数据变化导致的位置偏移属正常现象(新下单会出现在首页,不影响旧游标正确性)。

3. tab 归类谓词(唯一事实源,SQL 条件与内存判定同源)

外卖(pos_order)——照搬 UserOrderController.orderList:555-582 现行条件

tab 条件
unpaid payStatus=0 AND payType IN (2,3) AND state≠4 AND afterSaleStatus=0(仅在线支付未付)
active state IN (0,1,2) AND afterSaleStatus=0 AND (payStatus=1 OR (payType IN ('1','4') AND type IN (1,2)))(2026-09-21:payType 扩入现金 4,随堂食/自取现金下单开放)
completed state=3 AND afterSaleStatus=0
cancelled state=4 AND afterSaleStatus=0
refund afterSaleStatus>0
all 无条件(以上皆不过滤)

不变量提醒(specs/018):payStatus=2 必然 state=4 且 afterSaleStatus=3——refund 条件天然覆盖已退款单。

闪送(flash_delivery_order)

tab 条件
unpaid —(恒空,查询层直接跳过闪送路)
active status IN (WAITING_ACCEPTANCE, ACCEPTED, PICKED_UP, DELIVERED)(非终态)
completed status = COMPLETED
cancelled status = CANCELLED
refund —(恒空,同上)
all 无条件

谓词实现约束

  • UnifiedOrderTab 枚举内聚两域规则:wrapperFor(posOrder) / matches(PosOrder)wrapperFor(flash) / matches(FlashDeliveryOrder);SQL 构造与内存判定使用同一组常量,单测双向校验(构造出的条件查回的样本必须全部通过内存判定)。
  • unifiedStatus 取值 = 该单在谓词下命中的 tab(all 查询时由内存判定得出)。

4. 查询形态(每源,每次滚动)

-- 外卖路(role 恒 sender)
-- 注:PosOrder 实体无 del_flag 字段,且现有 orderList 亦不过滤,为保持行为零漂移不加该条件
SELECT ... FROM pos_order
WHERE user_id = ? AND <来源type条件> AND <tab条件> AND <游标推进>
ORDER BY cretim DESC, id DESC
LIMIT size+1

-- 闪送路(含收件视角,OR 单查询天然去重)
SELECT ... FROM flash_delivery_order
WHERE (user_id = ? OR receiver_user_id = ?) AND <tab条件> AND <游标推进>
ORDER BY create_time DESC, id DESC
LIMIT size+1
  • 来源 type 条件(2026-09-21 堂食/自取筛选):source=takeaway → type=0(仅外送)、dinein → type=2pickup → type=1source=all 不加 type 条件(堂食/自取照常混排)。dinein/pickup 是外卖路子集,跳过闪送路。
  • 游标推进中的"同刻同源 id < cursorId"与源内 ORDER BY ... id DESC 对应;跨源同刻并列由 Java 归并的 source 字典序处理。
  • tab=unpaid/refund:跳过闪送路;source 单选:跳过另一路。
  • Java 归并:按全序(§2)取前 size 条,第 size+1 条存在 → hasMore=truenextCursor = 末条(t, source, id)。

5. 索引核实清单(上线前置,条件性 SQL,写入 updatesql/sql.md 不直接执行)

-- 2026-09-20 统一订单列表查询索引(030-unified-order-list,核实后执行:已存在则跳过)
ALTER TABLE pos_order ADD INDEX idx_user_cretim (user_id, cretim);
ALTER TABLE flash_delivery_order ADD INDEX idx_user_ctime (user_id, create_time);
ALTER TABLE flash_delivery_order ADD INDEX idx_receiver_ctime (receiver_user_id, create_time);

开发者先在库上 SHOW INDEX 核实,缺哪条执行哪条。

6. 错误消息 key(新增,多语言)

key 用途
no.unifiedorder.cursor.invalid 游标格式非法
no.unifiedorder.param.invalid tab/source 取值非法