feat(education): add scalar catalog adapter

This commit is contained in:
2026-07-27 18:39:49 +08:00
parent 0f846fdaf5
commit 478d3d65b7
37 changed files with 3374 additions and 21 deletions

View File

@@ -2,35 +2,24 @@
教育业务模块,提供课程、练习、题库、考试等教育业务功能。
## 当前状态:应用外壳 (Shell)
## 当前状态
此模块目前处于**应用外壳**阶段,提供:
此模块提供教育业务功能骨架和题库目录浏览 tracer bullet。
**已实现**
- 模块骨架与包结构
- 能力探测端点 (`/education/capability`)
- 租户识别端点 (`/education/tenant/resolve`) — 学生端登录前使用
- 教育上下文端点 (`/education/context`) — 学生端已认证状态
- 独立的功能开关配置
- 错误码常量
- 权限与菜单种子数据(角色授权由管理员按租户完成
- 增量 SQL 交付约定
无业务表,无虚假 CRUD。
- 题库目录端点 (见下方 Catalog API) — 学生端已认证
- 独立的功能开关配置 + Scalar 数据源配置
- 错误码常量(通用 + 租户 + Catalog/Scalar
- 权限与菜单种子数据
## 功能配置
`application.yaml` 或对应 profile 中配置:
```yaml
yudao:
education:
enabled: true # 是否启用教育模块,默认 false
version: 1.0.0 # 模块版本号
hostname-tenant-map: # authority 到租户名的精确映射(可选,键在读取时统一转为小写)
"staging.school.com": "demo-school" # DNS 与 websites 不一致时使用
login-methods: [PASSWORD, SMS] # 当前部署全局启用的 Member 登录入口
```
- `yudao.education.enabled=true`启用模块Controller 注册、Swagger 分组可见)
## API
@@ -51,7 +40,7 @@ GET /admin-api/education/capability
"module": "education",
"enabled": true,
"version": "1.0.0",
"capabilities": ["shell"]
"capabilities": ["shell", "catalog"]
}
}
```
@@ -217,3 +206,94 @@ mysql -u root -p ruoyi-vue-pro < sql/mysql/education/001-education-tenant-rollba
1. 在 Vue3 admin 的路由中添加 `/education` 路由项,绑定 Education 菜单组件
2. 添加 `src/api/education/` API 封装层(调用上述教育端点)
3. Student Web/H5 端如需要独立入口,需新建对应前端项目
### 用户 APP - 题库目录Catalog
所有端点需要学生登录态Bearer Token`userId``tenantId` 由安全上下文派生,不接受客户端传参。
Scalar 代理层自动注入 `x-tenant-id` header来自 `TenantContextHolder`),前端不发起任何直达 Scalar 的请求。
#### 架构边界
```
Browser → Controller(/education/catalog/*) → CatalogService → CatalogProvider → [Scalar]
↑ 内部 DTO/VO ↑ Scalar DTO 仅此层
```
- **业务层**Controller/Service仅操作内部 Catalog VO`CatalogRegionRespVO` 等)
- **集成层**Scalar DTO + ScalarCatalogProvider封装 Scalar 协议差异DTO 不泄露到上层
#### 端点列表
| 端点 | 说明 | 参数 |
|------|------|------|
| `GET /app-api/education/catalog/regions` | 查询可用地区 | 无 |
| `GET /app-api/education/catalog/categories` | 查询题目分类 | `subjectId` (可选), `nodeId` (可选) |
| `GET /app-api/education/catalog/subjects` | 查询科目目录 | `regionId`, `schoolId`, `majorId`, `moduleId`, `type` (均可选) |
| `GET /app-api/education/catalog/module-nodes` | 查询模块导航节点 | `regionId`, `moduleId`, `parentId` (均可选) |
| `GET /app-api/education/catalog/content-entries` | 查询内容入口 | `regionId`, `entryType`, `includeHidden` (均可选) |
| `GET /app-api/education/catalog/content-nodes` | 查询内容导航节点 | `entryId` (必填), `parentId`, `mode`, `includeInactive`, `markerType` (可选) |
| `GET /app-api/education/catalog/question-collections` | 查询可用题集 | `regionId`, `entryId`, `nodeId`, `collectionType`, `limit` (均可选) |
#### 响应格式
所有成功响应返回 `CommonResult<List<T>>`
```json
{
"code": 0,
"msg": "成功",
"data": [
{"id": "uuid", "name": "全国", "order": 1, "active": true}
]
}
```
#### 错误响应
| HTTP 状态 | 错误码 | 说明 |
|-----------|--------|------|
| 401 | 1_016_000_002 | 未登录或会话过期 |
| 400 | 自定义 | 请求参数不合法 |
| 500 | 1_005_002_000 | 题库数据源未启用 |
| 500 | 1_005_002_001 | 上游题库服务异常 |
| 500 | 1_005_002_002 | 上游认证失败(配置问题) |
| 403 | 1_005_002_003 | 无权限访问上游资源 |
| 404 | 1_005_002_004 | 请求的题库资源不存在 |
| 409 | 1_005_002_005 | 资源状态冲突 |
| 429 | 1_005_002_006 | 请求过于频繁 |
| 500 | 1_005_002_007 | 上游超时 |
| 500 | 1_005_002_008 | 上游返回异常:{状态码} |
| 500 | 1_005_002_009 | 不支持的题库数据源模式 |
- **上游错误不会被转换为空列表或成功响应** — 每个上游非 2xx 均映射为明确的 `ServiceException`
- 日志记录脱敏后的端点名、tenant、上游 requestId、耗时和结果
#### 前端集成提示
前端就位后,学生端学习首页应:
1. 获取上下文(`/education/context`)确认登录态
2. 调用 `/education/catalog/regions` 获取地区筛选器
3. 根据地区调用 `subjects` / `categories` 获取科目分类
4. 调用 `content-entries``content-nodes` 构建目录树
5. 叶子节点调用 `question-collections` 获取题集摘要
**当前阻塞**:完整前端源码不存在,后端目录接口已就绪可通过 Swagger/curl 验证。
### 更新后的错误码
| 错误码 | 说明 |
|--------|------|
| 1_005_001_000 | 教育模块未启用 |
| 1_005_001_001 | 租户不存在 |
| 1_005_001_002 | 租户已被禁用 |
| 1_005_001_003 | 租户识别失败:{原因} |
| 1_005_001_004 | 当前租户不可用 |
| 1_005_002_000 | 题库数据源未启用 |
| 1_005_002_001 | 上游题库服务异常 |
| 1_005_002_002 | 上游认证失败 |
| 1_005_002_003 | 无权限访问上游资源 |
| 1_005_002_004 | 题库资源不存在 |
| 1_005_002_005 | 资源状态冲突 |
| 1_005_002_006 | 请求过于频繁 |
| 1_005_002_007 | 上游超时 |
| 1_005_002_008 | 上游返回异常:{状态码} |
| 1_005_002_009 | 不支持的题库数据源模式 |