包含多个会话的累积代码变更: - 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>
66 lines
2.8 KiB
Markdown
66 lines
2.8 KiB
Markdown
# 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` 等),前端并行请求 + 分段渲染
|