You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mail-yubao/docx/产品UI-UX设计方案-邮件自动预报-v1.0.md

453 lines
16 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 产品UI/UX设计方案 v1.0(邮件自动预报系统)
> 状态:可直接画原型 / 写前端(**2026-07-23 现行口径回写**)
> 依据:`docx/需求规格-邮件自动预报-v0.2.md`、`docx/技术设计方案-邮件自动预报-v1.0.md`
> UI 栈锁定:Ant Design 5 + TanStack Virtual(货件表)+ 本规范 Token
> **回写要点**:`/settings`;`/logs`=导入+拉取(无操作审计);空态无种子;详情业务意图摘要替代得分表;详见 `docx/现行口径-修订说明-v1.md`
---
# 1. 信息架构(Information Architecture)
## 1.1 页面列表
| 页面 | 路由 | 职责 |
|---|---|---|
| 登录页 | `/login` | 账号密码登录;写 session Cookie |
| 邮件列表页 | `/mails` | 时间倒序展示邮件;按类型/状态筛选;进入详情 |
| 邮件详情页 | `/mails/[id]` | 摘要、正文、附件、证据、货件预览;重新解析;Admin 改类型;进入确认导入 |
| 确认导入页 | `/mails/[id]/confirm` | 柜头编辑;TransMode/OperationType;货件勾选(虚拟滚动);二次确认后提交 CC |
| 导入日志/补偿页 | `/logs` | Tab:导入日志、拉取记录;失败重试 |
| 设置 | `/settings` | Admin:邮箱绑定、IMAP 间隔/过滤、CC、OAuth |
| Admin 改类型 | **详情页内 Modal**(非独立路由) | `ENABLE_TYPE_OVERRIDE`(及前端可见开关)+ `role=admin`;一期不写 audit_log |
不设 `/dashboard`、不设 `/admin/override` 独立页。登录后默认落点:`/mails`。
## 1.2 页面关系图
```
/login
→ /mails
→ /mails/[id]
→ /mails/[id]/confirm (mail_type=NEW_CONTAINER 且 status=PENDING_CONFIRM;或 Admin 改类型后满足条件)
→ /logs (提交结束:成功跳转;失败可停留 confirm 或跳 logs)
⇢ Modal「改类型」 (Admin)
⇢ 动作「重新解析」 (PARSE_FAILED / REJECTED_VALIDATION / 允许重解析的状态)
→ /logs (顶栏入口)
```
禁用路径:
- `mail_type ≠ NEW_CONTAINER` 且未改类型成功 → 不可进入 confirm(直链访问重定向详情 + Toast)
- `status ∈ {IMPORTING, SUCCESS}` → confirm 只读或重定向详情
## 1.3 路由结构(Next.js App Router)
```
/login
/mails
/mails/[id]
/mails/[id]/confirm
/logs
```
顶栏全局导航(登录后):`邮件列表` | `日志` | `设置`(Admin) | 健康/IMAP/CC 状态 | `用户名` | `Admin` 徽标 | `退出`
---
# 2. 交互原型(Interaction Design)
## 2.0 全站壳层
```
┌──────────────────────────────────────────────────────────┐
│ TopNav: Logo「邮件预报」 | 导航链接 | 用户/Admin | 退出 │
├──────────────────────────────────────────────────────────┤
│ PageHeader: 标题 + 右侧主操作(按页) │
├──────────────────────────────────────────────────────────┤
│ MainContent(白底 Card 或铺满表) │
└──────────────────────────────────────────────────────────┘
```
- 最小视口宽:1280px
- 内容最大宽:1440px,水平居中
- Toast:右上角;Modal:居中
---
## 2.1 登录页 `/login`
**结构**
- 居中 Card(宽 400px)
- 标题:邮件自动预报
- 字段:用户名、密码
- 主按钮:登录
**交互**
- 提交 → 按钮 loading → 成功跳转 `/mails`;失败 Toast error + 字段下方文案
- 已登录访问 `/login` → 重定向 `/mails`
**空/错**
- 用户名或密码空 → 内联校验,不发请求
---
## 2.2 邮件列表页 `/mails`
**结构**
```
PageHeader: 「邮件列表」
FilterBar: [类型 Select] [状态 Select] [关键词 Input] [查询 Button]
MailTable(非卡片列表,密度优先用表格):
列:类型Tag | 状态Pill | 主题 | 发件人 | 接收时间 | 柜号(若有)
Pagination: 底右,默认 pageSize=20
```
**交互**
- 行点击(整行可点)→ `/mails/[id]`
- 筛选变更 → 立即请求列表(防抖 300ms,关键词)
- 手动「刷新」按钮 → 重新拉列表(无 WebSocket)
**空态**
- 文案:暂无邮件,等待 IMAP 拉取
- 次按钮:刷新
**角标规则**
- 类型:左侧色点 8px + Tag 文字
- 状态:StatusPill 文字(不只靠颜色)
---
## 2.3 邮件详情页 `/mails/[id]`
**结构**
```
PageHeader:
[← 返回列表] 主题(H1) StatusPill TypeTag
右侧操作组:
[重新解析](条件可见)
[改类型](Admin 条件可见)
[确认导入](主按钮,条件启用)
SummaryStrip: 发件人 | 时间 | Message 状态
Tabs 或 纵向区块:
1) 正文摘要(等宽可读,max-height 240px 可滚动)
2) 附件列表:文件名 | 大小 | 下载
3) 业务意图摘要(动作/关键字/操作内容/转仓对;不展示得分分值);type_evidence JSON 可选收起
4) 货件预览表(前 50 行 + 「共 N 行,确认导入页查看全部」链接)
```
**确认导入按钮启用条件(全部满足)**
- `mail_type === NEW_CONTAINER`
- `status === PENDING_CONFIRM`
- `valid_shipment_count >= 1`
**禁用时 Tooltip / 旁注文案(写死)**
- 类型非 NEW:`类型为 {mail_type},一期不可导入`
- 状态非 PENDING_CONFIRM:`当前状态为 {status},不可导入`
- 无有效行:`无有效货件行`
**交互**
- 确认导入 → `/mails/[id]/confirm`
- 重新解析 → POST reparse → 按钮 loading → 成功 Toast → 重新拉详情;失败 Toast
- 改类型 → 打开 `TypeOverrideModal`:
- Select 目标类型
- Input 原因(必填)
- 展示当前 type_evidence 摘要
- 确认 → loading → 审计成功 Toast → 刷新详情(可能出现确认导入可点)
**直链保护**
- 非法 id → 404 页:邮件不存在 + 回列表
---
## 2.4 确认导入页 `/mails/[id]/confirm`(核心)
**结构**
```
PageHeader:
[← 返回详情] 主题截断 | 柜号大号展示
右侧无第二主按钮(主 CTA 在底栏)
Section「柜头」Card 两列表单:
左列: TransMode* | OperationType* | ContainerNo* | CabinetType | Classis
右列: ETD | ETA | ShippingLineId(Select 可搜索,可空)| MemoRemark | Instruction
* 必填;ContainerNo 失焦触发 ISO 校验
Section「货件」Card:
Toolbar: [全选有效] [反选] [SearchInput: FBACode/ShipmentID] [有效 m / 无效 k]
VirtualTable 高度固定 480px:
列: ☑ | # | 仓库ID | 渠道 | 件数 | FBA ID | Ref | ShipmentID | 行状态 | 警告
INVALID 行: 背景 #F3F4F6,勾选 disabled,行状态 Tag=INVALID
StickyFooter(视口底):
左: 已选 n / 有效 m
右: [取消] [确认导入 Primary]
```
**默认值**
- TransMode = 解析推荐或 `0`
- OperationType = 解析推荐或 `0`
- 勾选 = 全部 `VALID` 行
- `CHANNEL_UNMAPPED` 行可勾选,提交前若存在未 ack → 额外确认勾选「已知晓未映射渠道」
**二次确认 Modal**
- 标题:确认导入至 CarrierCentral
- 正文:`将向 CC 导入柜 {container_no},货件 {n} 行`
- 展示 TransMode / OperationType 文案
- 按钮:取消 | 确认提交
**提交交互**
1. Primary 点击 → 打开 Modal(本地校验先过)
2. Modal 确认 → Primary+Modal 双 loading;`disabled`
3. 成功 → Toast success → 跳转 `/logs?mail_id={id}`
4. 失败 → Toast error(展示 `error.message`)→ 留在本页;可再改再提(若 status 已 IMPORTING 则整页只读 + 「导入中,请稍后刷新」)
5. `409 VERSION_CONFLICT` → Toast + 强制刷新页面数据
**校验(内联)**
- TransMode / OperationType 空 → 阻止 Modal
- ContainerNo 空或 ISO 失败 → 字段 Error
- n=0 → Primary disabled,文案:请至少勾选一行有效货件
---
## 2.5 导入日志/补偿页 `/logs`
**结构**
```
PageHeader: 「导入日志」 [返回邮件列表]
Filter: 状态 Select | 柜号/主题 Search
Table 列:
时间 | 邮件主题(链到详情) | 柜号 | 导入状态Pill | external_id | last_error | 操作
操作:
FAILED / TIMEOUT_UNKNOWN / CONFLICT(可重试类) → [重试]
SUCCESS → 显示 external_id,无重试
```
**交互**
- 重试 → 按钮 loading → Toast → 刷新行
- `COMPENSATION_EXHAUSTED` → 重试按钮对普通 ops 隐藏;Admin 显示「重置并重试」
**空态**
- 暂无导入记录
---
## 2.6 统一交互规则(写死)
1. 所有触发写操作的按钮:点击即 `loading` + `disabled`,防重复提交。
2. 所有 API 失败:全局 Toast `error`;表单字段错误额外内联。
3. 所有必填/格式:失焦或提交前校验,不通过不发请求。
4. 导入类写操作:必须二次确认 Modal。
5. 货件表 ≥50 行:必须虚拟滚动(本系统确认页固定启用)。
6. 状态更新:一期无 WS;用户点「刷新」或返回列表重进。
7. IMPORTING 期间:详情/确认页禁止再次提交;展示 Alert「导入进行中」。
8. 色标旁必须有文字标签。
---
# 3. 视觉设计(Visual Design System)
## 3.1 色彩 Token
| Token | Hex | 用途 |
|---|---|---|
| `--color-primary` | `#2563EB` | 主按钮、链接、焦点 |
| `--color-primary-hover` | `#1D4ED8` | hover |
| `--color-success` | `#16A34A` | 成功 |
| `--color-warning` | `#F59E0B` | 警告/部分成功 |
| `--color-error` | `#DC2626` | 失败 |
| `--color-bg` | `#F8FAFC` | 页面底 |
| `--color-surface` | `#FFFFFF` | 卡片/表单 |
| `--color-text` | `#111827` | 主文字 |
| `--color-text-secondary` | `#6B7280` | 辅助 |
| `--color-border` | `#E5E7EB` | 边框 |
| `--color-disabled` | `#9CA3AF` | 禁用 |
**类型色(Tag 背景 / 文字白或深按对比度)**
| mail_type | 色 |
|---|---|
| NEW_CONTAINER | `#2563EB` |
| TRANSFER | `#F59E0B` |
| INSTRUCTION_HOLD_SPLIT | `#8B5CF6` |
| INSTRUCTION_LABEL | `#EC4899` |
| WORK_ORDER | `#0D9488` |
| UNKNOWN | `#6B7280` |
**状态色(StatusPill)**
| status | 色 |
|---|---|
| FETCHED / PARSING / PARSED | `#9CA3AF` |
| PENDING_CONFIRM | `#2563EB` |
| IMPORTING | `#F59E0B` |
| SUCCESS | `#16A34A` |
| PARTIAL_SUCCESS | `#F59E0B` |
| FAILED / PARSE_FAILED / REJECTED_VALIDATION | `#DC2626` |
| IGNORED | `#6B7280` |
## 3.2 字体
- 字体栈:`Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif`
- H1:24px / 700 / 1.2
- H2:20px / 600 / 1.3
- Body:14px / 400 / 1.5
- Caption:12px / 400 / 1.4
- Small:11px / 400 / 1.3
- 等宽(证据 JSON):`ui-monospace, SFMono-Regular, Menlo, Consolas, monospace` 12px
## 3.3 间距
`4 / 8 / 12 / 16 / 24 / 32 / 48 / 64`(px)
Card 内边距:16
区块间距:24
Filter 与表:16
## 3.4 圆角
| 元素 | 半径 |
|---|---|
| Button / Input | 6px |
| Card | 8px |
| Modal | 12px |
| Tag / Pill | 12px |
## 3.5 阴影
- Card:`0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)`
- Modal:`0 20px 60px rgba(0,0,0,0.15)`
## 3.6 组件视觉规格
| 组件 | 规格 |
|---|---|
| PrimaryButton | bg primary,文字白,h=36,px=16,radius 6;hover primary-hover;loading 内嵌 Spinner |
| SecondaryButton | bg 白,border primary,文字 primary |
| DangerButton | bg error,文字白 |
| Input / Select | h=36,border 1px border-color,focus:ring 2px primary 30% |
| Card | surface + shadow + radius 8 + p16 |
| Tag | h=22,px=8,文字 12px |
| StatusPill | 同 Tag |
| Table header | bg `#F9FAFB`,文字 secondary,字重 600 |
| INVALID 行 | bg `#F3F4F6`,文字 secondary |
| StickyFooter | 白底,上边框 border,h=56,z-index 10 |
| Toast success/error/warning | 对应色左边条 4px |
---
# 4. 设计规范(Design System for AI Coding)
## 4.1 React 组件清单(映射 Antd)
| 设计组件 | 实现映射 |
|---|---|
| `PrimaryButton` | `Button type="primary"` |
| `SecondaryButton` | `Button` |
| `DangerButton` | `Button danger` |
| `InputField` | `Form.Item` + `Input` |
| `SelectField` | `Form.Item` + `Select` |
| `DatePickerField` | `Form.Item` + `DatePicker` |
| `Checkbox` | `Checkbox` |
| `AppCard` | `Card` |
| `MailTable` | `Table` |
| `ShipmentVirtualTable` | 自研:TanStack Virtual + 行渲染 |
| `TypeTag` | `Tag` + 类型色 |
| `StatusPill` | `Tag` + 状态色 |
| `LoadingSpinner` | `Spin` |
| `ErrorBanner` | `Alert type="error"` |
| `AppToast` | `message` / `notification` |
| `ConfirmModal` | `Modal.confirm` 或受控 `Modal` |
| `SearchInput` | `Input.Search` |
| `Pagination` | `Pagination` |
| `TypeOverrideModal` | 受控 `Modal` + Form |
| `TopNav` | `Layout.Header` + `Menu` |
| `EmptyState` | `Empty` |
页面组件命名:
- `LoginPage`
- `MailListPage`
- `MailDetailPage`
- `MailConfirmPage`
- `ImportLogsPage`
## 4.2 组件状态
每个可交互组件支持:`idle | loading | success | error | disabled | empty`(按上下文取用)。
页面级状态机(前端):
- `pageStatus: idle | loading | error`
- 详情另:`actionLoading: reparse | override | none`
- 确认页另:`submitPhase: idle | validating | confirming | submitting`
## 4.3 命名规范
- 组件:PascalCase
- 路由文件:`page.tsx` 于 `app/mails/[id]/confirm/page.tsx`
- 状态布尔:`isLoading` `isSubmitting` `isAdmin`
- 文案常量:`src/constants/ui-copy.ts`
- Token CSS 变量:`--color-*` 写入 `globals.css`
## 4.4 UI 硬约束(编码强制)
1. 写操作按钮必须 `loading` + 防重复。
2. API 失败必须可见错误(禁止静默)。
3. 表单校验失败禁止发请求。
4. 导入提交必须二次确认 Modal。
5. 货件表 ≥50 行必须虚拟滚动(confirm 页强制)。
6. 空列表必须 EmptyState。
7. 桌面优先,min-width 1280。
8. Tag/Pill 必须带文字,不只靠颜色。
9. confirm 直链:服务端/客户端双重校验 NEW + PENDING_CONFIRM。
10. Admin 改类型按钮:仅 `isAdmin && enableTypeOverride` 渲染。
## 4.5 文案常量(摘录)
| key | 中文 |
|---|---|
| `empty.mails` | 暂无邮件,等待 IMAP 拉取 |
| `btn.confirmImport` | 确认导入 |
| `btn.reparse` | 重新解析 |
| `btn.overrideType` | 改类型 |
| `btn.retry` | 重试 |
| `modal.import.title` | 确认导入至 CarrierCentral |
| `modal.import.body` | 将向 CC 导入柜 {no},货件 {n} 行 |
| `disable.notNew` | 类型为 {type},一期不可导入 |
| `disable.badStatus` | 当前状态为 {status},不可导入 |
| `alert.importing` | 导入进行中,请稍后刷新查看结果 |
| `ack.unmapped` | 已知晓存在未映射渠道,仍提交原值 |
## 4.6 线框尺寸速查
| 区域 | 尺寸 |
|---|---|
| TopNav 高 | 56px |
| PageHeader 高 | 64px |
| FilterBar 高 | 48px |
| 确认页 VirtualTable | 高 480px |
| StickyFooter | 高 56px |
| 登录 Card | 宽 400px |
| Modal 宽 | 480px(改类型)/ 520px(导入确认) |
---
# 5. 页面 ↔ API 绑定(供前端直接接线)
| 页面 | 主要 API |
|---|---|
| Login | `POST /api/auth/login` |
| MailList | `GET /api/mails` |
| MailDetail | `GET /api/mails/:id`;`POST .../reparse`;`POST .../type` |
| Confirm | `POST /api/mails/:id/import` |
| Logs | `GET /api/imports`;`POST /api/imports/:id/retry` |
---
# 6. 文档索引
| 文档 | 路径 |
|---|---|
| 本设计 | `docx/产品UI-UX设计方案-邮件自动预报-v1.0.md` |
| PRD | `docx/需求规格-邮件自动预报-v0.2.md` |
| 技术设计 | `docx/技术设计方案-邮件自动预报-v1.0.md` |