feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本

包含多个会话的累积代码变更:
- backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔
- admin-web: ETL 状态页、任务管理、调度配置、登录优化
- miniprogram: 看板页面、聊天集成、UI 组件、导航更新
- etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强
- tenant-admin: 项目初始化
- db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8)
- packages/shared: 枚举和工具函数更新
- tools: 数据库工具、报表生成、健康检查
- docs: PRD/架构/部署/合约文档更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Neo
2026-04-06 00:03:48 +08:00
parent 70324d8542
commit 6f8f12314f
515 changed files with 76604 additions and 7456 deletions

View File

@@ -0,0 +1,137 @@
# P10-NS4-06表格组件的统一规范
## 简要结论
- 状态:⚠️ 部分解决
- tenant-admin 各页面表格在分页大小、loading 状态、筛选器位置上已形成事实一致的模式但缺少显式的统一配置抽象层排序交互完全缺失空数据展示未统一部分表格分页大小不一致20 vs 10
## 详细审查
### 前端代码
#### 1. 分页大小
| 页面/组件 | 默认 pageSize | showSizeChanger | showTotal | 后端分页 |
|-----------|:---:|:---:|:---:|:---:|
| UserApproval | 20 | ✅ | ✅ `共 N 条` | ✅ page/page_size |
| UserManagement | 20 | ✅ | ✅ `共 N 条` | ✅ page/page_size |
| ExcelUpload — 上传记录 | 20 | ✅ | ✅ `共 N 条` | ✅ page/page_size |
| ExcelUpload — 校验详情 | **10** | ❌ | ❌ | 前端分页 |
| RetentionClues — 客户搜索 | `false` | — | — | 无分页LIMIT 50 |
| RetentionClues — 线索列表 | **10** | ❌ | ❌ | 无分页(全量返回) |
| DiffTable — 冲突表 | `false` | — | — | 前端数据 |
结论:主列表页统一为 20 条/页 + showSizeChanger + showTotal但子表格校验详情、线索列表使用 10 条/页且缺少 showSizeChanger 和 showTotal**不一致**。
#### 2. 排序交互
所有 5 个表格组件均未配置 `sorter` 属性,前端不支持列排序。后端 SQL 统一使用 `ORDER BY created_at DESC`(固定倒序),无动态排序参数。
结论:**完全缺失**。用户无法按任意列排序。
#### 3. 筛选器位置
| 页面 | 筛选器位置 | 筛选方式 |
|------|-----------|---------|
| UserApproval | 表格上方独立区域 | Select状态筛选 |
| UserManagement | 表格上方独立区域 | Select角色+ Input.Search关键词 |
| ExcelUpload — 上传记录 | 无筛选 | — |
| RetentionClues | Card title 区域 + Card extra 区域 | Input.Search + SiteSelector上方Select×2Card extra 右侧) |
结论:筛选器统一放在表格上方(非表格内 column filter**位置一致**。但 RetentionClues 的线索筛选器放在 Card extra 右侧,与其他页面的左对齐布局略有差异。
#### 4. loading 状态
所有带后端请求的表格均通过 `loading={loading}` 传入 Ant Design Table 的 loading 属性,**统一且正确**。
#### 5. 空数据展示
| 页面 | 空数据处理 |
|------|-----------|
| UserApproval | Ant Design Table 默认空状态(无自定义) |
| UserManagement | Ant Design Table 默认空状态(无自定义) |
| ExcelUpload | Ant Design Table 默认空状态(无自定义) |
| RetentionClues — 客户搜索 | `<Empty description="未找到匹配客户" />` ✅ 自定义 |
| RetentionClues — 线索列表 | Ant Design Table 默认空状态(无自定义) |
| DiffTable | Ant Design Table 默认空状态(无自定义) |
结论:仅 RetentionClues 客户搜索有自定义空状态文案,其余均依赖 Ant Design 默认的英文 "No Data"。**未统一**,且未做中文化。
对比 admin-web`TaskManager` 页面使用了 `locale={{ emptyText: <Empty description="队列为空" /> }}` 自定义空状态tenant-admin 未跟进。
#### 6. 统一配置抽象
- tenant-admin 中**不存在**统一的表格配置文件、常量定义或封装组件
- 每个页面独立定义 `pageSize``pagination` 配置、`handleTableChange`
- 分页响应结构 `{ items, total, page, pageSize }` 在前后端已统一,但属于隐式约定
### 后端代码
#### 分页参数统一性
| 路由 | 参数名 | 默认值 | 范围约束 |
|------|--------|--------|---------|
| `GET /applications` | `page` + `page_size` | 1 / 20 | ge=1 / ge=1,le=100 |
| `GET /users` | `page` + `page_size` | 1 / 20 | ge=1 / ge=1,le=100 |
| `GET /excel/logs` | `page` + `page_size` | 1 / 20 | ge=1 / ge=1,le=100 |
| `GET /customers/search` | 无分页 | — | LIMIT 50 硬编码 |
| `GET /customers/{id}/clues` | 无分页 | — | 全量返回 |
结论:三个主列表接口的分页参数**完全统一**`page`/`page_size`,默认 20上限 100。客户搜索和线索列表不分页属于业务设计选择数据量可控但线索列表在数据量增长后可能需要补充分页。
响应格式统一为 `{ items: T[], total: int, page: int, pageSize: int }`**一致**。
### 差距分析
与 P10 标杆文件要求的差距:
| 规范项 | P10 要求(推断) | 当前状态 | 差距 |
|--------|-----------------|---------|------|
| 默认分页大小 | 统一值(如 20 | 主表 20子表 10 | 🟡 子表不一致 |
| showSizeChanger | 所有分页表格启用 | 仅主表启用 | 🟡 子表缺失 |
| showTotal | 所有分页表格显示 | 仅主表显示 | 🟡 子表缺失 |
| 排序交互 | 至少关键列支持排序 | 完全缺失 | 🔴 缺失 |
| 筛选器位置 | 统一在表格上方 | 基本一致 | ✅ |
| loading 状态 | 统一 loading 属性 | 全部已配置 | ✅ |
| 空数据展示 | 统一中文空状态 | 仅 1 处自定义,其余默认 | 🟡 未统一 |
| 统一配置抽象 | 提取公共 Table 配置 | 不存在 | 🔴 缺失 |
### 建议
1. **提取统一表格配置常量**(优先级:高)
`apps/tenant-admin/src/constants/table.ts` 中定义:
```ts
export const DEFAULT_PAGE_SIZE = 20;
export const PAGE_SIZE_OPTIONS = ['10', '20', '50'];
export const TABLE_LOCALE = {
emptyText: '暂无数据',
};
export const defaultPagination = (total: number, page: number, pageSize: number) => ({
current: page,
pageSize,
total,
showSizeChanger: true,
showTotal: (t: number) => `共 ${t} 条`,
pageSizeOptions: PAGE_SIZE_OPTIONS,
});
```
2. **统一空数据展示**(优先级:高)
通过 Ant Design ConfigProvider 全局设置中文 locale 和空状态:
```tsx
import zhCN from 'antd/locale/zh_CN';
<ConfigProvider locale={zhCN} renderEmpty={() => <Empty description="暂无数据" />}>
```
3. **子表格分页对齐**(优先级:中)
ExcelUpload 校验详情和 RetentionClues 线索列表的 pageSize 改为 20并补充 showSizeChanger 和 showTotal。
4. **排序交互**(优先级:低)
对时间列(申请时间、上传时间、记录时间)添加前端 `sorter` 支持。如数据量增长需后端排序,可在 API 中增加 `sort_by` + `sort_order` 参数。当前数据量下前端排序即可。
5. **线索列表补充分页**(优先级:低)
`GET /customers/{member_id}/clues` 当前全量返回,建议在数据量可能超过 50 条时补充后端分页。