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,65 @@
# P9→NS1/RNS1 缺失项 #1客户详情页分段加载策略
## 简要结论
- 状态:⚠️ 部分解决
- 风险等级:🔴 高
- 后端采用单 API 返回全部数据(无分段端点),但各扩展模块有独立 try/except 优雅降级;前端无 skeleton 占位,仅有全局 loading toast。
## 详细审查
### 审查范围
- `apps/backend/app/routers/xcx_customers.py` — CUST-1 路由
- `apps/backend/app/services/customer_service.py``get_customer_detail()` 实现
- `apps/miniprogram/miniprogram/pages/customer-detail/customer-detail.ts` — 前端加载逻辑
- `apps/miniprogram/miniprogram/pages/customer-detail/customer-detail.wxml` — 前端模板
### 发现
1. **后端:单 API无分段端点**
- `GET /api/xcx/customers/{customer_id}` 一次性返回全部数据(基本信息 + Banner + AI 洞察 + 关联助教 + 最亲密助教 + 消费记录 + 备注)
- 无独立的 `/ai-insight``/notes``/records` 等子端点
- P9 定义的"基本信息→消费汇总→AI 洞察→消费记录→备注"分段加载策略未实现
2. **后端:优雅降级已实现**
- 各扩展模块(`ai_insight``retention_clues``notes``consumption_records``coach_tasks``favorite_coaches`)均有独立 try/except失败时降级为空默认值
- 核心字段member_info失败直接 500符合预期
3. **前端:无 skeleton 占位**
- 加载态为全局 `g-toast-loading`(圆形 loading + "加载中..."文字),非 P9 定义的分段 skeleton
- `loadDetail()` 调用单个 `fetchCustomerDetail(id)` 后一次性 setData
- 无分段渲染逻辑(先展示基本信息,再逐步加载扩展模块)
### 证据
后端 `get_customer_detail()` 一次性返回所有模块:
```python
return {
"id": customer_id, "name": name, "phone": phone, ...
"balance": balance, "consumption_60d": consumption_60d, ...
"ai_insight": ai_insight,
"coach_tasks": coach_tasks,
"favorite_coaches": favorite_coaches,
"retention_clues": retention_clues,
"consumption_records": consumption_records,
"notes": notes,
}
```
前端加载逻辑(无分段):
```typescript
async loadDetail(id?: string) {
this.setData({ pageState: 'loading' })
try {
if (id) {
const detail = await fetchCustomerDetail(id)
// 一次性 setData
}
this.setData({ pageState: 'normal' })
} catch { ... }
}
```
### 建议(如未完全解决)
1. **短期**:前端可在单 API 返回后,先渲染 Banner 区域,再用 `nextTick``setTimeout` 分批 setData 扩展模块,减少首屏白屏时间
2. **中期**:为各扩展模块添加 skeleton 占位组件(参考 TDesign `t-skeleton`
3. **长期**:后端拆分为多个子端点(`/basic``/ai-insight``/records` 等),前端并行请求 + 分段渲染