业务字段概览

货柜大表(表名 cargo_sheet)覆盖运营全流程字段:

类别 字段示例
柜信息 柜型、柜号、MBL、DO、重量
时间 订单日、ETA、LFD、提柜日、还柜日
地点 Terminal、送仓地址
人员 提柜司机、还柜司机、预约同事
其它 预报窗口、仓库账号、备注

23+ 列,列定义集中在 container-columns.ts

前端架构

1
2
3
4
5
6
7
8
flowchart TB
PAGE["cargo-sheet/page.tsx"] --> COLS[container-columns.ts]
PAGE --> HOOK[useTablePreferences]
PAGE --> DND["dnd-kit 列拖拽"]
PAGE --> API["cargo-sheet API"]
API --> MAP[container-mapper.ts]
API --> HIST[container-history.ts]
HIST --> DB[(cargo_sheet_history)]

前端页面模式(共用表格范式)

各业务页(orderscontainersgoogle-sheet)共享同一套 可编辑表格 模式:

11.1 结构

1
2
3
4
5
DashboardLayout
├── Sidebar(导航)
├── 搜索栏 + 工具按钮
├── 可滚动表格(列拖拽/排序/列宽 → localStorage)
└── 分页

11.2 交互模式

模式 行为
只读行 双击 → 进入行内编辑
新建行 底部蓝色行,保存 POST
编辑行 PUT 单条 API
批量删除 勾选 + DELETE batch

11.3 列偏好 Hooks

Hook 用于
useOrderTablePreferences 订单页
useParseResultTablePreferences 解析结果页
useTablePreferences 货柜订单大表 页

列定义分别在 order-columns.tsparse-result-columns.tscontainer-columns.ts

11.4 重要组件

组件 用途
ParseResultDialog 解析结果弹框(按附件折叠展示明细)
ContainerHistoryDialog 货柜订单大表 历史版本
GmailSearchDialog 货柜订单大表 详情页搜邮件
GmailAuthNotifier Gmail 未连接时提示

货柜大表模块深入

行内编辑模式

  1. 双击单元格 → 本地 state 进入编辑
  2. Blur / Enter → PUT /api/v1/cargo-sheet/[id]
  3. 更新前 container-history.ts 写入 version 快照
1
2
3
4
5
// container-history.ts(示意)
await prisma.cargo_sheet_history.create({
data: { container_id: id, version: nextVersion, snapshot: rowJson },
});
await prisma.cargo_sheet.update({ where: { id }, data: patch });

列偏好持久化

useTablePreferences 将列宽、显隐、顺序存入 localStorage,键名按页面隔离,刷新不丢配置。

cargo_sheet API 一览

方法 路径 说明
GET/POST /api/v1/cargo-sheet 列表 / 新建
GET/PUT/DELETE /api/v1/cargo-sheet/[id] 单条(软删除)
GET /api/v1/cargo-sheet/[id]/history 历史快照
POST /api/v1/cargo-sheet/import Excel 批量导入
POST /api/v1/cargo-sheet/reorder 拖拽排序

Excel 批量导入

order-sheet-import.ts固定 23 列模板 导入,与派送表动态解析分离(见 第 04 篇)。

另一套 HEADER_ALIASES(不是 FBA 明细),同样用 excel-utils 读 xlsx。

软删除

deleted_at / deleted_by 标记删除,列表默认过滤,避免误删不可恢复。

线 B:货柜大表 + Gmail 弹框

:货柜订单大表 / 弹框检索

6.1 前端:GmailSearchDialog

位置:google-sheet/[containerNo]/page.tsx

用户操作 请求
打开弹框 自动 GET /api/v1/gmail/search?containerNo=xxx
看某封邮件 GET /api/v1/gmail/message/{id}
解析某附件入库 POST /api/v1/containers/by-no/{柜号}/parse-attachment
未授权 跳转 /api/v1/gmail/auth

6.2 按柜号一键解析(旧 API)

POST /api/v1/containers/by-no/[containerNo]parseContainerEmail()

  • 要求 cargo_sheet 已有该柜号
  • 自动搜邮件 → 选最佳 → 下 Excel → 解析 → 覆盖该柜号下旧 delivery_items
  • 更新 container_parse_meta 邮件元数据

6.3 与线 A 的差异摘要

  • 线 B 不一定containers.batch_no 批次模型(以 container-parse-service 为准)
  • 弹框可 手动选附件;线 A 自动处理所有 parseable 附件

链路 D:货柜大表保存

(补充):货柜订单大表 保存

与订单线 独立,共用 Gmail 能力但表不同。

1
2
3
4
5
google-sheet/page.tsx
→ PUT /api/v1/cargo-sheet/[id]
→ container-mapper.ts
→ container-history.ts(更新前写快照)
→ prisma.cargo_sheet.update

软删除:deleted_at 非 null 表示已删,列表默认过滤。

详情页 google-sheet/[containerNo]/page.tsx 可打开 GmailSearchDialog 搜邮件(不一定走 order-parse-service)。


GmailSearchDialog 交互

用户操作 请求
打开弹框 GET /api/v1/gmail/search?containerNo=xxx
看某封邮件 GET /api/v1/gmail/message/[id]
解析某附件入库 POST /api/v1/containers/by-no/[柜号]/parse-attachment
未授权 跳转 Gmail OAuth 授权

与线 A 订单检索的差异

对比项 线 A 订单检索 线 B 货柜大表
入口 订单页「检索」 详情页「邮件」弹框
Service order-parse-service container-parse-service
批次 每次新建 containers + batch_no 按柜号覆盖 delivery_items
附件选择 自动处理全部 parseable 用户可选手动指定附件

拖拽排序与列配置

  • 列拖拽:"dnd-kit 列拖拽"/core + "dnd-kit 列拖拽"/sortable(Mermaid 中记为 dnd-kit 列拖拽
  • 列宽调整:mousedown + 本地 state
  • 排序/筛选:Client 侧 state + API query

重要组件

组件 用途
ParseResultDialog 解析结果弹框(按附件折叠展示明细)
ContainerHistoryDialog 货柜大表历史版本
GmailSearchDialog 详情页搜邮件
GmailAuthNotifier Gmail 未连接时提示

数据流示意

1
2
3
4
5
6
7
8
9
10
11
sequenceDiagram
participant Page as "cargo-sheet 页面"
participant API as "cargo-sheet API"
participant Hist as container-history.ts
participant DB as PostgreSQL

Page->>API: PUT 保存行
API->>Hist: 写 history 快照
Hist->>DB: cargo_sheet_history.insert
API->>DB: cargo_sheet.update
DB-->>Page: serialize 后返回

系列导航

主题
上一篇 05 解析流水线
本篇 可编辑大表与历史快照
下一篇 07 CRUD 模板
索引 专栏首页

← 返回专栏首页