forked from wangziqi/ruoyi-vue-pro
feat(education): add scalar catalog adapter
This commit is contained in:
@@ -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 | 不支持的题库数据源模式 |
|
||||
|
||||
Reference in New Issue
Block a user