Add design spec for row highlight and column-header filters
- Row highlight: hover + click-to-pin via onRow/rowClassName, persists across horizontal scroll and filtering (keyed by rowKey=ID) - Column filters: antd controlled filterDropdown per column, type auto-inferred (date/category/text), multi-column AND; which columns are filterable is chosen by the user in the existing column-settings modal and persisted to localStorage - New module src/app/table-filters.tsx for FilterDropdown + type inference - 'Clear filters' button in the search bar - Long-content display explicitly deferred to a later iteration Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
# 行高亮 与 表头列筛选 — 设计文档
|
||||
|
||||
- 日期:2026-06-18
|
||||
- 状态:已确认,待编写实现计划
|
||||
- 适用项目:`web-table`(生产数据查询工具,Next.js 16 + React 19 + Ant Design v6)
|
||||
|
||||
## 背景与上下文
|
||||
|
||||
生产部使用「压力表合同生产数据」查询页(`src/app/page.tsx`)。数据按车间号模糊查询后一次性加载到客户端,表格约 57 列、很宽、横向滚动。现有功能:列显示/隐藏 + 拖拽排序(持久化)、模糊搜索、搜索历史、Excel 导出全部、展开行查看 5 个长文本字段。
|
||||
|
||||
本次按生产部需求新增两项功能;**「长内容完整显示」本次不做,留待后续单独开发**。
|
||||
|
||||
### 现状关键事实(实现依据)
|
||||
- 表格为 antd `<Table>`,`rowKey="ID"`,每列 `ellipsis: true`,`sticky` 表头,`scroll={{ x: 总宽, y: calc(100vh-140px) }}`。
|
||||
- 数据接口 `GET /api/production-data?workshopNo=...` 返回 `{ columns, data, total }`;**日期字段已被序列化为 `YYYY-MM-DD` 字符串**。
|
||||
- `ColumnConfig`(可见性 + 顺序)持久化在 `localStorage` 的 `web-table-column-config`。
|
||||
- 「导出全部」走独立服务端接口 `GET /api/export-excel`,导出全量、与前端无关。
|
||||
|
||||
## 目标
|
||||
|
||||
1. **行高亮**:横向滚动时不会看错行。悬停轻高亮跟随鼠标;点击锁定更醒目高亮、滚动时保持,再点切换/取消。
|
||||
2. **表头列筛选**:在列标题挂筛选下拉,支持分类勾选、文本搜索、日期范围,多列 AND 组合。哪些列可筛选由用户在「列设置」里自行勾选。
|
||||
|
||||
## 非目标(本次不做)
|
||||
- 长内容完整显示(换行/弹窗/tooltip/列宽自适应)。
|
||||
- 服务端筛选/分页(本次纯客户端,作用于已加载数据)。
|
||||
- 导出当前筛选结果(导出仍为全量)。
|
||||
- 筛选条件持久化(刷新即清;仅持久化"哪些列可筛选"这一配置)。
|
||||
|
||||
## 设计总览
|
||||
|
||||
两项功能均为 antd 原生能力 + 少量托管状态,纯前端,不新增接口、不改数据层。
|
||||
|
||||
- 行高亮:`onRow`(点击切换锁定)+ `rowClassName`(锁定行加 class)+ 一段 CSS。
|
||||
- 列筛选:antd 受控筛选(`filterDropdown` / `onFilter` / `filteredValue` / Table `onChange`),列的"可筛选"开关并入现有「列设置」弹窗。
|
||||
|
||||
---
|
||||
|
||||
## 功能一:行高亮(悬停 + 点击锁定)
|
||||
|
||||
### 交互
|
||||
- 悬停:复用 antd 默认 hover 行高亮(用 CSS 略加深,与锁定色区分)。
|
||||
- 点击行:锁定该行为高亮;点击当前已锁定行 → 取消;点击其他行 → 切换到该行。任意时刻至多一行被锁定。
|
||||
- 横向滚动:锁定行整行(固定列 + 滚动列)保持高亮。
|
||||
- 与筛选/排序/列隐藏均独立:锁定基于 `rowKey`,class 施加于整行所有片段。
|
||||
|
||||
### 实现
|
||||
- 状态:`const [lockedRowKey, setLockedRowKey] = useState<string | null>(null);`
|
||||
- `<Table onRow={(record) => ({ onClick: () => setLockedRowKey(prev => prev === record.ID ? null : String(record.ID)) })} />`
|
||||
- `rowClassName={(record) => String(record.ID) === lockedRowKey ? "row-locked" : ""}`
|
||||
- CSS(全局,建议放 `src/app/globals.css` 或等价处):
|
||||
```css
|
||||
.row-locked > td { background: #fff7e6 !important; } /* 锁定:橙底 */
|
||||
/* antd 默认 hover 已存在;如需加深可加:.ant-table-tbody > tr:hover > td { background:#fafafa; } */
|
||||
```
|
||||
> 实现时核对 antd v6 实际 DOM 结构(固定列与滚动列的 `<tr>`/`<td>` 层级),确保 `.row-locked` 选择器对左右片段都生效;必要时调整为作用于 row 容器的 class。
|
||||
|
||||
---
|
||||
|
||||
## 功能二:表头列筛选(用户勾选可筛选列)
|
||||
|
||||
### 配置扩展
|
||||
`ColumnConfig` 增加字段:
|
||||
```ts
|
||||
interface ColumnConfig {
|
||||
key: string;
|
||||
visible: boolean;
|
||||
filterable: boolean; // 新增,默认 false
|
||||
}
|
||||
```
|
||||
- 随现有 `web-table-column-config` 一起持久化。
|
||||
- 向前兼容:读取旧配置时缺 `filterable` 字段按 `false` 处理(`loadConfig` 兼容)。
|
||||
|
||||
### 「列设置」弹窗改动
|
||||
现有每行结构:`拖拽手柄 | 可见 Checkbox | 字段名`。新增**漏斗开关**表示「可筛选」:
|
||||
- UI:在可见 Checkbox 旁加一个漏斗图标按钮(`FilterOutlined`),点击切换 `filterable`。
|
||||
- 与可见性、拖拽排序并列,共用同一份 `local` 配置,「确定」时一次性 apply。
|
||||
- 弹窗底部统计文案同步:「确定 (可见 X/总数)」可扩展为同时提示可筛选数量(可选)。
|
||||
|
||||
### 列构建(`buildTableColumns`)
|
||||
对 `filterable && visible` 的列,挂上筛选相关属性;类型自动推断:
|
||||
|
||||
```ts
|
||||
type FilterType = "date" | "category" | "text";
|
||||
function inferFilterType(key: string, data: DataRow[]): FilterType { ... }
|
||||
```
|
||||
|
||||
推断规则:
|
||||
- **date**:非空值全部匹配 `/^\d{4}-\d{2}-\d{2}$/`。
|
||||
- **category**:去重后非空值数量 ≤ 50(阈值常量 `CATEGORY_THRESHOLD = 50`,可调)。
|
||||
- **text**:其余。
|
||||
|
||||
每列附带:
|
||||
- `filterDropdown`: 根据 `FilterType` 渲染
|
||||
- date → `DatePicker.RangePicker`(含「确定/重置」)。
|
||||
- category → 带搜索框的勾选列表(distinct 值,`useMemo` 计算)。
|
||||
- text → 单行搜索输入框(子串匹配,不区分大小写)。
|
||||
- `onFilter(value, record)`:按类型判断命中。
|
||||
- `filteredValue`: 受控值(见下)。
|
||||
|
||||
> `FilterDropdown` 组件、`inferFilterType`、distinct 计算等统一放入 **`src/app/table-filters.tsx`**(已确认拆分)。
|
||||
|
||||
### 筛选状态管理(受控)
|
||||
- `const [filters, setFilters] = useState<Record<string, React.Key[]>>({});`
|
||||
- 每个可筛选列:`filteredValue={filters[key] ?? null}`。
|
||||
- `<Table onChange={(_pag, tableFilters) => setFilters(tableFilters as Record<string, React.Key[]>)} />`
|
||||
- 多列 = AND(antd 默认组合)。
|
||||
- distinct 列表与类型推断用 `useMemo` 依赖 `data`。
|
||||
|
||||
### 清除筛选
|
||||
- 搜索栏(`SearchBar`)旁新增 **「清除筛选」按钮**(`FilterOutlined` 或 `ClearOutlined`),`disabled` 于无任何活跃筛选时。
|
||||
- 点击:`setFilters({})`,并对每列传 `filteredValue={null}`(空对象即清空,antd 会复位各下拉)。
|
||||
- 同时在搜索栏显示「已筛选 X/共 Y 条」之类的提示(可选增强)。
|
||||
|
||||
---
|
||||
|
||||
## 边界与交互
|
||||
|
||||
- 可筛选列被隐藏:antd 仅对可见列应用筛选,自动忽略;重新显示后筛选值仍在。
|
||||
- 锁定行被筛选掉:该行不显示高亮,但 `lockedRowKey` 保留;清除筛选后该行重现并高亮。
|
||||
- 筛选只作用于已加载的客户端数据,**不发新请求**。
|
||||
- 「导出全部」始终导出全量,与前端筛选/高亮无关(保持现状)。
|
||||
- 重新查询(换车间号)或「清除」:重置 `filters`、`lockedRowKey`(新数据集,旧锁定无意义)。
|
||||
- 性能:客户端筛选,适合预期数据量(数百~数千行)。
|
||||
|
||||
## 文件结构
|
||||
- `src/app/table-filters.tsx`(新增):`FilterDropdown` 组件、`inferFilterType`、distinct 工具、阈值常量。
|
||||
- `src/app/page.tsx`(改动):扩展 `ColumnConfig`;`Home` 增 `lockedRowKey`、`filters` 状态与 `onChange`;`buildTableColumns` 接筛选属性;`SearchBar` 增「清除筛选」按钮;列设置弹窗加漏斗开关。
|
||||
- 全局 CSS:`.row-locked` 规则。
|
||||
|
||||
## 验证(手动)
|
||||
1. 查询后点行 → 整行橙底高亮且横向滚动保持;再点该行 → 取消;点其他行 → 切换。
|
||||
2. 列设置勾选若干可筛选列 → 对应表头出现漏斗 → 分类勾选 / 文本搜索 / 日期范围分别生效,且多列 AND 组合;点「清除筛选」复位。
|
||||
3. 锁定某行 → 用筛选将其筛掉 → 高亮消失 → 清筛选 → 该行重新高亮。
|
||||
4. 重新查询或点「清除」→ 筛选与锁定均重置。
|
||||
5. 刷新页面 → 可筛选列配置仍在;活跃筛选值已清空。
|
||||
|
||||
## 实现注意事项
|
||||
- 项目为 **antd v6 + Next.js 16**,与训练数据可能不同。写代码前核对 `node_modules/antd`(`filterDropdown` 受控用法、`onRow`/`rowClassName`、`Table` `onChange` 签名、固定列 DOM 结构)与 `node_modules/next/dist/docs/`(按 `AGENTS.md` 要求),heed 弃用提示。
|
||||
Reference in New Issue
Block a user