forked from wangziqi/gongxue-base
feat: add public question bank sync
This commit is contained in:
@@ -184,7 +184,7 @@ tenant:<tenantId>:theme
|
||||
| 租户考试日期 | `GET/PUT /api/tenant-admin/exam-dates` |
|
||||
| 租户反馈处理 | `GET /api/tenant-admin/feedbacks`、`POST /api/tenant-admin/feedbacks/status`、`GET /api/tenant-admin/feedbacks/events` |
|
||||
| 租户勋章 | `GET/PUT /api/tenant-admin/badges`、`GET/POST /api/tenant-admin/badge-grants` |
|
||||
| 公共题库采纳 | `GET /api/tenant-content/public-question-banks`、`POST /api/tenant-content/public-question-banks/adopt` |
|
||||
| 公共题库采纳/同步 | `GET /api/tenant-content/public-question-banks`、`POST /api/tenant-content/public-question-banks/adopt`、`POST /api/tenant-content/public-question-banks/sync` |
|
||||
|
||||
## 练习访问控制契约
|
||||
|
||||
@@ -850,6 +850,7 @@ PUT /api/platform-admin/question-bank-grants
|
||||
```text
|
||||
GET /api/tenant-content/public-question-banks
|
||||
POST /api/tenant-content/public-question-banks/adopt
|
||||
POST /api/tenant-content/public-question-banks/sync
|
||||
```
|
||||
|
||||
采纳请求:
|
||||
@@ -868,7 +869,59 @@ POST /api/tenant-content/public-question-banks/adopt
|
||||
- 租户只能看到后端判定为已授权的公共题库,不要在前端用套餐码自行过滤。
|
||||
- 采纳成功后后端会生成本租户自己的 `questionBankId`、`entryId`、`collectionId` 和题目快照,学生端直接按普通 `/api/catalog/content-entries`、`question-collections`、`practice-sessions` 接入。
|
||||
- 重复采纳返回 `QUESTION_BANK_ALREADY_ADOPTED`,前端展示“已采纳”即可。
|
||||
- 当前版本是快照复制;平台公共题库后续更新不会自动进入租户题库,后续会由 worker 做版本同步、冲突处理和租户确认。
|
||||
- 已采纳公共题库可以手动同步平台后续新增/更新题目;同步会重新校验当前租户仍有授权,且只写入租户自己的题目副本。
|
||||
|
||||
同步请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"adoptionId": "<tenant_question_bank_adoptions.id>",
|
||||
"copyLimit": 1000
|
||||
}
|
||||
```
|
||||
|
||||
同步响应关键字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"item": {
|
||||
"id": "...",
|
||||
"syncStatus": "synced | failed",
|
||||
"copiedQuestionCount": 120,
|
||||
"targetQuestionBankId": "...",
|
||||
"targetEntryId": "...",
|
||||
"targetCollectionId": "..."
|
||||
},
|
||||
"sync": {
|
||||
"status": "synced | conflict",
|
||||
"counts": {
|
||||
"inserted": 1,
|
||||
"updated": 3,
|
||||
"skipped": 116,
|
||||
"conflicts": 0
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"sourceQuestionId": "...",
|
||||
"targetQuestionId": "...",
|
||||
"action": "inserted | updated | skipped | conflict",
|
||||
"sourceHash": "...",
|
||||
"previousSourceHash": "...",
|
||||
"targetHash": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
前端处理规则:
|
||||
|
||||
- `sync.status=synced`:刷新公共题库列表、题目集合和题目列表。
|
||||
- `sync.status=conflict` 或 `item.syncStatus=failed`:展示冲突数量和冲突题目,不要把它当系统异常。冲突表示租户已经改过这道采纳题,后端已跳过并保留租户内容。
|
||||
- `action=conflict` 的记录可以进入后续“冲突处理”页面:展示平台源题 ID、租户目标题 ID、上次平台 hash、当前平台 hash、租户当前 hash。当前后端只负责保护不覆盖,批量接受平台版本/保留租户版本的操作台后续补。
|
||||
- `QUESTION_BANK_GRANT_NOT_AVAILABLE`:说明 SaaS 套餐/授权已失效,提示联系平台或升级套餐。
|
||||
- `QUESTION_BANK_ADOPTION_NOT_FOUND`:说明不是当前租户的采纳记录或记录已归档,前端不要跨租户重试。
|
||||
- 后续会补自动同步 worker、版本通知、冲突操作台和批量确认策略;当前租户后台可以先提供手动“同步平台更新”按钮。
|
||||
|
||||
## 登录对接
|
||||
|
||||
|
||||
Reference in New Issue
Block a user