forked from wangziqi/ruoyi-vue-pro
feat(education): save practice answers idempotently
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
- 题库目录端点 (见下方 Catalog API) — 学生端已认证
|
||||
- 题目浏览与筛选端点 (见下方 Questions API) — 学生端已认证
|
||||
- 练习配置预览端点 (见下方 Practice API) — 学生端已认证
|
||||
- 答案保存端点 (见下方 Answer API) — 幂等保存,安全重试
|
||||
- 题目安全过滤(答案/解析绝不暴露到前端)
|
||||
- 独立的功能开关配置 + Scalar 数据源配置
|
||||
- 错误码常量(通用 + 租户 + Catalog/Scalar + 题目/练习)
|
||||
@@ -406,3 +407,56 @@ Browser -> Controller(/education/questions/*) -> QuestionCatalogService -> Quest
|
||||
| 1_005_003_002 | 无效的练习配置 |
|
||||
| 1_005_003_003 | 符合条件的题目数量不足 |
|
||||
| 1_005_003_004 | 题库数据源返回不安全内容 |
|
||||
|
||||
### 用户 APP - 答案保存(Answer)
|
||||
|
||||
需要学生登录态。`userId`/`tenantId` 由安全上下文派生。
|
||||
答案保存具有幂等性:同一 `idempotencyKey` + 相同载荷返回首次结果,相同 key + 不同载荷返回冲突。
|
||||
服务端乐观锁防止旧版本/旧序号覆盖更新答案。
|
||||
|
||||
```
|
||||
PUT /app-api/education/practice-session/answer
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{"sessionId":1001,"questionSequence":3,"selectedAnswer":"A","idempotencyKey":"uuid","clientSequence":5,"expectedSessionVersion":1}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| sessionId | Long | 是 | 练习会话 ID |
|
||||
| questionSequence | Integer | 是 | 题目序号(1-based) |
|
||||
| selectedAnswer | String | 否 | 学生选择的答案,null 表示清除 |
|
||||
| idempotencyKey | String | 是 | 客户端幂等键(UUID) |
|
||||
| clientSequence | Integer | 是 | 客户端命令序号(单调递增) |
|
||||
| expectedSessionVersion | Integer | 是 | 客户端期望的会话版本号 |
|
||||
|
||||
**成功响应:** `{"sessionId":1001,"questionSequence":3,"selectedAnswer":"A","serverVersion":2,"acceptedSequence":5}`
|
||||
|
||||
**前端保存状态契约**(客户端根据 API 响应派生,后端不提供状态枚举):
|
||||
|
||||
| 状态 | 条件 | 说明 |
|
||||
|------|------|------|
|
||||
| SAVING | 请求发送中 | 显示保存中指示器 |
|
||||
| SAVED | code=0 | 更新本地版本号和序号 |
|
||||
| RETRYING | 网络超时/5xx | 相同 idempotencyKey 安全重试 |
|
||||
| FAILED | 1\_005\_003\_014/015/016 | 刷新页面获取最新状态后重试 |
|
||||
|
||||
刷新页面通过 `GET /practice-session/current` 恢复服务端最后确认的答案。
|
||||
|
||||
### 答案保存错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 1\_005\_003\_006 | 练习会话不存在 |
|
||||
| 1\_005\_003\_007 | 无权访问该练习会话 |
|
||||
| 1\_005\_003\_008 | 练习会话已过期 |
|
||||
| 1\_005\_003\_009 | 练习会话已提交 |
|
||||
| 1\_005\_003\_010 | 练习会话已取消 |
|
||||
| 1\_005\_003\_014 | 幂等键相同但请求内容不一致 |
|
||||
| 1\_005\_003\_015 | 会话版本已更新,请刷新后重试 |
|
||||
| 1\_005\_003\_016 | 客户端命令序号已过期 |
|
||||
| 1\_005\_003\_017 | 无效的选项 |
|
||||
| 1\_005\_003\_019 | 题目不属于当前会话 |
|
||||
|
||||
Reference in New Issue
Block a user