# Image To Frontend Spec

## 1. 输入图片

| Image ID | Page ID | State | 图片路径 / 链接 | 评审结论 |
| --- | --- | --- | --- | --- |
| IMG-001 | ticket-list | default | `images/ticket-list-default.png` | PASS |
| IMG-002 | ticket-list | empty | `images/ticket-list-empty.png` | PASS |
| IMG-003 | ticket-list | loading | `images/ticket-list-loading.png` | PASS |
| IMG-004 | ticket-list | error | `images/ticket-list-error.png` | PASS |
| IMG-005 | ticket-list | permission_denied | `images/ticket-list-permission.png` | PASS |

## 2. 页面布局规格

| 区域 | 位置 | 尺寸 / 约束 | 内容 | 响应式行为 |
| --- | --- | --- | --- | --- |
| Header | 顶部 | 高度约 64px | 标题、说明、保存视图按钮 | mobile 保留标题，操作进菜单 |
| Filter Bar | Header 下方 | 横向排列 | 状态、优先级、负责人、搜索 | mobile 折叠为筛选抽屉 |
| Main Table | 主区域 | 宽度自适应 | 工单表格、状态标签、操作 | mobile 转卡片列表 |
| Pagination | 底部 | 右对齐 | 页码、每页数量 | mobile 简化为上一页/下一页 |

## 3. 组件实现映射

| 图片元素 | 前端组件 | 层级 | 复用来源 | Props / 数据 | 事件 | 状态 |
| --- | --- | --- | --- | --- | --- | --- |
| 筛选条 | `TicketFilterBar` | feature | existing business component | `TicketFilter` | `onChange`, `onReset` | default / dirty / mobile |
| 移动端筛选抽屉 | `TicketFilterDrawer` | feature | new business component | `TicketFilter`, `open` | `onApply`, `onClose` | mobile |
| 保存视图弹窗 | `SavedViewModal` | feature | new business component | `CreateTicketViewRequest` | `onSubmit`, `onCancel` | default / validation-error |
| 工单表格 | `TicketTable` | feature | table base component | `Ticket[]`, pagination | `onRetry` | default / empty / loading / error |
| 表格基础容器 | `DataTableShell` | primitive | new reusable component | rows, columns, pagination | generic callbacks | default / empty / loading |

## 4. CSS / Token 映射

| 图片表现 | Token / CSS 变量 | 值 | 备注 |
| --- | --- | --- | --- |
| 页面背景 | `--color-bg-subtle` | `#F6F7F9` | 来自 design tokens |
| 主面板 | `--color-bg-default` | `#FFFFFF` | |
| 高优先级强调 | `--color-status-warning` | `#B45309` | |
| 错误提示 | `--color-status-danger` | `#B91C1C` | |
| 面板圆角 | `--radius-md` | `8px` | |

## 5. 状态实现规格

| State | 数据条件 | UI 行为 | 组件变化 | 动效 | 测试 |
| --- | --- | --- | --- | --- | --- |
| default | `items.length > 0` | 展示表格和分页 | `TicketTable` default | rows fade in 160ms | story / e2e / visual |
| empty | `items.length === 0` | 展示空态和清除筛选 | `TicketTable` empty | opacity 160ms | story / e2e / visual |
| loading | 请求中 | 展示骨架屏并禁用保存 | `TicketTable` loading | skeleton, reduced motion disables shimmer | story / visual |
| error | 请求失败 | 展示错误和重试 | `TicketTable` error | opacity 160ms | story / e2e / visual |
| permission_denied | role=agent | 隐藏保存视图入口 | `TicketFilterBar` permission | none | e2e |
| mobile | viewport < 768px | 筛选进入抽屉，表格转卡片 | `TicketFilterDrawer`, `TicketCardList` | drawer 180ms | story / e2e / visual |

## 6. 响应式与动效规格

| Viewport | 布局 | 筛选策略 | 表格 / 列表策略 | 操作区策略 | 截图要求 |
| --- | --- | --- | --- | --- | --- |
| Desktop 1440x900 | Header + inline filter + table | 横向筛选条和 chip 回显 | 完整表格 | 保存按钮在 header | required |
| Tablet 768x1024 | Header + wrapping filter + table | 筛选条换行，次要筛选进菜单 | 隐藏低优先级列 | 操作进菜单 | optional |
| Mobile 375x812 | Header + filter drawer + cards | 筛选按钮打开抽屉 | 表格转卡片 | 保存视图进更多菜单 | required |

动效规则:

- 弹窗和抽屉必须支持 reduced motion。
- 表格刷新不得造成分页、表头和筛选区位移。
- 筛选 chip 删除按钮必须可键盘访问。

## 7. 架构输入

- 前端质量规则: `docs/harness/frontend-quality-rules.md`
- 前端架构: `docs/design/frontend-architecture.md`
- 通用能力候选: `DataTableShell`
- 业务内保留: `TicketFilterBar`, `TicketFilterDrawer`, `SavedViewModal`, `TicketTable`
