feat(education): question browsing and practice configuration preview
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
## 当前状态
|
||||
|
||||
此模块提供教育业务功能骨架和题库目录浏览 tracer bullet。
|
||||
此模块提供教育业务功能骨架、题库目录浏览 tracer bullet,以及题目预览与练习配置预览。
|
||||
|
||||
**已实现**:
|
||||
- 模块骨架与包结构
|
||||
@@ -12,8 +12,11 @@
|
||||
- 租户识别端点 (`/education/tenant/resolve`) — 学生端登录前使用
|
||||
- 教育上下文端点 (`/education/context`) — 学生端已认证状态
|
||||
- 题库目录端点 (见下方 Catalog API) — 学生端已认证
|
||||
- 题目浏览与筛选端点 (见下方 Questions API) — 学生端已认证
|
||||
- 练习配置预览端点 (见下方 Practice API) — 学生端已认证
|
||||
- 题目安全过滤(答案/解析绝不暴露到前端)
|
||||
- 独立的功能开关配置 + Scalar 数据源配置
|
||||
- 错误码常量(通用 + 租户 + Catalog/Scalar)
|
||||
- 错误码常量(通用 + 租户 + Catalog/Scalar + 题目/练习)
|
||||
- 权限与菜单种子数据
|
||||
|
||||
## 功能配置
|
||||
@@ -40,7 +43,7 @@ GET /admin-api/education/capability
|
||||
"module": "education",
|
||||
"enabled": true,
|
||||
"version": "1.0.0",
|
||||
"capabilities": ["shell", "catalog"]
|
||||
"capabilities": ["shell", "catalog", "questions", "practice-preview"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -166,6 +169,7 @@ mysql -u root -p ruoyi-vue-pro < sql/mysql/education/001-education-tenant-rollba
|
||||
- 每个正向脚本应有对应的回滚脚本
|
||||
- schema 文件仅包含 DDL,seed 文件仅包含 DML
|
||||
- **不修改**项目根目录的 `ruoyi-vue-pro.sql` 巨量全量转储
|
||||
- Ticket #5 为只读/预览操作,无新增数据库 schema 或 DML
|
||||
|
||||
## 前端状态
|
||||
|
||||
@@ -278,6 +282,104 @@ Browser → Controller(/education/catalog/*) → CatalogService → CatalogProvi
|
||||
|
||||
**当前阻塞**:完整前端源码不存在,后端目录接口已就绪可通过 Swagger/curl 验证。
|
||||
|
||||
### 用户 APP - 题目与练习预览(Questions & Practice)
|
||||
|
||||
所有端点需要学生登录态(Bearer Token)。`userId` 和 `tenantId` 由安全上下文派生,不接受客户端传参。
|
||||
返回的题目数据经过白名单过滤,绝不包含 `correctAnswer`、`answer`、`explanation`、`analysis` 或选项的 `isCorrect` 字段。
|
||||
|
||||
#### 架构边界
|
||||
|
||||
```
|
||||
Browser -> Controller(/education/questions/*) -> QuestionCatalogService -> QuestionCatalogProvider -> [Scalar]
|
||||
↑ SafeQuestionRespVO ↑ CatalogQuestionDTO
|
||||
```
|
||||
- **业务层**(Controller/Service):仅操作安全 VO(`SafeQuestionRespVO` 等),答案字段在 DTO→VO 转换时被剥离
|
||||
- **集成层**(Scalar DTO + ScalarCatalogProvider):封装 Scalar 协议差异,答案字段在此层被映射但绝不透传到上层
|
||||
|
||||
#### 端点列表
|
||||
|
||||
| 端点 | 说明 | 参数 |
|
||||
|------|------|------|
|
||||
| `GET /app-api/education/questions/page` | 分页查询安全题目 | `collectionId`, `nodeId`, `type`, `difficulty` (可选), `pageNo` (默认1), `pageSize` (默认20) |
|
||||
| `GET /app-api/education/questions/get` | 获取单个安全题目 | `id` (必填) |
|
||||
| `GET /app-api/education/questions/collection-questions` | 查询题集中的安全题目 | `collectionId` (必填), `type`, `difficulty` (可选), `pageNo`, `pageSize` |
|
||||
| `GET /app-api/education/practice-config/preview` | 预览练习配置(不创建会话) | `collectionId` (必填), `nodeId`, `type`, `difficulty` (可选), `questionCount` (默认10, 1-1000) |
|
||||
|
||||
#### 分页响应格式
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "成功",
|
||||
"data": {
|
||||
"list": [
|
||||
{
|
||||
"id": "q-001",
|
||||
"contentVersion": "v2",
|
||||
"stem": "1+1等于几?",
|
||||
"type": "choice",
|
||||
"difficulty": "easy",
|
||||
"options": [
|
||||
{"label": "A", "content": "2", "order": 1.0}
|
||||
]
|
||||
}
|
||||
],
|
||||
"total": 50
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 练习预览响应格式
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "成功",
|
||||
"data": {
|
||||
"eligibleCount": 50,
|
||||
"totalCount": 100,
|
||||
"availableTypes": ["choice", "fill"],
|
||||
"availableDifficulties": ["easy", "medium"],
|
||||
"minQuestions": 1,
|
||||
"maxQuestions": 50,
|
||||
"suggestedCount": 20,
|
||||
"normalizedCount": 10,
|
||||
"countWithinRange": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 错误响应
|
||||
|
||||
| HTTP 状态 | 错误码 | 说明 |
|
||||
|-----------|--------|------|
|
||||
| 401 | 1_016_000_002 | 未登录或会话过期 |
|
||||
| 404 | 1_005_003_001 | 题目不存在或不可见 |
|
||||
| 400 | 1_005_003_002 | 无效的练习配置 |
|
||||
| 400 | 1_005_003_003 | 符合条件的题目数量不足 |
|
||||
| 500 | 1_005_003_004 | 题库数据源返回不安全内容 |
|
||||
|
||||
#### 安全字段白名单
|
||||
|
||||
`SafeQuestionRespVO` 仅包含以下字段,前端可安全展示:
|
||||
- `id`, `contentVersion`, `stem`, `type`, `difficulty`
|
||||
- `options[]` 中仅包含 `label`, `content`, `order`
|
||||
|
||||
以下字段**绝不**出现在响应中:
|
||||
- `correctAnswer`, `answer`, `explanation`, `analysis`
|
||||
- 选项的 `isCorrect`
|
||||
- 任何管理元数据
|
||||
|
||||
#### 前端集成提示
|
||||
|
||||
前端就位后,学生端练习入口应:
|
||||
1. 浏览题库目录(Catalog API)选择题集
|
||||
2. 调用 `/education/questions/page` 或 `/education/questions/collection-questions` 预览题目概要
|
||||
3. 调用 `/education/practice-config/preview` 获取可用题量范围和建议配置
|
||||
4. 展示预览结果后,用户在可用范围内选择题量开始练习(Ticket #6 创建持久会话)
|
||||
|
||||
**当前阻塞**:完整前端源码不存在,后端接口已就绪可通过 Swagger/curl 验证。
|
||||
|
||||
### 更新后的错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
@@ -297,3 +399,10 @@ Browser → Controller(/education/catalog/*) → CatalogService → CatalogProvi
|
||||
| 1_005_002_007 | 上游超时 |
|
||||
| 1_005_002_008 | 上游返回异常:{状态码} |
|
||||
| 1_005_002_009 | 不支持的题库数据源模式 |
|
||||
| 1_005_002_010 | Scalar 数据源未配置 |
|
||||
| 1_005_002_011 | 上游题库返回数据格式异常 |
|
||||
| 1_005_002_012 | 上游题库服务不可达 |
|
||||
| 1_005_003_001 | 题目不存在或不可见 |
|
||||
| 1_005_003_002 | 无效的练习配置 |
|
||||
| 1_005_003_003 | 符合条件的题目数量不足 |
|
||||
| 1_005_003_004 | 题库数据源返回不安全内容 |
|
||||
|
||||
Reference in New Issue
Block a user