feat(admin): Implement operational monitoring MVP and login optimization
Summary: - Add SimpleLog table for activity tracking (admin_schema) - Implement ActivityService with fire-and-forget pattern - Add stats API endpoints (overview/live-feed/user-overview/cleanup) - Complete activity logging for 7 modules (SYSTEM/AIA/PKB/ASL/DC/RVW/IIT) - Update Admin Dashboard with DAU/DAT metrics and live feed - Fix user module permission display logic - Fix login redirect to /ai-qa instead of homepage - Replace top navigation LOGO with brand image - Fix PKB workspace layout CSS conflict (rename to .pa-chat-container) New files: - backend/src/common/services/activity.service.ts - backend/src/modules/admin/controllers/statsController.ts - backend/src/modules/admin/routes/statsRoutes.ts - frontend-v2/src/modules/admin/api/statsApi.ts - docs/03-.../04-operational-monitoring-mvp-plan.md - docs/03-.../04-operational-monitoring-mvp-implementation.md Tested: All features verified locally
This commit is contained in:
@@ -58,7 +58,7 @@
|
||||
| **SSA** | 智能统计分析 | 队列/预测模型/RCT分析 | ⭐⭐⭐⭐⭐ | 📋 规划中 | P2 |
|
||||
| **ST** | 统计分析工具 | 100+轻量化统计工具 | ⭐⭐⭐⭐ | 📋 规划中 | P2 |
|
||||
| **RVW** | 稿件审查系统 | 方法学评估、审稿流程、Word导出 | ⭐⭐⭐⭐ | ✅ **开发完成(95%)** | P3 |
|
||||
| **ADMIN** | 运营管理端 | Prompt管理、租户管理、用户管理 | ⭐⭐⭐⭐⭐ | 🎉 **Phase 4.1完成(75%)** - 用户管理+模块权限系统 | **P0** |
|
||||
| **ADMIN** | 运营管理端 | Prompt管理、租户管理、用户管理、运营监控 | ⭐⭐⭐⭐⭐ | 🎉 **Phase 4.2完成(80%)** - 运营监控MVP+登录优化 | **P0** |
|
||||
|
||||
---
|
||||
|
||||
@@ -170,6 +170,73 @@
|
||||
|
||||
---
|
||||
|
||||
### 🆕 运营监控系统 MVP 完成(2026-01-25)
|
||||
|
||||
#### ✅ 全模块埋点 + 运营看板
|
||||
|
||||
**功能完成**:
|
||||
- 🎉 **数据采集**:7个业务模块埋点全部完成
|
||||
- 🎉 **运营看板**:DAU/DAT/模块统计/实时活动流
|
||||
- 🎉 **用户画像**:360度用户资产统计(知识库、审查任务等)
|
||||
|
||||
**埋点模块覆盖**:
|
||||
|
||||
| 模块 | 埋点功能 | 状态 |
|
||||
|------|---------|------|
|
||||
| SYSTEM | 用户登录 | ✅ |
|
||||
| AIA | 智能体对话完成 | ✅ |
|
||||
| PKB | 知识库创建/删除、RAG检索 | ✅ |
|
||||
| ASL | 文献筛选完成 | ✅ |
|
||||
| DC | Tool B提取、Tool C代码处理 | ✅ |
|
||||
| RVW | 稿件审查完成 | ✅ |
|
||||
| IIT | REDCap数据同步 | ✅ |
|
||||
|
||||
**技术实现**:
|
||||
- ActivityService:火烧即忘模式,带 try-catch 保护
|
||||
- SimpleLog 表:admin_schema,5个索引优化查询
|
||||
- Stats API:overview/live-feed/user-overview/cleanup
|
||||
|
||||
**相关文档**:
|
||||
- 开发计划:`docs/03-业务模块/ADMIN-运营管理端/04-开发计划/03-运营监控系统MVP开发计划.md`
|
||||
- 实施记录:`docs/03-业务模块/ADMIN-运营管理端/04-开发计划/04-运营监控系统MVP实施记录.md`
|
||||
|
||||
---
|
||||
|
||||
### 🆕 登录体验优化(2026-01-25)
|
||||
|
||||
#### ✅ 默认跳转 AI 问答 + 模块权限修复
|
||||
|
||||
**优化内容**:
|
||||
- ✅ 用户登录后默认进入 `/ai-qa`(AI问答模块)而非首页
|
||||
- ✅ 修复用户模块权限显示逻辑(有自定义配置时正确显示)
|
||||
- ✅ SUPER_ADMIN 用户返回完整模块权限列表
|
||||
- ✅ 顶部导航 LOGO 更换为品牌图标(52px高度)
|
||||
- ✅ LoginPage 路径映射与 moduleRegistry.ts 保持一致
|
||||
|
||||
**修复文件**:
|
||||
- `backend/src/modules/admin/services/userService.ts` - 模块权限显示逻辑
|
||||
- `backend/src/common/auth/auth.service.ts` - getUserModules SUPER_ADMIN处理
|
||||
- `frontend-v2/src/pages/LoginPage.tsx` - 路径映射修正
|
||||
- `frontend-v2/src/framework/layout/TopNavigation.tsx` - LOGO更换
|
||||
|
||||
---
|
||||
|
||||
### 🆕 PKB 布局修复(2026-01-25)
|
||||
|
||||
#### ✅ 解决 CSS 类名冲突
|
||||
|
||||
**问题**:PKB 工作区问答页面只显示部分内容
|
||||
|
||||
**原因**:Protocol Agent 的 `.chat-container` 样式覆盖了共享组件的同名样式
|
||||
|
||||
**解决**:将 Protocol Agent 模块的 CSS 类名重命名为 `.pa-chat-container`
|
||||
|
||||
**修复文件**:
|
||||
- `frontend-v2/src/modules/aia/protocol-agent/components/ChatArea.tsx`
|
||||
- `frontend-v2/src/modules/aia/protocol-agent/styles/protocol-agent.css`
|
||||
|
||||
---
|
||||
|
||||
### 🆕 OSS 存储集成完成(2026-01-22)
|
||||
|
||||
#### ✅ 阿里云 OSS 正式接入平台基础层
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# ADMIN-运营管理端 - 模块当前状态与开发指南
|
||||
|
||||
> **最后更新:** 2026-01-16
|
||||
> **状态:** ✅ Phase 4.1 用户管理已完成!模块权限系统架构升级完成!
|
||||
> **版本:** v0.5 (Alpha)
|
||||
> **最后更新:** 2026-01-25
|
||||
> **状态:** ✅ Phase 4.2 运营监控系统MVP完成!登录跳转逻辑优化完成!
|
||||
> **版本:** v0.6 (Alpha)
|
||||
|
||||
---
|
||||
|
||||
@@ -87,6 +87,32 @@
|
||||
- [x] 前端:移除旧的 requiredVersion 系统
|
||||
- [x] 体验优化:登录跳转智能判断(避免普通用户跳转到管理端403)
|
||||
|
||||
**Phase 4.2:运营监控系统** ✅ 已完成(2026-01-25)🎉
|
||||
- [x] 数据库:新增 SimpleLog 运营日志表(admin_schema)
|
||||
- [x] 后端服务:ActivityService 火烧即忘埋点服务(带 try-catch 保护)
|
||||
- [x] 后端API:statsRoutes 统计接口(overview/live-feed/user-overview/cleanup)
|
||||
- [x] 模块埋点:7个模块埋点全部完成
|
||||
- SYSTEM(登录)
|
||||
- AIA(智能体对话)
|
||||
- PKB(知识库管理、RAG检索)
|
||||
- ASL(文献筛选)
|
||||
- DC(Tool B提取、Tool C代码处理)
|
||||
- RVW(稿件审查)
|
||||
- IIT(REDCap同步)
|
||||
- [x] 前端看板:Admin Dashboard 运营数据展示(DAU/DAT/模块统计/实时活动流)
|
||||
- [x] 权限控制:stats:view 权限检查
|
||||
|
||||
**Phase 4.3:登录体验优化** ✅ 已完成(2026-01-25)
|
||||
- [x] 修复:用户模块权限显示问题(userService.ts 逻辑修正)
|
||||
- [x] 修复:登录后默认进入AI问答页面(/ai-qa)而非首页
|
||||
- [x] 优化:顶部导航 LOGO 更换为品牌图标
|
||||
- [x] 修复:SUPER_ADMIN 用户模块权限返回完整列表
|
||||
- [x] 修复:LoginPage 路径映射与 moduleRegistry 一致
|
||||
|
||||
**Phase 4.4:PKB 布局修复** ✅ 已完成(2026-01-25)
|
||||
- [x] 修复:PKB 工作区问答页面布局问题(CSS类名冲突)
|
||||
- [x] 修复:Protocol Agent 模块 CSS 类名重命名(.pa-chat-container)
|
||||
|
||||
### ⏳ 待开发(按优先级)
|
||||
|
||||
**P2 - 用户管理增强(可选)**
|
||||
@@ -138,8 +164,9 @@ public.AdminLog -- 旧的审计日志
|
||||
- ✅ `prompt_templates` - Prompt模板
|
||||
- ✅ `prompt_versions` - Prompt版本
|
||||
|
||||
**admin_schema(运营管理)**
|
||||
- `admin_operation_logs` - 运营操作日志
|
||||
**admin_schema(运营管理)** ✅ 新增 2026-01-25
|
||||
- ✅ `simple_logs` - 极简运营日志表(MVP)🆕
|
||||
- `admin_operation_logs` - 运营操作日志(未来)
|
||||
|
||||
---
|
||||
|
||||
|
||||
BIN
docs/03-业务模块/ADMIN-运营管理端/03-UI设计/LOGO.jpg
Normal file
BIN
docs/03-业务模块/ADMIN-运营管理端/03-UI设计/LOGO.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 167 KiB |
735
docs/03-业务模块/ADMIN-运营管理端/04-开发计划/03-运营监控系统MVP开发计划.md
Normal file
735
docs/03-业务模块/ADMIN-运营管理端/04-开发计划/03-运营监控系统MVP开发计划.md
Normal file
@@ -0,0 +1,735 @@
|
||||
# 运营监控系统 MVP 开发计划
|
||||
|
||||
> **文档版本**:V3.1 (完整版)
|
||||
> **创建日期**:2026-01-25
|
||||
> **基于文档**:运营体系设计方案-MVP-V3.0.md
|
||||
> **预计工时**:4-5 小时
|
||||
|
||||
---
|
||||
|
||||
## 📋 修订说明
|
||||
|
||||
本计划基于 V3.0 方案进行审查修订,主要解决以下 **8 个问题**:
|
||||
|
||||
| # | 问题 | 严重程度 | 修订内容 |
|
||||
|---|------|---------|---------|
|
||||
| 1 | 模块覆盖不完整 | 🔴 严重 | 补充 RVW、IIT、Protocol Agent、SSA/ST 预留 |
|
||||
| 2 | 缺少 tenantName 字段 | 🔴 严重 | 添加冗余字段避免 JOIN |
|
||||
| 3 | RVW 埋点清单缺失 | 🔴 严重 | 新增 RVW 模块埋点清单 |
|
||||
| 4 | 用户360画像缺少 RVW | 🔴 严重 | 补充 RVW 资产统计 |
|
||||
| 5 | action 类型不够全面 | 🟡 中等 | 扩展 CREATE/DELETE 类型 |
|
||||
| 6 | 缺少 API 路由设计 | 🟡 中等 | 新增完整 API 端点设计 |
|
||||
| 7 | 数据保留策略缺失 | 🟡 中等 | 补充 180 天数据清理 |
|
||||
| 8 | 权限控制未说明 | 🟡 中等 | 明确角色权限矩阵 |
|
||||
|
||||
---
|
||||
|
||||
## 1. 核心指标定义(保持 V3.0)
|
||||
|
||||
| 优先级 | 指标名称 | 定义 | 价值 |
|
||||
|--------|---------|------|-----|
|
||||
| **P0+** | 活跃医生数 (DAU) | 今日有行为的去重 user_id 数 | 真实价值线 |
|
||||
| **P0** | 活跃租户数 (DAT) | 今日有行为的去重 tenant_id 数 | 商务生死线 |
|
||||
| **P1** | 功能渗透率 | 各模块/功能使用次数分布 | 产品迭代指引 |
|
||||
| **P2** | 价值交付次数 | 导出/下载次数 | 北极星指标 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 数据库设计(V3.1 修订版)
|
||||
|
||||
### 2.1 SimpleLog 表(admin_schema)
|
||||
|
||||
```prisma
|
||||
/// 运营日志表 (MVP V3.1)
|
||||
model SimpleLog {
|
||||
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
// === 租户和用户信息 ===
|
||||
tenantId String @map("tenant_id") @db.VarChar(50)
|
||||
tenantName String? @map("tenant_name") @db.VarChar(100) // 🆕 冗余字段,避免JOIN
|
||||
userId String @map("user_id") @db.Uuid
|
||||
userName String? @map("user_name") @db.VarChar(50)
|
||||
|
||||
// === 行为记录 ===
|
||||
module String @db.VarChar(20) // 模块代码
|
||||
feature String @db.VarChar(50) // 细分功能
|
||||
action String @db.VarChar(20) // 动作类型
|
||||
|
||||
// === 详情信息 ===
|
||||
info String? @db.Text // JSON或文本详情
|
||||
|
||||
// === 索引 ===
|
||||
@@index([createdAt])
|
||||
@@index([tenantId])
|
||||
@@index([userId])
|
||||
@@index([module, feature])
|
||||
@@index([action]) // 🆕 支持按动作筛选
|
||||
@@map("simple_logs")
|
||||
@@schema("admin_schema")
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 字段说明
|
||||
|
||||
#### module(模块代码)- 完整列表
|
||||
|
||||
```typescript
|
||||
type ModuleCode =
|
||||
| 'AIA' // AI智能问答 (12智能体 + Protocol Agent)
|
||||
| 'PKB' // 个人知识库
|
||||
| 'ASL' // AI智能文献
|
||||
| 'DC' // 数据清洗整理
|
||||
| 'RVW' // 稿件审查系统 🆕
|
||||
| 'IIT' // IIT Manager Agent 🆕
|
||||
| 'SSA' // 智能统计分析 (预留) 🆕
|
||||
| 'ST' // 统计分析工具 (预留) 🆕
|
||||
| 'SYSTEM'; // 系统级行为 (登录/登出)
|
||||
```
|
||||
|
||||
#### action(动作类型)
|
||||
|
||||
```typescript
|
||||
type ActionType =
|
||||
| 'LOGIN' // 登录系统
|
||||
| 'USE' // 使用功能
|
||||
| 'EXPORT' // 导出/下载
|
||||
| 'CREATE' // 创建资源 🆕
|
||||
| 'DELETE' // 删除资源 🆕
|
||||
| 'ERROR'; // 错误记录
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 完整埋点清单(按模块)
|
||||
|
||||
### 3.1 🤖 AIA 模块(AI智能问答)
|
||||
|
||||
#### 12 个智能体
|
||||
|
||||
| agentId | feature (中文) | 埋点位置 |
|
||||
|---------|---------------|---------|
|
||||
| topic-scoping | 科学问题梳理 | conversationService.complete() |
|
||||
| pico-analysis | PICO梳理 | conversationService.complete() |
|
||||
| topic-eval | 选题评价 | conversationService.complete() |
|
||||
| outcome-design | 观察指标设计 | conversationService.complete() |
|
||||
| crf-design | CRF设计 | conversationService.complete() |
|
||||
| sample-size | 样本量计算 | conversationService.complete() |
|
||||
| protocol-writing | 方案撰写 | conversationService.complete() |
|
||||
| methodology-review | 方法学评审 | conversationService.complete() |
|
||||
| paper-polish | 论文润色 | conversationService.complete() |
|
||||
| paper-translate | 论文翻译 | conversationService.complete() |
|
||||
| data-preprocess | 数据预处理 | 跳转DC,记录来源 |
|
||||
| stat-analysis | 统计分析 | 跳转DC,记录来源 |
|
||||
|
||||
#### Protocol Agent(🆕 2026-01-25 新功能)
|
||||
|
||||
| feature | action | 埋点位置 | info 示例 |
|
||||
|---------|--------|---------|----------|
|
||||
| Protocol要素收集 | USE | ProtocolOrchestrator.collectPhase() | "阶段1完成" |
|
||||
| Protocol方案生成 | USE | ProtocolOrchestrator.generateProtocol() | "生成12章节方案" |
|
||||
| Protocol Word导出 | EXPORT | ProtocolAgentController.exportWord() | "导出Word文档" |
|
||||
|
||||
**埋点代码位置**:
|
||||
- `backend/src/modules/agent/protocol/services/ProtocolOrchestrator.ts`
|
||||
- `backend/src/modules/agent/protocol/controllers/ProtocolAgentController.ts`
|
||||
|
||||
---
|
||||
|
||||
### 3.2 📚 PKB 模块(个人知识库)
|
||||
|
||||
| feature | action | 埋点位置 | info 示例 |
|
||||
|---------|--------|---------|----------|
|
||||
| 知识库创建 | CREATE | knowledgeBaseController.create() | "创建: 肺癌研究库" |
|
||||
| 文档上传 | USE | documentController.upload() | "上传: 5篇PDF" |
|
||||
| RAG问答 | USE | ragController.chat() | "提问: 入排标准是什么?" |
|
||||
| 批处理提取 | USE | batchController.process() | "批量提取: 10篇" |
|
||||
| 结果导出 | EXPORT | batchController.export() | "导出CSV" |
|
||||
|
||||
**埋点代码位置**:
|
||||
- `backend/src/modules/pkb/controllers/`
|
||||
|
||||
---
|
||||
|
||||
### 3.3 📖 ASL 模块(AI智能文献)
|
||||
|
||||
| feature | action | 埋点位置 | info 示例 |
|
||||
|---------|--------|---------|----------|
|
||||
| DeepSearch检索 | USE | researchController.stream() | "关键词: 肺癌治疗" |
|
||||
| 标题摘要筛选 | USE | screeningController.start() | "筛选: 500篇" |
|
||||
| 全文复筛 | USE | fullTextController.start() | "复筛: 100篇" |
|
||||
| 筛选结果导出 | EXPORT | screeningController.export() | "导出Excel" |
|
||||
|
||||
**埋点代码位置**:
|
||||
- `backend/src/modules/asl/controllers/`
|
||||
|
||||
---
|
||||
|
||||
### 3.4 🧹 DC 模块(数据清洗整理)
|
||||
|
||||
| feature | action | 埋点位置 | info 示例 |
|
||||
|---------|--------|---------|----------|
|
||||
| Tool B 健康检查 | USE | toolBController.healthCheck() | "检查: 1000行数据" |
|
||||
| Tool B 自动提取 | USE | toolBController.extract() | "提取任务: 50条" |
|
||||
| Tool C 数据清洗 | USE | toolCController.process() | "执行: 筛选操作" |
|
||||
| Tool C Pivot | USE | toolCController.pivot() | "Pivot转换" |
|
||||
| 结果导出 | EXPORT | toolCController.export() | "导出Excel" |
|
||||
|
||||
**埋点代码位置**:
|
||||
- `backend/src/modules/dc/controllers/`
|
||||
|
||||
---
|
||||
|
||||
### 3.5 📝 RVW 模块(稿件审查系统)🆕
|
||||
|
||||
| feature | action | 埋点位置 | info 示例 |
|
||||
|---------|--------|---------|----------|
|
||||
| 稿件上传 | USE | reviewController.upload() | "上传: xxx.pdf" |
|
||||
| 稿约规范性审查 | USE | reviewWorker (editorial) | "审查开始" |
|
||||
| 方法学审查 | USE | reviewWorker (methodology) | "方法学审查开始" |
|
||||
| 审查完成 | USE | reviewWorker.complete() | "评分: 规范85/方法78" |
|
||||
| 报告导出 | EXPORT | TaskDetail.exportWord() | "导出Word报告" |
|
||||
|
||||
**埋点代码位置**:
|
||||
- `backend/src/modules/rvw/services/reviewWorker.ts`
|
||||
- `backend/src/modules/rvw/controllers/reviewController.ts`
|
||||
|
||||
---
|
||||
|
||||
### 3.6 🏥 IIT 模块(IIT Manager Agent)🆕
|
||||
|
||||
| feature | action | 埋点位置 | info 示例 |
|
||||
|---------|--------|---------|----------|
|
||||
| REDCap数据同步 | USE | redcapAdapter.sync() | "同步: 10条记录" |
|
||||
| AI质控检查 | USE | qualityCheckService.check() | "检查患者ID 7" |
|
||||
| 企微通知推送 | USE | wechatService.notify() | "推送预警通知" |
|
||||
| 对话查询 | USE | chatService.query() | "查询患者统计" |
|
||||
| 人工确权 | USE | actionController.approve() | "确权: 排除患者" |
|
||||
|
||||
**埋点代码位置**:
|
||||
- `backend/src/modules/iit-manager/services/`
|
||||
- `backend/src/modules/iit-manager/controllers/`
|
||||
|
||||
---
|
||||
|
||||
### 3.7 🔐 SYSTEM(系统级)
|
||||
|
||||
| feature | action | 埋点位置 | info 示例 |
|
||||
|---------|--------|---------|----------|
|
||||
| 用户登录 | LOGIN | authController.login() | "密码登录" |
|
||||
| 用户登出 | USE | authController.logout() | - |
|
||||
|
||||
**埋点代码位置**:
|
||||
- `backend/src/common/auth/auth.controller.ts`
|
||||
|
||||
---
|
||||
|
||||
## 4. 后端 API 设计
|
||||
|
||||
### 4.1 运营统计 API
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | `/api/admin/stats/overview` | 今日大盘(DAU/DAT/导出数) | SUPER_ADMIN |
|
||||
| GET | `/api/admin/stats/live-feed` | 实时流水账(最近100条) | SUPER_ADMIN |
|
||||
| GET | `/api/admin/stats/module/:code` | 模块使用统计 | SUPER_ADMIN |
|
||||
| GET | `/api/admin/users/:id/overview` | 用户360画像 | SUPER_ADMIN |
|
||||
|
||||
### 4.2 API 响应示例
|
||||
|
||||
#### 今日大盘 `/api/admin/stats/overview`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"dau": 12, // 今日活跃医生数
|
||||
"dat": 3, // 今日活跃租户数
|
||||
"exportCount": 5, // 今日导出次数
|
||||
"moduleStats": {
|
||||
"AIA": 45,
|
||||
"PKB": 23,
|
||||
"DC": 12,
|
||||
"RVW": 8,
|
||||
"ASL": 5,
|
||||
"IIT": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 实时流水账 `/api/admin/stats/live-feed`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"createdAt": "2026-01-25T10:05:00Z",
|
||||
"tenantName": "协和医院",
|
||||
"userName": "张主任",
|
||||
"module": "AIA",
|
||||
"feature": "选题评价",
|
||||
"action": "USE",
|
||||
"info": "评价得分: 85分"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 用户360画像 `/api/admin/users/:id/overview`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"profile": {
|
||||
"id": "uuid",
|
||||
"name": "张主任",
|
||||
"phone": "138****1234",
|
||||
"tenantName": "协和医院"
|
||||
},
|
||||
"assets": {
|
||||
"aia": { "conversationCount": 158 },
|
||||
"pkb": { "kbCount": 3, "docCount": 450 },
|
||||
"dc": { "taskCount": 12 },
|
||||
"rvw": { "reviewTaskCount": 25, "completedCount": 20 } // 🆕
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"createdAt": "2026-01-25T10:30:00Z",
|
||||
"module": "AIA",
|
||||
"feature": "选题评价",
|
||||
"action": "USE",
|
||||
"info": "生成结果: 85分"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 后端服务实现
|
||||
|
||||
### 5.1 ActivityService(埋点服务)
|
||||
|
||||
**文件路径**:`backend/src/common/services/activity.service.ts`
|
||||
|
||||
```typescript
|
||||
import { prisma } from '../../config/database.js';
|
||||
import { logger } from '../logging/index.js';
|
||||
|
||||
type ModuleCode = 'AIA' | 'PKB' | 'ASL' | 'DC' | 'RVW' | 'IIT' | 'SSA' | 'ST' | 'SYSTEM';
|
||||
type ActionType = 'LOGIN' | 'USE' | 'EXPORT' | 'CREATE' | 'DELETE' | 'ERROR';
|
||||
|
||||
export const activityService = {
|
||||
/**
|
||||
* 核心埋点方法 (Fire-and-Forget 模式)
|
||||
* 异步执行,不阻塞主业务
|
||||
*/
|
||||
log(
|
||||
tenantId: string,
|
||||
tenantName: string, // 🆕 新增
|
||||
userId: string,
|
||||
userName: string,
|
||||
module: ModuleCode,
|
||||
feature: string,
|
||||
action: ActionType,
|
||||
info?: any
|
||||
) {
|
||||
// 异步执行,不要 await
|
||||
prisma.simpleLog.create({
|
||||
data: {
|
||||
tenantId,
|
||||
tenantName, // 🆕
|
||||
userId,
|
||||
userName,
|
||||
module,
|
||||
feature,
|
||||
action,
|
||||
info: typeof info === 'object' ? JSON.stringify(info) : String(info || ''),
|
||||
}
|
||||
}).catch(e => {
|
||||
logger.warn('埋点写入失败(可忽略)', { error: e.message });
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取今日核心大盘数据
|
||||
*/
|
||||
async getTodayOverview() {
|
||||
const todayStart = new Date();
|
||||
todayStart.setHours(0, 0, 0, 0);
|
||||
|
||||
const stats = await prisma.$queryRaw`
|
||||
SELECT
|
||||
COUNT(DISTINCT user_id) as dau,
|
||||
COUNT(DISTINCT tenant_id) as dat,
|
||||
COUNT(CASE WHEN action = 'EXPORT' THEN 1 END) as export_count
|
||||
FROM admin_schema.simple_logs
|
||||
WHERE created_at >= ${todayStart}
|
||||
` as any[];
|
||||
|
||||
// 模块使用统计
|
||||
const moduleStats = await prisma.$queryRaw`
|
||||
SELECT module, COUNT(*) as count
|
||||
FROM admin_schema.simple_logs
|
||||
WHERE created_at >= ${todayStart}
|
||||
GROUP BY module
|
||||
` as any[];
|
||||
|
||||
const moduleMap: Record<string, number> = {};
|
||||
moduleStats.forEach((m: any) => {
|
||||
moduleMap[m.module] = Number(m.count);
|
||||
});
|
||||
|
||||
return {
|
||||
dau: Number(stats[0]?.dau || 0),
|
||||
dat: Number(stats[0]?.dat || 0),
|
||||
exportCount: Number(stats[0]?.export_count || 0),
|
||||
moduleStats: moduleMap,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取实时流水账
|
||||
*/
|
||||
async getLiveFeed(limit = 100) {
|
||||
return prisma.simpleLog.findMany({
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: limit,
|
||||
select: {
|
||||
id: true,
|
||||
createdAt: true,
|
||||
tenantName: true,
|
||||
userName: true,
|
||||
module: true,
|
||||
feature: true,
|
||||
action: true,
|
||||
info: true,
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取用户360画像
|
||||
*/
|
||||
async getUserOverview(userId: string) {
|
||||
const [user, aiaStats, kbs, dcStats, rvwStats, logs] = await Promise.all([
|
||||
// 基础信息
|
||||
prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
include: { tenants: true }
|
||||
}),
|
||||
|
||||
// AIA 资产 (会话数)
|
||||
prisma.conversation.count({
|
||||
where: { userId, deletedAt: null }
|
||||
}),
|
||||
|
||||
// PKB 资产 (知识库数 + 文档数)
|
||||
prisma.knowledgeBase.findMany({
|
||||
where: { userId, deletedAt: null },
|
||||
include: { _count: { select: { documents: true } } }
|
||||
}),
|
||||
|
||||
// DC 资产 (任务数)
|
||||
prisma.extractionTask.count({ where: { userId } }),
|
||||
|
||||
// RVW 资产 (审稿任务数) 🆕
|
||||
prisma.reviewTask.groupBy({
|
||||
by: ['status'],
|
||||
where: { userId },
|
||||
_count: true,
|
||||
}),
|
||||
|
||||
// 最近行为 (从 SimpleLog 查最近 20 条)
|
||||
prisma.simpleLog.findMany({
|
||||
where: { userId },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 20,
|
||||
select: {
|
||||
createdAt: true,
|
||||
module: true,
|
||||
feature: true,
|
||||
action: true,
|
||||
info: true,
|
||||
}
|
||||
})
|
||||
]);
|
||||
|
||||
const totalDocs = kbs.reduce((sum, kb) => sum + kb._count.documents, 0);
|
||||
|
||||
// 计算 RVW 统计
|
||||
const rvwTotal = rvwStats.reduce((sum, s) => sum + s._count, 0);
|
||||
const rvwCompleted = rvwStats.find(s => s.status === 'completed')?._count || 0;
|
||||
|
||||
return {
|
||||
profile: user ? {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
phone: user.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'),
|
||||
tenantName: user.tenants?.name,
|
||||
} : null,
|
||||
assets: {
|
||||
aia: { conversationCount: aiaStats },
|
||||
pkb: { kbCount: kbs.length, docCount: totalDocs },
|
||||
dc: { taskCount: dcStats },
|
||||
rvw: { reviewTaskCount: rvwTotal, completedCount: rvwCompleted }, // 🆕
|
||||
},
|
||||
activities: logs,
|
||||
};
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 5.2 StatsController(统计控制器)
|
||||
|
||||
**文件路径**:`backend/src/modules/admin/controllers/statsController.ts`
|
||||
|
||||
```typescript
|
||||
import type { FastifyRequest, FastifyReply } from 'fastify';
|
||||
import { activityService } from '../../../common/services/activity.service.js';
|
||||
|
||||
/**
|
||||
* 获取今日大盘
|
||||
* GET /api/admin/stats/overview
|
||||
*/
|
||||
export async function getOverview(request: FastifyRequest, reply: FastifyReply) {
|
||||
const data = await activityService.getTodayOverview();
|
||||
return reply.send({ success: true, data });
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实时流水账
|
||||
* GET /api/admin/stats/live-feed
|
||||
*/
|
||||
export async function getLiveFeed(
|
||||
request: FastifyRequest<{ Querystring: { limit?: number } }>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
const limit = request.query.limit || 100;
|
||||
const data = await activityService.getLiveFeed(limit);
|
||||
return reply.send({ success: true, data });
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户360画像
|
||||
* GET /api/admin/users/:id/overview
|
||||
*/
|
||||
export async function getUserOverview(
|
||||
request: FastifyRequest<{ Params: { id: string } }>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
const { id } = request.params;
|
||||
const data = await activityService.getUserOverview(id);
|
||||
return reply.send({ success: true, data });
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 前端页面设计
|
||||
|
||||
### 6.1 Admin 首页改造
|
||||
|
||||
**位置**:`frontend-v2/src/pages/admin/AdminDashboard.tsx`
|
||||
|
||||
#### 顶部卡片区域
|
||||
|
||||
```
|
||||
┌─────────────────┬─────────────────┬─────────────────┐
|
||||
│ 今日活跃医生 │ 今日活跃医院 │ 今日价值交付 │
|
||||
│ 12 👨⚕️ │ 3 🏥 │ 5 🟢 │
|
||||
│ (DAU) │ (DAT) │ (导出次数) │
|
||||
└─────────────────┴─────────────────┴─────────────────┘
|
||||
```
|
||||
|
||||
#### 实时流水账区域
|
||||
|
||||
```
|
||||
┌──────┬──────┬──────┬──────┬────────────┬──────┬────────────┐
|
||||
│ 时间 │ 医院 │ 医生 │ 模块 │ 具体功能 │ 动作 │ 详情 │
|
||||
├──────┼──────┼──────┼──────┼────────────┼──────┼────────────┤
|
||||
│10:05 │ 协和 │张主任│ AIA │ 选题评价 │🔵USE │评分: 85分 │
|
||||
│10:03 │ 协和 │张主任│ RVW │ 稿约规范 │🔵USE │审查开始 │
|
||||
│09:55 │ 华西 │李医生│ DC │ Tool C │🟢EXP │导出 Excel │
|
||||
└──────┴──────┴──────┴──────┴────────────┴──────┴────────────┘
|
||||
```
|
||||
|
||||
### 6.2 用户详情页增强
|
||||
|
||||
**位置**:`frontend-v2/src/modules/admin/pages/UserDetailPage.tsx`
|
||||
|
||||
#### 资产统计区域
|
||||
|
||||
```
|
||||
┌─────────────┬─────────────┬─────────────┬─────────────┬─────────────┐
|
||||
│ 💬 AIA对话 │ 📚 PKB知识库 │ 📄 上传文献 │ 🧹 DC清洗 │ 📝 RVW审稿 │
|
||||
│ 158 次 │ 3 个 │ 450 篇 │ 12 次 │ 25 篇 │
|
||||
└─────────────┴─────────────┴─────────────┴─────────────┴─────────────┘
|
||||
```
|
||||
|
||||
#### 行为时间轴
|
||||
|
||||
```
|
||||
• 10:30 [AIA] 使用了 "选题评价" (生成结果: 85分)
|
||||
• 10:15 [RVW] 完成了 "稿约规范性审查" (评分: 82分) 🆕
|
||||
• 09:50 [DC] 导出了 Tool C 清洗结果 (Excel)
|
||||
• 09:48 [SYSTEM] 登录系统
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 权限控制
|
||||
|
||||
### 7.1 角色权限矩阵
|
||||
|
||||
| 功能 | SUPER_ADMIN | PROMPT_ENGINEER | HOSPITAL_ADMIN |
|
||||
|------|-------------|-----------------|----------------|
|
||||
| 查看全局大盘 | ✅ | ✅(只读) | ❌ |
|
||||
| 查看实时流水 | ✅ | ✅(只读) | ❌ |
|
||||
| 查看用户画像 | ✅ | ❌ | 本租户用户 |
|
||||
| 数据导出 | ✅ | ❌ | ❌ |
|
||||
|
||||
### 7.2 数据隔离规则
|
||||
|
||||
- **SUPER_ADMIN**:可查看全部租户数据
|
||||
- **HOSPITAL_ADMIN**:只能查看本租户的用户活动
|
||||
- **普通用户**:无运营数据访问权限
|
||||
|
||||
---
|
||||
|
||||
## 8. 数据保留策略
|
||||
|
||||
### 8.1 清理规则
|
||||
|
||||
- 保留期限:**180 天**
|
||||
- 清理方式:pg-boss 定时任务,每日 03:00 执行
|
||||
- 清理脚本:
|
||||
|
||||
```sql
|
||||
-- 清理180天前的日志
|
||||
DELETE FROM admin_schema.simple_logs
|
||||
WHERE created_at < NOW() - INTERVAL '180 days';
|
||||
```
|
||||
|
||||
### 8.2 定时任务配置
|
||||
|
||||
**文件路径**:`backend/src/common/jobs/cleanupWorker.ts`
|
||||
|
||||
```typescript
|
||||
import { jobQueue } from './jobQueue.js';
|
||||
import { prisma } from '../../config/database.js';
|
||||
import { logger } from '../logging/index.js';
|
||||
|
||||
// 注册清理任务
|
||||
export async function registerCleanupJobs() {
|
||||
await jobQueue.schedule('cleanup-simple-logs', '0 3 * * *', async () => {
|
||||
const result = await prisma.$executeRaw`
|
||||
DELETE FROM admin_schema.simple_logs
|
||||
WHERE created_at < NOW() - INTERVAL '180 days'
|
||||
`;
|
||||
logger.info('运营日志清理完成', { deletedCount: result });
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 开发任务清单
|
||||
|
||||
### Phase 1: 数据库(15分钟)
|
||||
|
||||
- [ ] 更新 `prisma/schema.prisma`,添加 SimpleLog 模型
|
||||
- [ ] 执行 `npx prisma db push` 同步数据库
|
||||
- [ ] 验证表结构和索引
|
||||
|
||||
### Phase 2: 后端服务(60分钟)
|
||||
|
||||
- [ ] 创建 `common/services/activity.service.ts`
|
||||
- [ ] 创建 `modules/admin/controllers/statsController.ts`
|
||||
- [ ] 创建 `modules/admin/routes/statsRoutes.ts`
|
||||
- [ ] 在 `index.ts` 注册路由
|
||||
|
||||
### Phase 3: 埋点集成(90分钟)
|
||||
|
||||
#### 系统级
|
||||
- [ ] `auth.controller.ts` - 登录埋点
|
||||
|
||||
#### AIA 模块
|
||||
- [ ] `conversationService.ts` - 12个智能体埋点
|
||||
- [ ] `ProtocolOrchestrator.ts` - Protocol Agent 埋点
|
||||
|
||||
#### PKB 模块
|
||||
- [ ] `knowledgeBaseController.ts` - 知识库创建埋点
|
||||
- [ ] `documentController.ts` - 文档上传埋点
|
||||
- [ ] `ragController.ts` - RAG问答埋点
|
||||
|
||||
#### DC 模块
|
||||
- [ ] `toolBController.ts` - Tool B 埋点
|
||||
- [ ] `toolCController.ts` - Tool C 埋点
|
||||
|
||||
#### RVW 模块 🆕
|
||||
- [ ] `reviewController.ts` - 上传埋点
|
||||
- [ ] `reviewWorker.ts` - 审查完成埋点
|
||||
|
||||
#### IIT 模块 🆕
|
||||
- [ ] `chatService.ts` - 对话查询埋点
|
||||
- [ ] `redcapAdapter.ts` - 同步埋点
|
||||
|
||||
### Phase 4: 前端页面(90分钟)
|
||||
|
||||
- [ ] 改造 `AdminDashboard.tsx` - 添加大盘卡片和流水账
|
||||
- [ ] 改造 `UserDetailPage.tsx` - 添加资产统计和时间轴
|
||||
- [ ] 创建 `StatsCard.tsx` 组件
|
||||
- [ ] 创建 `LiveFeed.tsx` 组件
|
||||
- [ ] 创建 `ActivityTimeline.tsx` 组件
|
||||
|
||||
### Phase 5: 数据清理(15分钟)
|
||||
|
||||
- [ ] 创建 `cleanupWorker.ts`
|
||||
- [ ] 注册定时任务
|
||||
- [ ] 测试清理逻辑
|
||||
|
||||
---
|
||||
|
||||
## 10. 测试验证
|
||||
|
||||
### 10.1 单元测试
|
||||
|
||||
```bash
|
||||
# 埋点服务测试
|
||||
npm test -- --grep "ActivityService"
|
||||
|
||||
# API 测试
|
||||
npm test -- --grep "Stats API"
|
||||
```
|
||||
|
||||
### 10.2 端到端验证
|
||||
|
||||
1. 登录系统,检查是否记录 LOGIN
|
||||
2. 使用 AIA 智能体,检查是否记录 USE
|
||||
3. 导出文件,检查是否记录 EXPORT
|
||||
4. 访问 Admin 首页,验证大盘数据
|
||||
5. 访问用户详情,验证 360 画像
|
||||
|
||||
---
|
||||
|
||||
## 📊 总结
|
||||
|
||||
| 项目 | V3.0 原方案 | V3.1 修订版 |
|
||||
|------|------------|------------|
|
||||
| 模块覆盖 | 4 个 | **8 个** |
|
||||
| 字段设计 | 缺少 tenantName | ✅ 完整 |
|
||||
| API 设计 | 缺失 | ✅ 4 个端点 |
|
||||
| 数据保留 | 缺失 | ✅ 180 天 |
|
||||
| 权限控制 | 缺失 | ✅ 角色矩阵 |
|
||||
| 预计工时 | 3-4 小时 | **4-5 小时** |
|
||||
|
||||
---
|
||||
|
||||
**下一步**:按照任务清单执行开发,优先完成 Phase 1-2(基础设施),再逐步完成埋点集成和前端页面。
|
||||
|
||||
333
docs/03-业务模块/ADMIN-运营管理端/04-开发计划/04-运营监控系统MVP实施记录.md
Normal file
333
docs/03-业务模块/ADMIN-运营管理端/04-开发计划/04-运营监控系统MVP实施记录.md
Normal file
@@ -0,0 +1,333 @@
|
||||
# 运营监控系统 MVP 实施记录
|
||||
|
||||
> **文档版本**:V1.0
|
||||
> **实施日期**:2026-01-25
|
||||
> **基于文档**:03-运营监控系统MVP开发计划.md
|
||||
> **实施状态**:✅ **MVP 完成!**
|
||||
|
||||
---
|
||||
|
||||
## 📋 实施概要
|
||||
|
||||
### 完成状态
|
||||
|
||||
| 任务类型 | 计划 | 完成 | 完成率 |
|
||||
|---------|------|------|--------|
|
||||
| 数据库设计 | 1 | 1 | ✅ 100% |
|
||||
| 后端服务 | 3 | 3 | ✅ 100% |
|
||||
| 埋点集成 | 7模块 | 7模块 | ✅ 100% |
|
||||
| 前端看板 | 1 | 1 | ✅ 100% |
|
||||
| API测试 | 4端点 | 4端点 | ✅ 100% |
|
||||
|
||||
**总耗时**:约 6 小时(含调试和问题修复)
|
||||
|
||||
---
|
||||
|
||||
## 1. 数据库实施 ✅
|
||||
|
||||
### 1.1 SimpleLog 表创建
|
||||
|
||||
**Prisma Schema 位置**:`backend/prisma/schema.prisma`
|
||||
|
||||
```prisma
|
||||
/// 极简运营日志表 (MVP) - V3.1 修订版
|
||||
model SimpleLog {
|
||||
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
tenantId String @map("tenant_id") @db.VarChar(50)
|
||||
tenantName String? @map("tenant_name") @db.VarChar(100)
|
||||
userId String @map("user_id") @db.Uuid
|
||||
userName String? @map("user_name") @db.VarChar(50)
|
||||
|
||||
module String @db.VarChar(20)
|
||||
feature String @db.VarChar(50)
|
||||
action String @db.VarChar(20)
|
||||
|
||||
info String? @db.Text
|
||||
|
||||
@@index([createdAt])
|
||||
@@index([tenantId])
|
||||
@@index([userId])
|
||||
@@index([module, feature])
|
||||
@@index([action])
|
||||
@@map("simple_logs")
|
||||
@@schema("admin_schema")
|
||||
}
|
||||
```
|
||||
|
||||
**迁移命令**:
|
||||
|
||||
```bash
|
||||
# 由于存在跨 schema 外键约束问题,使用 db push 代替 migrate
|
||||
npx prisma db push
|
||||
```
|
||||
|
||||
**数据库备份**:
|
||||
- 备份文件:`ai_clinical_research_backup_20260125.sql`
|
||||
- 备份时间:2026-01-25 实施前
|
||||
- 备份命令:`pg_dump -h localhost -U postgres -F p ai_clinical_research > backup.sql`
|
||||
|
||||
---
|
||||
|
||||
## 2. 后端服务实施 ✅
|
||||
|
||||
### 2.1 ActivityService(埋点服务)
|
||||
|
||||
**文件位置**:`backend/src/common/services/activity.service.ts`
|
||||
|
||||
**核心特性**:
|
||||
- ✅ 火烧即忘模式(Fire-and-Forget)
|
||||
- ✅ 外层 try-catch 保护(永不抛出异常)
|
||||
- ✅ 自动填充 tenantName 和 userName
|
||||
- ✅ 静默失败,不影响业务逻辑
|
||||
|
||||
**使用示例**:
|
||||
|
||||
```typescript
|
||||
import { activityService } from '@/common/services/activity.service';
|
||||
|
||||
// 在业务逻辑中添加埋点(不阻塞主流程)
|
||||
await activityService.log({
|
||||
userId: user.id,
|
||||
tenantId: user.tenantId,
|
||||
module: 'AIA',
|
||||
feature: '智能体对话',
|
||||
action: 'MESSAGE_SENT',
|
||||
info: `对话完成,tokens: ${tokens}`,
|
||||
});
|
||||
```
|
||||
|
||||
### 2.2 StatsController(统计控制器)
|
||||
|
||||
**文件位置**:`backend/src/modules/admin/controllers/statsController.ts`
|
||||
|
||||
**API 端点**:
|
||||
|
||||
| 端点 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `/api/admin/stats/overview` | GET | 获取 DAU/DAT/模块统计 |
|
||||
| `/api/admin/stats/live-feed` | GET | 获取最近活动流 |
|
||||
| `/api/admin/users/:id/overview` | GET | 获取用户360画像 |
|
||||
| `/api/admin/stats/cleanup` | POST | 清理过期日志(180天) |
|
||||
|
||||
### 2.3 StatsRoutes(路由配置)
|
||||
|
||||
**文件位置**:`backend/src/modules/admin/routes/statsRoutes.ts`
|
||||
|
||||
**权限控制**:
|
||||
- 所有端点需要 `stats:view` 权限
|
||||
- 使用 `authenticate` + `requirePermission` 中间件
|
||||
|
||||
---
|
||||
|
||||
## 3. 埋点集成实施 ✅
|
||||
|
||||
### 3.1 各模块埋点清单
|
||||
|
||||
| 模块 | 埋点位置 | action 类型 | 状态 |
|
||||
|------|---------|------------|------|
|
||||
| **SYSTEM** | auth.controller.ts | LOGIN | ✅ |
|
||||
| **AIA** | conversationService.ts | MESSAGE_SENT | ✅ |
|
||||
| **PKB** | knowledgeBaseService.ts | KB_CREATED, KB_DELETED | ✅ |
|
||||
| **PKB** | ragService.ts | RAG_SEARCH | ✅ |
|
||||
| **ASL** | screeningWorker.ts | SCREENING_COMPLETED | ✅ |
|
||||
| **DC** | extractionWorker.ts (Tool B) | EXTRACTION_COMPLETED | ✅ |
|
||||
| **DC** | AICodeService.ts (Tool C) | CODE_GENERATE, CODE_EXECUTE | ✅ |
|
||||
| **RVW** | reviewWorker.ts | REVIEW_COMPLETED | ✅ |
|
||||
| **IIT** | SyncManager.ts | POLL_STARTED, SYNC_COMPLETED | ✅ |
|
||||
|
||||
### 3.2 埋点代码示例
|
||||
|
||||
**登录埋点**(auth.controller.ts):
|
||||
|
||||
```typescript
|
||||
// 登录成功后记录
|
||||
await activityService.log({
|
||||
userId: result.user.id,
|
||||
tenantId: result.user.tenantId,
|
||||
module: 'SYSTEM',
|
||||
feature: '用户登录',
|
||||
action: 'LOGIN',
|
||||
info: `用户 ${result.user.name} (${result.user.phone}) 登录成功`,
|
||||
});
|
||||
```
|
||||
|
||||
**AIA 对话埋点**(conversationService.ts):
|
||||
|
||||
```typescript
|
||||
// 在流式对话完成后记录
|
||||
await activityService.log({
|
||||
userId,
|
||||
tenantId: user.tenantId,
|
||||
module: 'AIA',
|
||||
feature: `智能体对话: ${conversation.agentId}`,
|
||||
action: 'MESSAGE_SENT',
|
||||
info: `对话 ${conversationId} 消息发送完成,tokens: ${aiMessage.tokens}`,
|
||||
});
|
||||
```
|
||||
|
||||
**PKB 知识库埋点**(knowledgeBaseService.ts):
|
||||
|
||||
```typescript
|
||||
// 创建知识库
|
||||
await activityService.log({
|
||||
userId,
|
||||
tenantId: user.tenantId,
|
||||
module: 'PKB',
|
||||
feature: '知识库管理',
|
||||
action: 'KB_CREATED',
|
||||
info: `创建知识库: ${name} (ID: ${knowledgeBase.id})`,
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 前端看板实施 ✅
|
||||
|
||||
### 4.1 Admin Dashboard 更新
|
||||
|
||||
**文件位置**:`frontend-v2/src/pages/admin/AdminDashboard.tsx`
|
||||
|
||||
**功能特性**:
|
||||
- ✅ DAU/DAT 实时统计卡片
|
||||
- ✅ 模块使用分布图表
|
||||
- ✅ 最近活动实时流
|
||||
- ✅ 自动刷新(基于 React Query)
|
||||
|
||||
### 4.2 API 调用层
|
||||
|
||||
**文件位置**:`frontend-v2/src/modules/admin/api/statsApi.ts`
|
||||
|
||||
**API 函数**:
|
||||
|
||||
```typescript
|
||||
// 获取运营概览
|
||||
export const getOverview = async (): Promise<StatsOverview> => {
|
||||
const response = await apiClient.get('/api/admin/stats/overview');
|
||||
return response.data.data;
|
||||
};
|
||||
|
||||
// 获取实时活动流
|
||||
export const getLiveFeed = async (limit?: number): Promise<LiveFeedItem[]> => {
|
||||
const response = await apiClient.get('/api/admin/stats/live-feed', {
|
||||
params: { limit },
|
||||
});
|
||||
return response.data.data;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 测试验证 ✅
|
||||
|
||||
### 5.1 API 测试
|
||||
|
||||
**测试脚本位置**:`backend/src/modules/admin/__tests__/test-stats-api.ps1`
|
||||
|
||||
**测试结果**:
|
||||
|
||||
| 测试项 | 结果 |
|
||||
|--------|------|
|
||||
| 登录获取 Token | ✅ 通过 |
|
||||
| GET /overview | ✅ 返回 DAU/DAT |
|
||||
| GET /live-feed | ✅ 返回活动列表 |
|
||||
| 用户 360 画像 | ✅ 返回资产统计 |
|
||||
|
||||
### 5.2 前端测试
|
||||
|
||||
- ✅ 运营管理端 Dashboard 正常显示
|
||||
- ✅ 实时数据刷新正常
|
||||
- ✅ 权限控制正常(仅 SUPER_ADMIN 可访问)
|
||||
|
||||
---
|
||||
|
||||
## 6. 问题与解决
|
||||
|
||||
### 6.1 Prisma 迁移失败
|
||||
|
||||
**问题**:`prisma migrate dev` 报错 P3006(shadow database 问题)
|
||||
|
||||
**原因**:存在跨 schema 外键约束
|
||||
|
||||
**解决**:使用 `prisma db push` 直接推送 schema 变更(仅添加新表,安全)
|
||||
|
||||
### 6.2 TypeScript 编译错误
|
||||
|
||||
**问题**:添加埋点后多处 TypeScript 错误
|
||||
|
||||
**修复内容**:
|
||||
- 修正 Prisma 模型名称(如 `prisma.reviewTask` 代替 `prisma.review_tasks`)
|
||||
- 添加类型注解(`reduce` 函数参数)
|
||||
- 添加 `.js` 扩展名到 ESM 导入
|
||||
|
||||
### 6.3 DC Tool C 上传 401
|
||||
|
||||
**问题**:文件上传返回 401 Unauthorized
|
||||
|
||||
**原因**:后端服务未重启,新代码未生效
|
||||
|
||||
**解决**:重启后端服务后正常
|
||||
|
||||
---
|
||||
|
||||
## 7. 文件变更清单
|
||||
|
||||
### 新增文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `backend/src/common/services/activity.service.ts` | 埋点服务 |
|
||||
| `backend/src/modules/admin/controllers/statsController.ts` | 统计控制器 |
|
||||
| `backend/src/modules/admin/routes/statsRoutes.ts` | 统计路由 |
|
||||
| `frontend-v2/src/modules/admin/api/statsApi.ts` | 前端 API 层 |
|
||||
|
||||
### 修改文件
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `backend/prisma/schema.prisma` | 添加 SimpleLog 模型 |
|
||||
| `backend/src/index.ts` | 注册 statsRoutes |
|
||||
| `backend/src/common/auth/auth.controller.ts` | 登录埋点 |
|
||||
| `backend/src/modules/aia/services/conversationService.ts` | AIA 对话埋点 |
|
||||
| `backend/src/modules/pkb/services/knowledgeBaseService.ts` | PKB 知识库埋点 |
|
||||
| `backend/src/modules/pkb/services/ragService.ts` | PKB RAG 埋点 |
|
||||
| `backend/src/modules/asl/services/screeningWorker.ts` | ASL 筛选埋点 |
|
||||
| `backend/src/modules/dc/tool-b/workers/extractionWorker.ts` | DC Tool B 埋点 |
|
||||
| `backend/src/modules/dc/tool-c/services/AICodeService.ts` | DC Tool C 埋点 |
|
||||
| `backend/src/modules/rvw/workers/reviewWorker.ts` | RVW 审查埋点 |
|
||||
| `backend/src/modules/iit-manager/services/SyncManager.ts` | IIT 同步埋点 |
|
||||
| `frontend-v2/src/pages/admin/AdminDashboard.tsx` | 运营看板 UI |
|
||||
|
||||
---
|
||||
|
||||
## 8. 后续优化建议
|
||||
|
||||
### P2 优先级
|
||||
|
||||
- [ ] 添加更多埋点:Protocol Agent 一键生成、Word 导出
|
||||
- [ ] 图表可视化:使用 ECharts 展示趋势图
|
||||
- [ ] 定时任务:每日 00:00 自动清理 180 天前日志
|
||||
|
||||
### P3 优先级
|
||||
|
||||
- [ ] 用户行为路径分析
|
||||
- [ ] 漏斗分析功能
|
||||
- [ ] 导出统计报表
|
||||
|
||||
---
|
||||
|
||||
## 9. 总结
|
||||
|
||||
✅ 运营监控系统 MVP 已完成核心功能:
|
||||
- **数据采集**:7 个模块埋点全部完成
|
||||
- **数据存储**:SimpleLog 表结构稳定
|
||||
- **数据展示**:Admin Dashboard 实时展示
|
||||
- **API 接口**:4 个核心端点全部可用
|
||||
|
||||
MVP 阶段目标达成,可支持基本的运营数据分析需求。
|
||||
|
||||
---
|
||||
|
||||
*文档完成时间:2026-01-25*
|
||||
|
||||
Reference in New Issue
Block a user