forked from wangziqi/ruoyi-vue-pro
220 lines
7.1 KiB
Markdown
220 lines
7.1 KiB
Markdown
# yudao-module-education
|
||
|
||
教育业务模块,提供课程、练习、题库、考试等教育业务功能。
|
||
|
||
## 当前状态:应用外壳 (Shell)
|
||
|
||
此模块目前处于**应用外壳**阶段,提供:
|
||
- 模块骨架与包结构
|
||
- 能力探测端点 (`/education/capability`)
|
||
- 租户识别端点 (`/education/tenant/resolve`) — 学生端登录前使用
|
||
- 教育上下文端点 (`/education/context`) — 学生端已认证状态
|
||
- 独立的功能开关配置
|
||
- 错误码常量
|
||
- 权限与菜单种子数据(角色授权由管理员按租户完成)
|
||
- 增量 SQL 交付约定
|
||
|
||
无业务表,无虚假 CRUD。
|
||
|
||
## 功能配置
|
||
|
||
在 `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
|
||
|
||
### 管理后台 - 能力信息
|
||
|
||
```
|
||
GET /admin-api/education/capability
|
||
```
|
||
|
||
- 权限:`education:capability`
|
||
- 响应示例:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"msg": "成功",
|
||
"data": {
|
||
"module": "education",
|
||
"enabled": true,
|
||
"version": "1.0.0",
|
||
"capabilities": ["shell"]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 用户 APP - 教育租户识别
|
||
|
||
```
|
||
GET /app-api/education/tenant/resolve?hostname=school.example.com
|
||
GET /app-api/education/tenant/resolve?tenantName=demo-school
|
||
GET /app-api/education/tenant/resolve?hostname=school.example.com&tenantName=demo-school
|
||
```
|
||
|
||
- 权限:无需认证(`@PermitAll`)
|
||
- 说明:通过主机名或租户名解析租户,返回学生端登录引导所需的基础字段。
|
||
hostname 和 tenantName 至少提供一个。解析规则:
|
||
1. 如果同时提供两者,它们必须解析到同一个租户,否则拒绝请求
|
||
2. hostname 经过标准化(保留端口并转为小写),先查 `EducationProperties.hostnameTenantMap` 配置映射,再按 `system_tenant.websites` 的精确 authority 值查询
|
||
- 响应示例(成功):
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"msg": "成功",
|
||
"data": {
|
||
"tenantId": 1024,
|
||
"tenantName": "demo-school",
|
||
"displayName": "demo-school",
|
||
"status": "ACTIVE",
|
||
"loginMethods": ["PASSWORD", "SMS"]
|
||
}
|
||
}
|
||
```
|
||
|
||
- 错误响应:
|
||
|
||
| 错误码 | 说明 |
|
||
|--------|------|
|
||
| 1_005_001_001 | 租户不存在 |
|
||
| 1_005_001_002 | 租户已被禁用 |
|
||
| 1_005_001_003 | 租户识别失败(hostname 格式不合法等) |
|
||
| 1_005_001_004 | 当前租户不可用(过期等) |
|
||
|
||
### 用户 APP - 教育当前上下文
|
||
|
||
```
|
||
GET /app-api/education/context
|
||
```
|
||
|
||
- 权限:需要认证(登录态)
|
||
- 说明:根据当前认证用户和租户上下文返回教育业务信息。不信任请求体中的 userId,一切从安全上下文和 TenantContext 派生。TenantSecurityWebFilter 前置完成租户校验,此处二次验证确保租户处于活跃状态。
|
||
- 响应示例:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"msg": "成功",
|
||
"data": {
|
||
"userId": 1024,
|
||
"tenantId": 2048,
|
||
"tenantName": "demo-school",
|
||
"displayName": "demo-school"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 错误码
|
||
|
||
| 错误码 | 说明 |
|
||
|--------|------|
|
||
| 1_005_001_000 | 教育模块未启用 |
|
||
| 1_005_001_001 | 租户不存在 |
|
||
| 1_005_001_002 | 租户已被禁用 |
|
||
| 1_005_001_003 | 租户识别失败:{原因} |
|
||
| 1_005_001_004 | 当前租户不可用,请联系管理员 |
|
||
|
||
## 构建与运行
|
||
|
||
### 单独编译测试
|
||
|
||
```bash
|
||
# 编译 education 模块
|
||
mvn compile -pl yudao-module-education -am
|
||
|
||
# 运行 education 模块单元测试
|
||
mvn test -pl yudao-module-education -am
|
||
```
|
||
|
||
### 整体编译(含 server)
|
||
|
||
```bash
|
||
# 编译全量(member + education + system + infra + server)
|
||
mvn compile -pl yudao-server -am
|
||
|
||
# 打包(跳过测试加速)
|
||
mvn package -pl yudao-server -am -DskipTests
|
||
```
|
||
|
||
### 启动验证
|
||
|
||
1. 确保 `yudao.education.enabled=true`
|
||
2. 启动 `yudao-server`
|
||
3. 访问 Swagger UI 查看 `education` 分组
|
||
4. 调用 `GET /admin-api/education/capability`
|
||
|
||
## SQL 应用
|
||
|
||
```bash
|
||
# 应用基础种子数据(菜单 + 权限定义;执行后由管理员为目标租户角色授权)
|
||
mysql -u root -p ruoyi-vue-pro < sql/mysql/education/000-education-seed.sql
|
||
|
||
# 应用租户识别种子数据
|
||
mysql -u root -p ruoyi-vue-pro < sql/mysql/education/001-education-tenant-seed.sql
|
||
|
||
# 回滚
|
||
mysql -u root -p ruoyi-vue-pro < sql/mysql/education/000-education-rollback.sql
|
||
mysql -u root -p ruoyi-vue-pro < sql/mysql/education/001-education-tenant-rollback.sql
|
||
```
|
||
|
||
## SQL 交付约定
|
||
|
||
- 所有 Education SQL 文件存放在 `sql/mysql/education/` 目录下
|
||
- 文件命名:`NNN-描述.sql`(NNN 为三位递增序号)
|
||
- 每个正向脚本应有对应的回滚脚本
|
||
- schema 文件仅包含 DDL,seed 文件仅包含 DML
|
||
- **不修改**项目根目录的 `ruoyi-vue-pro.sql` 巨量全量转储
|
||
|
||
## 前端状态
|
||
|
||
**当前工作区未检出完整的前端源码。** `yudao-ui/yudao-ui-admin-vue3/` 仅包含部分 MES 相关文件(`src/api/mes/`、`src/views/mes/`),缺少 `package.json`、`router/`、`store/`、`config/` 等核心框架文件。
|
||
|
||
因此:
|
||
- **管理后台教育菜单项**:基础 SQL 仅注册了 `system_menu` 记录(ID 6800-6801)。租户解析与当前上下文属于学生端接口,不创建虚假的后台权限菜单。前端无路由/页面组件可渲染,菜单在管理后台不会显示。
|
||
- **Student Web/H5 应用外壳**:前端源码不存在,无法建立。
|
||
|
||
### Student 端前端集成契约
|
||
|
||
前端就位后必须实现以下流程(不能伪造静态页面):
|
||
|
||
1. **租户识别**(登录前)
|
||
- URL: `GET /app-api/education/tenant/resolve`
|
||
- 从浏览器 `window.location.host` 获取 authority(包含非默认端口),传入 `hostname` 参数
|
||
- 备用:支持手动输入 `tenantName`
|
||
- 根据返回的 `loginMethods` 决定展示哪种登录方式(PASSWORD/SMS)
|
||
- 获得 `tenantId` 后,在后续请求中通过 `tenant-id` header 传递
|
||
|
||
2. **用户认证**(复用 Member 模块)
|
||
- 密码登录: `POST /app-api/member/auth/login`
|
||
- 短信登录: `POST /app-api/member/auth/sms-login`
|
||
- 刷新令牌: `POST /app-api/member/auth/refresh-token`
|
||
- 登出: `POST /app-api/member/auth/logout`
|
||
- 所有请求携带 `tenant-id: {tenantId}` header
|
||
|
||
3. **获取上下文**(登录后)
|
||
- URL: `GET /app-api/education/context`
|
||
- 携带有效 Bearer Token + `tenant-id` header
|
||
- 从响应获取 `userId`、`tenantId`、`tenantName` 用于页面展示
|
||
|
||
4. **跨租户防护**
|
||
- 前端不应允许用户手动切换 `tenant-id` header
|
||
- 后端通过 `TenantSecurityWebFilter` 拒绝认证用户的跨租户 header 操作
|
||
|
||
**阻塞项**:完整前端源码(含 router、store、package.json)是上述前端集成的必要前提。一旦前端源码就位,需:
|
||
1. 在 Vue3 admin 的路由中添加 `/education` 路由项,绑定 Education 菜单组件
|
||
2. 添加 `src/api/education/` API 封装层(调用上述教育端点)
|
||
3. Student Web/H5 端如需要独立入口,需新建对应前端项目
|