Features - User Management (Phase 4.1): - Database: Add user_modules table for fine-grained module permissions - Database: Add 4 user permissions (view/create/edit/delete) to role_permissions - Backend: UserService (780 lines) - CRUD with tenant isolation - Backend: UserController + UserRoutes (648 lines) - 13 API endpoints - Backend: Batch import users from Excel - Frontend: UserListPage (412 lines) - list/filter/search/pagination - Frontend: UserFormPage (341 lines) - create/edit with module config - Frontend: UserDetailPage (393 lines) - details/tenant/module management - Frontend: 3 modal components (592 lines) - import/assign/configure - API: GET/POST/PUT/DELETE /api/admin/users/* endpoints Architecture Upgrade - Module Permission System: - Backend: Add getUserModules() method in auth.service - Backend: Login API returns modules array in user object - Frontend: AuthContext adds hasModule() method - Frontend: Navigation filters modules based on user.modules - Frontend: RouteGuard checks requiredModule instead of requiredVersion - Frontend: Remove deprecated version-based permission system - UX: Only show accessible modules in navigation (clean UI) - UX: Smart redirect after login (avoid 403 for regular users) Fixes: - Fix UTF-8 encoding corruption in ~100 docs files - Fix pageSize type conversion in userService (String to Number) - Fix authUser undefined error in TopNavigation - Fix login redirect logic with role-based access check - Update Git commit guidelines v1.2 with UTF-8 safety rules Database Changes: - CREATE TABLE user_modules (user_id, tenant_id, module_code, is_enabled) - ADD UNIQUE CONSTRAINT (user_id, tenant_id, module_code) - INSERT 4 permissions + role assignments - UPDATE PUBLIC tenant with 8 module subscriptions Technical: - Backend: 5 new files (~2400 lines) - Frontend: 10 new files (~2500 lines) - Docs: 1 development record + 2 status updates + 1 guideline update - Total: ~4900 lines of code Status: User management 100% complete, module permission system operational
571 lines
11 KiB
Markdown
571 lines
11 KiB
Markdown
# AIA V2.1 后端 API 设计
|
||
|
||
> **版本**:V2.1
|
||
> **创建日期**:2026-01-11
|
||
> **基础路径**:`/api/v2/aia`
|
||
|
||
---
|
||
|
||
## 📋 API 概览
|
||
|
||
| 方法 | 路径 | 描述 | 认证 |
|
||
|------|------|------|------|
|
||
| GET | `/agents` | 获取智能体列表 | ✅ |
|
||
| GET | `/agents/:id` | 获取智能体详情 | ✅ |
|
||
| POST | `/intent/route` | 意图路由 | ✅ |
|
||
| GET | `/conversations` | 获取对话列表 | ✅ |
|
||
| POST | `/conversations` | 创建对话 | ✅ |
|
||
| GET | `/conversations/:id` | 获取对话详情 | ✅ |
|
||
| DELETE | `/conversations/:id` | 删除对话 | ✅ |
|
||
| POST | `/conversations/:id/messages/stream` | 发送消息(流式) | ✅ |
|
||
| POST | `/conversations/:id/attachments` | 上传附件 | ✅ |
|
||
| GET | `/projects` | 获取项目列表 | ✅ |
|
||
| GET | `/projects/:id` | 获取项目详情 | ✅ |
|
||
|
||
---
|
||
|
||
## 🔐 认证
|
||
|
||
所有 API 需要在请求头中携带 JWT Token:
|
||
|
||
```
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
---
|
||
|
||
## 📖 API 详细定义
|
||
|
||
### 1. 智能体相关
|
||
|
||
#### 1.1 获取智能体列表
|
||
|
||
```http
|
||
GET /api/v2/aia/agents
|
||
```
|
||
|
||
**查询参数**:
|
||
|
||
| 参数 | 类型 | 必填 | 描述 |
|
||
|------|------|------|------|
|
||
| stage | string | 否 | 筛选阶段:`design`, `data`, `analysis`, `write`, `publish` |
|
||
|
||
**响应**:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"agents": [
|
||
{
|
||
"id": "research-design",
|
||
"name": "科研设计小助手",
|
||
"description": "帮助您完成研究方案设计、文献检索、方法学指导",
|
||
"icon": "🔬",
|
||
"stage": "design",
|
||
"color": "#3B82F6",
|
||
"knowledgeBaseId": "kb-001",
|
||
"isTool": false
|
||
},
|
||
{
|
||
"id": "dc-tool",
|
||
"name": "数据采集工具",
|
||
"description": "跳转到数据采集模块",
|
||
"icon": "📊",
|
||
"stage": "data",
|
||
"color": "#8B5CF6",
|
||
"targetModule": "/data-collection",
|
||
"isTool": true
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 1.2 获取智能体详情
|
||
|
||
```http
|
||
GET /api/v2/aia/agents/:id
|
||
```
|
||
|
||
**响应**:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"id": "research-design",
|
||
"name": "科研设计小助手",
|
||
"description": "帮助您完成研究方案设计、文献检索、方法学指导",
|
||
"icon": "🔬",
|
||
"stage": "design",
|
||
"color": "#3B82F6",
|
||
"knowledgeBaseId": "kb-001",
|
||
"systemPrompt": "你是一个专业的医学科研设计专家...",
|
||
"welcomeMessage": "您好!我是科研设计小助手,我可以帮您:\n- 设计研究方案\n- 检索相关文献\n- 指导研究方法",
|
||
"suggestedQuestions": [
|
||
"如何设计一个RCT研究?",
|
||
"帮我检索近5年糖尿病研究文献",
|
||
"什么情况下使用倾向性评分匹配?"
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 2. 意图路由
|
||
|
||
#### 2.1 智能意图识别
|
||
|
||
```http
|
||
POST /api/v2/aia/intent/route
|
||
```
|
||
|
||
**请求体**:
|
||
|
||
```json
|
||
{
|
||
"query": "帮我分析一下这份数据"
|
||
}
|
||
```
|
||
|
||
**响应**:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"agentId": "data-analysis",
|
||
"agentName": "统计分析小助手",
|
||
"confidence": 0.92,
|
||
"prefillPrompt": "请帮我分析这份数据,包括描述性统计和相关性分析"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3. 对话管理
|
||
|
||
#### 3.1 获取对话列表
|
||
|
||
```http
|
||
GET /api/v2/aia/conversations
|
||
```
|
||
|
||
**查询参数**:
|
||
|
||
| 参数 | 类型 | 必填 | 描述 |
|
||
|------|------|------|------|
|
||
| agentId | string | 否 | 按智能体筛选 |
|
||
| projectId | string | 否 | 按项目筛选(NULL 表示通用对话) |
|
||
| page | number | 否 | 页码,默认 1 |
|
||
| pageSize | number | 否 | 每页数量,默认 20 |
|
||
|
||
**响应**:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"conversations": [
|
||
{
|
||
"id": "conv-001",
|
||
"title": "RCT研究设计咨询",
|
||
"agentId": "research-design",
|
||
"agentName": "科研设计小助手",
|
||
"projectId": null,
|
||
"messageCount": 12,
|
||
"lastMessage": "好的,我来帮您设计研究方案...",
|
||
"createdAt": "2026-01-11T10:00:00Z",
|
||
"updatedAt": "2026-01-11T12:30:00Z"
|
||
}
|
||
],
|
||
"pagination": {
|
||
"total": 25,
|
||
"page": 1,
|
||
"pageSize": 20,
|
||
"totalPages": 2
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3.2 创建对话
|
||
|
||
```http
|
||
POST /api/v2/aia/conversations
|
||
```
|
||
|
||
**请求体**:
|
||
|
||
```json
|
||
{
|
||
"agentId": "research-design",
|
||
"projectId": null,
|
||
"title": "新对话"
|
||
}
|
||
```
|
||
|
||
**响应**:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"id": "conv-002",
|
||
"title": "新对话",
|
||
"agentId": "research-design",
|
||
"projectId": null,
|
||
"createdAt": "2026-01-11T14:00:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3.3 获取对话详情(含历史消息)
|
||
|
||
```http
|
||
GET /api/v2/aia/conversations/:id
|
||
```
|
||
|
||
**查询参数**:
|
||
|
||
| 参数 | 类型 | 必填 | 描述 |
|
||
|------|------|------|------|
|
||
| limit | number | 否 | 获取最近N条消息,默认 50 |
|
||
|
||
**响应**:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"id": "conv-001",
|
||
"title": "RCT研究设计咨询",
|
||
"agentId": "research-design",
|
||
"agentName": "科研设计小助手",
|
||
"projectId": null,
|
||
"createdAt": "2026-01-11T10:00:00Z",
|
||
"updatedAt": "2026-01-11T12:30:00Z",
|
||
"messages": [
|
||
{
|
||
"id": "msg-001",
|
||
"role": "user",
|
||
"content": "帮我设计一个关于糖尿病的RCT研究",
|
||
"attachments": [],
|
||
"createdAt": "2026-01-11T10:00:00Z"
|
||
},
|
||
{
|
||
"id": "msg-002",
|
||
"role": "assistant",
|
||
"content": "好的,我来帮您设计一个糖尿病RCT研究方案...",
|
||
"thinkingContent": "用户想设计RCT研究,需要考虑:1)研究目的 2)入排标准 3)样本量 4)随机化方法 5)盲法 6)结局指标...",
|
||
"model": "deepseek-v3",
|
||
"tokens": 1250,
|
||
"createdAt": "2026-01-11T10:00:30Z"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3.4 删除对话
|
||
|
||
```http
|
||
DELETE /api/v2/aia/conversations/:id
|
||
```
|
||
|
||
**响应**:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"deleted": true
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4. 消息发送(流式)
|
||
|
||
#### 4.1 发送消息并获取流式响应
|
||
|
||
```http
|
||
POST /api/v2/aia/conversations/:id/messages/stream
|
||
```
|
||
|
||
**请求头**:
|
||
|
||
```
|
||
Content-Type: application/json
|
||
Accept: text/event-stream
|
||
```
|
||
|
||
**请求体**:
|
||
|
||
```json
|
||
{
|
||
"content": "帮我分析这份数据",
|
||
"attachmentIds": ["att-001", "att-002"],
|
||
"enableDeepThinking": true
|
||
}
|
||
```
|
||
|
||
**响应(SSE 格式)**:
|
||
|
||
```
|
||
event: thinking_start
|
||
data: {}
|
||
|
||
event: thinking_delta
|
||
data: {"content": "用户上传了数据文件,需要"}
|
||
|
||
event: thinking_delta
|
||
data: {"content": "进行描述性统计分析..."}
|
||
|
||
event: thinking_end
|
||
data: {"duration": 3200}
|
||
|
||
event: message_start
|
||
data: {"id": "msg-003"}
|
||
|
||
event: delta
|
||
data: {"content": "根据您上传的数据,"}
|
||
|
||
event: delta
|
||
data: {"content": "我来为您进行分析..."}
|
||
|
||
event: message_end
|
||
data: {"id": "msg-003", "tokens": 850, "model": "deepseek-v3"}
|
||
|
||
event: done
|
||
data: {}
|
||
```
|
||
|
||
**SSE 事件类型**:
|
||
|
||
| 事件 | 描述 | 数据格式 |
|
||
|------|------|---------|
|
||
| `thinking_start` | 开始深度思考 | `{}` |
|
||
| `thinking_delta` | 思考内容片段 | `{"content": "..."}` |
|
||
| `thinking_end` | 思考结束 | `{"duration": number}` |
|
||
| `message_start` | 开始生成回复 | `{"id": "..."}` |
|
||
| `delta` | 回复内容片段 | `{"content": "..."}` |
|
||
| `message_end` | 回复结束 | `{"id": "...", "tokens": number, "model": "..."}` |
|
||
| `error` | 发生错误 | `{"code": "...", "message": "..."}` |
|
||
| `done` | 流结束 | `{}` |
|
||
|
||
---
|
||
|
||
### 5. 附件上传
|
||
|
||
#### 5.1 上传附件
|
||
|
||
```http
|
||
POST /api/v2/aia/conversations/:id/attachments
|
||
```
|
||
|
||
**请求头**:
|
||
|
||
```
|
||
Content-Type: multipart/form-data
|
||
```
|
||
|
||
**请求体(FormData)**:
|
||
|
||
| 字段 | 类型 | 必填 | 描述 |
|
||
|------|------|------|------|
|
||
| file | File | 是 | 文件(PDF/Word/TXT/Excel,最大20MB) |
|
||
|
||
**响应**:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"id": "att-001",
|
||
"filename": "研究数据.xlsx",
|
||
"mimeType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||
"size": 1024000,
|
||
"ossUrl": "https://oss.example.com/attachments/att-001.xlsx",
|
||
"textExtracted": true,
|
||
"tokenCount": 15000,
|
||
"truncated": false,
|
||
"createdAt": "2026-01-11T14:00:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
**错误码**:
|
||
|
||
| 错误码 | 描述 |
|
||
|--------|------|
|
||
| `ATTACHMENT_TOO_LARGE` | 文件超过 20MB |
|
||
| `ATTACHMENT_TYPE_NOT_SUPPORTED` | 不支持的文件类型 |
|
||
| `ATTACHMENT_LIMIT_EXCEEDED` | 附件数量超过上限(5个) |
|
||
| `TEXT_EXTRACTION_FAILED` | 文本提取失败 |
|
||
|
||
---
|
||
|
||
### 6. 项目管理
|
||
|
||
#### 6.1 获取项目列表
|
||
|
||
```http
|
||
GET /api/v2/aia/projects
|
||
```
|
||
|
||
**响应**:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"projects": [
|
||
{
|
||
"id": "proj-001",
|
||
"name": "糖尿病研究项目",
|
||
"description": "2型糖尿病患者生活方式干预研究",
|
||
"conversationCount": 5,
|
||
"createdAt": "2026-01-01T10:00:00Z",
|
||
"updatedAt": "2026-01-11T12:00:00Z"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 错误处理
|
||
|
||
### 错误响应格式
|
||
|
||
```json
|
||
{
|
||
"code": -1,
|
||
"error": {
|
||
"code": "CONVERSATION_NOT_FOUND",
|
||
"message": "对话不存在"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 通用错误码
|
||
|
||
| 错误码 | HTTP 状态码 | 描述 |
|
||
|--------|------------|------|
|
||
| `UNAUTHORIZED` | 401 | 未授权 |
|
||
| `FORBIDDEN` | 403 | 无权限 |
|
||
| `NOT_FOUND` | 404 | 资源不存在 |
|
||
| `VALIDATION_ERROR` | 400 | 参数验证失败 |
|
||
| `INTERNAL_ERROR` | 500 | 服务器内部错误 |
|
||
| `LLM_ERROR` | 500 | LLM 调用失败 |
|
||
| `RATE_LIMITED` | 429 | 请求过于频繁 |
|
||
|
||
---
|
||
|
||
## 📊 数据模型
|
||
|
||
### Attachment(附件)
|
||
|
||
```typescript
|
||
interface Attachment {
|
||
id: string; // 附件ID
|
||
filename: string; // 原始文件名
|
||
mimeType: string; // MIME 类型
|
||
size: number; // 文件大小(字节)
|
||
ossUrl: string; // OSS 存储地址
|
||
textContent?: string; // 提取的文本内容(存储时截断)
|
||
tokenCount: number; // 文本 Token 数
|
||
truncated: boolean; // 是否被截断(超过30K tokens)
|
||
createdAt: string; // 创建时间
|
||
}
|
||
```
|
||
|
||
### Message(消息)
|
||
|
||
```typescript
|
||
interface Message {
|
||
id: string;
|
||
conversationId: string;
|
||
role: 'user' | 'assistant';
|
||
content: string;
|
||
thinkingContent?: string; // 深度思考内容
|
||
attachments?: Attachment[];
|
||
model?: string;
|
||
tokens?: number;
|
||
isPinned: boolean;
|
||
createdAt: string;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🧪 测试示例(REST Client)
|
||
|
||
```http
|
||
### 获取智能体列表
|
||
GET {{baseUrl}}/api/v2/aia/agents
|
||
Authorization: Bearer {{token}}
|
||
|
||
### 意图路由
|
||
POST {{baseUrl}}/api/v2/aia/intent/route
|
||
Authorization: Bearer {{token}}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"query": "帮我分析数据"
|
||
}
|
||
|
||
### 创建对话
|
||
POST {{baseUrl}}/api/v2/aia/conversations
|
||
Authorization: Bearer {{token}}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"agentId": "research-design",
|
||
"title": "测试对话"
|
||
}
|
||
|
||
### 发送消息(流式)
|
||
POST {{baseUrl}}/api/v2/aia/conversations/{{conversationId}}/messages/stream
|
||
Authorization: Bearer {{token}}
|
||
Content-Type: application/json
|
||
Accept: text/event-stream
|
||
|
||
{
|
||
"content": "帮我设计一个RCT研究",
|
||
"enableDeepThinking": true
|
||
}
|
||
|
||
### 上传附件
|
||
POST {{baseUrl}}/api/v2/aia/conversations/{{conversationId}}/attachments
|
||
Authorization: Bearer {{token}}
|
||
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
|
||
|
||
------WebKitFormBoundary
|
||
Content-Disposition: form-data; name="file"; filename="data.xlsx"
|
||
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||
|
||
< ./data.xlsx
|
||
------WebKitFormBoundary--
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 更新日志
|
||
|
||
| 日期 | 版本 | 内容 |
|
||
|------|------|------|
|
||
| 2026-01-11 | V1.0 | 创建 API 设计文档 |
|
||
|
||
|
||
|
||
|
||
|
||
|