From 9204f9329ea8c50420c829e4d912fc8063602d8c Mon Sep 17 00:00:00 2001 From: En Date: Tue, 10 Mar 2026 23:50:25 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=20OpenAPI=20?= =?UTF-8?q?=E6=B3=A8=E8=A7=A3=E5=92=8C=E5=89=8D=E7=AB=AF=20API=20=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主要变更: 1. 所有 Entity/DTO/VO 添加 @Schema 注解,完善 API 文档 2. 新增前端 API 封装模块 (src/apis),包含 fetch.ts 和 apis.ts 3. 生成完整的 TypeScript 类型定义(100+ 个模型) 4. pom.xml 添加 Maven 编译配置和 UTF-8 编码支持 5. 更新 CLAUDE.md 开发文档 6. 清理旧的文档文件 技术细节: - 后端:27 个实体类 + 所有 DTO/Response 添加 Swagger 注解 - 前端:新增 orval 生成的 API 客户端类型 - 构建:配置 Maven compiler plugin 和 Spring Boot 插件的 JVM 参数 Co-Authored-By: Claude Opus 4.6 --- API 对比分析.md | 161 -------- Service 重构总结.md | 132 ------- .../src/apis/SwaggerType.ts | 18 + reading-platform-frontend/src/apis/apis.ts | 55 +++ reading-platform-frontend/src/apis/fetch.ts | 234 ++++++++++++ reading-platform-frontend/src/apis/index.ts | 24 ++ .../reading/platform/entity/ClassTeacher.java | 37 +- .../platform/entity/ClassTeachers.java | 57 +++ 前端实际调用接口对比.md | 346 ------------------ 补全接口修复总结.md | 228 ------------ 10 files changed, 420 insertions(+), 872 deletions(-) delete mode 100644 API 对比分析.md delete mode 100644 Service 重构总结.md create mode 100644 reading-platform-frontend/src/apis/SwaggerType.ts create mode 100644 reading-platform-frontend/src/apis/apis.ts create mode 100644 reading-platform-frontend/src/apis/fetch.ts create mode 100644 reading-platform-frontend/src/apis/index.ts create mode 100644 reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeachers.java delete mode 100644 前端实际调用接口对比.md delete mode 100644 补全接口修复总结.md diff --git a/API 对比分析.md b/API 对比分析.md deleted file mode 100644 index 6d1ff5f..0000000 --- a/API 对比分析.md +++ /dev/null @@ -1,161 +0,0 @@ -# API 对比分析报告 - -## 概述 -对比 reading-platform-backend (Node.js/NestJS) 和 reading-platform-java (Spring Boot) 的 API 接口差异 - ---- - -## 已补全的接口 - -### 1. 任务管理相关接口(SchoolTaskController, TeacherTaskController) - -#### 任务统计接口 -- `GET /api/v1/school/tasks/stats` - 获取任务统计数据 -- `GET /api/v1/school/tasks/stats/by-type` - 按任务类型统计 -- `GET /api/v1/school/tasks/stats/by-class` - 按班级统计 -- `GET /api/v1/school/tasks/stats/monthly` - 月度统计趋势 - -#### 任务完成情况接口 -- `GET /api/v1/school/tasks/:id/completions` - 获取任务完成情况分页 -- `PUT /api/v1/school/tasks/:taskId/completions/:studentId` - 更新任务完成状态 - -#### 任务模板接口 -- `GET /api/v1/school/task-templates` - 获取任务模板列表 -- `GET /api/v1/school/task-templates/:id` - 获取单个模板 -- `GET /api/v1/school/task-templates/default/:taskType` - 获取默认模板 -- `POST /api/v1/school/task-templates` - 创建模板 -- `PUT /api/v1/school/task-templates/:id` - 更新模板 -- `DELETE /api/v1/school/task-templates/:id` - 删除模板 -- `POST /api/v1/school/tasks/from-template` - 从模板创建任务 - -### 2. 通知相关接口 - -#### 学校管理员通知(SchoolNotificationController - 新增) -- `GET /api/v1/school/notifications` - 获取通知列表 -- `GET /api/v1/school/notifications/:id` - 根据 ID 获取通知 -- `GET /api/v1/school/notifications/unread-count` - 获取未读数量 -- `POST /api/v1/school/notifications/:id/read` - 标记已读 -- `POST /api/v1/school/notifications/read-all` - 全部标记已读 - -### 3. 排课和课表相关接口(SchoolScheduleController) -- `GET /api/v1/school/schedules/timetable` - 获取课表(带日期范围) -- `POST /api/v1/school/schedules/batch` - 批量创建排课 -- `GET /api/v1/school/schedules/templates/:id` - 获取单个模板 -- `PUT /api/v1/school/schedules/templates/:id` - 更新模板 -- `POST /api/v1/school/schedules/templates/:id/apply` - 应用模板 - -### 4. 新增 DTO -- `TaskTemplateCreateRequest` - 任务模板创建请求 -- `TaskTemplateUpdateRequest` - 任务模板更新请求 -- `CreateTaskFromTemplateRequest` - 从模板创建任务请求 -- `SchedulePlanCreateRequest` - 课表计划创建请求 -- `ScheduleTemplateApplyRequest` - 课表模板应用请求 - ---- - -## 仍需补全的接口 - -### P1 - 重要功能 - -#### 1. 成长档案接口(SchoolGrowthController, TeacherGrowthController) -- `GET /api/v1/school/students/:studentId/growth-records` - 按学生查询成长档案 -- `GET /api/v1/school/classes/:classId/growth-records` - 按班级查询成长档案 -- `GET /api/v1/teacher/classes/:classId/growth-records` - 教师端按班级查询 - -#### 2. 教师端课时增强接口(TeacherLessonController) -- `POST /api/v1/teacher/lessons/:id/finish` - 完成课时(带反馈数据) -- `POST /api/v1/teacher/lessons/:id/students/:studentId/record` - 保存学生记录 -- `GET /api/v1/teacher/lessons/:id/student-records` - 获取学生记录 -- `POST /api/v1/teacher/lessons/:id/student-records/batch` - 批量保存学生记录 -- `POST /api/v1/teacher/lessons/:id/feedback` - 提交反馈 -- `GET /api/v1/teacher/lessons/:id/feedback` - 获取反馈 - -#### 3. 教师端课程增强接口(TeacherCourseController) -- `GET /api/v1/teacher/courses/classes` - 获取班级列表 -- `GET /api/v1/teacher/students` - 获取所有学生 -- `GET /api/v1/teacher/classes/:id/students` - 获取班级学生 -- `GET /api/v1/teacher/classes/:id/teachers` - 获取班级教师 -- `GET /api/v1/teacher/schedules/timetable` - 获取课表 -- `GET /api/v1/teacher/schedules/today` - 获取今天排课 -- `POST /api/v1/teacher/schedules` - 创建排课 -- `PUT /api/v1/teacher/schedules/:id` - 更新排课 -- `DELETE /api/v1/teacher/schedules/:id` - 取消排课 - -#### 4. 班级管理接口(SchoolClassController) -- `GET /api/v1/school/classes/:id/students` - 获取班级学生 -- `GET /api/v1/school/classes/:id/teachers` - 获取班级教师 -- `POST /api/v1/school/classes/:id/teachers` - 添加班级教师 -- `PUT /api/v1/school/classes/:id/teachers/:teacherId` - 更新班级教师 -- `DELETE /api/v1/school/classes/:id/teachers/:teacherId` - 移除班级教师 -- `POST /api/v1/school/students/:id/transfer` - 学生调班 -- `GET /api/v1/school/students/:id/history` - 学生调班历史 -- `POST /api/v1/school/students/import` - 批量导入学生 -- `GET /api/v1/school/students/import/template` - 获取导入模板 - -### P2 - 辅助功能 - -#### 1. 统计报告接口(SchoolStatsController) -- `GET /api/v1/school/stats/teachers` - 活跃教师统计 -- `GET /api/v1/school/stats/courses` - 课程使用统计 -- `GET /api/v1/school/stats/activities` - 最近活动 -- `GET /api/v1/school/stats/lesson-trend` - 课时趋势 -- `GET /api/v1/school/stats/course-distribution` - 课程分布 -- `GET /api/v1/school/reports/overview` - 概览报告 -- `GET /api/v1/school/reports/teachers` - 教师报告 -- `GET /api/v1/school/reports/courses` - 课程报告 -- `GET /api/v1/school/reports/students` - 学生报告 - -#### 2. 导出接口增强(SchoolExportController) -- `GET /api/v1/school/export/lessons?startDate=&endDate=` - 导出课时(带日期范围) -- `GET /api/v1/school/export/teacher-stats?startDate=&endDate=` - 导出教师统计 -- `GET /api/v1/school/export/student-stats?classId=` - 导出学生统计(按班级) - -#### 3. 课程包/套餐接口 -- `GET /api/v1/school/package` - 获取套餐信息 -- `GET /api/v1/school/package/usage` - 获取套餐使用情况 - -#### 4. 家长相关接口 -- `POST /api/v1/school/parents/:parentId/children/:studentId` - 添加孩子到家长 -- `DELETE /api/v1/school/parents/:parentId/children/:studentId` - 从家长移除孩子 - -#### 5. 管理员课程接口 -- `GET /api/v1/admin/courses/:id/stats` - 课程统计 -- `GET /api/v1/admin/courses/:id/validate` - 验证课程 -- `GET /api/v1/admin/courses/:id/versions` - 版本历史 -- `POST /api/v1/admin/courses/:id/submit` - 提交审核 -- `POST /api/v1/admin/courses/:id/withdraw` - 撤销审核 -- `POST /api/v1/admin/courses/:id/approve` - 审核通过 -- `POST /api/v1/admin/courses/:id/reject` - 审核驳回 -- `POST /api/v1/admin/courses/:id/direct-publish` - 直接发布 -- `POST /api/v1/admin/courses/:id/publish` - 发布 -- `POST /api/v1/admin/courses/:id/unpublish` - 下架 -- `POST /api/v1/admin/courses/:id/republish` - 重新发布 - -#### 6. 资源接口增强 -- `POST /api/v1/admin/resources/items/batch-delete` - 批量删除资源项 -- `GET /api/v1/admin/resources/stats` - 资源统计 - -#### 7. 反馈接口 -- `GET /api/v1/teacher/feedbacks` - 获取反馈列表 -- `GET /api/v1/teacher/feedbacks/stats` - 获取反馈统计 -- `GET /api/v1/school/feedbacks` - 获取反馈列表(学校端) -- `GET /api/v1/school/feedbacks/stats` - 获取反馈统计(学校端) - -#### 8. 认证接口 -- `GET /api/v1/auth/profile` - 获取用户信息 -- `POST /api/v1/auth/logout` - 登出 - ---- - -## 总结 - -本次补全了以下主要功能: -1. 任务管理:统计、模板、完成情况更新 -2. 通知:学校管理员通知接口 -3. 排课:课表模板、批量创建、应用模板 - -下一步建议优先补全: -1. 成长档案按学生/班级查询接口 -2. 教师端课时反馈接口 -3. 班级管理相关接口 -4. 学生调班和批量导入接口 diff --git a/Service 重构总结.md b/Service 重构总结.md deleted file mode 100644 index ac6deab..0000000 --- a/Service 重构总结.md +++ /dev/null @@ -1,132 +0,0 @@ -# Service 层重构总结 - -## 重构时间 -2026-03-10 - -## 重构目的 -将 Service 层从"直接 class 实现"重构为"interface + impl"模式,符合 Spring 最佳实践。 - -## 重构的 Service 列表 - -本次重构共完成了 14 个 Service 的 interface + impl 模式改造: - -### 新增的 Interface 文件 - -| 序号 | 接口文件 | 实现类文件 | -|------|----------|------------| -| 1 | `AdminStatsService.java` | `AdminStatsServiceImpl.java` | -| 2 | `CourseLessonService.java` | `CourseLessonServiceImpl.java` | -| 3 | `CoursePackageService.java` | `CoursePackageServiceImpl.java` | -| 4 | `ExportService.java` | `ExportServiceImpl.java` | -| 5 | `FileUploadService.java` | `FileUploadServiceImpl.java` | -| 6 | `OperationLogService.java` | `OperationLogServiceImpl.java` | -| 7 | `ResourceService.java` | `ResourceServiceImpl.java` | -| 8 | `SchoolCourseService.java` | `SchoolCourseServiceImpl.java` | -| 9 | `SystemSettingService.java` | `SystemSettingServiceImpl.java` | -| 10 | `TeacherDashboardService.java` | `TeacherDashboardServiceImpl.java` | -| 11 | `ScheduleService.java` | `ScheduleServiceImpl.java` | -| 12 | `ThemeService.java` | `ThemeServiceImpl.java` | -| 13 | `TenantService.java` | `TenantServiceImpl.java` (已存在) | -| 14 | `SchoolStatsService.java` | `SchoolStatsServiceImpl.java` | - -### 已有的 Interface + Impl 模式 Service - -以下 Service 在重构前已经是 interface + impl 模式: - -1. `AuthService` → `AuthServiceImpl` -2. `ClassService` → `ClassServiceImpl` -3. `StudentService` → `StudentServiceImpl` -4. `TaskService` → `TaskServiceImpl` -5. `CourseService` → `CourseServiceImpl` -6. `GrowthRecordService` → `GrowthRecordServiceImpl` -7. `LessonService` → `LessonServiceImpl` -8. `NotificationService` → `NotificationServiceImpl` -9. `ParentService` → `ParentServiceImpl` -10. `TeacherService` → `TeacherServiceImpl` -11. `TokenService` → `TokenServiceImpl` - -## 重构模式 - -所有 Service 遵循以下模式: - -### Interface 定义 -```java -package com.reading.platform.service; - -import java.util.List; -import java.util.Map; - -/** - * 服务接口 - */ -public interface XxxService { - - /** - * 方法描述 - */ - List getXxxList(Long id); - - /** - * 方法描述 - */ - Xxx createXxx(XxxCreateRequest request); -} -``` - -### Impl 实现类 -```java -package com.reading.platform.service.impl; - -import com.reading.platform.mapper.XxxMapper; -import com.reading.platform.service.XxxService; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -/** - * 服务实现类 - */ -@Service -@RequiredArgsConstructor -public class XxxServiceImpl implements XxxService { - - private final XxxMapper xxxMapper; - - @Override - public List getXxxList(Long id) { - // 业务逻辑 - } - - @Override - public Xxx createXxx(XxxCreateRequest request) { - // 业务逻辑 - } -} -``` - -## 架构优势 - -1. **依赖倒置**:Controller 依赖接口而非具体实现 -2. **易于测试**:可以通过 Mock 接口进行测试 -3. **易于扩展**:可以轻松切换不同的实现 -4. **代码规范**:符合 Spring 官方推荐的最佳实践 - -## 编译验证 - -```bash -cd reading-platform-java -mvn clean compile -DskipTests -``` - -编译结果:**BUILD SUCCESS** - -## 文件统计 - -- 接口文件:25 个 -- 实现类文件:25 个 -- 总计:50 个 Service 相关文件 - -## 后续建议 - -1. 为新实现的接口添加单元测试 -2. 在 CI/CD 流程中确保编译使用 JDK 17 -3. 保持新增 Service 遵循 interface + impl 模式 diff --git a/reading-platform-frontend/src/apis/SwaggerType.ts b/reading-platform-frontend/src/apis/SwaggerType.ts new file mode 100644 index 0000000..770ee5b --- /dev/null +++ b/reading-platform-frontend/src/apis/SwaggerType.ts @@ -0,0 +1,18 @@ +// type Swagger = 'get' | 'post'; +// http://192.168.1.110:8280/stat/doc.html#/home +export interface RequestType { + param: { + path?: string[] | number[] | string | number; + query?: { [key: string]: string | number }; + data?: { [key: string]: string | number }; + }; + response: any; +} +export interface SwaggerType { + [key: string]: { + get?: RequestType; + post?: RequestType; + put?: RequestType; + delete?: RequestType; + }; +} diff --git a/reading-platform-frontend/src/apis/apis.ts b/reading-platform-frontend/src/apis/apis.ts new file mode 100644 index 0000000..c153404 --- /dev/null +++ b/reading-platform-frontend/src/apis/apis.ts @@ -0,0 +1,55 @@ +import { SwaggerType } from './SwaggerType'; +export default interface SwaggerInterface extends SwaggerType { + /*** + * 视频大盘-卡片核心指标 + */ + '/test/xxxx': { + get: { + param: { + query: { + /**统计类型:1=周,2=月,3=季度,4=年,5=自定义 */ + type: number; + /**开始日期(yyyy-MM-dd),type=5 时必填 */ + startDate?: string; + /**结束日期(yyyy-MM-dd),type=5 时必填 */ + endDate?: string; + /**机构ID,不传则从登录用户部门获取 */ + institutionId?: number; + /**分类ID */ + categoryId?: number; + }; + }; + response: { + /**访问人次 */ + userCount: { + /**数值 */ + value: number; + /**环比百分比 */ + ratio: number; + }; + /**点击量 */ + clickCount: { + value: number; + ratio: number; + }; + /**观看时长(小时) */ + watchDuration: { + value: number; + ratio: number; + }; + /**请求数 */ + requestCount: { + value: number; + ratio: number; + }; + /**出口流量(GB) */ + trafficOut: { + value: number; + ratio: number; + }; + /**存储用量,暂未实现 */ + storageUsage: null; + }; + }; + }; +} diff --git a/reading-platform-frontend/src/apis/fetch.ts b/reading-platform-frontend/src/apis/fetch.ts new file mode 100644 index 0000000..bed9156 --- /dev/null +++ b/reading-platform-frontend/src/apis/fetch.ts @@ -0,0 +1,234 @@ +import type { UrlKey, MethodKey, Param, Response } from './index'; +// import { message } from 'ant-design-vue'; +// import { LocalStorageKey } from '@/utils/useLocalStorage'; +// import { getAppEnvConfig } from '@/utils/env'; +import { reactive, ref } from 'vue'; +import { defHttp } from '/@/utils/http/axios'; +// const { VITE_BASE_API, VITE_PREFIX_API } = getAppEnvConfig(); +export type FetchOptions = Omit & { + type?: 'arrayBuffer' | 'blob' | 'formData' | 'json' | 'text'; + payloadType?: 'json' | 'text' | 'formData' | 'form-urlencoded'; + successMsg?: string; + noMsg?: boolean; + apiType?: 'BOOK'; +}; + +// const payloadMapping = { +// json: 'application/json;charset=UTF-8', +// text: 'text/plain;charset=UTF-8', +// formData: 'multipart/form-data', +// 'form-urlencoded': 'application/x-www-form-urlencoded', +// }; + +// // const noAuthUrl: UrlKey[] = ['/activity/bbs/login', '/activity/bbs/randomImage', '/activity/bbs/bbsSection/all', '/activity/bbs/bbsPost/list', '/activity/bbs/bbsPost/queryById']; +// const noAuthUrl: UrlKey[] = ['/activity/bbs/login', '/activity/bbs/randomImage']; +// function useAuthToken() { +// // const _token = localStorage.getItem(LocalStorageKey.tokenKey); +// return { +// token: '', +// // token: _token && _token.trim().length > 0 ? _token : null, +// }; +// } + +/** + * 请求header + * @description: contentTyp + */ +export enum ConfigEnum { + // TOKEN + TOKEN = 'Authorization', + XTOKEN = 'X-Access-Token', + // TIMESTAMP + TIMESTAMP = 'X-TIMESTAMP', + // Sign + Sign = 'X-Sign', + // 租户id + TENANT_ID = 'X-Tenant-Id', + // 版本 + VERSION = 'X-Version', + // 低代码应用ID + X_LOW_APP_ID = 'X-Low-App-ID', +} + +// export const baseToken = ref(useAuthToken().token); +// export function getHeaders() { +// const defaultHeaders = { +// // "Content-Type": payloadMapping[payloadType] +// }; + +// let authHeaders = { +// Authorization: `Bearer ${baseToken.value}`, +// }; +// return Object.assign(defaultHeaders, authHeaders); +// } + +type MethodType = 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE' | 'CONNECT'; +/** + * + * @param url 路径,直接从swagger上拷贝下来的路径,包括{id}这类的动态路径 + * @param param FetchParams 请求参数,分为 path query body 分别对应 路径参数(类似/delete/{id})、查询参数(类似/query?id=123)、body(post body参数,将会JSON.stringfiy为字符串) + * @param options FetchOptions fetch 去除body、method的原生参数,增加 type 用于格式化掉用res.json()类型的功能。 + * @returns fetch + */ +export default async function request>( + url: U, + method: M, + params?: Param | undefined, + { apiType, type = 'json', payloadType = 'json', successMsg, noMsg, headers, ...restOptions }: FetchOptions = {} +): Promise> { + const requestMethod = (method as string).toLowerCase() as MethodType; + + const { path, query, data } = (params || {}) as { + path?: string[] | string; + query?: any; + data?: any; + }; + // let iUrl = `${VITE_BASE_API}${VITE_PREFIX_API}${url}`; + let iUrl = `${url}`; + + if (path) { + if (Array.isArray(path)) { + iUrl = `${iUrl}/${path.join('/')}`; + } else { + iUrl = `${iUrl}/${path}`; + } + } + iUrl = getQuery(iUrl, filterEmpty(query)); + + return defHttp.request({ + method: requestMethod, + url: iUrl, + data: filterEmpty(data), + }); + + // const defaultHeaders = { + // 'Content-Type': payloadMapping[payloadType], + // }; + + // // 将token加入进去 + // let authHeaders: any = { + // // 'Content-Type': 'application/json' + // }; + // if (!noAuthUrl.includes(url)) { + // // const { token } = useAuthToken(); + // authHeaders[ConfigEnum.TOKEN] = baseToken.value ? `Bearer ${baseToken.value}` : ''; + // // authHeaders[ConfigEnum.XTOKEN] = token; + // } + // const param: any = { + // ...restOptions, + // method: requestMethod, + // // body: JSON.stringify(filterEmpty(data)), + // headers: Object.assign(defaultHeaders, headers, authHeaders), + // }; + // if (requestMethod.toLowerCase() !== 'get') { + // param.body = JSON.stringify(filterEmpty(data)); + // } + // return fetch(iUrl, param) + // .then((response) => response.json()) + // .then((res: any) => { + // if (res.code === 200 || res.code === 0) { + // if (requestMethod.toLowerCase() != 'get' || successMsg) { + // if (!noMsg) { + // showToast(successMsg || '操作成功', 'success'); + // } + // } + // return res.result; + // } else if (res.code === 401) { + // baseToken.value = null; + // showToast('登录已过期', 'error'); + // } else { + // let msg = res.message; + // if (res.code === 402) { + // } else if (res.code === 403) { + // } else { + // } + // showToast(msg, 'error'); + // } + + // throw new Error(JSON.stringify(res)); + // }) + // .catch((err) => { + // console.error('fetch Error', err); + + // throw err; + // }); +} +function filterEmpty(obj: any = {}): any { + const _obj: any = {}; + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + const element = obj[key]; + if (!(element === null || element === undefined || String(element).trim().length < 1)) { + _obj[key] = element; + } + } + } + return _obj; +} + +function getQuery(iUrl: string, query: { [key: string]: string }): string { + if (!query) { + return iUrl; + } + const keys: string[] = []; + for (const key in query) { + keys.push(`${key}=${query[key]}`); + } + return `${iUrl}?${keys.join('&')}`; +} + +// type MsgType = 'error' | 'success' | 'loading' | 'info' | 'warning'; +// function showToast(msg: string, type: MsgType) { +// message[type](msg); +// } + +type CallbackObjs = { + loading: boolean; + callback: Function[][]; +}; +type Requests = { + userOpenid: CallbackObjs; +}; +type RequestsName = keyof Requests; +const requests = reactive({ + userOpenid: { + loading: false, + callback: [], + }, +}); +/** + * + * 请求节流封装 + * @param name 求节nameKey + * @param requestCallback + * @returns + */ +export async function getRequests(name: RequestsName, requestCallback: Function) { + // const requestInfo = requests[name]; + // + if (requests[name].loading) { + return new Promise<[]>((resolve, reject) => { + requests[name].callback.push([resolve, reject]); + }); + } + requests[name].loading = true; + + try { + const data = await requestCallback(); + requests[name].callback.forEach((callbacks) => { + const [resolve, reject] = callbacks; + !!resolve && resolve(data); + }); + requests[name].loading = false; + requests[name].callback = []; + return data; + } catch (error) { + requests[name].callback.forEach((callbacks) => { + const [resolve, reject] = callbacks; + reject([]); + }); + } finally { + requests[name].loading = false; + requests[name].callback = []; + } +} diff --git a/reading-platform-frontend/src/apis/index.ts b/reading-platform-frontend/src/apis/index.ts new file mode 100644 index 0000000..8c3d582 --- /dev/null +++ b/reading-platform-frontend/src/apis/index.ts @@ -0,0 +1,24 @@ +import apis from './apis'; +type SwaggerInterface = apis; + +export type UrlKey = keyof SwaggerInterface; +export type MethodKey = string & keyof SwaggerInterface[U]; + +type SwaggerInterfaceSingle> = SwaggerInterface[U][M]; +type SwaggerField> = keyof SwaggerInterfaceSingle; +type SwaggerFieldType< + U extends UrlKey, + M extends MethodKey, + F extends SwaggerField, +> = SwaggerInterfaceSingle[F]; + +export type Param> = SwaggerFieldType< + U, + M, + 'param' & SwaggerField +>; +export type Response> = SwaggerFieldType< + U, + M, + 'response' & SwaggerField +>; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeacher.java b/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeacher.java index 86d6ef3..ca6da84 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeacher.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeacher.java @@ -1,29 +1,56 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; /** - * 班级-教师关联实体 + * 班级 - 教师关联实体 */ @Data @TableName("class_teachers") +@Schema(description = "班级教师关联") public class ClassTeacher { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long classId; + private String classId; - private Long teacherId; + private String teacherId; private String role; + /** + * 是否主教 + */ + private Boolean isPrimary; + + /** + * 排序 + */ + private Integer sortOrder; + + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updatedAt; + + @Schema(description = "逻辑删除标志", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeachers.java b/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeachers.java new file mode 100644 index 0000000..3994ee3 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeachers.java @@ -0,0 +1,57 @@ +package com.reading.platform.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 班级-教师关联实体 + */ +@Data +@TableName("class_teachers") +@Schema(description = "班级教师关联") +public class ClassTeacher { + + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; + + private String classId; + + private String teacherId; + + private String role; + + /** + * 是否主教 + */ + private Boolean isPrimary; + + /** + * 排序 + */ + private Integer sortOrder; + + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createdAt; + + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updatedAt; + + @Schema(description = "逻辑删除标志", accessMode = Schema.AccessMode.READ_ONLY) + @TableLogic + private Integer deleted; + +} diff --git a/前端实际调用接口对比.md b/前端实际调用接口对比.md deleted file mode 100644 index a98dd5b..0000000 --- a/前端实际调用接口对比.md +++ /dev/null @@ -1,346 +0,0 @@ -# 前端实际调用但 Java 后端缺失的接口 - -## 分析方法 -- 对比 `reading-platform-frontend/src/api/generated/api.ts` 中的实际调用 -- 检查 `reading-platform-java/src/main/java/com/reading/platform/controller` 中的实现 -- 只列出前端实际调用但 Java 后端缺失的接口 - ---- - -## ✅ 已实现的接口列表 - -### 1. 认证接口 (AuthController) -- ✅ `POST /api/v1/auth/login` - 登录 -- ✅ `POST /api/v1/auth/logout` - 登出 -- ✅ `POST /api/v1/auth/change-password` - 修改密码 -- ✅ `GET /api/v1/auth/me` - 获取当前用户信息 - -### 2. 文件接口 (FileUploadController) -- ✅ `POST /api/v1/files/upload` - 上传文件 -- ✅ `DELETE /api/v1/files/delete` - 删除文件 - -### 3. 教师端 - 任务 (TeacherTaskController) -- ✅ `GET /api/v1/teacher/tasks` - 获取任务分页 -- ✅ `POST /api/v1/teacher/tasks` - 创建任务 -- ✅ `GET /api/v1/teacher/tasks/{id}` - 根据 ID 获取任务 -- ✅ `PUT /api/v1/teacher/tasks/{id}` - 更新任务 -- ✅ `DELETE /api/v1/teacher/tasks/{id}` - 删除任务 - -### 4. 教师端 - 课时 (TeacherLessonController) -- ✅ `GET /api/v1/teacher/lessons` - 获取课时分页 -- ✅ `POST /api/v1/teacher/lessons` - 创建课时 -- ✅ `GET /api/v1/teacher/lessons/{id}` - 根据 ID 获取课时 -- ✅ `PUT /api/v1/teacher/lessons/{id}` - 更新课时 -- ✅ `POST /api/v1/teacher/lessons/{id}/start` - 开始课时 -- ✅ `POST /api/v1/teacher/lessons/{id}/complete` - 完成课时 -- ✅ `POST /api/v1/teacher/lessons/{id}/cancel` - 取消课时 -- ✅ `GET /api/v1/teacher/lessons/today` - 获取今天课时 - -### 5. 教师端 - 成长档案 (TeacherGrowthController) -- ✅ `GET /api/v1/teacher/growth-records` - 获取成长档案分页 -- ✅ `POST /api/v1/teacher/growth-records` - 创建成长档案 -- ✅ `GET /api/v1/teacher/growth-records/{id}` - 根据 ID 获取成长档案 -- ✅ `PUT /api/v1/teacher/growth-records/{id}` - 更新成长档案 -- ✅ `DELETE /api/v1/teacher/growth-records/{id}` - 删除成长档案 - -### 6. 教师端 - 通知 (TeacherNotificationController) -- ✅ `GET /api/v1/teacher/notifications` - 获取通知分页 -- ✅ `GET /api/v1/teacher/notifications/{id}` - 根据 ID 获取通知 -- ✅ `GET /api/v1/teacher/notifications/unread-count` - 获取未读数量 -- ✅ `POST /api/v1/teacher/notifications/{id}/read` - 标记已读 -- ✅ `POST /api/v1/teacher/notifications/read-all` - 全部标记已读 - -### 7. 教师端 - 课程 (TeacherCourseController) -- ✅ `GET /api/v1/teacher/courses` - 获取课程分页 -- ✅ `GET /api/v1/teacher/courses/{id}` - 根据 ID 获取课程 -- ✅ `GET /api/v1/teacher/courses/all` - 获取所有课程 - -### 8. 教师端 - 课程课时 (TeacherCourseLessonController) -- ✅ `GET /api/v1/teacher/courses/{courseId}/lessons` - 获取课程课时列表 -- ✅ `GET /api/v1/teacher/courses/{courseId}/lessons/{id}` - 根据 ID 获取课时 - -### 9. 教师端 - 校本课程 (TeacherSchoolCourseController) -- ✅ `GET /api/v1/teacher/school-courses` - 获取校本课程分页 -- ✅ `GET /api/v1/teacher/school-courses/{id}` - 根据 ID 获取校本课程 - -### 10. 教师端 - 课表 (TeacherScheduleController) -- ✅ `GET /api/v1/teacher/schedules` - 获取课表计划分页 -- ✅ `GET /api/v1/teacher/schedules/{id}` - 根据 ID 获取课表计划 - -### 11. 教师端 - 仪表板 (TeacherDashboardController) -- ✅ `GET /api/v1/teacher/dashboard` - 获取仪表板数据 -- ✅ `GET /api/v1/teacher/dashboard/weekly` - 获取周统计 -- ✅ `GET /api/v1/teacher/dashboard/today` - 获取今天数据 - -### 12. 学校管理员 - 教师 (SchoolTeacherController) -- ✅ `GET /api/v1/school/teachers` - 获取教师分页 -- ✅ `POST /api/v1/school/teachers` - 创建教师 -- ✅ `GET /api/v1/school/teachers/{id}` - 根据 ID 获取教师 -- ✅ `PUT /api/v1/school/teachers/{id}` - 更新教师 -- ✅ `DELETE /api/v1/school/teachers/{id}` - 删除教师 -- ✅ `POST /api/v1/school/teachers/{id}/reset-password` - 重置密码 - -### 13. 学校管理员 - 任务 (SchoolTaskController) -- ✅ `GET /api/v1/school/tasks` - 获取任务分页 -- ✅ `POST /api/v1/school/tasks` - 创建任务 -- ✅ `GET /api/v1/school/tasks/{id}` - 根据 ID 获取任务 -- ✅ `PUT /api/v1/school/tasks/{id}` - 更新任务 -- ✅ `DELETE /api/v1/school/tasks/{id}` - 删除任务 - -### 14. 学校管理员 - 学生 (SchoolStudentController) -- ✅ `GET /api/v1/school/students` - 获取学生分页 -- ✅ `POST /api/v1/school/students` - 创建学生 -- ✅ `GET /api/v1/school/students/{id}` - 根据 ID 获取学生 -- ✅ `PUT /api/v1/school/students/{id}` - 更新学生 -- ✅ `DELETE /api/v1/school/students/{id}` - 删除学生 - -### 15. 学校管理员 - 校本课程 (SchoolCourseController) -- ✅ `GET /api/v1/school/school-courses` - 获取校本课程分页 -- ✅ `POST /api/v1/school/school-courses` - 创建校本课程 -- ✅ `GET /api/v1/school/school-courses/{id}` - 根据 ID 获取校本课程 -- ✅ `PUT /api/v1/school/school-courses/{id}` - 更新校本课程 -- ✅ `DELETE /api/v1/school/school-courses/{id}` - 删除校本课程 - -### 16. 学校管理员 - 课表 (SchoolScheduleController) -- ✅ `GET /api/v1/school/schedules` - 获取课表计划分页 -- ✅ `POST /api/v1/school/schedules` - 创建课表计划 -- ✅ `GET /api/v1/school/schedules/{id}` - 根据 ID 获取课表计划 -- ✅ `PUT /api/v1/school/schedules/{id}` - 更新课表计划 -- ✅ `DELETE /api/v1/school/schedules/{id}` - 删除课表计划 -- ✅ `GET /api/v1/school/schedules/templates` - 获取课表模板分页 -- ✅ `POST /api/v1/school/schedules/templates` - 创建课表模板 -- ✅ `GET /api/v1/school/schedules/templates/{id}` - 根据 ID 获取课表模板 -- ✅ `PUT /api/v1/school/schedules/templates/{id}` - 更新课表模板 -- ✅ `DELETE /api/v1/school/schedules/templates/{id}` - 删除课表模板 -- ✅ `POST /api/v1/school/schedules/templates/{id}/apply` - 应用课表模板 - -### 17. 学校管理员 - 家长 (SchoolParentController) -- ✅ `GET /api/v1/school/parents` - 获取家长分页 -- ✅ `POST /api/v1/school/parents` - 创建家长 -- ✅ `GET /api/v1/school/parents/{id}` - 根据 ID 获取家长 -- ✅ `PUT /api/v1/school/parents/{id}` - 更新家长 -- ✅ `DELETE /api/v1/school/parents/{id}` - 删除家长 -- ✅ `POST /api/v1/school/parents/{id}/reset-password` - 重置密码 -- ✅ `POST /api/v1/school/parents/{parentId}/students/{studentId}` - 绑定学生 -- ✅ `DELETE /api/v1/school/parents/{parentId}/students/{studentId}` - 解绑学生 - -### 18. 学校管理员 - 成长档案 (SchoolGrowthController) -- ✅ `GET /api/v1/school/growth-records` - 获取成长档案分页 -- ✅ `POST /api/v1/school/growth-records` - 创建成长档案 -- ✅ `GET /api/v1/school/growth-records/{id}` - 根据 ID 获取成长档案 -- ✅ `PUT /api/v1/school/growth-records/{id}` - 更新成长档案 -- ✅ `DELETE /api/v1/school/growth-records/{id}` - 删除成长档案 - -### 19. 学校管理员 - 班级 (SchoolClassController) -- ✅ `GET /api/v1/school/classes` - 获取班级分页 -- ✅ `POST /api/v1/school/classes` - 创建班级 -- ✅ `GET /api/v1/school/classes/{id}` - 根据 ID 获取班级 -- ✅ `PUT /api/v1/school/classes/{id}` - 更新班级 -- ✅ `DELETE /api/v1/school/classes/{id}` - 删除班级 -- ✅ `POST /api/v1/school/classes/{id}/teachers` - 分配教师到班级 -- ✅ `POST /api/v1/school/classes/{id}/students` - 分配学生到班级 - -### 20. 学校管理员 - 通知 (SchoolNotificationController) -- ✅ `GET /api/v1/school/notifications` - 获取通知分页 -- ✅ `GET /api/v1/school/notifications/{id}` - 根据 ID 获取通知 -- ✅ `GET /api/v1/school/notifications/unread-count` - 获取未读数量 -- ✅ `POST /api/v1/school/notifications/{id}/read` - 标记已读 -- ✅ `POST /api/v1/school/notifications/read-all` - 全部标记已读 - -### 21. 学校管理员 - 统计 (SchoolStatsController) -- ✅ `GET /api/v1/school/stats` - 获取统计数据 - -### 22. 学校管理员 - 操作日志 (SchoolOperationLogController) -- ✅ `GET /api/v1/school/operation-logs` - 获取操作日志分页 - -### 23. 学校管理员 - 导出 (SchoolExportController) -- ✅ `GET /api/v1/school/export/teachers` - 导出教师数据 -- ✅ `GET /api/v1/school/export/students` - 导出学生数据 -- ✅ `GET /api/v1/school/export/lessons` - 导出课时数据 -- ✅ `GET /api/v1/school/export/growth-records` - 导出成长档案 - -### 24. 学校管理员 - 课程包 (SchoolCoursePackageController) -- ✅ `GET /api/v1/school/course-packages` - 获取课程包分页 -- ✅ `GET /api/v1/school/course-packages/{id}` - 根据 ID 获取课程包 - -### 25. 家长端 - 孩子 (ParentChildController) -- ✅ `GET /api/v1/parent/children` - 获取我的孩子 -- ✅ `GET /api/v1/parent/children/{id}` - 根据 ID 获取孩子 - -### 26. 家长端 - 任务 (ParentTaskController) -- ✅ `GET /api/v1/parent/tasks/{id}` - 根据 ID 获取任务 -- ✅ `GET /api/v1/parent/tasks/student/{studentId}` - 根据学生 ID 获取任务 -- ✅ `POST /api/v1/parent/tasks/{taskId}/complete` - 完成任务 - -### 27. 家长端 - 通知 (ParentNotificationController) -- ✅ `GET /api/v1/parent/notifications` - 获取通知分页 -- ✅ `GET /api/v1/parent/notifications/{id}` - 根据 ID 获取通知 -- ✅ `GET /api/v1/parent/notifications/unread-count` - 获取未读数量 -- ✅ `POST /api/v1/parent/notifications/{id}/read` - 标记已读 -- ✅ `POST /api/v1/parent/notifications/read-all` - 全部标记已读 - -### 28. 家长端 - 成长档案 (ParentGrowthController) -- ✅ `GET /api/v1/parent/growth-records` - 获取成长档案分页 -- ✅ `POST /api/v1/parent/growth-records` - 创建成长档案 -- ✅ `GET /api/v1/parent/growth-records/{id}` - 根据 ID 获取成长档案 -- ✅ `PUT /api/v1/parent/growth-records/{id}` - 更新成长档案 -- ✅ `DELETE /api/v1/parent/growth-records/{id}` - 删除成长档案 -- ✅ `GET /api/v1/parent/growth-records/student/{studentId}` - 根据学生 ID 获取成长档案 -- ✅ `GET /api/v1/parent/growth-records/student/{studentId}/recent` - 获取最近成长档案 - -### 29. 管理员端 - 租户 (AdminTenantController) -- ✅ `GET /api/v1/admin/tenants` - 获取租户分页 -- ✅ `POST /api/v1/admin/tenants` - 创建租户 -- ✅ `GET /api/v1/admin/tenants/{id}` - 根据 ID 获取租户 -- ✅ `PUT /api/v1/admin/tenants/{id}` - 更新租户 -- ✅ `DELETE /api/v1/admin/tenants/{id}` - 删除租户 -- ✅ `GET /api/v1/admin/tenants/active` - 获取活跃租户 -- ✅ `PUT /api/v1/admin/tenants/{id}/status` - 更新租户状态 -- ✅ `PUT /api/v1/admin/tenants/{id}/quota` - 更新租户配额 -- ✅ `POST /api/v1/admin/tenants/{id}/reset-password` - 重置密码 - -### 30. 管理员端 - 主题 (AdminThemeController) -- ✅ `GET /api/v1/admin/themes` - 获取主题分页 -- ✅ `POST /api/v1/admin/themes` - 创建主题 -- ✅ `GET /api/v1/admin/themes/{id}` - 根据 ID 获取主题 -- ✅ `PUT /api/v1/admin/themes/{id}` - 更新主题 -- ✅ `DELETE /api/v1/admin/themes/{id}` - 删除主题 - -### 31. 管理员端 - 资源 (AdminResourceController) -- ✅ `GET /api/v1/admin/resources/libraries` - 获取资源库分页 -- ✅ `POST /api/v1/admin/resources/libraries` - 创建资源库 -- ✅ `GET /api/v1/admin/resources/libraries/{id}` - 根据 ID 获取资源库 -- ✅ `PUT /api/v1/admin/resources/libraries/{id}` - 更新资源库 -- ✅ `DELETE /api/v1/admin/resources/libraries/{id}` - 删除资源库 -- ✅ `GET /api/v1/admin/resources/items` - 获取资源项分页 -- ✅ `POST /api/v1/admin/resources/items` - 创建资源项 -- ✅ `GET /api/v1/admin/resources/items/{id}` - 根据 ID 获取资源项 -- ✅ `PUT /api/v1/admin/resources/items/{id}` - 更新资源项 -- ✅ `DELETE /api/v1/admin/resources/items/{id}` - 删除资源项 - -### 32. 管理员端 - 课程包 (AdminCoursePackageController) -- ✅ `GET /api/v1/admin/packages` - 获取课程包分页 -- ✅ `POST /api/v1/admin/packages` - 创建课程包 -- ✅ `GET /api/v1/admin/packages/{id}` - 根据 ID 获取课程包 -- ✅ `PUT /api/v1/admin/packages/{id}` - 更新课程包 -- ✅ `DELETE /api/v1/admin/packages/{id}` - 删除课程包 -- ✅ `POST /api/v1/admin/packages/{id}/submit` - 提交审核 -- ✅ `POST /api/v1/admin/packages/{id}/review` - 审核 -- ✅ `POST /api/v1/admin/packages/{id}/publish` - 发布 -- ✅ `POST /api/v1/admin/packages/{id}/offline` - 下架 - -### 33. 管理员端 - 课程 (AdminCourseController) -- ✅ `GET /api/v1/admin/courses` - 获取课程分页 -- ✅ `POST /api/v1/admin/courses` - 创建课程 -- ✅ `GET /api/v1/admin/courses/{id}` - 根据 ID 获取课程 -- ✅ `PUT /api/v1/admin/courses/{id}` - 更新课程 -- ✅ `DELETE /api/v1/admin/courses/{id}` - 删除课程 -- ✅ `GET /api/v1/admin/courses/review` - 获取待审核课程 -- ✅ `POST /api/v1/admin/courses/{id}/submit` - 提交审核 -- ✅ `POST /api/v1/admin/courses/{id}/approve` - 审核通过 -- ✅ `POST /api/v1/admin/courses/{id}/reject` - 审核驳回 -- ✅ `POST /api/v1/admin/courses/{id}/publish` - 发布 -- ✅ `POST /api/v1/admin/courses/{id}/direct-publish` - 直接发布 -- ✅ `POST /api/v1/admin/courses/{id}/withdraw` - 撤销审核 -- ✅ `POST /api/v1/admin/courses/{id}/unpublish` - 下架 -- ✅ `POST /api/v1/admin/courses/{id}/republish` - 重新发布 -- ✅ `POST /api/v1/admin/courses/{id}/archive` - 归档 - -### 34. 管理员端 - 课程课时 (AdminCourseLessonController) -- ✅ `GET /api/v1/admin/courses/{courseId}/lessons` - 获取课程课时列表 -- ✅ `POST /api/v1/admin/courses/{courseId}/lessons` - 创建课程课时 -- ✅ `GET /api/v1/admin/courses/{courseId}/lessons/{id}` - 根据 ID 获取课时 -- ✅ `PUT /api/v1/admin/courses/{courseId}/lessons/{id}` - 更新课程课时 -- ✅ `DELETE /api/v1/admin/courses/{courseId}/lessons/{id}` - 删除课程课时 - -### 35. 管理员端 - 统计 (AdminStatsController) -- ✅ `GET /api/v1/admin/stats` - 获取整体统计数据 -- ✅ `GET /api/v1/admin/stats/trend` - 获取趋势数据 -- ✅ `GET /api/v1/admin/stats/tenants/active` - 获取活跃租户 -- ✅ `GET /api/v1/admin/stats/courses/popular` - 获取热门课程 -- ✅ `GET /api/v1/admin/stats/activities` - 获取最近活动 - -### 36. 管理员端 - 操作日志 (AdminOperationLogController) -- ✅ `GET /api/v1/admin/operation-logs` - 获取操作日志分页 - -### 37. 管理员端 - 设置 (AdminSettingsController) -- ✅ `GET /api/v1/admin/settings` - 获取系统设置 -- ✅ `PUT /api/v1/admin/settings` - 更新系统设置 - ---- - -## ❌ 缺失接口列表 - -### 1. 学校管理员端 - 班级 (SchoolClassController) - -前端调用但 Java 后端缺失: -- ❌ `DELETE /api/v1/school/classes/{id}/teachers/{teacherId}` - 移除班级教师 -- ❌ `DELETE /api/v1/school/classes/{id}/students/{studentId}` - 移除班级学生 - -Java 后端已有: -- ✅ `POST /api/v1/school/classes/{id}/teachers` - 分配教师到班级 -- ✅ `POST /api/v1/school/classes/{id}/students` - 分配学生到班级 - -### 2. 学校管理员端 - 学生 (SchoolStudentController) - -前端调用但 Java 后端缺失: -- ❌ `POST /api/v1/school/students/import` - 批量导入学生 -- ❌ `GET /api/v1/school/students/import/template` - 获取导入模板 - ---- - -## 总结 - -绝大部分接口已经在 Java 后端实现,仅剩以下缺失接口需要补全: - -### P0 - 核心功能缺失(必须补全) -暂无 - -### P1 - 重要功能缺失 -暂无 - -### P2 - 辅助功能缺失 -暂无 - ---- - -## 本次补全的接口 - -### 1. 学校管理员端 - 班级 (SchoolClassController) -新增接口: -- ✅ `DELETE /api/v1/school/classes/{id}/teachers/{teacherId}` - 移除班级教师 -- ✅ `DELETE /api/v1/school/classes/{id}/students/{studentId}` - 移除班级学生 - -新增 Service 方法 (ClassService): -- `void removeTeacher(Long classId, Long teacherId)` -- `void removeStudent(Long classId, Long studentId)` - -### 2. 学校管理员端 - 学生 (SchoolStudentController) -新增接口: -- ✅ `POST /api/v1/school/students/import` - 批量导入学生 -- ✅ `GET /api/v1/school/students/import/template` - 获取导入模板 - -新增 Service 方法 (StudentService): -- `List importStudents(Long tenantId, List requests)` - -### 3. 学校统计接口 (SchoolStatsController + SchoolStatsService) -新增接口: -- ✅ `GET /api/v1/school/stats/teachers` - 获取活跃教师统计 -- ✅ `GET /api/v1/school/stats/courses` - 获取课程使用统计 -- ✅ `GET /api/v1/school/stats/activities` - 获取最近活动记录 -- ✅ `GET /api/v1/school/stats/lesson-trend` - 获取课时趋势(最近 N 个月) -- ✅ `GET /api/v1/school/stats/course-distribution` - 获取课程分布统计(饼图数据) - -新增 Service 方法 (SchoolStatsService): -- `List> getActiveTeachers(Long tenantId, Integer limit)` -- `List> getCourseUsageStats(Long tenantId)` -- `List> getRecentActivities(Long tenantId, Integer limit)` -- `List> getLessonTrend(Long tenantId, Integer months)` -- `List> getCourseDistribution(Long tenantId)` -- `String formatActivityTitle(Lesson lesson)` - 私有方法,格式化活动标题 - ---- - -## 最终结论 - -**前端实际调用的所有接口已在 Java 后端全部实现。** diff --git a/补全接口修复总结.md b/补全接口修复总结.md deleted file mode 100644 index 992dec6..0000000 --- a/补全接口修复总结.md +++ /dev/null @@ -1,228 +0,0 @@ -# API 接口补全修复总结 - -## 修复日期 -2026-03-09 - -## 问题修复 - -### Bug 修复 -修复了 `TaskServiceImpl.java` 中使用 `ClassEntity` 的错误,改为使用 `Clazz`(因为 `class` 是 Java 关键字,项目中使用 `Clazz` 作为班级实体名称)。 - -**修改位置**: `reading-platform-java/src/main/java/com/reading/platform/service/impl/TaskServiceImpl.java` -- 第 284 行:`List classes` → `List classes` -- 第 288 行:`for (ClassEntity cls : classes)` → `for (Clazz cls : classes)` - -### 数据库迁移 -新增数据库迁移脚本 `V7__fix_schedule_plans.sql`,为 `schedule_plans` 表添加以下字段: -- `course_id` - 课程 ID -- `teacher_id` - 教师 ID -- `day_of_week` - 星期几 (1-7) -- `period` - 节次 -- `start_time` - 开始时间 -- `end_time` - 结束时间 -- `location` - 教室/地点 -- `note` - 备注 - ---- - -## 已补全的 API 接口 - -### 1. 任务管理接口 - -#### 新增 Service 方法 (TaskService) -```java -// 任务统计 -Map getTaskStats(Long tenantId); -Map getStatsByType(Long tenantId); -List> getStatsByClass(Long tenantId); -List> getMonthlyStats(Long tenantId, Integer months); - -// 任务完成情况 -Page getTaskCompletions(Long tenantId, Long taskId, Integer pageNum, Integer pageSize, String status); -TaskCompletion updateTaskCompletion(Long tenantId, Long taskId, Long studentId, String status, String feedback); - -// 任务模板 -Page getTemplatePage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type); -TaskTemplate getTemplateById(Long tenantId, Long id); -TaskTemplate getDefaultTemplate(Long tenantId, String taskType); -TaskTemplate createTemplate(Long tenantId, Long creatorId, TaskTemplateCreateRequest request); -TaskTemplate updateTemplate(Long tenantId, Long id, TaskTemplateUpdateRequest request); -void deleteTemplate(Long tenantId, Long id); -Task createTaskFromTemplate(Long tenantId, Long creatorId, String creatorRole, CreateTaskFromTemplateRequest request); -``` - -#### 新增 Controller 端点 - -**SchoolTaskController** (学校管理员 - 任务管理): -- `GET /api/v1/school/tasks/stats` - 获取任务统计数据 -- `GET /api/v1/school/tasks/stats/by-type` - 按任务类型统计 -- `GET /api/v1/school/tasks/stats/by-class` - 按班级统计 -- `GET /api/v1/school/tasks/stats/monthly` - 月度统计趋势 -- `GET /api/v1/school/tasks/:id/completions` - 获取任务完成情况分页 -- `PUT /api/v1/school/tasks/:taskId/completions/:studentId` - 更新任务完成状态 -- `GET /api/v1/school/task-templates` - 获取任务模板列表 -- `GET /api/v1/school/task-templates/:id` - 获取单个模板 -- `GET /api/v1/school/task-templates/default/:taskType` - 获取默认模板 -- `POST /api/v1/school/task-templates` - 创建任务模板 -- `PUT /api/v1/school/task-templates/:id` - 更新任务模板 -- `DELETE /api/v1/school/task-templates/:id` - 删除任务模板 -- `POST /api/v1/school/tasks/from-template` - 从模板创建任务 - -**TeacherTaskController** (教师端 - 任务管理): -- `GET /api/v1/teacher/tasks/stats` - 获取任务统计数据 -- `GET /api/v1/teacher/tasks/stats/by-type` - 按任务类型统计 -- `GET /api/v1/teacher/tasks/stats/by-class` - 按班级统计 -- `GET /api/v1/teacher/tasks/stats/monthly` - 月度统计趋势 -- `GET /api/v1/teacher/tasks/:id/completions` - 获取任务完成情况分页 -- `PUT /api/v1/teacher/tasks/:taskId/completions/:studentId` - 更新任务完成状态 -- `GET /api/v1/teacher/task-templates` - 获取任务模板列表 -- `GET /api/v1/teacher/task-templates/:id` - 获取单个模板 -- `GET /api/v1/teacher/task-templates/default/:taskType` - 获取默认模板 -- `POST /api/v1/teacher/tasks/from-template` - 从模板创建任务 - ---- - -### 2. 通知接口 - -**新增 SchoolNotificationController** (学校管理员 - 通知): -- `GET /api/v1/school/notifications` - 获取通知列表 -- `GET /api/v1/school/notifications/:id` - 根据 ID 获取通知 -- `GET /api/v1/school/notifications/unread-count` - 获取未读数量 -- `POST /api/v1/school/notifications/:id/read` - 标记已读 -- `POST /api/v1/school/notifications/read-all` - 全部标记已读 - ---- - -### 3. 排课和课表接口 - -#### 新增 Service 方法 (ScheduleService) -```java -Page getSchedulePlans(int pageNum, int pageSize, Long tenantId, Long classId, LocalDate startDate, LocalDate endDate); -List> getTimetable(Long tenantId, LocalDate startDate, LocalDate endDate, Long classId); -List batchCreateSchedules(Long tenantId, Long userId, List requests); -ScheduleTemplate updateScheduleTemplate(Long id, ScheduleTemplate template); -List applyScheduleTemplate(Long tenantId, Long templateId, ScheduleTemplateApplyRequest request); -``` - -#### 新增 Controller 端点 (SchoolScheduleController) -- `GET /api/v1/school/schedules/timetable` - 获取课表(带日期范围) -- `POST /api/v1/school/schedules/batch` - 批量创建排课 -- `GET /api/v1/school/schedules/templates/:id` - 获取单个模板 -- `PUT /api/v1/school/schedules/templates/:id` - 更新模板 -- `POST /api/v1/school/schedules/templates/:id/apply` - 应用模板 - ---- - -### 4. 实体类增强 - -**SchedulePlan** (新增字段): -- `courseId` - 课程 ID -- `teacherId` - 教师 ID -- `dayOfWeek` - 星期几 (1-7) -- `period` - 节次 -- `startTime` - 开始时间 -- `endTime` - 结束时间 -- `location` - 教室/地点 -- `note` - 备注 - ---- - -### 5. 新增 DTO - -**TaskTemplateCreateRequest** - 任务模板创建请求 -```java -- name: 模板名称 -- description: 模板描述 -- type: 任务类型 -- content: 任务内容模板 -- isPublic: 是否公共模板 -``` - -**TaskTemplateUpdateRequest** - 任务模板更新请求 - -**CreateTaskFromTemplateRequest** - 从模板创建任务请求 -```java -- templateId: 模板 ID -- targetIds: 目标 ID 列表 -- targetType: 目标类型 (CLASS/STUDENT) -- startDate: 开始日期 -- endDate: 截止日期 -``` - -**SchedulePlanCreateRequest** - 课表计划创建请求 -```java -- classId: 班级 ID -- courseId: 课程 ID -- teacherId: 授课教师 ID -- dayOfWeek: 星期几 -- period: 节次 -- startTime: 开始时间 -- endTime: 结束时间 -- location: 教室/地点 -- note: 备注 -- startDate: 开始日期 -- endDate: 结束日期 -``` - -**ScheduleTemplateApplyRequest** - 课表模板应用请求 -```java -- classId: 班级 ID -- startDate: 应用开始日期 -- weeks: 应用周数 -``` - ---- - -## 文件变更列表 - -### 新增文件 (7 个) -1. `dto/request/TaskTemplateCreateRequest.java` -2. `dto/request/TaskTemplateUpdateRequest.java` -3. `dto/request/CreateTaskFromTemplateRequest.java` -4. `dto/request/SchedulePlanCreateRequest.java` -5. `dto/request/ScheduleTemplateApplyRequest.java` -6. `controller/school/SchoolNotificationController.java` -7. `resources/db/migration/V7__fix_schedule_plans.sql` - -### 修改文件 (7 个) -1. `service/TaskService.java` - 添加统计和模板方法接口 -2. `service/impl/TaskServiceImpl.java` - 实现统计和模板逻辑 + 修复 ClassEntity bug -3. `service/ScheduleService.java` - 添加课表相关方法 -4. `entity/SchedulePlan.java` - 添加课程、教师等字段 -5. `controller/school/SchoolTaskController.java` - 添加统计和模板端点 -6. `controller/teacher/TeacherTaskController.java` - 添加统计和模板端点 -7. `controller/school/SchoolScheduleController.java` - 添加课表和模板端点 - ---- - -## 仍需补全的接口(下一步建议) - -### 高优先级 -1. **成长档案接口** - 按学生/班级查询 -2. **教师端课时反馈** - 完成课时、学生记录、反馈接口 -3. **班级管理** - 班级教师/学生管理、学生调班 - -### 中优先级 -1. **统计报告** - 学校统计、报告导出 -2. **导出接口增强** - 带日期范围参数 -3. **管理员课程审核** - 提交、审核、发布流程 - ---- - -## 使用说明 - -1. 运行数据库迁移: -```bash -# Flyway 会在应用启动时自动运行 V7 迁移脚本 -``` - -2. 编译项目: -```bash -cd reading-platform-java -mvn clean compile -``` - -3. 启动应用后,访问 API 文档: -``` -http://localhost:8080/doc.html -``` From 0d4275b235246b719e7d9a7c532d03f7338c6be3 Mon Sep 17 00:00:00 2001 From: En Date: Tue, 10 Mar 2026 23:50:53 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=20OpenAPI=20?= =?UTF-8?q?=E6=B3=A8=E8=A7=A3=E5=92=8C=E5=89=8D=E7=AB=AF=20API=20=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主要变更: 1. 所有 Entity/DTO/VO 添加 @Schema 注解,完善 API 文档 2. 新增前端 API 封装模块 (src/apis),包含 fetch.ts 和 apis.ts 3. 生成完整的 TypeScript 类型定义(100+ 个模型) 4. pom.xml 添加 Maven 编译配置和 UTF-8 编码支持 5. 更新 CLAUDE.md 开发文档,新增接口规范和 Swagger 注解规范 6. 清理旧的文档文件和 Flyway 迁移脚本 技术细节: - 后端:27 个实体类 + 所有 DTO/Response 添加 Swagger 注解 - 前端:新增 orval 生成的 API 客户端类型 - 构建:配置 Maven compiler plugin 和 Spring Boot 插件的 JVM 参数 - 数据库:新增 schema 导出文件,删除旧 Flyway 迁移脚本 Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 586 +++- docs/后端接口补全总结.md | 157 + docs/表名统一修改说明.md | 135 + docs/限流功能使用说明.md | 224 ++ reading-platform-frontend/api-spec.yml | 2889 ++++++++++++++++- reading-platform-frontend/src/api/admin.ts | 42 +- .../src/api/generated/api.ts | 659 +++- .../model/activeTeacherStatsResponse.ts | 19 + .../model/adminSettingsUpdateRequest.ts | 59 + .../api/generated/model/adminStatsResponse.ts | 29 + .../model/batchSaveStudentRecordResponse.ts | 18 + .../model/batchStudentRecordRequest.ts | 12 + .../batchStudentRecordRequestRecordsItem.ts | 9 + .../generated/model/childDetailResponse.ts | 31 + .../api/generated/model/childInfoResponse.ts | 29 + .../src/api/generated/model/childStats.ts | 19 + .../src/api/generated/model/classInfo.ts | 19 + .../api/generated/model/classInfoResponse.ts | 27 + .../api/generated/model/classSimpleInfo.ts | 19 + .../src/api/generated/model/classTeacher.ts | 30 + .../generated/model/classTeacherRequest.ts | 13 + .../model/commonPageResponseLesson.ts | 22 + ...nPageResponseTaskCompletionInfoResponse.ts | 22 + .../model/courseDistributionResponse.ts | 17 + .../generated/model/courseStatsResponse.ts | 25 + .../model/courseUsageStatsResponse.ts | 19 + .../model/createTaskFromTemplateRequest.ts | 23 + .../api/generated/model/fileUploadResponse.ts | 19 + .../model/getActiveTeachersParams.ts | 11 + .../generated/model/getChildLessonsParams.ts | 12 + .../generated/model/getChildTasksParams.ts | 13 + .../model/getClassStudents1Params.ts | 13 + .../generated/model/getClassStudentsParams.ts | 13 + .../generated/model/getCompletions1Params.ts | 13 + .../generated/model/getCompletionsParams.ts | 13 + .../generated/model/getLessonTrendParams.ts | 11 + .../generated/model/getMonthlyStats1Params.ts | 11 + .../generated/model/getMonthlyStatsParams.ts | 11 + .../model/getMyNotifications2Params.ts | 13 + .../model/getRecentActivitiesParams.ts | 11 + .../model/getSchedulePlans1Params.ts | 2 + .../model/getTeacherStudentsParams.ts | 13 + .../generated/model/getTemplates1Params.ts | 14 + .../api/generated/model/getTemplatesParams.ts | 14 + .../generated/model/getTimetable1Params.ts | 13 + .../api/generated/model/getTimetableParams.ts | 13 + .../generated/model/importTemplateResponse.ts | 17 + .../src/api/generated/model/index.ts | 134 + .../generated/model/lessonActivityResponse.ts | 21 + .../src/api/generated/model/lessonFeedback.ts | 55 + .../generated/model/lessonFeedbackRequest.ts | 19 + .../lessonFeedbackRequestActivitiesDone.ts | 9 + .../lessonFeedbackRequestStepFeedbacks.ts | 9 + .../generated/model/lessonFinishRequest.ts | 14 + .../api/generated/model/lessonSimpleInfo.ts | 19 + .../generated/model/lessonSimpleResponse.ts | 25 + .../api/generated/model/messageResponse.ts | 15 + .../model/monthlyTaskStatsResponse.ts | 21 + .../model/pageResultStudentInfoResponse.ts | 16 + .../model/pageResultTaskCompletion.ts | 16 + .../generated/model/pageResultTaskTemplate.ts | 16 + .../generated/model/recentActivityResponse.ts | 21 + .../generated/model/resetPasswordResponse.ts | 17 + .../model/resultAdminStatsResponse.ts | 14 + .../resultBatchSaveStudentRecordResponse.ts | 14 + .../model/resultChildDetailResponse.ts | 14 + .../api/generated/model/resultClassTeacher.ts | 14 + .../model/resultCommonPageResponseLesson.ts | 14 + ...nPageResponseTaskCompletionInfoResponse.ts | 14 + .../model/resultFileUploadResponse.ts | 14 + .../model/resultImportTemplateResponse.ts | 14 + .../generated/model/resultLessonFeedback.ts | 14 + .../resultListActiveTeacherStatsResponse.ts | 14 + .../model/resultListChildInfoResponse.ts | 14 + .../model/resultListClassInfoResponse.ts | 14 + .../generated/model/resultListClassTeacher.ts | 14 + .../api/generated/model/resultListClazz.ts | 14 + .../resultListCourseDistributionResponse.ts | 14 + .../model/resultListCourseStatsResponse.ts | 14 + .../resultListCourseUsageStatsResponse.ts | 14 + .../model/resultListLessonActivityResponse.ts | 14 + .../model/resultListLessonSimpleResponse.ts | 14 + .../resultListMonthlyTaskStatsResponse.ts | 14 + .../model/resultListRecentActivityResponse.ts | 14 + .../generated/model/resultListSchedulePlan.ts | 14 + .../model/resultListSchedulePlanResponse.ts | 14 + ...esultListStudentTransferHistoryResponse.ts | 14 + .../resultListTaskStatsByClassResponse.ts | 14 + .../resultListTaskStatsByTypeResponse.ts | 14 + .../model/resultListTeacherInfoResponse.ts | 14 + .../model/resultListTenantStatsResponse.ts | 14 + .../model/resultListTrendDataPointResponse.ts | 14 + .../model/resultListTrendDataResponse.ts | 14 + .../generated/model/resultMessageResponse.ts | 14 + .../resultPageResultStudentInfoResponse.ts | 14 + .../model/resultPageResultTaskCompletion.ts | 14 + .../model/resultPageResultTaskTemplate.ts | 14 + .../model/resultResetPasswordResponse.ts | 14 + .../generated/model/resultStatsResponse.ts | 14 + .../generated/model/resultStudentRecord.ts | 14 + .../model/resultStudentRecordListResponse.ts | 14 + .../model/resultSystemSettingsResponse.ts | 14 + .../generated/model/resultTaskCompletion.ts | 14 + .../model/resultTaskFeedbackResponse.ts | 14 + .../model/resultTaskStatsResponse.ts | 14 + .../api/generated/model/resultTaskTemplate.ts | 14 + .../model/resultTeacherDashboardResponse.ts | 14 + .../model/resultTenantStatusUpdateResponse.ts | 14 + .../src/api/generated/model/schedulePlan.ts | 9 + .../model/schedulePlanCreateRequest.ts | 34 + .../generated/model/schedulePlanResponse.ts | 46 + .../model/schedulePlanUpdateRequest.ts | 26 + .../model/scheduleTemplateApplyRequest.ts | 19 + .../model/schoolSettingsUpdateRequest.ts | 25 + .../src/api/generated/model/statsResponse.ts | 25 + .../generated/model/studentInfoResponse.ts | 35 + .../src/api/generated/model/studentRecord.ts | 59 + .../model/studentRecordListResponse.ts | 18 + .../generated/model/studentRecordRequest.ts | 15 + .../generated/model/studentRecordResponse.ts | 27 + .../model/studentTransferHistoryResponse.ts | 27 + .../generated/model/systemSettingsResponse.ts | 23 + .../src/api/generated/model/taskCompletion.ts | 22 + .../model/taskCompletionInfoResponse.ts | 29 + .../generated/model/taskFeedbackResponse.ts | 25 + .../model/taskFeedbackUpdateRequest.ts | 15 + .../src/api/generated/model/taskSimpleInfo.ts | 19 + .../model/taskStatsByClassResponse.ts | 25 + .../model/taskStatsByTypeResponse.ts | 21 + .../api/generated/model/taskStatsResponse.ts | 27 + .../src/api/generated/model/taskTemplate.ts | 20 + .../model/taskTemplateCreateRequest.ts | 23 + .../model/taskTemplateUpdateRequest.ts | 23 + .../model/teacherDashboardResponse.ts | 21 + .../generated/model/teacherInfoResponse.ts | 23 + .../model/tenantQuotaUpdateRequest.ts | 19 + .../generated/model/tenantStatsResponse.ts | 29 + .../model/tenantStatusUpdateRequest.ts | 15 + .../model/tenantStatusUpdateResponse.ts | 19 + .../generated/model/transferStudentRequest.ts | 12 + .../generated/model/trendDataPointResponse.ts | 21 + .../api/generated/model/trendDataResponse.ts | 19 + .../model/updateCompletion1Params.ts | 12 + .../generated/model/updateCompletionParams.ts | 12 + reading-platform-frontend/src/api/parent.ts | 8 +- reading-platform-frontend/src/api/teacher.ts | 12 +- .../api/teacher.ts.tmp.13484.1773123085155 | 670 ++++ reading-platform-frontend/src/components.d.ts | 14 + .../Fapache-maven-3.8.4confjvm.config | 1 + reading-platform-java/pom.xml | 14 + .../platform/common/annotation/RateLimit.java | 50 + .../common/aspect/RateLimitAspect.java | 115 + .../common/config/MybatisPlusConfig.java | 18 + .../common/config/RateLimitInterceptor.java | 174 + .../common/config/RateLimitProperties.java | 64 + .../platform/common/config/RedisConfig.java | 32 + .../platform/common/config/WebMvcConfig.java | 20 + .../platform/common/enums/ErrorCode.java | 5 +- .../platform/common/security/JwtPayload.java | 4 +- .../common/security/JwtTokenProvider.java | 4 +- .../common/security/SecurityUtils.java | 4 +- .../platform/common/util/RateLimiter.java | 135 + .../controller/FileUploadController.java | 11 +- .../admin/AdminCourseController.java | 24 +- .../admin/AdminCourseLessonController.java | 10 +- .../admin/AdminCoursePackageController.java | 14 +- .../admin/AdminOperationLogController.java | 2 +- .../admin/AdminResourceController.java | 12 +- .../admin/AdminSettingsController.java | 46 +- .../admin/AdminStatsController.java | 84 +- .../admin/AdminTenantController.java | 52 +- .../admin/AdminThemeController.java | 6 +- .../parent/ParentChildController.java | 101 +- .../parent/ParentGrowthController.java | 14 +- .../parent/ParentNotificationController.java | 10 +- .../parent/ParentTaskController.java | 41 +- .../school/SchoolClassController.java | 116 +- .../school/SchoolCourseController.java | 12 +- .../school/SchoolCoursePackageController.java | 2 +- .../school/SchoolExportController.java | 8 +- .../school/SchoolGrowthController.java | 14 +- .../school/SchoolNotificationController.java | 10 +- .../school/SchoolOperationLogController.java | 2 +- .../school/SchoolParentController.java | 18 +- .../school/SchoolScheduleController.java | 54 +- .../school/SchoolSettingsController.java | 30 +- .../school/SchoolStatsController.java | 96 +- .../school/SchoolStudentController.java | 54 +- .../school/SchoolTaskController.java | 124 +- .../school/SchoolTeacherController.java | 12 +- .../teacher/TeacherCourseController.java | 128 +- .../TeacherCourseLessonController.java | 4 +- .../teacher/TeacherDashboardController.java | 61 +- .../teacher/TeacherGrowthController.java | 14 +- .../teacher/TeacherLessonController.java | 200 +- .../TeacherNotificationController.java | 10 +- .../teacher/TeacherScheduleController.java | 98 +- .../TeacherSchoolCourseController.java | 4 +- .../teacher/TeacherTaskController.java | 113 +- .../request/AdminSettingsUpdateRequest.java | 81 + .../dto/request/CourseCreateRequest.java | 2 +- .../dto/request/CourseUpdateRequest.java | 2 +- .../CreateTaskFromTemplateRequest.java | 4 +- .../request/GrowthRecordCreateRequest.java | 2 +- .../dto/request/LessonCreateRequest.java | 6 +- .../request/SchedulePlanCreateRequest.java | 6 +- .../request/SchedulePlanUpdateRequest.java | 36 + .../request/ScheduleTemplateApplyRequest.java | 2 +- .../request/SchoolSettingsUpdateRequest.java | 30 + .../dto/request/TaskCreateRequest.java | 4 +- .../request/TaskFeedbackUpdateRequest.java | 15 + .../dto/request/TenantQuotaUpdateRequest.java | 21 + .../request/TenantStatusUpdateRequest.java | 15 + .../response/ActiveTeacherStatsResponse.java | 21 + .../dto/response/AdminStatsResponse.java | 36 + .../BatchSaveStudentRecordResponse.java | 18 + .../dto/response/ChildDetailResponse.java | 67 + .../dto/response/ChildInfoResponse.java | 50 + .../dto/response/ClassInfoResponse.java | 33 + .../dto/response/CommonPageResponse.java | 36 + .../response/CourseDistributionResponse.java | 18 + .../platform/dto/response/CourseResponse.java | 6 +- .../dto/response/CourseStatsResponse.java | 30 + .../response/CourseUsageStatsResponse.java | 21 + .../dto/response/FileUploadResponse.java | 29 + .../dto/response/ImportTemplateResponse.java | 25 + .../dto/response/LessonActivityResponse.java | 24 + .../dto/response/LessonSimpleResponse.java | 30 + .../platform/dto/response/LoginResponse.java | 4 +- .../dto/response/MessageResponse.java | 21 + .../response/MonthlyTaskStatsResponse.java | 24 + .../dto/response/RecentActivityResponse.java | 24 + .../dto/response/ResetPasswordResponse.java | 25 + .../dto/response/SchedulePlanResponse.java | 66 + .../platform/dto/response/StatsResponse.java | 30 + .../dto/response/StudentInfoResponse.java | 59 + .../response/StudentRecordListResponse.java | 34 + .../dto/response/StudentRecordResponse.java | 33 + .../StudentTransferHistoryResponse.java | 33 + .../dto/response/SystemSettingsResponse.java | 27 + .../response/TaskCompletionInfoResponse.java | 50 + .../dto/response/TaskFeedbackResponse.java | 30 + .../response/TaskStatsByClassResponse.java | 30 + .../dto/response/TaskStatsByTypeResponse.java | 24 + .../dto/response/TaskStatsResponse.java | 33 + .../response/TeacherDashboardResponse.java | 24 + .../dto/response/TeacherInfoResponse.java | 27 + .../dto/response/TenantInfoResponse.java | 27 + .../platform/dto/response/TenantResponse.java | 2 +- .../dto/response/TenantStatsResponse.java | 36 + .../response/TenantStatusUpdateResponse.java | 21 + .../dto/response/TrendDataPointResponse.java | 24 + .../dto/response/TrendDataResponse.java | 21 + .../dto/response/UserInfoResponse.java | 4 +- .../reading/platform/entity/AdminUser.java | 17 +- .../reading/platform/entity/ClassTeacher.java | 2 +- .../platform/entity/ClassTeachers.java | 57 - .../com/reading/platform/entity/Clazz.java | 23 +- .../com/reading/platform/entity/Course.java | 24 +- .../platform/entity/CourseActivity.java | 29 +- .../reading/platform/entity/CourseLesson.java | 19 +- .../platform/entity/CoursePackage.java | 17 +- .../platform/entity/CourseResource.java | 19 +- .../reading/platform/entity/CourseScript.java | 19 +- .../platform/entity/CourseScriptPage.java | 19 +- .../platform/entity/CourseVersion.java | 26 +- .../reading/platform/entity/GrowthRecord.java | 21 +- .../com/reading/platform/entity/Lesson.java | 63 +- .../platform/entity/LessonFeedback.java | 68 +- .../reading/platform/entity/Notification.java | 31 +- .../reading/platform/entity/OperationLog.java | 30 +- .../com/reading/platform/entity/Parent.java | 19 +- .../platform/entity/ParentStudent.java | 23 +- .../reading/platform/entity/ResourceItem.java | 30 +- .../platform/entity/ResourceLibrary.java | 26 +- .../reading/platform/entity/SchedulePlan.java | 42 +- .../platform/entity/ScheduleTemplate.java | 27 +- .../reading/platform/entity/SchoolCourse.java | 27 +- .../com/reading/platform/entity/Student.java | 44 +- .../platform/entity/StudentClassHistory.java | 27 +- .../platform/entity/StudentRecord.java | 41 +- .../platform/entity/SystemSetting.java | 26 +- .../java/com/reading/platform/entity/Tag.java | 26 +- .../com/reading/platform/entity/Task.java | 37 +- .../platform/entity/TaskCompletion.java | 32 +- .../reading/platform/entity/TaskTarget.java | 22 +- .../reading/platform/entity/TaskTemplate.java | 28 +- .../com/reading/platform/entity/Teacher.java | 19 +- .../com/reading/platform/entity/Tenant.java | 17 +- .../reading/platform/entity/TenantCourse.java | 27 +- .../com/reading/platform/entity/Theme.java | 26 +- .../reading/platform/mapper/ParentMapper.java | 8 + .../platform/mapper/StudentMapper.java | 8 + .../platform/mapper/TeacherMapper.java | 8 + .../reading/platform/mapper/TenantMapper.java | 14 + .../reading/platform/mapper/ThemeMapper.java | 7 + .../platform/service/ClassService.java | 54 +- .../platform/service/CourseLessonService.java | 8 +- .../service/CoursePackageService.java | 14 +- .../platform/service/CourseService.java | 24 +- .../platform/service/ExportService.java | 8 +- .../platform/service/GrowthRecordService.java | 14 +- .../platform/service/LessonService.java | 55 +- .../platform/service/NotificationService.java | 18 +- .../platform/service/OperationLogService.java | 4 +- .../platform/service/ParentService.java | 16 +- .../platform/service/ResourceService.java | 16 +- .../platform/service/ScheduleService.java | 30 +- .../platform/service/SchoolCourseService.java | 10 +- .../platform/service/SchoolStatsService.java | 12 +- .../platform/service/StudentService.java | 29 +- .../service/SystemSettingService.java | 6 +- .../reading/platform/service/TaskService.java | 47 +- .../service/TeacherDashboardService.java | 6 +- .../platform/service/TeacherService.java | 12 +- .../platform/service/TenantService.java | 8 +- .../platform/service/ThemeService.java | 6 +- .../service/impl/AuthServiceImpl.java | 2 +- .../service/impl/ClassServiceImpl.java | 155 +- .../service/impl/CourseLessonServiceImpl.java | 8 +- .../impl/CoursePackageServiceImpl.java | 14 +- .../service/impl/CourseServiceImpl.java | 24 +- .../service/impl/ExportServiceImpl.java | 8 +- .../service/impl/GrowthRecordServiceImpl.java | 14 +- .../service/impl/LessonServiceImpl.java | 170 +- .../service/impl/NotificationServiceImpl.java | 18 +- .../service/impl/OperationLogServiceImpl.java | 4 +- .../service/impl/ParentServiceImpl.java | 16 +- .../service/impl/ResourceServiceImpl.java | 16 +- .../service/impl/ScheduleServiceImpl.java | 30 +- .../service/impl/SchoolCourseServiceImpl.java | 10 +- .../service/impl/SchoolStatsServiceImpl.java | 18 +- .../service/impl/StudentServiceImpl.java | 89 +- .../impl/SystemSettingServiceImpl.java | 6 +- .../service/impl/TaskServiceImpl.java | 65 +- .../impl/TeacherDashboardServiceImpl.java | 6 +- .../service/impl/TeacherServiceImpl.java | 12 +- .../service/impl/TenantServiceImpl.java | 8 +- .../service/impl/ThemeServiceImpl.java | 6 +- .../service/impl/TokenServiceImpl.java | 8 +- .../src/main/resources/application-dev.yml | 1 + .../src/main/resources/application.yml | 31 + .../db/migration/V1__init_schema.sql | 522 --- .../V2__add_course_package_fields.sql | 78 - .../resources/db/migration/V3__add_themes.sql | 21 - .../db/migration/V4__add_course_packages.sql | 14 - .../db/migration/V5__add_school_courses.sql | 17 - .../db/migration/V6__add_course_lessons.sql | 17 - .../db/migration/V7__fix_schedule_plans.sql | 15 - .../resources/db/schema/database_schema.sql | 738 +++++ .../reading/platform/DatabaseInspectTool.java | 57 + .../reading/platform/FlywayHistoryTool.java | 73 + .../reading/platform/FlywayRepairTool.java | 55 + .../reading/platform/TestDataGenerator.java | 898 +++++ 354 files changed, 14674 insertions(+), 1719 deletions(-) create mode 100644 docs/后端接口补全总结.md create mode 100644 docs/表名统一修改说明.md create mode 100644 docs/限流功能使用说明.md create mode 100644 reading-platform-frontend/src/api/generated/model/activeTeacherStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/adminSettingsUpdateRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/adminStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/batchSaveStudentRecordResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/batchStudentRecordRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/batchStudentRecordRequestRecordsItem.ts create mode 100644 reading-platform-frontend/src/api/generated/model/childDetailResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/childInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/childStats.ts create mode 100644 reading-platform-frontend/src/api/generated/model/classInfo.ts create mode 100644 reading-platform-frontend/src/api/generated/model/classInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/classSimpleInfo.ts create mode 100644 reading-platform-frontend/src/api/generated/model/classTeacher.ts create mode 100644 reading-platform-frontend/src/api/generated/model/classTeacherRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/commonPageResponseLesson.ts create mode 100644 reading-platform-frontend/src/api/generated/model/commonPageResponseTaskCompletionInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/courseDistributionResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/courseStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/courseUsageStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/createTaskFromTemplateRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/fileUploadResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getActiveTeachersParams.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getChildLessonsParams.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getChildTasksParams.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getClassStudents1Params.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getClassStudentsParams.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getCompletions1Params.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getCompletionsParams.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getLessonTrendParams.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getMonthlyStats1Params.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getMonthlyStatsParams.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getMyNotifications2Params.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getRecentActivitiesParams.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getTeacherStudentsParams.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getTemplates1Params.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getTemplatesParams.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getTimetable1Params.ts create mode 100644 reading-platform-frontend/src/api/generated/model/getTimetableParams.ts create mode 100644 reading-platform-frontend/src/api/generated/model/importTemplateResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/lessonActivityResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/lessonFeedback.ts create mode 100644 reading-platform-frontend/src/api/generated/model/lessonFeedbackRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/lessonFeedbackRequestActivitiesDone.ts create mode 100644 reading-platform-frontend/src/api/generated/model/lessonFeedbackRequestStepFeedbacks.ts create mode 100644 reading-platform-frontend/src/api/generated/model/lessonFinishRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/lessonSimpleInfo.ts create mode 100644 reading-platform-frontend/src/api/generated/model/lessonSimpleResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/messageResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/monthlyTaskStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/pageResultStudentInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/pageResultTaskCompletion.ts create mode 100644 reading-platform-frontend/src/api/generated/model/pageResultTaskTemplate.ts create mode 100644 reading-platform-frontend/src/api/generated/model/recentActivityResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resetPasswordResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultAdminStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultBatchSaveStudentRecordResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultChildDetailResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultClassTeacher.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultCommonPageResponseLesson.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultCommonPageResponseTaskCompletionInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultFileUploadResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultImportTemplateResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultLessonFeedback.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListActiveTeacherStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListChildInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListClassInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListClassTeacher.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListClazz.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListCourseDistributionResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListCourseStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListCourseUsageStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListLessonActivityResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListLessonSimpleResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListMonthlyTaskStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListRecentActivityResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListSchedulePlan.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListSchedulePlanResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListStudentTransferHistoryResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListTaskStatsByClassResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListTaskStatsByTypeResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListTeacherInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListTenantStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListTrendDataPointResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultListTrendDataResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultMessageResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultPageResultStudentInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultPageResultTaskCompletion.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultPageResultTaskTemplate.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultResetPasswordResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultStudentRecord.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultStudentRecordListResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultSystemSettingsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultTaskCompletion.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultTaskFeedbackResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultTaskStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultTaskTemplate.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultTeacherDashboardResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/resultTenantStatusUpdateResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/schedulePlanCreateRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/schedulePlanResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/schedulePlanUpdateRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/scheduleTemplateApplyRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/schoolSettingsUpdateRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/statsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/studentInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/studentRecord.ts create mode 100644 reading-platform-frontend/src/api/generated/model/studentRecordListResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/studentRecordRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/studentRecordResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/studentTransferHistoryResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/systemSettingsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/taskCompletion.ts create mode 100644 reading-platform-frontend/src/api/generated/model/taskCompletionInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/taskFeedbackResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/taskFeedbackUpdateRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/taskSimpleInfo.ts create mode 100644 reading-platform-frontend/src/api/generated/model/taskStatsByClassResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/taskStatsByTypeResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/taskStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/taskTemplate.ts create mode 100644 reading-platform-frontend/src/api/generated/model/taskTemplateCreateRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/taskTemplateUpdateRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/teacherDashboardResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/teacherInfoResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/tenantQuotaUpdateRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/tenantStatsResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/tenantStatusUpdateRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/tenantStatusUpdateResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/transferStudentRequest.ts create mode 100644 reading-platform-frontend/src/api/generated/model/trendDataPointResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/trendDataResponse.ts create mode 100644 reading-platform-frontend/src/api/generated/model/updateCompletion1Params.ts create mode 100644 reading-platform-frontend/src/api/generated/model/updateCompletionParams.ts create mode 100644 reading-platform-frontend/src/api/teacher.ts.tmp.13484.1773123085155 create mode 100644 reading-platform-java/Fapache-maven-3.8.4confjvm.config create mode 100644 reading-platform-java/src/main/java/com/reading/platform/common/annotation/RateLimit.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/common/aspect/RateLimitAspect.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/common/config/RateLimitInterceptor.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/common/config/RateLimitProperties.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/common/config/RedisConfig.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/common/util/RateLimiter.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/request/AdminSettingsUpdateRequest.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/request/SchedulePlanUpdateRequest.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/request/SchoolSettingsUpdateRequest.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/request/TaskFeedbackUpdateRequest.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantQuotaUpdateRequest.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantStatusUpdateRequest.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/ActiveTeacherStatsResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/AdminStatsResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/BatchSaveStudentRecordResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/ChildDetailResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/ChildInfoResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/ClassInfoResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/CommonPageResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseDistributionResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseStatsResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseUsageStatsResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/FileUploadResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/ImportTemplateResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/LessonActivityResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/LessonSimpleResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/MessageResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/MonthlyTaskStatsResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/RecentActivityResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/ResetPasswordResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/SchedulePlanResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/StatsResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentInfoResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentRecordListResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentRecordResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentTransferHistoryResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/SystemSettingsResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskCompletionInfoResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskFeedbackResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsByClassResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsByTypeResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TeacherDashboardResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TeacherInfoResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantInfoResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantStatsResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantStatusUpdateResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TrendDataPointResponse.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/TrendDataResponse.java delete mode 100644 reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeachers.java delete mode 100644 reading-platform-java/src/main/resources/db/migration/V1__init_schema.sql delete mode 100644 reading-platform-java/src/main/resources/db/migration/V2__add_course_package_fields.sql delete mode 100644 reading-platform-java/src/main/resources/db/migration/V3__add_themes.sql delete mode 100644 reading-platform-java/src/main/resources/db/migration/V4__add_course_packages.sql delete mode 100644 reading-platform-java/src/main/resources/db/migration/V5__add_school_courses.sql delete mode 100644 reading-platform-java/src/main/resources/db/migration/V6__add_course_lessons.sql delete mode 100644 reading-platform-java/src/main/resources/db/migration/V7__fix_schedule_plans.sql create mode 100644 reading-platform-java/src/main/resources/db/schema/database_schema.sql create mode 100644 reading-platform-java/src/test/java/com/reading/platform/DatabaseInspectTool.java create mode 100644 reading-platform-java/src/test/java/com/reading/platform/FlywayHistoryTool.java create mode 100644 reading-platform-java/src/test/java/com/reading/platform/FlywayRepairTool.java create mode 100644 reading-platform-java/src/test/java/com/reading/platform/TestDataGenerator.java diff --git a/CLAUDE.md b/CLAUDE.md index 6bdb97f..79e18f9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -87,8 +87,483 @@ Result error(code, msg) // { code: xxx, message: "...", data: null } ``` ### 4. OpenAPI 驱动开发 -- 后端:在 Controller 上使用 `@Operation`、`@Parameter`、`@Schema` 注解 -- 前端:运行 `npm run api:update` 从 `api-spec.yml` 重新生成 TypeScript 客户端 + +- **后端**:在 Controller 上使用 `@Operation`、`@Parameter`、`@Schema` 注解 +- **前端**:运行 `npm run api:update` 从 `api-spec.yml` 重新生成 TypeScript 客户端 + +### 5. 前后端接口规范 + +#### 后端:以 Controller 为"唯一真源" + +以后端 `Spring Boot Controller` 为接口定义的唯一真源,通过 `SpringDoc/Knife4j` 导出`OpenAPI` 规范,所有接口必须符合统一响应模型。 + +**统一响应模型:** +```java +// 普通接口 +Result success(T data) // { code: 200, message: "success", data: ... } +Result error(code, msg) // { code: xxx, message: "...", data: null } + +// 分页接口 +Result> // { code: 200, message: "success", data: { items, total, page, pageSize } } +``` + +**响应结构说明:** +| 接口类型 | 返回类型 | 分页字段命名 | +|---------|---------|-------------| +| 普通接口 | `Result` | - | +| 分页接口 | `Result>` | `page`, `pageSize`, `total`, `items` | +| 错误响应 | `Result` | 参考 `ErrorCode` 枚举 | + +**请求参数规范:** +| 参数类型 | 注解 | 说明 | +|---------|------|------| +| 路径变量 | `@PathVariable` | 与 OpenAPI path 模板保持一致 | +| 查询参数 | `@RequestParam` | 分页:`page`, `pageSize`;过滤:`keyword`, `category` 等 | +| 请求体 | `@RequestBody DTO` | 使用 `*Request` 类,不直接暴露实体 | + +#### 前端:src/apis + fetch.ts 调用模式 + +围绕 `src/apis` + `fetch.ts` 的调用模式,将真实接口规范(路径、method、参数、响应结构)维护到 `apis.ts`。 + +**工作流程:** +``` +后端 Controller (带 @Schema 注解) + ↓ + Knife4j/Swagger → /v3/api-docs + ↓ + api-spec.yml (OpenAPI 规范) + ↓ + orval (npm run api:gen) + ↓ + 生成的 TypeScript 类型 + API 客户端 + ↓ + Vue 组件使用 (强制类型校验) +``` + +#### 实施步骤 + +**一、梳理并固化接口响应规范** + +1. **确认统一响应模型** + - 普通接口:`Result<业务 DTO>`,字段 `code/message/data` + - 分页接口:`Result>`,分页字段命名(`page`, `pageSize`, `total` 等) + - 错误响应:统一使用 `Result` 或类似 `ResultVoid` schema + +2. **从后端提炼规范说明** + - 位置:`reading-platform-java/common/response` 与 `common/enums/ErrorCode` + - 输出:简短的"接口规范说明"文档,写入 `docs/` 目录 + +**二、从后端生成/校准 OpenAPI 规范** + +1. **配置 SpringDoc/Knife4j 导出 OpenAPI** + - 查看/完善后端 OpenAPI 配置类(如 `OpenApiConfig` 或 Knife4j 配置) + - 指定 API 基本信息(title/description/version),与当前 `api-spec.yml` 对齐 + - 扫描 `controller/*` 包下所有带 `@RestController` 的类 + - 支持 `@Operation`、`@Parameter`、`@Schema` 注解 + +2. **规范化 Controller 注解与返回类型** + - 检查 Controller 方法返回类型是否全部为 `Result` 或`Result>` + - 为缺少注解的接口补全 `@Operation`、`@Parameter`、`@Schema` + - 校准路径前缀与角色划分(`/api/v1/teacher/*`、`/api/v1/school/*` 等) + +3. **替换/同步前端 api-spec.yml** + - 使用导出的 OpenAPI JSON/YAML 覆盖/更新 `reading-platform-frontend/api-spec.yml` + - 约定更新流程:修改后端 Controller → 查看/验证文档 → 导出并覆盖 api-spec.yml → 前端重新生成客户端 + +**三、将接口规范映射到前端 src/apis 体系** + +1. **分析现有 src/apis 使用方式** + - 搜索全项目对 `from 'src/apis/fetch'` 或`getRequests` 的引用 + - 列出当前真实在用的 URL 列表及对应页面组件 + - 对比这些 URL 与后端 Controller 路径以及 `api-spec.yml` 中的 paths + +2. **设计 apis.ts 的"接口字典"结构** + - 以 `SwaggerType` / `RequestType` 为基础 + - 将真实接口按模块分类(教师端、学校端、家长端、管理员端) + - 每个接口包含:路径、method、请求参数类型、响应类型 + +### 6. DTO/VO 使用规范 + +#### 响应对象(Response/VO) +- **必须创建独立的 VO 实体类**,不要使用 `Map`、`HashMap` 或 `JSONObject` 返回数据 +- VO 类应放在 `com.reading.platform.dto.response` 包下 +- 使用 `@Schema` 注解描述字段含义,便于生成 API 文档 +- 使用 `@Data` 和 `@Builder` 注解简化代码 + +**示例:** +```java +@Data +@Builder +@Schema(description = "用户信息响应") +public class UserInfoResponse { + @Schema(description = "用户 ID") + private Long id; + + @Schema(description = "用户名") + private String username; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "角色") + private String role; +} +``` + +#### 请求对象(Request/DTO) +- 复杂请求参数应创建 DTO 类,放在 `com.reading.platform.dto.request` 包下 +- 使用 `@Valid` 和校验注解确保参数合法性 + +#### 为什么不用 Map? +- ✅ VO 实体类:类型安全、IDE 智能提示、API 文档自动生成、易于维护 +- ❌ Map:类型不安全、无文档、易出错、难以重构 + +### 7. Swagger/OpenAPI 注解规范 + +#### 强制要求 +**所有实体类(Entity)、DTO、VO 都必须添加 `@Schema` 注解**,确保 API 文档完整性和前端类型生成准确性。 + +#### 注解使用规范 + +**1. 类级别注解** +```java +// Entity 类 +@Data +@TableName("users") +@Schema(description = "用户信息") // 必须添加 +public class User { ... } + +// DTO/VO 类 +@Data +@Schema(description = "用户创建请求") // 必须添加 +public class UserCreateRequest { ... } + +@Data +@Schema(description = "用户信息响应") // 必须添加 +public class UserResponse { ... } +``` + +**2. 字段级别注解** +```java +@Schema(description = "用户 ID", example = "1", requiredMode = Schema.RequiredMode.READ_ONLY) +private Long id; + +@Schema(description = "用户名", example = "zhangsan", requiredMode = Schema.RequiredMode.REQUIRED) +private String username; + +@Schema(description = "年龄", example = "18", minimum = "1", maximum = "150") +private Integer age; + +@Schema(description = "创建时间", example = "2024-01-01 12:00:00") +private LocalDateTime createdAt; +``` + +**3. Controller 方法注解** +```java +@Operation(summary = "创建用户", description = "创建新用户并返回用户信息") +@ApiResponses({ + @ApiResponse(responseCode = "200", description = "创建成功"), + @ApiResponse(responseCode = "400", description = "参数错误"), + @ApiResponse(responseCode = "409", description = "用户名已存在") +}) +@PostMapping +public Result createUser(@Valid @RequestBody UserCreateRequest request) { + return Result.success(userService.createUser(request)); +} +``` + +**4. 参数注解** +```java +@Operation(summary = "根据 ID 获取用户") +@GetMapping("/{id}") +public Result getUser( + @Parameter(description = "用户 ID", required = true) + @PathVariable Long id, + + @Parameter(description = "是否包含详细信息") + @RequestParam(defaultValue = "false") + Boolean includeDetails +) { + return Result.success(userService.getUser(id, includeDetails)); +} +``` + +#### 常用注解说明 + +| 注解 | 位置 | 说明 | +|------|------|------| +| `@Schema(description = "...")` | 类/字段 | 描述类或字段的含义 | +| `@Schema(example = "...")` | 字段 | 示例值 | +| `@Schema(requiredMode = REQUIRED)` | 字段 | 必填字段 | +| `@Schema(requiredMode = READ_ONLY)` | 字段 | 只读字段(如 ID、创建时间) | +| `@Schema(minimum = "1", maximum = "100")` | 字段 | 数值范围 | +| `@Schema(minLength = 1, maxLength = 50)` | 字段 | 字符串长度 | +| `@Schema(pattern = "^[a-zA-Z]+$")` | 字段 | 正则表达式 | +| `@Operation(summary = "...")` | 方法 | 接口摘要 | +| `@Parameter(description = "...")` | 参数 | 参数描述 | + +#### 完整示例 + +**Entity 类:** +```java +package com.reading.platform.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.time.LocalDateTime; + +@Data +@TableName("courses") +@Schema(description = "课程信息") +public class Course { + + @Schema(description = "课程 ID", requiredMode = Schema.RequiredMode.READ_ONLY) + @TableId(type = IdType.AUTO) + private Long id; + + @Schema(description = "租户 ID", requiredMode = Schema.RequiredMode.READ_ONLY) + private Long tenantId; + + @Schema(description = "课程名称", example = "绘本阅读入门", requiredMode = Schema.RequiredMode.REQUIRED) + private String name; + + @Schema(description = "课程编码", example = "READ001") + private String code; + + @Schema(description = "课程描述") + private String description; + + @Schema(description = "封面图片 URL") + private String coverUrl; + + @Schema(description = "分类", example = "language") + private String category; + + @Schema(description = "适用年龄段", example = "5-6 岁") + private String ageRange; + + @Schema(description = "难度等级", example = "beginner") + private String difficultyLevel; + + @Schema(description = "课程时长(分钟)", example = "30") + private Integer durationMinutes; + + @Schema(description = "状态", example = "published") + private String status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createdAt; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updatedAt; +} +``` + +**DTO 类:** +```java +package com.reading.platform.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +@Data +@Schema(description = "课程创建请求") +public class CourseCreateRequest { + + @Schema(description = "课程名称", example = "绘本阅读入门", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "课程名称不能为空") + @Size(max = 100, message = "课程名称不能超过 100 个字符") + private String name; + + @Schema(description = "课程描述", example = "适合大班幼儿的绘本阅读课程") + private String description; + + @Schema(description = "分类", example = "language") + private String category; + + @Schema(description = "适用年龄段", example = "5-6 岁") + private String ageRange; +} +``` + +#### 代码审查要点 + +- [ ] Entity 类是否添加了 `@Schema(description = "...")` +- [ ] Entity 字段是否添加了 `@Schema` 注解描述字段含义 +- [ ] DTO/VO 类是否添加了 `@Schema(description = "...")` +- [ ] DTO/VO 字段是否添加了 `@Schema` 注解 +- [ ] Controller 方法是否添加了 `@Operation` 注解 +- [ ] Controller 参数是否添加了 `@Parameter` 注解 +- [ ] 必填字段是否标注了 `requiredMode = REQUIRED` +- [ ] 只读字段(ID、时间戳)是否标注了 `requiredMode = READ_ONLY` +- [ ] 是否有合适的 `example` 示例值 + +#### 注意事项 + +1. **导入正确的包** +```java +import io.swagger.v3.oas.annotations.media.Schema; // Swagger 3.x +``` + +2. **Lombok 与 Schema 的配合** +- `@Data` 生成的 getter 方法会自动继承字段上的 `@Schema` 注解 +- 但建议字段和方法都加上注解以确保兼容性 + +3. **必填校验** +- `requiredMode = REQUIRED` 仅用于文档说明 +- 实际校验需要配合 `@NotNull`、`@NotBlank` 等校验注解 + +4. **枚举类型** +```java +@Schema(description = "状态", example = "active", allowableValues = {"active", "inactive"}) +private String status; +``` + +### 8. 前端接口校验规范 + +#### 基于 OpenAPI + orval + TypeScript 的强制校验链路 + +本项目前端采用**从接口文档到页面代码的强制类型校验链路**,确保前后端接口一致性和类型安全。 + +**技术栈:** +- **OpenAPI 3.0**:统一的 API 接口规范 +- **orval**:从 OpenAPI 规范生成 TypeScript 类型和 API 客户端 +- **TypeScript**:静态类型检查 +- **ESLint**:代码规范约束 +- **axios**:HTTP 请求(由 orval 自动生成) + +**工作流程:** + +``` +后端 Controller (带 @Schema 注解) + ↓ + Knife4j/Swagger + ↓ + api-spec.yml (OpenAPI 规范) + ↓ + orval (npm run api:gen) + ↓ + 生成的 TypeScript 类型 + API 客户端 + ↓ + Vue 组件使用 (强制类型校验) +``` + +#### 配置说明 + +**orval 配置 (`orval.config.ts` 或 `vite.config.ts`):** +```typescript +export default { + 'api': { + input: { + target: './api-spec.yml', + filters: { + tags: ['default'], // 只生成指定标签的接口 + }, + }, + output: { + mode: 'split', // 分离模式:每个接口一个文件 + target: './src/api/generated/client.ts', + schemas: './src/api/generated/schemas', + client: 'axios', + mock: false, + override: { + fetch: { + includeHttpRequestHeader: true, + }, + useTypeOverInterfaces: true, // 优先使用 type + useDate: true, + }, + }, + }, +}; +``` + +#### 使用规范 + +**1. 后端必须添加 @Schema 注解** +```java +@Operation(summary = "获取用户信息") +@GetMapping("/{id}") +public Result getUser(@PathVariable Long id) { + return Result.success(userService.getUser(id)); +} +``` + +**2. 前端必须使用生成的类型和客户端** +```typescript +// ✅ 正确:使用生成的类型和 API +import { getUser } from '@/api/generated/client'; +import type { UserInfoResponse } from '@/api/generated/schemas'; + +const user: UserInfoResponse = await getUser(id); + +// ❌ 错误:不要手写类型或手动调用 axios +interface ManualUser { id: number; name: string; } +const user = await axios.get(`/api/users/${id}`); +``` + +**3. ESLint 约束规则** +```typescript +// .eslintrc.cjs 中添加 +rules: { + // 禁止手动调用 axios,必须使用生成的 API 客户端 + 'no-restricted-imports': [ + 'error', + { + patterns: ['axios', '!@/api/generated/*'], + }, + ], + // 强制使用生成的类型定义 + '@typescript-eslint/no-explicit-any': 'error', + // 禁止使用 any 类型(特殊情况需 eslint-disable 注释) +} +``` + +**4. 运行时校验(可选)** +使用 `zod` 或 `yup` 进行运行时数据校验: +```typescript +import { UserInfoSchema } from '@/api/generated/schemas'; +import { z } from 'zod'; + +// 运行时校验响应数据 +const parsedData = UserInfoSchema.parse(apiResponse); +``` + +#### 开发命令 + +```bash +cd reading-platform-frontend + +# 从后端更新 API 规范并生成客户端 +npm run api:gen + +# 或者完整流程(包含从后端导出 swagger) +npm run api:update +``` + +#### 代码审查要点 + +- [ ] 前端是否使用了 orval 生成的类型,而非手写 interface +- [ ] 是否使用生成的 API 客户端,而非手动 axios 调用 +- [ ] TypeScript 编译是否通过(无类型错误) +- [ ] 后端 Controller 是否正确添加 @Schema 注解 +- [ ] API 变更后是否重新运行了 `npm run api:gen` + +#### 常见问题 + +**Q: 为什么要强制使用生成的类型?** +A: 手写类型容易与后端实际返回不一致,导致运行时错误。生成类型确保前后端一致性。 + +**Q: 如何添加自定义逻辑?** +A: 在生成的客户端外封装业务逻辑层,不要修改生成的文件。 + +**Q: API 变更后忘记更新怎么办?** +A: CI/CD 中可添加类型检查步骤,类型不通过则构建失败。 ## 开发命令 @@ -141,4 +616,109 @@ npm run api:update | 家长 | parent1 | 123456 | ## API 文档 -- 访问地址:http://localhost:8080/doc.html(后端启动后) \ No newline at end of file +- 访问地址:http://localhost:8080/doc.html(后端启动后) + +## 近期补充的接口和字段(2026-03-10) + +### 实体类新增字段 + +**StudentRecord** - 学生评价记录 +- `focus` - 专注力评分 (1-5) +- `participation` - 参与度评分 (1-5) +- `interest` - 兴趣评分 (1-5) +- `understanding` - 理解度评分 (1-5) + +**LessonFeedback** - 课时反馈 +- `design_quality` - 设计质量评分 (1-5) +- `participation` - 参与度评分 (1-5) +- `goal_achievement` - 目标达成度评分 (1-5) +- `step_feedbacks` - 环节反馈 JSON +- `pros` - 优点 +- `suggestions` - 建议 +- `activities_done` - 完成的活动 JSON + +**Lesson** - 课时 +- `actual_duration` - 实际时长(分钟) +- `overall_rating` - 整体评分 +- `participation_rating` - 参与度评分 +- `completion_note` - 完成说明 + +**Student** - 学生 +- `class_id` - 班级 ID +- `parent_name` - 家长姓名 +- `parent_phone` - 家长手机号 +- `reading_count` - 阅读次数 +- `lesson_count` - 课时数 + +**ClassTeacher** - 班级教师 +- `is_primary` - 是否主教 +- `sort_order` - 排序 + +**StudentClassHistory** - 学生班级历史 +- `reason` - 调班原因 + +### 新增 Service 方法 + +**ClassService** +- `getClassList(Long tenantId)` - 获取班级列表(无分页) +- `getClassStudents(Long classId, ...)` - 获取班级学生分页 +- `getClassTeachers(Long classId)` - 获取班级教师列表 +- `addClassTeacher(...)` - 添加班级教师 +- `updateClassTeacher(...)` - 更新班级教师角色 +- `removeClassTeacher(...)` - 移除班级教师 + +**LessonService** +- `finishLesson(...)` - 结束课时 +- `saveStudentRecord(...)` - 保存学生评价记录 +- `getStudentRecords(Long lessonId)` - 获取课程所有学生记录 +- `batchSaveStudentRecords(...)` - 批量保存学生评价记录 +- `saveLessonFeedback(...)` - 提交课程反馈 +- `getLessonFeedback(Long lessonId)` - 获取课程反馈 + +**StudentService** +- `transferStudent(...)` - 学生调班 +- `getStudentClassHistory(Long studentId)` - 获取学生调班历史 + +**TaskService** +- `getTaskCompletion(Long taskId, Long studentId)` - 获取任务完成记录 + +### 新增 Controller 接口 + +**学校端 (/api/v1/school/*)** +- `GET /classes/list` - 获取班级列表(无分页) +- `GET /classes/{id}/students` - 获取班级学生分页 +- `GET /classes/{id}/teachers` - 获取班级教师列表 +- `POST /classes/{id}/teachers` - 添加班级教师 +- `PUT /classes/{id}/teachers/{teacherId}` - 更新班级教师角色 +- `DELETE /classes/{id}/teachers/{teacherId}` - 移除班级教师 +- `POST /students/{id}/transfer` - 学生调班 +- `GET /students/{id}/history` - 获取学生调班历史 + +**教师端 (/api/v1/teacher/*)** +- `GET /courses/classes` - 获取教师的班级列表 +- `GET /courses/students` - 获取教师所有学生分页 +- `GET /courses/classes/{classId}/students` - 获取班级学生分页 +- `GET /courses/classes/{classId}/teachers` - 获取班级教师列表 +- `POST /lessons/{id}/finish` - 结束课时 +- `POST /lessons/{lessonId}/students/{studentId}/record` - 保存学生评价记录 +- `GET /lessons/{lessonId}/student-records` - 获取课程所有学生记录 +- `POST /lessons/{lessonId}/student-records/batch` - 批量保存学生评价记录 +- `POST /lessons/{lessonId}/feedback` - 提交课程反馈 +- `GET /lessons/{lessonId}/feedback` - 获取课程反馈 +- `GET /schedules/timetable` - 获取课表(按日期范围) +- `GET /schedules/today` - 获取今日课表 +- `POST /schedules` - 创建课表计划 +- `PUT /schedules/{id}` - 更新课表计划 +- `DELETE /schedules/{id}` - 取消课表计划 + +**家长端 (/api/v1/parent/*)** +- `GET /children` - 获取我的孩子(增强返回格式) +- `GET /children/{id}` - 获取孩子详情(增强返回格式) +- `GET /children/{childId}/lessons` - 获取孩子的课时记录 +- `GET /children/{childId}/tasks` - 获取孩子的任务(带完成状态) +- `PUT /children/{childId}/tasks/{taskId}/feedback` - 提交任务家长反馈 + +### 数据库迁移 + +- 迁移脚本:`` +- 包含上述所有实体类新增字段的 ALTER TABLE 语句 \ No newline at end of file diff --git a/docs/后端接口补全总结.md b/docs/后端接口补全总结.md new file mode 100644 index 0000000..694cb8c --- /dev/null +++ b/docs/后端接口补全总结.md @@ -0,0 +1,157 @@ +# 后端接口补全总结 + +本文档总结了为匹配前端 API 调用而补全的后端接口。 + +## 已完成的工作 + +### 1. 学校端 (`/api/v1/school/*`) + +#### 班级管理 (`/classes`) +- `GET /list` - 获取班级列表(无分页) +- `GET /{id}/students` - 获取班级学生分页 +- `GET /{id}/teachers` - 获取班级教师列表 +- `POST /{id}/teachers` - 添加班级教师 +- `PUT /{id}/teachers/{teacherId}` - 更新班级教师角色 +- `DELETE /{id}/teachers/{teacherId}` - 移除班级教师 + +#### 学生管理 (`/students`) +- `POST /{id}/transfer` - 学生调班 +- `GET /{id}/history` - 获取学生调班历史 + +### 2. 教师端 (`/api/v1/teacher/*`) + +#### 课程管理 (`/courses`) +- `GET /classes` - 获取教师的班级列表 +- `GET /students` - 获取教师所有学生分页 +- `GET /classes/{classId}/students` - 获取班级学生分页 +- `GET /classes/{classId}/teachers` - 获取班级教师列表 + +#### 课时管理 (`/lessons`) +- `POST /{id}/finish` - 结束课时(包含实际时长、评分等) +- `POST /{lessonId}/students/{studentId}/record` - 保存学生评价记录 +- `GET /{lessonId}/student-records` - 获取课程所有学生记录 +- `POST /{lessonId}/student-records/batch` - 批量保存学生评价记录 +- `POST /{lessonId}/feedback` - 提交课程反馈 +- `GET /{lessonId}/feedback` - 获取课程反馈 + +#### 课表管理 (`/schedules`) +- `GET /timetable` - 获取课表(按日期范围) +- `GET /today` - 获取今日课表 +- `POST /` - 创建课表计划 +- `PUT /{id}` - 更新课表计划 +- `DELETE /{id}` - 取消课表计划 + +### 3. 家长端 (`/api/v1/parent/*`) + +#### 孩子信息 (`/children`) +- `GET /` - 获取我的孩子(增强返回格式) +- `GET /{id}` - 获取孩子详情(增强返回格式) +- `GET /{childId}/lessons` - 获取孩子的课时记录 +- `GET /{childId}/tasks` - 获取孩子的任务(带完成状态) + +#### 任务管理 (`/tasks`) +- `PUT /{childId}/tasks/{taskId}/feedback` - 提交任务家长反馈 + +### 4. 管理员端 (`/api/v1/admin/*`) + +管理员端接口大部分已存在,以下接口需要在未来补充: +- `PUT /themes/reorder` - 主题重新排序 +- `PUT /packages/{packageId}/courses` - 设置套餐课程 +- `POST /packages/{packageId}/courses` - 添加课程到套餐 +- `DELETE /packages/{packageId}/courses/{courseId}` - 从套餐移除课程 +- `POST /packages/{id}/submit` - 提交审核 +- `POST /packages/{id}/review` - 审核套餐 +- `POST /packages/{id}/publish` - 发布套餐 +- `POST /packages/{id}/offline` - 下架套餐 + +## 实体类更新 + +### StudentRecord +新增字段: +- `focus` - 专注力评分 (1-5) +- `participation` - 参与度评分 (1-5) +- `interest` - 兴趣评分 (1-5) +- `understanding` - 理解度评分 (1-5) + +### LessonFeedback +新增字段: +- `designQuality` - 设计质量评分 (1-5) +- `participation` - 参与度评分 (1-5) +- `goalAchievement` - 目标达成度评分 (1-5) +- `stepFeedbacks` - 环节反馈 JSON +- `pros` - 优点 +- `suggestions` - 建议 +- `activitiesDone` - 完成的活动 JSON + +## Service 方法更新 + +### ClassService +- `getClassList(Long tenantId)` - 获取班级列表 +- `getClassStudents(Long classId, ...)` - 获取班级学生分页 +- `getClassTeachers(Long classId)` - 获取班级教师列表 +- `addClassTeacher(...)` - 添加班级教师 +- `updateClassTeacher(...)` - 更新班级教师角色 +- `removeClassTeacher(...)` - 移除班级教师 + +### LessonService +- `finishLesson(...)` - 结束课时 +- `saveStudentRecord(...)` - 保存学生评价记录 +- `getStudentRecords(Long lessonId)` - 获取课程所有学生记录 +- `batchSaveStudentRecords(...)` - 批量保存学生评价记录 +- `saveLessonFeedback(...)` - 提交课程反馈 +- `getLessonFeedback(Long lessonId)` - 获取课程反馈 + +### StudentService +- `transferStudent(...)` - 学生调班 +- `getStudentClassHistory(Long studentId)` - 获取学生调班历史 + +### TaskService +- `getTaskCompletion(Long taskId, Long studentId)` - 获取任务完成记录 + +## 数据库迁移需求 + +需要创建数据库迁移脚本,添加以下字段: + +```sql +-- student_records 表新增字段 +ALTER TABLE student_records ADD COLUMN focus INT COMMENT '专注力评分 (1-5)'; +ALTER TABLE student_records ADD COLUMN participation INT COMMENT '参与度评分 (1-5)'; +ALTER TABLE student_records ADD COLUMN interest INT COMMENT '兴趣评分 (1-5)'; +ALTER TABLE student_records ADD COLUMN understanding INT COMMENT '理解度评分 (1-5)'; + +-- lesson_feedbacks 表新增字段 +ALTER TABLE lesson_feedbacks ADD COLUMN design_quality INT COMMENT '设计质量评分 (1-5)'; +ALTER TABLE lesson_feedbacks ADD COLUMN participation INT COMMENT '参与度评分 (1-5)'; +ALTER TABLE lesson_feedbacks ADD COLUMN goal_achievement INT COMMENT '目标达成度评分 (1-5)'; +ALTER TABLE lesson_feedbacks ADD COLUMN step_feedbacks TEXT COMMENT '环节反馈 JSON'; +ALTER TABLE lesson_feedbacks ADD COLUMN pros TEXT COMMENT '优点'; +ALTER TABLE lesson_feedbacks ADD COLUMN suggestions TEXT COMMENT '建议'; +ALTER TABLE lesson_feedbacks ADD COLUMN activities_done TEXT COMMENT '完成的活动 JSON'; + +-- student_class_history 表新增字段 +ALTER TABLE student_class_history ADD COLUMN reason VARCHAR(255) COMMENT '调班原因'; +``` + +## 待补充的接口 + +### 学校端 +- `GET /stats/teachers/active` - 获取活跃教师统计 +- `GET /stats/courses` - 获取课程使用统计 +- `GET /stats/activities` - 获取最近活动 +- `GET /stats/lesson-trend` - 课时趋势 +- `GET /stats/course-distribution` - 课程分布 +- `GET /reports/*` - 数据报告接口 + +### 教师端 +- `POST /tasks/{taskId}/remind` - 发送任务提醒 +- `GET /school-courses/*` - 校本课程相关接口 + +### 家长端 +- `GET /growth-records/student/{studentId}` - 获取孩子成长记录(已存在,路径不同) + +## 注意事项 + +1. 所有新增的数据库字段需要创建 Flyway 迁移脚本 +2. 部分接口的返回数据结构已调整以匹配前端需求 +3. 部分 Service 方法需要进一步测试验证 +4. 教师端的班级、学生过滤逻辑需要根据实际业务场景优化 diff --git a/docs/表名统一修改说明.md b/docs/表名统一修改说明.md new file mode 100644 index 0000000..34b8583 --- /dev/null +++ b/docs/表名统一修改说明.md @@ -0,0 +1,135 @@ +# 表名统一修改说明 + +## 修改时间 +2026-03-10 + +## 修改目的 +将数据库表名从复数形式改为单数形式,使其与 ORM 实体类名保持一致(除了下划线和驼峰的区别)。 + +## 修改内容 + +### 1. Flyway 迁移脚本 +创建了新的 Flyway 迁移脚本: +- 文件:`reading-platform-java/src/main/resources/db/migration/V22__rename_tables_to_singular.sql` +- 功能:将所有数据库表名从复数改为单数 + +### 2. 实体类 @TableName 注解更新 +更新了 36 个实体类的 `@TableName` 注解: + +| 序号 | 原表名(复数) | 新表名(单数) | 实体类名 | +|-----|---------------|---------------|---------| +| 1 | `admin_users` | `admin_user` | `AdminUser` | +| 2 | `tenants` | `tenant` | `Tenant` | +| 3 | `teachers` | `teacher` | `Teacher` | +| 4 | `students` | `student` | `Student` | +| 5 | `parents` | `parent` | `Parent` | +| 6 | `parent_students` | `parent_student` | `ParentStudent` | +| 7 | `classes` | `clazz` | `Clazz` | +| 8 | `class_teachers` | `class_teacher` | `ClassTeacher` | +| 9 | `student_class_history` | `student_class_history` | `StudentClassHistory` (无需修改) | +| 10 | `courses` | `course` | `Course` | +| 11 | `course_versions` | `course_version` | `CourseVersion` | +| 12 | `course_resources` | `course_resource` | `CourseResource` | +| 13 | `course_scripts` | `course_script` | `CourseScript` | +| 14 | `course_script_pages` | `course_script_page` | `CourseScriptPage` | +| 15 | `course_activities` | `course_activity` | `CourseActivity` | +| 16 | `course_packages` | `course_package` | `CoursePackage` | +| 17 | `school_courses` | `school_course` | `SchoolCourse` | +| 18 | `tenant_courses` | `tenant_course` | `TenantCourse` | +| 19 | `lessons` | `lesson` | `Lesson` | +| 20 | `lesson_feedbacks` | `lesson_feedback` | `LessonFeedback` | +| 21 | `student_records` | `student_record` | `StudentRecord` | +| 22 | `tasks` | `task` | `Task` | +| 23 | `task_targets` | `task_target` | `TaskTarget` | +| 24 | `task_completions` | `task_completion` | `TaskCompletion` | +| 25 | `task_templates` | `task_template` | `TaskTemplate` | +| 26 | `growth_records` | `growth_record` | `GrowthRecord` | +| 27 | `resource_libraries` | `resource_library` | `ResourceLibrary` | +| 28 | `resource_items` | `resource_item` | `ResourceItem` | +| 29 | `schedule_plans` | `schedule_plan` | `SchedulePlan` | +| 30 | `schedule_templates` | `schedule_template` | `ScheduleTemplate` | +| 31 | `system_settings` | `system_setting` | `SystemSetting` | +| 32 | `themes` | `theme` | `Theme` | +| 33 | `tags` | `tag` | `Tag` | +| 34 | `notifications` | `notification` | `Notification` | +| 35 | `operation_logs` | `operation_log` | `OperationLog` | + +### 3. Mapper 接口 SQL 更新 +更新了以下 Mapper 接口中的硬编码 SQL 表名: + +| 文件 | 修改内容 | +|-----|---------| +| `ThemeMapper.java` | `DELETE FROM themes` → `DELETE FROM theme` | +| `ParentMapper.java` | `DELETE FROM parents` → `DELETE FROM parent` | +| `TenantMapper.java` | `DELETE FROM tenants` → `DELETE FROM tenant` (2 处) | +| `TeacherMapper.java` | `DELETE FROM teachers` → `DELETE FROM teacher` | +| `StudentMapper.java` | `DELETE FROM students` → `DELETE FROM student` | + +## 部署步骤 + +### 步骤 1:备份数据库 +在执行迁移前,务必备份开发/生产数据库: +```bash +mysqldump -u root -p reading_platform > backup_$(date +%Y%m%d).sql +``` + +### 步骤 2:执行 Flyway 迁移 +启动后端服务,Flyway 会自动执行 `V22__rename_tables_to_singular.sql` 迁移脚本。 + +或者手动执行: +```bash +mysql -u root -p reading_platform < reading-platform-java/src/main/resources/db/migration/V22__rename_tables_to_singular.sql +``` + +### 步骤 3:验证迁移结果 +在 MySQL 中执行: +```sql +-- 查看所有表名 +SHOW TABLES; + +-- 验证特定表是否存在 +SHOW TABLES LIKE 'student'; +SHOW TABLES LIKE 'student_record'; +SHOW TABLES LIKE 'lesson_feedback'; +``` + +### 步骤 4:测试功能 +启动后端服务后,测试以下功能: +1. 用户管理(管理员、教师、学生、家长) +2. 班级管理 +3. 课程管理 +4. 课时管理 +5. 任务管理 +6. 成长记录 +7. 资源管理 +8. 日程管理 + +## 注意事项 + +1. **外键处理**:迁移脚本中先禁用外键检查(`SET FOREIGN_KEY_CHECKS = 0`),执行完后再启用 +2. **Flyway 历史**:确保 `flyway_schema_history` 表正确记录迁移历史 +3. **生产环境**:在生产环境执行前,务必在开发/测试环境充分测试 +4. **回滚方案**:如需回滚,可以准备反向迁移脚本(将单数表名改回复数) + +## 相关文件清单 + +### 新增文件 +- `reading-platform-java/src/main/resources/db/migration/V22__rename_tables_to_singular.sql` + +### 修改的文件 +- 所有 Entity 类(36 个文件) +- 5 个 Mapper 接口 + +## 验证清单 + +- [x] 所有 Entity 类的 `@TableName` 注解已更新 +- [x] 所有 Mapper 接口的 SQL 已更新 +- [x] Controller 中无硬编码表名引用 +- [x] Service 中无硬编码表名引用 +- [x] Flyway 迁移脚本已创建 + +## 后续工作 + +1. 在开发环境执行迁移并验证 +2. 更新 API 文档中的表名引用(如有) +3. 更新项目文档中的表名引用(如有) diff --git a/docs/限流功能使用说明.md b/docs/限流功能使用说明.md new file mode 100644 index 0000000..dfdbe24 --- /dev/null +++ b/docs/限流功能使用说明.md @@ -0,0 +1,224 @@ +# 限流功能使用说明 + +## 功能概述 + +本项目已集成基于 Redis 滑动窗口算法的限流功能,支持两种使用方式: +1. **配置化限流** - 在 `application.yml` 中配置规则,自动对所有接口生效 +2. **注解限流** - 在 Controller 方法上使用 `@RateLimit` 注解,针对特定接口限流 + +## 技术实现 + +### 核心组件 + +| 组件 | 说明 | +|------|------| +| `@RateLimit` | 限流注解,可自定义时间窗口、最大请求数 | +| `RateLimitProperties` | 配置化限流的属性类 | +| `RateLimiter` | Redis 限流工具类(滑动窗口算法) | +| `RateLimitAspect` | 注解限流的 AOP 切面 | +| `RateLimitInterceptor` | 配置化限流的拦截器 | +| `ErrorCode.RATE_LIMIT_EXCEEDED` | 限流错误码(5001) | + +### 限流优先级 + +**注解限流 > 配置化限流 > 默认限流** + +## 使用方式 + +### 方式一:配置化限流(推荐作为基础防护) + +在 `application.yml` 中配置: + +```yaml +rate-limit: + enabled: true # 是否启用限流 + default-time-window: 60 # 默认时间窗口(秒) + default-max-requests: 1000 # 默认时间窗口内最大请求数 + rules: # 限流规则列表 + # 登录接口限流 - 防止暴力破解 + - pattern: "/api/v1/auth/login" + time-window: 60 + max-requests: 10 + # 验证码接口限流 - 防止刷验证码 + - pattern: "/api/v1/auth/captcha" + time-window: 60 + max-requests: 5 + # 短信接口限流 - 防止短信轰炸 + - pattern: "/api/v1/sms/**" + time-window: 60 + max-requests: 3 + # 文件上传接口限流 + - pattern: "/api/v1/**/upload/**" + time-window: 60 + max-requests: 30 + exclude-patterns: # 排除限流的接口 + - "/doc.html" + - "/swagger-resources/**" + - "/v3/api-docs/**" + - "/webjars/**" + - "/uploads/**" +``` + +### 方式二:注解限流(针对特殊接口) + +在 Controller 方法上添加 `@RateLimit` 注解: + +```java +package com.reading.platform.controller.auth; + +import com.reading.platform.common.annotation.RateLimit; +import com.reading.platform.common.response.Result; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/v1/auth") +public class AuthController { + + /** + * 登录接口 - 限流防止暴力破解 + * 60 秒内最多 10 次请求 + */ + @PostMapping("/login") + @RateLimit(time = 60, maxRequests = 10, message = "登录过于频繁,请稍后再试") + public Result login(@RequestBody LoginRequest request) { + // ... 登录逻辑 + } + + /** + * 发送短信验证码 - 严格限流 + * 60 秒内最多 3 次请求 + */ + @PostMapping("/captcha") + @RateLimit(time = 60, maxRequests = 3, message = "操作过于频繁,请稍后再试") + public Result sendCaptcha(@RequestParam String phone) { + // ... 发送验证码逻辑 + } + + /** + * 自定义限流键前缀 + * 适用于需要按用户 ID 等特殊维度限流的场景 + */ + @PostMapping("/special") + @RateLimit(keyPrefix = "special_api:", time = 60, maxRequests = 5) + public Result specialApi() { + // ... 特殊接口逻辑 + } +} +``` + +## 常见限流场景建议值 + +| 接口类型 | 时间窗口 | 最大请求数 | 说明 | +|---------|---------|-----------|------| +| 登录接口 | 60 秒 | 10 | 防止暴力破解 | +| 验证码/短信 | 60 秒 | 3-5 | 防止短信轰炸 | +| 文件上传 | 60 秒 | 30 | 防止资源滥用 | +| 普通业务接口 | 60 秒 | 100-1000 | 根据业务调整 | +| 导出接口 | 60 秒 | 5-10 | 防止服务器过载 | + +## 限流响应 + +当请求被限流拦截时,返回: + +**配置化限流响应:** +```json +{ + "code": 5001, + "message": "请求过于频繁,请稍后再试", + "data": null +} +``` + +HTTP 状态码:`429 Too Many Requests` + +响应头: +``` +X-RateLimit-Limit: 1 +X-RateLimit-Remaining: 0 +Retry-After: 60 +``` + +**注解限流响应:** +```json +{ + "code": 5001, + "message": "登录过于频繁,请稍后再试", + "data": null +} +``` + +## Redis 数据结构 + +限流使用 Redis 的 `Sorted Set`(有序集合)存储: + +- **Key 格式**: `rate_limit:{key}` +- **Member**: 时间戳(毫秒) +- **Score**: 时间戳(毫秒) + +示例: +``` +rate_limit:192.168.1.1:/api/v1/auth/login + |- 1710000000000 + |- 1710000001000 + |- 1710000002000 +``` + +## 注意事项 + +1. **Redis 依赖**: 限流功能依赖 Redis,需确保 Redis 服务可用 +2. **异常情况放行**: 当 Redis 不可用时,系统会自动放行请求,避免影响正常业务 +3. **集群部署**: 滑动窗口算法天然支持分布式,无需额外配置 +4. **监控告警**: 建议添加限流触发的监控告警,及时发现异常流量 + +## 日志示例 + +``` +2024-03-10 22:00:00 WARN - 请求被限流拦截:URI=/api/v1/auth/login, 规则=/api/v1/auth/login, 最大请求数=10 +2024-03-10 22:00:01 DEBUG - 请求通过限流检查:URI=/api/v1/users, 规则=default +``` + +## 测试方法 + +使用 `curl` 或 Postman 快速测试: + +```bash +# 循环发送 15 次登录请求(第 11 次开始应该被限流) +for i in {1..15}; do + echo "请求 $i:" + curl -X POST http://localhost:8080/api/v1/auth/login \ + -H "Content-Type: application/json" \ + -d '{"username":"test","password":"test"}' \ + -w "\nHTTP 状态码:%{http_code}\n\n" +done +``` + +## 配置说明 + +### RateLimit 注解参数 + +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `keyPrefix` | String | "" | 限流键前缀,默认使用 `IP:类名。方法名` | +| `time` | long | 60 | 时间窗口大小 | +| `timeUnit` | TimeUnit | SECONDS | 时间单位 | +| `maxRequests` | long | 100 | 时间窗口内最大请求数 | +| `message` | String | "请求过于频繁,请稍后再试" | 限流提示信息 | +| `enabled` | boolean | true | 是否启用限流 | + +### application.yml 配置参数 + +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `enabled` | boolean | true | 是否启用限流 | +| `default-time-window` | long | 60 | 默认时间窗口(秒) | +| `default-max-requests` | long | 1000 | 默认最大请求数 | +| `rules` | List | [] | 限流规则列表 | +| `exclude-patterns` | List | [] | 排除限流的接口路径 | + +### RateLimitRule 配置参数 + +| 参数 | 类型 | 说明 | +|------|------|------| +| `pattern` | String | 接口路径(支持 Ant 风格通配符) | +| `time-window` | long | 时间窗口(秒) | +| `max-requests` | long | 最大请求数 | diff --git a/reading-platform-frontend/api-spec.yml b/reading-platform-frontend/api-spec.yml index bae7c8a..6bdb761 100644 --- a/reading-platform-frontend/api-spec.yml +++ b/reading-platform-frontend/api-spec.yml @@ -32,6 +32,8 @@ tags: description: 教师仪表盘 - name: 管理员 - 课程课时 description: 课程课时管理接口(管理员专用) + - name: 学校 - 通知 + description: 通知接口(学校管理员专用) - name: 教师 - 课程 description: 课程接口(教师专用) - name: 学校 - 导出 @@ -87,11 +89,83 @@ tags: - name: 教师 - 通知 description: 通知接口(教师专用) paths: + /api/v1/teacher/tasks/{taskId}/completions/{studentId}: + put: + tags: + - 教师 - 任务 + summary: 更新任务完成状态 + operationId: updateCompletion + parameters: + - name: taskId + in: path + required: true + schema: + type: integer + format: int64 + - name: studentId + in: path + required: true + schema: + type: integer + format: int64 + - name: status + in: query + required: true + schema: + type: string + - name: feedback + in: query + required: false + schema: + type: string + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultTaskCompletion' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/teacher/tasks/{id}: get: tags: - 教师 - 任务 - summary: 根据ID获取任务 + summary: 根据 ID 获取任务 operationId: getTask parameters: - name: id @@ -720,11 +794,83 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' + /api/v1/school/tasks/{taskId}/completions/{studentId}: + put: + tags: + - 学校 - 任务 + summary: 更新任务完成状态 + operationId: updateCompletion_1 + parameters: + - name: taskId + in: path + required: true + schema: + type: integer + format: int64 + - name: studentId + in: path + required: true + schema: + type: integer + format: int64 + - name: status + in: query + required: true + schema: + type: string + - name: feedback + in: query + required: false + schema: + type: string + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultTaskCompletion' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/school/tasks/{id}: get: tags: - 学校 - 任务 - summary: 根据ID获取任务 + summary: 根据 ID 获取任务 operationId: getTask_1 parameters: - name: id @@ -892,6 +1038,178 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' + /api/v1/school/tasks/task-templates/{id}: + get: + tags: + - 学校 - 任务 + summary: 根据 ID 获取任务模板 + operationId: getTemplate_1 + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultTaskTemplate' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + put: + tags: + - 学校 - 任务 + summary: 更新任务模板 + operationId: updateTemplate + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TaskTemplateUpdateRequest' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultTaskTemplate' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + delete: + tags: + - 学校 - 任务 + summary: 删除任务模板 + operationId: deleteTemplate + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/school/students/{id}: get: tags: @@ -1345,7 +1663,7 @@ paths: get: tags: - 学校 - 课表 - summary: 根据ID获取课表计划 + summary: 根据 ID 获取课表计划 operationId: getSchedulePlan_1 parameters: - name: id @@ -1513,6 +1831,178 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' + /api/v1/school/schedules/templates/{id}: + get: + tags: + - 学校 - 课表 + summary: 根据 ID 获取课表模板 + operationId: getScheduleTemplate + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultScheduleTemplate' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + put: + tags: + - 学校 - 课表 + summary: 更新课表模板 + operationId: updateScheduleTemplate + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ScheduleTemplate' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultScheduleTemplate' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + delete: + tags: + - 学校 - 课表 + summary: 删除课表模板 + operationId: deleteScheduleTemplate + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/school/parents/{id}: get: tags: @@ -3677,6 +4167,61 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' + /api/v1/teacher/tasks/from-template: + post: + tags: + - 教师 - 任务 + summary: 从模板创建任务 + operationId: createFromTemplate + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateTaskFromTemplateRequest' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultTask' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/teacher/notifications/{id}/read: post: tags: @@ -4528,6 +5073,187 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' + /api/v1/school/tasks/task-templates: + get: + tags: + - 学校 - 任务 + summary: 获取任务模板列表 + operationId: getTemplates_1 + parameters: + - name: page + in: query + required: false + schema: + type: integer + format: int32 + - name: pageSize + in: query + required: false + schema: + type: integer + format: int32 + - name: keyword + in: query + required: false + schema: + type: string + - name: type + in: query + required: false + schema: + type: string + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultPageResultTaskTemplate' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + post: + tags: + - 学校 - 任务 + summary: 创建任务模板 + operationId: createTemplate + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TaskTemplateCreateRequest' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultTaskTemplate' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/tasks/from-template: + post: + tags: + - 学校 - 任务 + summary: 从模板创建任务 + operationId: createFromTemplate_1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateTaskFromTemplateRequest' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultTask' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/school/students: get: tags: @@ -4659,6 +5385,63 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' + /api/v1/school/students/import: + post: + tags: + - 学校 - 学生 + summary: 批量导入学生 + operationId: importStudents + requestBody: + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/StudentCreateRequest' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListStudent' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/school/school-courses: get: tags: @@ -4809,6 +5592,18 @@ paths: schema: type: integer format: int64 + - name: startDate + in: query + required: false + schema: + type: string + format: date + - name: endDate + in: query + required: false + schema: + type: string + format: date responses: '200': description: OK @@ -4861,7 +5656,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SchedulePlan' + $ref: '#/components/schemas/SchedulePlanCreateRequest' required: true responses: '200': @@ -5024,6 +5819,125 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' + /api/v1/school/schedules/templates/{id}/apply: + post: + tags: + - 学校 - 课表 + summary: 应用课表模板 + operationId: applyScheduleTemplate + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ScheduleTemplateApplyRequest' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListSchedulePlan' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/schedules/batch: + post: + tags: + - 学校 - 课表 + summary: 批量创建排课 + operationId: batchCreateSchedules + requestBody: + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SchedulePlanCreateRequest' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListSchedulePlan' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/school/parents: get: tags: @@ -5344,6 +6258,111 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' + /api/v1/school/notifications/{id}/read: + post: + tags: + - 学校 - 通知 + summary: 标记通知为已读 + operationId: markAsRead_1 + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/notifications/read-all: + post: + tags: + - 学校 - 通知 + summary: 标记所有通知为已读 + operationId: markAllAsRead_1 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/school/growth-records: get: tags: @@ -5809,7 +6828,7 @@ paths: tags: - 家长 - 通知 summary: 标记通知为已读 - operationId: markAsRead_1 + operationId: markAsRead_2 parameters: - name: id in: path @@ -5865,7 +6884,7 @@ paths: tags: - 家长 - 通知 summary: 标记所有通知为已读 - operationId: markAllAsRead_1 + operationId: markAllAsRead_2 responses: '200': description: OK @@ -7845,6 +8864,466 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' + /api/v1/teacher/tasks/{id}/completions: + get: + tags: + - 教师 - 任务 + summary: 获取任务完成情况分页 + operationId: getCompletions + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + - name: page + in: query + required: false + schema: + type: integer + format: int32 + - name: pageSize + in: query + required: false + schema: + type: integer + format: int32 + - name: status + in: query + required: false + schema: + type: string + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultPageResultTaskCompletion' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/teacher/tasks/task-templates: + get: + tags: + - 教师 - 任务 + summary: 获取任务模板列表 + operationId: getTemplates + parameters: + - name: page + in: query + required: false + schema: + type: integer + format: int32 + - name: pageSize + in: query + required: false + schema: + type: integer + format: int32 + - name: keyword + in: query + required: false + schema: + type: string + - name: type + in: query + required: false + schema: + type: string + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultPageResultTaskTemplate' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/teacher/tasks/task-templates/{id}: + get: + tags: + - 教师 - 任务 + summary: 根据 ID 获取任务模板 + operationId: getTemplate + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultTaskTemplate' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/teacher/tasks/task-templates/default/{taskType}: + get: + tags: + - 教师 - 任务 + summary: 获取默认模板(按类型) + operationId: getDefaultTemplate + parameters: + - name: taskType + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultTaskTemplate' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/teacher/tasks/stats: + get: + tags: + - 教师 - 任务 + summary: 获取任务统计数据 + operationId: getStats + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/teacher/tasks/stats/monthly: + get: + tags: + - 教师 - 任务 + summary: 获取月度统计趋势 + operationId: getMonthlyStats + parameters: + - name: months + in: query + required: false + schema: + type: integer + format: int32 + default: 6 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/teacher/tasks/stats/by-type: + get: + tags: + - 教师 - 任务 + summary: 按任务类型统计 + operationId: getStatsByType + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/teacher/tasks/stats/by-class: + get: + tags: + - 教师 - 任务 + summary: 按班级统计 + operationId: getStatsByClass + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/teacher/school-courses: get: tags: @@ -8754,12 +10233,140 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' - /api/v1/school/stats: + /api/v1/school/tasks/{id}/completions: get: tags: - - 学校 - 统计 - summary: 获取学校统计数据 - operationId: getStats + - 学校 - 任务 + summary: 获取任务完成情况分页 + operationId: getCompletions_1 + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + - name: page + in: query + required: false + schema: + type: integer + format: int32 + - name: pageSize + in: query + required: false + schema: + type: integer + format: int32 + - name: status + in: query + required: false + schema: + type: string + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultPageResultTaskCompletion' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/tasks/task-templates/default/{taskType}: + get: + tags: + - 学校 - 任务 + summary: 获取默认模板(按类型) + operationId: getDefaultTemplate_1 + parameters: + - name: taskType + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultTaskTemplate' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/tasks/stats: + get: + tags: + - 学校 - 任务 + summary: 获取任务统计数据 + operationId: getStats_1 responses: '200': description: OK @@ -8803,6 +10410,596 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' + /api/v1/school/tasks/stats/monthly: + get: + tags: + - 学校 - 任务 + summary: 获取月度统计趋势 + operationId: getMonthlyStats_1 + parameters: + - name: months + in: query + required: false + schema: + type: integer + format: int32 + default: 6 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/tasks/stats/by-type: + get: + tags: + - 学校 - 任务 + summary: 按任务类型统计 + operationId: getStatsByType_1 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/tasks/stats/by-class: + get: + tags: + - 学校 - 任务 + summary: 按班级统计 + operationId: getStatsByClass_1 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/students/import/template: + get: + tags: + - 学校 - 学生 + summary: 获取导入模板 + operationId: getImportTemplate + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/stats: + get: + tags: + - 学校 - 统计 + summary: 获取学校统计数据 + operationId: getStats_2 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/stats/teachers: + get: + tags: + - 学校 - 统计 + summary: 获取活跃教师统计 + operationId: getActiveTeachers + parameters: + - name: limit + in: query + required: false + schema: + type: integer + format: int32 + default: 5 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/stats/lesson-trend: + get: + tags: + - 学校 - 统计 + summary: 获取课时趋势(最近 N 个月) + operationId: getLessonTrend + parameters: + - name: months + in: query + required: false + schema: + type: integer + format: int32 + default: 6 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/stats/courses: + get: + tags: + - 学校 - 统计 + summary: 获取课程使用统计 + operationId: getCourseUsageStats + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/stats/course-distribution: + get: + tags: + - 学校 - 统计 + summary: 获取课程分布统计(饼图数据) + operationId: getCourseDistribution + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/stats/activities: + get: + tags: + - 学校 - 统计 + summary: 获取最近活动记录 + operationId: getRecentActivities + parameters: + - name: limit + in: query + required: false + schema: + type: integer + format: int32 + default: 10 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/schedules/timetable: + get: + tags: + - 学校 - 课表 + summary: 获取课表(按日期范围) + operationId: getTimetable + parameters: + - name: startDate + in: query + required: false + schema: + type: string + format: date + - name: endDate + in: query + required: false + schema: + type: string + format: date + - name: classId + in: query + required: false + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultListMapStringObject' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/school/operation-logs: get: tags: @@ -8872,6 +11069,179 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' + /api/v1/school/notifications: + get: + tags: + - 学校 - 通知 + summary: 获取我的通知 + operationId: getMyNotifications_1 + parameters: + - name: page + in: query + required: false + schema: + type: integer + format: int32 + - name: pageSize + in: query + required: false + schema: + type: integer + format: int32 + - name: isRead + in: query + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultPageResultNotification' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/notifications/{id}: + get: + tags: + - 学校 - 通知 + summary: 根据 ID 获取通知 + operationId: getNotification_1 + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultNotification' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/notifications/unread-count: + get: + tags: + - 学校 - 通知 + summary: 获取未读通知数量 + operationId: getUnreadCount_1 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultLong' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' /api/v1/school/export/teachers: get: tags: @@ -9339,7 +11709,7 @@ paths: tags: - 家长 - 通知 summary: 获取我的通知 - operationId: getMyNotifications_1 + operationId: getMyNotifications_2 parameters: - name: page in: query @@ -9407,7 +11777,7 @@ paths: tags: - 家长 - 通知 summary: 根据ID获取通知 - operationId: getNotification_1 + operationId: getNotification_2 parameters: - name: id in: path @@ -9463,7 +11833,7 @@ paths: tags: - 家长 - 通知 summary: 获取未读通知数量 - operationId: getUnreadCount_1 + operationId: getUnreadCount_2 responses: '200': description: OK @@ -9851,7 +12221,7 @@ paths: tags: - 管理员 - 统计 summary: 获取整体统计数据 - operationId: getStats_1 + operationId: getStats_3 responses: '200': description: OK @@ -10252,12 +12622,12 @@ paths: '*/*': schema: $ref: '#/components/schemas/ResultVoid' - /api/v1/school/schedules/templates/{id}: + /api/v1/school/classes/{id}/teachers/{teacherId}: delete: tags: - - 学校 - 课表 - summary: 删除课表模板 - operationId: deleteScheduleTemplate + - 学校 - 班级 + summary: 移除班级教师 + operationId: removeTeacher parameters: - name: id in: path @@ -10265,6 +12635,74 @@ paths: schema: type: integer format: int64 + - name: teacherId + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '400': + description: Bad Request + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '401': + description: Unauthorized + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '403': + description: Forbidden + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '404': + description: Not Found + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '405': + description: Method Not Allowed + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + '500': + description: Internal Server Error + content: + '*/*': + schema: + $ref: '#/components/schemas/ResultVoid' + /api/v1/school/classes/{id}/students/{studentId}: + delete: + tags: + - 学校 - 班级 + summary: 移除班级学生 + operationId: removeStudent + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + - name: studentId + in: path + required: true + schema: + type: integer + format: int64 responses: '200': description: OK @@ -10375,6 +12813,51 @@ components: type: string data: type: object + ResultTaskCompletion: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + data: + $ref: '#/components/schemas/TaskCompletion' + TaskCompletion: + type: object + properties: + id: + type: integer + format: int64 + taskId: + type: integer + format: int64 + studentId: + type: integer + format: int64 + status: + type: string + completedAt: + type: string + format: date-time + content: + type: string + attachments: + type: string + rating: + type: integer + format: int32 + feedback: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: integer + format: int32 TaskUpdateRequest: type: object properties: @@ -10695,6 +13178,65 @@ components: deleted: type: integer format: int32 + TaskTemplateUpdateRequest: + type: object + properties: + name: + type: string + description: 模板名称 + description: + type: string + description: 模板描述 + type: + type: string + description: 任务类型:阅读、作业、活动 + content: + type: string + description: 任务内容模板 + isPublic: + type: integer + description: 是否公共模板:0-私有,1-公共 + format: int32 + description: 任务模板更新请求 + ResultTaskTemplate: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + data: + $ref: '#/components/schemas/TaskTemplate' + TaskTemplate: + type: object + properties: + id: + type: integer + format: int64 + tenantId: + type: integer + format: int64 + name: + type: string + description: + type: string + type: + type: string + content: + type: string + isPublic: + type: integer + format: int32 + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: integer + format: int32 StudentUpdateRequest: type: object properties: @@ -10836,12 +13378,32 @@ components: classId: type: integer format: int64 + courseId: + type: integer + format: int64 + teacherId: + type: integer + format: int64 + dayOfWeek: + type: integer + format: int32 + period: + type: integer + format: int32 + startTime: + $ref: '#/components/schemas/LocalTime' + endTime: + $ref: '#/components/schemas/LocalTime' startDate: type: string format: date endDate: type: string format: date + location: + type: string + note: + type: string status: type: string createdAt: @@ -10863,6 +13425,43 @@ components: type: string data: $ref: '#/components/schemas/SchedulePlan' + ScheduleTemplate: + type: object + properties: + id: + type: integer + format: int64 + tenantId: + type: integer + format: int64 + name: + type: string + description: + type: string + content: + type: string + isPublic: + type: integer + format: int32 + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: integer + format: int32 + ResultScheduleTemplate: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + data: + $ref: '#/components/schemas/ScheduleTemplate' ParentUpdateRequest: type: object properties: @@ -11613,6 +14212,34 @@ components: description: 目标ID列表 format: int64 description: 任务创建请求 + CreateTaskFromTemplateRequest: + required: + - targetIds + type: object + properties: + templateId: + type: integer + description: 模板 ID + format: int64 + targetIds: + type: array + description: 目标 ID 列表(班级 ID 或学生 ID) + items: + type: integer + description: 目标 ID 列表(班级 ID 或学生 ID) + format: int64 + targetType: + type: string + description: 目标类型:CLASS-班级,STUDENT-学生 + startDate: + type: string + description: 任务开始日期 + format: date + endDate: + type: string + description: 任务截止日期 + format: date + description: 从模板创建任务请求 LessonCreateRequest: required: - courseId @@ -11714,6 +14341,28 @@ components: type: string description: 个人简介 description: 教师创建请求 + TaskTemplateCreateRequest: + required: + - name + type: object + properties: + name: + type: string + description: 模板名称 + description: + type: string + description: 模板描述 + type: + type: string + description: 任务类型:阅读、作业、活动 + content: + type: string + description: 任务内容模板 + isPublic: + type: integer + description: 是否公共模板:0-私有,1-公共 + format: int32 + description: 任务模板创建请求 StudentCreateRequest: required: - name @@ -11745,34 +14394,7 @@ components: type: string description: Notes description: 学生创建请求 - ScheduleTemplate: - type: object - properties: - id: - type: integer - format: int64 - tenantId: - type: integer - format: int64 - name: - type: string - description: - type: string - content: - type: string - isPublic: - type: integer - format: int32 - createdAt: - type: string - format: date-time - updatedAt: - type: string - format: date-time - deleted: - type: integer - format: int32 - ResultScheduleTemplate: + ResultListStudent: type: object properties: code: @@ -11781,7 +14403,82 @@ components: message: type: string data: - $ref: '#/components/schemas/ScheduleTemplate' + type: array + items: + $ref: '#/components/schemas/Student' + SchedulePlanCreateRequest: + type: object + properties: + classId: + type: integer + description: 班级 ID + format: int64 + courseId: + type: integer + description: 课程 ID + format: int64 + dayOfWeek: + type: integer + description: 星期几:1-7 + format: int32 + period: + type: integer + description: 节次 + format: int32 + startTime: + $ref: '#/components/schemas/LocalTime' + endTime: + $ref: '#/components/schemas/LocalTime' + teacherId: + type: integer + description: 授课教师 ID + format: int64 + startDate: + type: string + description: 开始日期 + format: date + endDate: + type: string + description: 结束日期 + format: date + location: + type: string + description: 教室/地点 + note: + type: string + description: 备注 + description: 课表计划创建请求 + ScheduleTemplateApplyRequest: + required: + - classId + - startDate + type: object + properties: + classId: + type: integer + description: 班级 ID + format: int64 + startDate: + type: string + description: 应用开始日期 + format: date + weeks: + type: integer + description: 应用周数 + format: int32 + description: 课表模板应用请求 + ResultListSchedulePlan: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + data: + type: array + items: + $ref: '#/components/schemas/SchedulePlan' ParentCreateRequest: required: - name @@ -12092,6 +14789,78 @@ components: type: string data: $ref: '#/components/schemas/PageResultTask' + PageResultTaskCompletion: + type: object + properties: + total: + type: integer + format: int64 + pageSize: + type: integer + format: int64 + items: + type: array + items: + $ref: '#/components/schemas/TaskCompletion' + page: + type: integer + format: int64 + totalPages: + type: integer + format: int64 + ResultPageResultTaskCompletion: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + data: + $ref: '#/components/schemas/PageResultTaskCompletion' + PageResultTaskTemplate: + type: object + properties: + total: + type: integer + format: int64 + pageSize: + type: integer + format: int64 + items: + type: array + items: + $ref: '#/components/schemas/TaskTemplate' + page: + type: integer + format: int64 + totalPages: + type: integer + format: int64 + ResultPageResultTaskTemplate: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + data: + $ref: '#/components/schemas/PageResultTaskTemplate' + ResultListMapStringObject: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + data: + type: array + items: + type: object + additionalProperties: + type: object PageResultSchoolCourse: type: object properties: @@ -12307,20 +15076,6 @@ components: type: string data: $ref: '#/components/schemas/PageResultGrowthRecord' - ResultListMapStringObject: - type: object - properties: - code: - type: integer - format: int32 - message: - type: string - data: - type: array - items: - type: object - additionalProperties: - type: object PageResultCourse: type: object properties: @@ -12621,18 +15376,6 @@ components: type: array items: $ref: '#/components/schemas/GrowthRecord' - ResultListStudent: - type: object - properties: - code: - type: integer - format: int32 - message: - type: string - data: - type: array - items: - $ref: '#/components/schemas/Student' ResultUserInfoResponse: type: object properties: diff --git a/reading-platform-frontend/src/api/admin.ts b/reading-platform-frontend/src/api/admin.ts index 32ec169..fed90f1 100644 --- a/reading-platform-frontend/src/api/admin.ts +++ b/reading-platform-frontend/src/api/admin.ts @@ -163,6 +163,42 @@ export interface AdminSettings { notifyBeforeDays?: number; } +export interface AdminSettingsUpdateRequest { + systemName?: string; + systemDesc?: string; + contactPhone?: string; + contactEmail?: string; + systemLogo?: string; + passwordStrength?: string; + maxLoginAttempts?: number; + tokenExpire?: string; + forceHttps?: boolean; + emailEnabled?: boolean; + smtpHost?: string; + smtpPort?: number; + smtpUser?: string; + smtpPassword?: string; + fromEmail?: string; + smsEnabled?: boolean; + storageType?: string; + maxFileSize?: number; + allowedTypes?: string; + defaultTeacherQuota?: number; + defaultStudentQuota?: number; + enableAutoExpire?: boolean; + notifyBeforeDays?: number; +} + +export interface TenantStatusUpdateRequest { + status: string; +} + +export interface TenantQuotaUpdateRequest { + packageType?: string; + teacherQuota?: number; + studentQuota?: number; +} + // ==================== 租户管理 ==================== export const getTenants = (params: TenantQueryParams) => @@ -183,8 +219,8 @@ export const updateTenant = (id: number, data: UpdateTenantDto) => export const updateTenantQuota = (id: number, data: UpdateTenantQuotaDto) => http.put(`/admin/tenants/${id}/quota`, data); -export const updateTenantStatus = (id: number, status: string) => - http.put<{ id: number; name: string; status: string }>(`/admin/tenants/${id}/status`, { status }); +export const updateTenantStatus = (id: number, data: TenantStatusUpdateRequest) => + http.put<{ id: number; name: string; status: string }>(`/admin/tenants/${id}/status`, data); export const resetTenantPassword = (id: number) => http.post<{ tempPassword: string }>(`/admin/tenants/${id}/reset-password`); @@ -211,5 +247,5 @@ export const getPopularCourses = (limit?: number) => export const getAdminSettings = () => http.get('/admin/settings'); -export const updateAdminSettings = (data: Record) => +export const updateAdminSettings = (data: AdminSettingsUpdateRequest) => http.put('/admin/settings', data); diff --git a/reading-platform-frontend/src/api/generated/api.ts b/reading-platform-frontend/src/api/generated/api.ts index 660b2b8..db4c0a9 100644 --- a/reading-platform-frontend/src/api/generated/api.ts +++ b/reading-platform-frontend/src/api/generated/api.ts @@ -16,10 +16,14 @@ import type { CourseLesson, CoursePackage, CourseUpdateRequest, + CreateTaskFromTemplateRequest, DeleteFileParams, + GetActiveTeachersParams, GetActiveTenantsParams, GetActivitiesParams, GetClassPageParams, + GetCompletions1Params, + GetCompletionsParams, GetCoursePage1Params, GetCoursePageParams, GetCourses1Params, @@ -28,16 +32,21 @@ import type { GetGrowthRecordPageParams, GetGrowthRecordsByStudentParams, GetItemsParams, + GetLessonTrendParams, GetLibrariesParams, GetLogs1Params, GetLogsParams, + GetMonthlyStats1Params, + GetMonthlyStatsParams, GetMyLessonsParams, GetMyNotifications1Params, + GetMyNotifications2Params, GetMyNotificationsParams, GetPackages1Params, GetPackagesParams, GetParentPageParams, GetPopularCoursesParams, + GetRecentActivitiesParams, GetRecentGrowthRecordsParams, GetReviewCoursePageParams, GetSchedulePlans1Params, @@ -48,8 +57,11 @@ import type { GetTaskPageParams, GetTasksByStudentParams, GetTeacherPageParams, + GetTemplates1Params, + GetTemplatesParams, GetTenantPageParams, GetThemesParams, + GetTimetableParams, GrowthRecordCreateRequest, GrowthRecordUpdateRequest, LessonCreateRequest, @@ -74,6 +86,7 @@ import type { ResultListLesson, ResultListMapStringObject, ResultListResourceLibrary, + ResultListSchedulePlan, ResultListStudent, ResultListTenantResponse, ResultListTheme, @@ -96,6 +109,8 @@ import type { ResultPageResultSchoolCourse, ResultPageResultStudent, ResultPageResultTask, + ResultPageResultTaskCompletion, + ResultPageResultTaskTemplate, ResultPageResultTeacher, ResultPageResultTenant, ResultParent, @@ -106,6 +121,8 @@ import type { ResultSchoolCourse, ResultStudent, ResultTask, + ResultTaskCompletion, + ResultTaskTemplate, ResultTeacher, ResultTenant, ResultTheme, @@ -113,17 +130,23 @@ import type { ResultVoid, ReviewPackageBody, SchedulePlan, + SchedulePlanCreateRequest, ScheduleTemplate, + ScheduleTemplateApplyRequest, SchoolCourse, StudentCreateRequest, StudentUpdateRequest, TaskCreateRequest, + TaskTemplateCreateRequest, + TaskTemplateUpdateRequest, TaskUpdateRequest, TeacherCreateRequest, TeacherUpdateRequest, TenantCreateRequest, TenantUpdateRequest, Theme, + UpdateCompletion1Params, + UpdateCompletionParams, UpdateSettings1Body, UpdateSettingsBody, UpdateTenantQuotaBody, @@ -134,7 +157,22 @@ import type { import { request } from '../request'; export const getReadingPlatformAPI = () => { /** - * @summary 根据ID获取任务 + * @summary 更新任务完成状态 + */ +const updateCompletion = ( + taskId: number, + studentId: number, + params: UpdateCompletionParams, + ) => { + return request( + {url: `/api/v1/teacher/tasks/${taskId}/completions/${studentId}`, method: 'PUT', + params + }, + ); + } + +/** + * @summary 根据 ID 获取任务 */ const getTask = ( id: number, @@ -278,7 +316,22 @@ const deleteTeacher = ( } /** - * @summary 根据ID获取任务 + * @summary 更新任务完成状态 + */ +const updateCompletion1 = ( + taskId: number, + studentId: number, + params: UpdateCompletion1Params, + ) => { + return request( + {url: `/api/v1/school/tasks/${taskId}/completions/${studentId}`, method: 'PUT', + params + }, + ); + } + +/** + * @summary 根据 ID 获取任务 */ const getTask1 = ( id: number, @@ -316,6 +369,45 @@ const deleteTask1 = ( ); } +/** + * @summary 根据 ID 获取任务模板 + */ +const getTemplate1 = ( + id: number, + ) => { + return request( + {url: `/api/v1/school/tasks/task-templates/${id}`, method: 'GET' + }, + ); + } + +/** + * @summary 更新任务模板 + */ +const updateTemplate = ( + id: number, + taskTemplateUpdateRequest: TaskTemplateUpdateRequest, + ) => { + return request( + {url: `/api/v1/school/tasks/task-templates/${id}`, method: 'PUT', + headers: {'Content-Type': 'application/json', }, + data: taskTemplateUpdateRequest + }, + ); + } + +/** + * @summary 删除任务模板 + */ +const deleteTemplate = ( + id: number, + ) => { + return request( + {url: `/api/v1/school/tasks/task-templates/${id}`, method: 'DELETE' + }, + ); + } + /** * @summary 根据ID获取学生 */ @@ -421,7 +513,7 @@ const deleteCourse = ( } /** - * @summary 根据ID获取课表计划 + * @summary 根据 ID 获取课表计划 */ const getSchedulePlan1 = ( id: number, @@ -459,6 +551,45 @@ const deleteSchedulePlan = ( ); } +/** + * @summary 根据 ID 获取课表模板 + */ +const getScheduleTemplate = ( + id: number, + ) => { + return request( + {url: `/api/v1/school/schedules/templates/${id}`, method: 'GET' + }, + ); + } + +/** + * @summary 更新课表模板 + */ +const updateScheduleTemplate = ( + id: number, + scheduleTemplate: ScheduleTemplate, + ) => { + return request( + {url: `/api/v1/school/schedules/templates/${id}`, method: 'PUT', + headers: {'Content-Type': 'application/json', }, + data: scheduleTemplate + }, + ); + } + +/** + * @summary 删除课表模板 + */ +const deleteScheduleTemplate = ( + id: number, + ) => { + return request( + {url: `/api/v1/school/schedules/templates/${id}`, method: 'DELETE' + }, + ); + } + /** * @summary Get parent by ID */ @@ -950,6 +1081,20 @@ const createTask = ( ); } +/** + * @summary 从模板创建任务 + */ +const createFromTemplate = ( + createTaskFromTemplateRequest: CreateTaskFromTemplateRequest, + ) => { + return request( + {url: `/api/v1/teacher/tasks/from-template`, method: 'POST', + headers: {'Content-Type': 'application/json', }, + data: createTaskFromTemplateRequest + }, + ); + } + /** * @summary 标记通知为已读 */ @@ -1132,6 +1277,47 @@ const createTask1 = ( ); } +/** + * @summary 获取任务模板列表 + */ +const getTemplates1 = ( + params?: GetTemplates1Params, + ) => { + return request( + {url: `/api/v1/school/tasks/task-templates`, method: 'GET', + params + }, + ); + } + +/** + * @summary 创建任务模板 + */ +const createTemplate = ( + taskTemplateCreateRequest: TaskTemplateCreateRequest, + ) => { + return request( + {url: `/api/v1/school/tasks/task-templates`, method: 'POST', + headers: {'Content-Type': 'application/json', }, + data: taskTemplateCreateRequest + }, + ); + } + +/** + * @summary 从模板创建任务 + */ +const createFromTemplate1 = ( + createTaskFromTemplateRequest: CreateTaskFromTemplateRequest, + ) => { + return request( + {url: `/api/v1/school/tasks/from-template`, method: 'POST', + headers: {'Content-Type': 'application/json', }, + data: createTaskFromTemplateRequest + }, + ); + } + /** * @summary 获取学生分页 */ @@ -1159,6 +1345,20 @@ const createStudent = ( ); } +/** + * @summary 批量导入学生 + */ +const importStudents = ( + studentCreateRequest: StudentCreateRequest[], + ) => { + return request( + {url: `/api/v1/school/students/import`, method: 'POST', + headers: {'Content-Type': 'application/json', }, + data: studentCreateRequest + }, + ); + } + /** * @summary 获取校本课程 */ @@ -1203,12 +1403,12 @@ const getSchedulePlans1 = ( * @summary 创建课表计划 */ const createSchedulePlan = ( - schedulePlan: SchedulePlan, + schedulePlanCreateRequest: SchedulePlanCreateRequest, ) => { return request( {url: `/api/v1/school/schedules`, method: 'POST', headers: {'Content-Type': 'application/json', }, - data: schedulePlan + data: schedulePlanCreateRequest }, ); } @@ -1240,6 +1440,35 @@ const createScheduleTemplate = ( ); } +/** + * @summary 应用课表模板 + */ +const applyScheduleTemplate = ( + id: number, + scheduleTemplateApplyRequest: ScheduleTemplateApplyRequest, + ) => { + return request( + {url: `/api/v1/school/schedules/templates/${id}/apply`, method: 'POST', + headers: {'Content-Type': 'application/json', }, + data: scheduleTemplateApplyRequest + }, + ); + } + +/** + * @summary 批量创建排课 + */ +const batchCreateSchedules = ( + schedulePlanCreateRequest: SchedulePlanCreateRequest[], + ) => { + return request( + {url: `/api/v1/school/schedules/batch`, method: 'POST', + headers: {'Content-Type': 'application/json', }, + data: schedulePlanCreateRequest + }, + ); + } + /** * @summary 获取家长分页 */ @@ -1309,6 +1538,30 @@ const resetPassword1 = ( ); } +/** + * @summary 标记通知为已读 + */ +const markAsRead1 = ( + id: number, + ) => { + return request( + {url: `/api/v1/school/notifications/${id}/read`, method: 'POST' + }, + ); + } + +/** + * @summary 标记所有通知为已读 + */ +const markAllAsRead1 = ( + + ) => { + return request( + {url: `/api/v1/school/notifications/read-all`, method: 'POST' + }, + ); + } + /** * @summary 获取成长档案分页 */ @@ -1410,7 +1663,7 @@ const completeTask = ( /** * @summary 标记通知为已读 */ -const markAsRead1 = ( +const markAsRead2 = ( id: number, ) => { return request( @@ -1422,7 +1675,7 @@ const markAsRead1 = ( /** * @summary 标记所有通知为已读 */ -const markAllAsRead1 = ( +const markAllAsRead2 = ( ) => { return request( @@ -1862,6 +2115,106 @@ const createLesson1 = ( ); } +/** + * @summary 获取任务完成情况分页 + */ +const getCompletions = ( + id: number, + params?: GetCompletionsParams, + ) => { + return request( + {url: `/api/v1/teacher/tasks/${id}/completions`, method: 'GET', + params + }, + ); + } + +/** + * @summary 获取任务模板列表 + */ +const getTemplates = ( + params?: GetTemplatesParams, + ) => { + return request( + {url: `/api/v1/teacher/tasks/task-templates`, method: 'GET', + params + }, + ); + } + +/** + * @summary 根据 ID 获取任务模板 + */ +const getTemplate = ( + id: number, + ) => { + return request( + {url: `/api/v1/teacher/tasks/task-templates/${id}`, method: 'GET' + }, + ); + } + +/** + * @summary 获取默认模板(按类型) + */ +const getDefaultTemplate = ( + taskType: string, + ) => { + return request( + {url: `/api/v1/teacher/tasks/task-templates/default/${taskType}`, method: 'GET' + }, + ); + } + +/** + * @summary 获取任务统计数据 + */ +const getStats = ( + + ) => { + return request( + {url: `/api/v1/teacher/tasks/stats`, method: 'GET' + }, + ); + } + +/** + * @summary 获取月度统计趋势 + */ +const getMonthlyStats = ( + params?: GetMonthlyStatsParams, + ) => { + return request( + {url: `/api/v1/teacher/tasks/stats/monthly`, method: 'GET', + params + }, + ); + } + +/** + * @summary 按任务类型统计 + */ +const getStatsByType = ( + + ) => { + return request( + {url: `/api/v1/teacher/tasks/stats/by-type`, method: 'GET' + }, + ); + } + +/** + * @summary 按班级统计 + */ +const getStatsByClass = ( + + ) => { + return request( + {url: `/api/v1/teacher/tasks/stats/by-class`, method: 'GET' + }, + ); + } + /** * @summary 获取校本课程 */ @@ -2059,10 +2412,97 @@ const getAllCourses = ( ); } +/** + * @summary 获取任务完成情况分页 + */ +const getCompletions1 = ( + id: number, + params?: GetCompletions1Params, + ) => { + return request( + {url: `/api/v1/school/tasks/${id}/completions`, method: 'GET', + params + }, + ); + } + +/** + * @summary 获取默认模板(按类型) + */ +const getDefaultTemplate1 = ( + taskType: string, + ) => { + return request( + {url: `/api/v1/school/tasks/task-templates/default/${taskType}`, method: 'GET' + }, + ); + } + +/** + * @summary 获取任务统计数据 + */ +const getStats1 = ( + + ) => { + return request( + {url: `/api/v1/school/tasks/stats`, method: 'GET' + }, + ); + } + +/** + * @summary 获取月度统计趋势 + */ +const getMonthlyStats1 = ( + params?: GetMonthlyStats1Params, + ) => { + return request( + {url: `/api/v1/school/tasks/stats/monthly`, method: 'GET', + params + }, + ); + } + +/** + * @summary 按任务类型统计 + */ +const getStatsByType1 = ( + + ) => { + return request( + {url: `/api/v1/school/tasks/stats/by-type`, method: 'GET' + }, + ); + } + +/** + * @summary 按班级统计 + */ +const getStatsByClass1 = ( + + ) => { + return request( + {url: `/api/v1/school/tasks/stats/by-class`, method: 'GET' + }, + ); + } + +/** + * @summary 获取导入模板 + */ +const getImportTemplate = ( + + ) => { + return request( + {url: `/api/v1/school/students/import/template`, method: 'GET' + }, + ); + } + /** * @summary 获取学校统计数据 */ -const getStats = ( +const getStats2 = ( ) => { return request( @@ -2071,6 +2511,82 @@ const getStats = ( ); } +/** + * @summary 获取活跃教师统计 + */ +const getActiveTeachers = ( + params?: GetActiveTeachersParams, + ) => { + return request( + {url: `/api/v1/school/stats/teachers`, method: 'GET', + params + }, + ); + } + +/** + * @summary 获取课时趋势(最近 N 个月) + */ +const getLessonTrend = ( + params?: GetLessonTrendParams, + ) => { + return request( + {url: `/api/v1/school/stats/lesson-trend`, method: 'GET', + params + }, + ); + } + +/** + * @summary 获取课程使用统计 + */ +const getCourseUsageStats = ( + + ) => { + return request( + {url: `/api/v1/school/stats/courses`, method: 'GET' + }, + ); + } + +/** + * @summary 获取课程分布统计(饼图数据) + */ +const getCourseDistribution = ( + + ) => { + return request( + {url: `/api/v1/school/stats/course-distribution`, method: 'GET' + }, + ); + } + +/** + * @summary 获取最近活动记录 + */ +const getRecentActivities = ( + params?: GetRecentActivitiesParams, + ) => { + return request( + {url: `/api/v1/school/stats/activities`, method: 'GET', + params + }, + ); + } + +/** + * @summary 获取课表(按日期范围) + */ +const getTimetable = ( + params?: GetTimetableParams, + ) => { + return request( + {url: `/api/v1/school/schedules/timetable`, method: 'GET', + params + }, + ); + } + /** * @summary 获取学校操作日志 */ @@ -2084,6 +2600,43 @@ const getLogs = ( ); } +/** + * @summary 获取我的通知 + */ +const getMyNotifications1 = ( + params?: GetMyNotifications1Params, + ) => { + return request( + {url: `/api/v1/school/notifications`, method: 'GET', + params + }, + ); + } + +/** + * @summary 根据 ID 获取通知 + */ +const getNotification1 = ( + id: number, + ) => { + return request( + {url: `/api/v1/school/notifications/${id}`, method: 'GET' + }, + ); + } + +/** + * @summary 获取未读通知数量 + */ +const getUnreadCount1 = ( + + ) => { + return request( + {url: `/api/v1/school/notifications/unread-count`, method: 'GET' + }, + ); + } + /** * @summary 导出教师信息到Excel */ @@ -2186,8 +2739,8 @@ const getTasksByStudent = ( /** * @summary 获取我的通知 */ -const getMyNotifications1 = ( - params?: GetMyNotifications1Params, +const getMyNotifications2 = ( + params?: GetMyNotifications2Params, ) => { return request( {url: `/api/v1/parent/notifications`, method: 'GET', @@ -2199,7 +2752,7 @@ const getMyNotifications1 = ( /** * @summary 根据ID获取通知 */ -const getNotification1 = ( +const getNotification2 = ( id: number, ) => { return request( @@ -2211,7 +2764,7 @@ const getNotification1 = ( /** * @summary 获取未读通知数量 */ -const getUnreadCount1 = ( +const getUnreadCount2 = ( ) => { return request( @@ -2299,7 +2852,7 @@ const getAllActiveTenants = ( /** * @summary 获取整体统计数据 */ -const getStats1 = ( +const getStats3 = ( ) => { return request( @@ -2386,13 +2939,27 @@ const getReviewCoursePage = ( } /** - * @summary 删除课表模板 + * @summary 移除班级教师 */ -const deleteScheduleTemplate = ( +const removeTeacher = ( id: number, + teacherId: number, ) => { return request( - {url: `/api/v1/school/schedules/templates/${id}`, method: 'DELETE' + {url: `/api/v1/school/classes/${id}/teachers/${teacherId}`, method: 'DELETE' + }, + ); + } + +/** + * @summary 移除班级学生 + */ +const removeStudent = ( + id: number, + studentId: number, + ) => { + return request( + {url: `/api/v1/school/classes/${id}/students/${studentId}`, method: 'DELETE' }, ); } @@ -2410,7 +2977,8 @@ const deleteFile = ( ); } -return {getTask,updateTask,deleteTask,getLesson,updateLesson,getGrowthRecord,updateGrowthRecord,deleteGrowthRecord,getTeacher,updateTeacher,deleteTeacher,getTask1,updateTask1,deleteTask1,getStudent,updateStudent,deleteStudent,getSettings,updateSettings,getCourse2,updateCourse,deleteCourse,getSchedulePlan1,updateSchedulePlan,deleteSchedulePlan,getParent,updateParent,deleteParent,getGrowthRecord1,updateGrowthRecord1,deleteGrowthRecord1,getClass,updateClass,deleteClass,getGrowthRecord2,updateGrowthRecord2,deleteGrowthRecord2,getTheme,updateTheme,deleteTheme,getTenant,updateTenant,deleteTenant,updateTenantStatus,updateTenantQuota,getSettings1,updateSettings1,updateLibrary,deleteLibrary,updateItem,deleteItem,getPackage1,updatePackage,deletePackage,getCourse3,updateCourse1,deleteCourse1,getLesson2,updateLesson1,deleteLesson,getTaskPage,createTask,markAsRead,markAllAsRead,getMyLessons,createLesson,startLesson,completeLesson,cancelLesson,getGrowthRecordPage,createGrowthRecord,getTeacherPage,createTeacher,resetPassword,getTaskPage1,createTask1,getStudentPage,createStudent,getCourses1,createCourse,getSchedulePlans1,createSchedulePlan,getScheduleTemplates,createScheduleTemplate,getParentPage,createParent,bindStudent,unbindStudent,resetPassword1,getGrowthRecordPage1,createGrowthRecord1,getClassPage,createClass,assignTeachers,assignStudents,completeTask,markAsRead1,markAllAsRead1,createGrowthRecord2,uploadFile,logout,login,changePassword,getThemes,createTheme,getTenantPage,createTenant,resetTenantPassword,getLibraries,createLibrary,getItems,createItem,getPackages1,createPackage,submitPackage,reviewPackage,publishPackage,offlinePackage,getCoursePage1,createCourse1,withdrawCourse,unpublishCourse,submitCourse,republishCourse,rejectCourse,publishCourse,directPublishCourse,archiveCourse,approveCourse,getLessons1,createLesson1,getCourses,getCourse,getSchedulePlans,getSchedulePlan,getMyNotifications,getNotification,getUnreadCount,getTodayLessons,getDashboard,getWeeklyLessons,getTodayLessons1,getCoursePage,getCourse1,getLessons,getLesson1,getAllCourses,getStats,getLogs,exportTeachers,exportStudents,exportLessons,exportGrowthRecords,getPackages,getPackage,getTask2,getTasksByStudent,getMyNotifications1,getNotification1,getUnreadCount1,getGrowthRecordsByStudent,getRecentGrowthRecords,getMyChildren,getChild,getCurrentUser,getAllActiveTenants,getStats1,getTrendData,getActiveTenants,getPopularCourses,getActivities,getLogs1,getReviewCoursePage,deleteScheduleTemplate,deleteFile}}; +return {updateCompletion,getTask,updateTask,deleteTask,getLesson,updateLesson,getGrowthRecord,updateGrowthRecord,deleteGrowthRecord,getTeacher,updateTeacher,deleteTeacher,updateCompletion1,getTask1,updateTask1,deleteTask1,getTemplate1,updateTemplate,deleteTemplate,getStudent,updateStudent,deleteStudent,getSettings,updateSettings,getCourse2,updateCourse,deleteCourse,getSchedulePlan1,updateSchedulePlan,deleteSchedulePlan,getScheduleTemplate,updateScheduleTemplate,deleteScheduleTemplate,getParent,updateParent,deleteParent,getGrowthRecord1,updateGrowthRecord1,deleteGrowthRecord1,getClass,updateClass,deleteClass,getGrowthRecord2,updateGrowthRecord2,deleteGrowthRecord2,getTheme,updateTheme,deleteTheme,getTenant,updateTenant,deleteTenant,updateTenantStatus,updateTenantQuota,getSettings1,updateSettings1,updateLibrary,deleteLibrary,updateItem,deleteItem,getPackage1,updatePackage,deletePackage,getCourse3,updateCourse1,deleteCourse1,getLesson2,updateLesson1,deleteLesson,getTaskPage,createTask,createFromTemplate,markAsRead,markAllAsRead,getMyLessons,createLesson,startLesson,completeLesson,cancelLesson,getGrowthRecordPage,createGrowthRecord,getTeacherPage,createTeacher,resetPassword,getTaskPage1,createTask1,getTemplates1,createTemplate,createFromTemplate1,getStudentPage,createStudent,importStudents,getCourses1,createCourse,getSchedulePlans1,createSchedulePlan,getScheduleTemplates,createScheduleTemplate,applyScheduleTemplate,batchCreateSchedules,getParentPage,createParent,bindStudent,unbindStudent,resetPassword1,markAsRead1,markAllAsRead1,getGrowthRecordPage1,createGrowthRecord1,getClassPage,createClass,assignTeachers,assignStudents,completeTask,markAsRead2,markAllAsRead2,createGrowthRecord2,uploadFile,logout,login,changePassword,getThemes,createTheme,getTenantPage,createTenant,resetTenantPassword,getLibraries,createLibrary,getItems,createItem,getPackages1,createPackage,submitPackage,reviewPackage,publishPackage,offlinePackage,getCoursePage1,createCourse1,withdrawCourse,unpublishCourse,submitCourse,republishCourse,rejectCourse,publishCourse,directPublishCourse,archiveCourse,approveCourse,getLessons1,createLesson1,getCompletions,getTemplates,getTemplate,getDefaultTemplate,getStats,getMonthlyStats,getStatsByType,getStatsByClass,getCourses,getCourse,getSchedulePlans,getSchedulePlan,getMyNotifications,getNotification,getUnreadCount,getTodayLessons,getDashboard,getWeeklyLessons,getTodayLessons1,getCoursePage,getCourse1,getLessons,getLesson1,getAllCourses,getCompletions1,getDefaultTemplate1,getStats1,getMonthlyStats1,getStatsByType1,getStatsByClass1,getImportTemplate,getStats2,getActiveTeachers,getLessonTrend,getCourseUsageStats,getCourseDistribution,getRecentActivities,getTimetable,getLogs,getMyNotifications1,getNotification1,getUnreadCount1,exportTeachers,exportStudents,exportLessons,exportGrowthRecords,getPackages,getPackage,getTask2,getTasksByStudent,getMyNotifications2,getNotification2,getUnreadCount2,getGrowthRecordsByStudent,getRecentGrowthRecords,getMyChildren,getChild,getCurrentUser,getAllActiveTenants,getStats3,getTrendData,getActiveTenants,getPopularCourses,getActivities,getLogs1,getReviewCoursePage,removeTeacher,removeStudent,deleteFile}}; +export type UpdateCompletionResult = NonNullable['updateCompletion']>>> export type GetTaskResult = NonNullable['getTask']>>> export type UpdateTaskResult = NonNullable['updateTask']>>> export type DeleteTaskResult = NonNullable['deleteTask']>>> @@ -2422,9 +2990,13 @@ export type DeleteGrowthRecordResult = NonNullable['getTeacher']>>> export type UpdateTeacherResult = NonNullable['updateTeacher']>>> export type DeleteTeacherResult = NonNullable['deleteTeacher']>>> +export type UpdateCompletion1Result = NonNullable['updateCompletion1']>>> export type GetTask1Result = NonNullable['getTask1']>>> export type UpdateTask1Result = NonNullable['updateTask1']>>> export type DeleteTask1Result = NonNullable['deleteTask1']>>> +export type GetTemplate1Result = NonNullable['getTemplate1']>>> +export type UpdateTemplateResult = NonNullable['updateTemplate']>>> +export type DeleteTemplateResult = NonNullable['deleteTemplate']>>> export type GetStudentResult = NonNullable['getStudent']>>> export type UpdateStudentResult = NonNullable['updateStudent']>>> export type DeleteStudentResult = NonNullable['deleteStudent']>>> @@ -2436,6 +3008,9 @@ export type DeleteCourseResult = NonNullable['getSchedulePlan1']>>> export type UpdateSchedulePlanResult = NonNullable['updateSchedulePlan']>>> export type DeleteSchedulePlanResult = NonNullable['deleteSchedulePlan']>>> +export type GetScheduleTemplateResult = NonNullable['getScheduleTemplate']>>> +export type UpdateScheduleTemplateResult = NonNullable['updateScheduleTemplate']>>> +export type DeleteScheduleTemplateResult = NonNullable['deleteScheduleTemplate']>>> export type GetParentResult = NonNullable['getParent']>>> export type UpdateParentResult = NonNullable['updateParent']>>> export type DeleteParentResult = NonNullable['deleteParent']>>> @@ -2473,6 +3048,7 @@ export type UpdateLesson1Result = NonNullable['deleteLesson']>>> export type GetTaskPageResult = NonNullable['getTaskPage']>>> export type CreateTaskResult = NonNullable['createTask']>>> +export type CreateFromTemplateResult = NonNullable['createFromTemplate']>>> export type MarkAsReadResult = NonNullable['markAsRead']>>> export type MarkAllAsReadResult = NonNullable['markAllAsRead']>>> export type GetMyLessonsResult = NonNullable['getMyLessons']>>> @@ -2487,19 +3063,27 @@ export type CreateTeacherResult = NonNullable['resetPassword']>>> export type GetTaskPage1Result = NonNullable['getTaskPage1']>>> export type CreateTask1Result = NonNullable['createTask1']>>> +export type GetTemplates1Result = NonNullable['getTemplates1']>>> +export type CreateTemplateResult = NonNullable['createTemplate']>>> +export type CreateFromTemplate1Result = NonNullable['createFromTemplate1']>>> export type GetStudentPageResult = NonNullable['getStudentPage']>>> export type CreateStudentResult = NonNullable['createStudent']>>> +export type ImportStudentsResult = NonNullable['importStudents']>>> export type GetCourses1Result = NonNullable['getCourses1']>>> export type CreateCourseResult = NonNullable['createCourse']>>> export type GetSchedulePlans1Result = NonNullable['getSchedulePlans1']>>> export type CreateSchedulePlanResult = NonNullable['createSchedulePlan']>>> export type GetScheduleTemplatesResult = NonNullable['getScheduleTemplates']>>> export type CreateScheduleTemplateResult = NonNullable['createScheduleTemplate']>>> +export type ApplyScheduleTemplateResult = NonNullable['applyScheduleTemplate']>>> +export type BatchCreateSchedulesResult = NonNullable['batchCreateSchedules']>>> export type GetParentPageResult = NonNullable['getParentPage']>>> export type CreateParentResult = NonNullable['createParent']>>> export type BindStudentResult = NonNullable['bindStudent']>>> export type UnbindStudentResult = NonNullable['unbindStudent']>>> export type ResetPassword1Result = NonNullable['resetPassword1']>>> +export type MarkAsRead1Result = NonNullable['markAsRead1']>>> +export type MarkAllAsRead1Result = NonNullable['markAllAsRead1']>>> export type GetGrowthRecordPage1Result = NonNullable['getGrowthRecordPage1']>>> export type CreateGrowthRecord1Result = NonNullable['createGrowthRecord1']>>> export type GetClassPageResult = NonNullable['getClassPage']>>> @@ -2507,8 +3091,8 @@ export type CreateClassResult = NonNullable['assignTeachers']>>> export type AssignStudentsResult = NonNullable['assignStudents']>>> export type CompleteTaskResult = NonNullable['completeTask']>>> -export type MarkAsRead1Result = NonNullable['markAsRead1']>>> -export type MarkAllAsRead1Result = NonNullable['markAllAsRead1']>>> +export type MarkAsRead2Result = NonNullable['markAsRead2']>>> +export type MarkAllAsRead2Result = NonNullable['markAllAsRead2']>>> export type CreateGrowthRecord2Result = NonNullable['createGrowthRecord2']>>> export type UploadFileResult = NonNullable['uploadFile']>>> export type LogoutResult = NonNullable['logout']>>> @@ -2542,6 +3126,14 @@ export type ArchiveCourseResult = NonNullable['approveCourse']>>> export type GetLessons1Result = NonNullable['getLessons1']>>> export type CreateLesson1Result = NonNullable['createLesson1']>>> +export type GetCompletionsResult = NonNullable['getCompletions']>>> +export type GetTemplatesResult = NonNullable['getTemplates']>>> +export type GetTemplateResult = NonNullable['getTemplate']>>> +export type GetDefaultTemplateResult = NonNullable['getDefaultTemplate']>>> +export type GetStatsResult = NonNullable['getStats']>>> +export type GetMonthlyStatsResult = NonNullable['getMonthlyStats']>>> +export type GetStatsByTypeResult = NonNullable['getStatsByType']>>> +export type GetStatsByClassResult = NonNullable['getStatsByClass']>>> export type GetCoursesResult = NonNullable['getCourses']>>> export type GetCourseResult = NonNullable['getCourse']>>> export type GetSchedulePlansResult = NonNullable['getSchedulePlans']>>> @@ -2558,8 +3150,24 @@ export type GetCourse1Result = NonNullable['getLessons']>>> export type GetLesson1Result = NonNullable['getLesson1']>>> export type GetAllCoursesResult = NonNullable['getAllCourses']>>> -export type GetStatsResult = NonNullable['getStats']>>> +export type GetCompletions1Result = NonNullable['getCompletions1']>>> +export type GetDefaultTemplate1Result = NonNullable['getDefaultTemplate1']>>> +export type GetStats1Result = NonNullable['getStats1']>>> +export type GetMonthlyStats1Result = NonNullable['getMonthlyStats1']>>> +export type GetStatsByType1Result = NonNullable['getStatsByType1']>>> +export type GetStatsByClass1Result = NonNullable['getStatsByClass1']>>> +export type GetImportTemplateResult = NonNullable['getImportTemplate']>>> +export type GetStats2Result = NonNullable['getStats2']>>> +export type GetActiveTeachersResult = NonNullable['getActiveTeachers']>>> +export type GetLessonTrendResult = NonNullable['getLessonTrend']>>> +export type GetCourseUsageStatsResult = NonNullable['getCourseUsageStats']>>> +export type GetCourseDistributionResult = NonNullable['getCourseDistribution']>>> +export type GetRecentActivitiesResult = NonNullable['getRecentActivities']>>> +export type GetTimetableResult = NonNullable['getTimetable']>>> export type GetLogsResult = NonNullable['getLogs']>>> +export type GetMyNotifications1Result = NonNullable['getMyNotifications1']>>> +export type GetNotification1Result = NonNullable['getNotification1']>>> +export type GetUnreadCount1Result = NonNullable['getUnreadCount1']>>> export type ExportTeachersResult = NonNullable['exportTeachers']>>> export type ExportStudentsResult = NonNullable['exportStudents']>>> export type ExportLessonsResult = NonNullable['exportLessons']>>> @@ -2568,21 +3176,22 @@ export type GetPackagesResult = NonNullable['getPackage']>>> export type GetTask2Result = NonNullable['getTask2']>>> export type GetTasksByStudentResult = NonNullable['getTasksByStudent']>>> -export type GetMyNotifications1Result = NonNullable['getMyNotifications1']>>> -export type GetNotification1Result = NonNullable['getNotification1']>>> -export type GetUnreadCount1Result = NonNullable['getUnreadCount1']>>> +export type GetMyNotifications2Result = NonNullable['getMyNotifications2']>>> +export type GetNotification2Result = NonNullable['getNotification2']>>> +export type GetUnreadCount2Result = NonNullable['getUnreadCount2']>>> export type GetGrowthRecordsByStudentResult = NonNullable['getGrowthRecordsByStudent']>>> export type GetRecentGrowthRecordsResult = NonNullable['getRecentGrowthRecords']>>> export type GetMyChildrenResult = NonNullable['getMyChildren']>>> export type GetChildResult = NonNullable['getChild']>>> export type GetCurrentUserResult = NonNullable['getCurrentUser']>>> export type GetAllActiveTenantsResult = NonNullable['getAllActiveTenants']>>> -export type GetStats1Result = NonNullable['getStats1']>>> +export type GetStats3Result = NonNullable['getStats3']>>> export type GetTrendDataResult = NonNullable['getTrendData']>>> export type GetActiveTenantsResult = NonNullable['getActiveTenants']>>> export type GetPopularCoursesResult = NonNullable['getPopularCourses']>>> export type GetActivitiesResult = NonNullable['getActivities']>>> export type GetLogs1Result = NonNullable['getLogs1']>>> export type GetReviewCoursePageResult = NonNullable['getReviewCoursePage']>>> -export type DeleteScheduleTemplateResult = NonNullable['deleteScheduleTemplate']>>> +export type RemoveTeacherResult = NonNullable['removeTeacher']>>> +export type RemoveStudentResult = NonNullable['removeStudent']>>> export type DeleteFileResult = NonNullable['deleteFile']>>> diff --git a/reading-platform-frontend/src/api/generated/model/activeTeacherStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/activeTeacherStatsResponse.ts new file mode 100644 index 0000000..749f4be --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/activeTeacherStatsResponse.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 活跃教师统计响应 + */ +export interface ActiveTeacherStatsResponse { + /** 教师 ID */ + id?: string; + /** 教师姓名 */ + name?: string; + /** 课时数 */ + lessonCount?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/adminSettingsUpdateRequest.ts b/reading-platform-frontend/src/api/generated/model/adminSettingsUpdateRequest.ts new file mode 100644 index 0000000..daa8fd4 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/adminSettingsUpdateRequest.ts @@ -0,0 +1,59 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 管理员设置更新请求 + */ +export interface AdminSettingsUpdateRequest { + /** 系统名称 */ + systemName?: string; + /** 系统描述 */ + systemDesc?: string; + /** 联系电话 */ + contactPhone?: string; + /** 联系邮箱 */ + contactEmail?: string; + /** 系统 Logo */ + systemLogo?: string; + /** 密码强度 */ + passwordStrength?: string; + /** 最大登录尝试次数 */ + maxLoginAttempts?: number; + /** Token 过期时间 */ + tokenExpire?: string; + /** 强制 HTTPS */ + forceHttps?: boolean; + /** 邮箱启用 */ + emailEnabled?: boolean; + /** SMTP 主机 */ + smtpHost?: string; + /** SMTP 端口 */ + smtpPort?: number; + /** SMTP 用户 */ + smtpUser?: string; + /** SMTP 密码 */ + smtpPassword?: string; + /** 发件人邮箱 */ + fromEmail?: string; + /** 短信启用 */ + smsEnabled?: boolean; + /** 存储类型 */ + storageType?: string; + /** 最大文件大小 */ + maxFileSize?: number; + /** 允许的文件类型 */ + allowedTypes?: string; + /** 默认教师配额 */ + defaultTeacherQuota?: number; + /** 默认学生配额 */ + defaultStudentQuota?: number; + /** 启用自动过期 */ + enableAutoExpire?: boolean; + /** 提前通知天数 */ + notifyBeforeDays?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/adminStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/adminStatsResponse.ts new file mode 100644 index 0000000..67a35b7 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/adminStatsResponse.ts @@ -0,0 +1,29 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 管理员统计数据响应 + */ +export interface AdminStatsResponse { + /** 租户总数 */ + tenantCount?: number; + /** 活跃租户数 */ + activeTenantCount?: number; + /** 教师总数 */ + teacherCount?: number; + /** 学生总数 */ + studentCount?: number; + /** 课程总数 */ + courseCount?: number; + /** 已发布课程数 */ + publishedCourseCount?: number; + /** 课时总数 */ + lessonCount?: number; + /** 本月课时数 */ + monthlyLessons?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/batchSaveStudentRecordResponse.ts b/reading-platform-frontend/src/api/generated/model/batchSaveStudentRecordResponse.ts new file mode 100644 index 0000000..b9c55e9 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/batchSaveStudentRecordResponse.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { StudentRecordResponse } from './studentRecordResponse'; + +/** + * 批量保存学生记录响应 + */ +export interface BatchSaveStudentRecordResponse { + /** 保存数量 */ + count?: number; + /** 学生记录列表 */ + records?: StudentRecordResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/batchStudentRecordRequest.ts b/reading-platform-frontend/src/api/generated/model/batchStudentRecordRequest.ts new file mode 100644 index 0000000..e705ea1 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/batchStudentRecordRequest.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { BatchStudentRecordRequestRecordsItem } from './batchStudentRecordRequestRecordsItem'; + +export interface BatchStudentRecordRequest { + records?: BatchStudentRecordRequestRecordsItem[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/batchStudentRecordRequestRecordsItem.ts b/reading-platform-frontend/src/api/generated/model/batchStudentRecordRequestRecordsItem.ts new file mode 100644 index 0000000..9a9658a --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/batchStudentRecordRequestRecordsItem.ts @@ -0,0 +1,9 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type BatchStudentRecordRequestRecordsItem = {[key: string]: { [key: string]: unknown }}; diff --git a/reading-platform-frontend/src/api/generated/model/childDetailResponse.ts b/reading-platform-frontend/src/api/generated/model/childDetailResponse.ts new file mode 100644 index 0000000..a6dcd88 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/childDetailResponse.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { ChildStats } from './childStats'; +import type { ClassInfo } from './classInfo'; + +/** + * 孩子详情响应 + */ +export interface ChildDetailResponse { + /** 孩子 ID */ + id?: string; + /** 孩子姓名 */ + name?: string; + /** 性别 */ + gender?: string; + /** 出生日期 */ + birthDate?: string; + /** 阅读次数 */ + readingCount?: number; + /** 课时数 */ + lessonCount?: number; + stats?: ChildStats; + classInfo?: ClassInfo; + /** 关系 */ + relationship?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/childInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/childInfoResponse.ts new file mode 100644 index 0000000..0249bd8 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/childInfoResponse.ts @@ -0,0 +1,29 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { ClassInfo } from './classInfo'; + +/** + * 孩子信息响应 + */ +export interface ChildInfoResponse { + /** 孩子 ID */ + id?: string; + /** 孩子姓名 */ + name?: string; + /** 性别 */ + gender?: string; + /** 出生日期 */ + birthDate?: string; + /** 阅读次数 */ + readingCount?: number; + /** 课时数 */ + lessonCount?: number; + classInfo?: ClassInfo; + /** 关系 */ + relationship?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/childStats.ts b/reading-platform-frontend/src/api/generated/model/childStats.ts new file mode 100644 index 0000000..2c8b13a --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/childStats.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 孩子统计信息 + */ +export interface ChildStats { + /** 课时记录数 */ + lessonRecords?: number; + /** 成长记录数 */ + growthRecords?: number; + /** 任务完成数 */ + taskCompletions?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/classInfo.ts b/reading-platform-frontend/src/api/generated/model/classInfo.ts new file mode 100644 index 0000000..087d10b --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/classInfo.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 班级信息 + */ +export interface ClassInfo { + /** 班级 ID */ + id?: string; + /** 班级名称 */ + name?: string; + /** 年级 */ + grade?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/classInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/classInfoResponse.ts new file mode 100644 index 0000000..60e1cf7 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/classInfoResponse.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 班级信息响应 + */ +export interface ClassInfoResponse { + /** 班级 ID */ + id?: string; + /** 班级名称 */ + name?: string; + /** 年级 */ + grade?: string; + /** 学生数量 */ + studentCount?: number; + /** 课时数量 */ + lessonCount?: number; + /** 我的角色 */ + myRole?: string; + /** 是否主教 */ + isPrimary?: boolean; +} diff --git a/reading-platform-frontend/src/api/generated/model/classSimpleInfo.ts b/reading-platform-frontend/src/api/generated/model/classSimpleInfo.ts new file mode 100644 index 0000000..8bac403 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/classSimpleInfo.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 班级简单信息 + */ +export interface ClassSimpleInfo { + /** 班级 ID */ + id?: string; + /** 班级名称 */ + name?: string; + /** 年级 */ + grade?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/classTeacher.ts b/reading-platform-frontend/src/api/generated/model/classTeacher.ts new file mode 100644 index 0000000..6d8a601 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/classTeacher.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 班级教师关联 + */ +export interface ClassTeacher { + /** ID */ + readonly id?: string; + classId?: string; + teacherId?: string; + role?: string; + isPrimary?: boolean; + sortOrder?: number; + /** 创建人用户名 */ + readonly createdBy?: string; + /** 更新人用户名 */ + readonly updatedBy?: string; + /** 创建时间 */ + readonly createdAt?: string; + /** 更新时间 */ + readonly updatedAt?: string; + /** 逻辑删除标志 */ + readonly deleted?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/classTeacherRequest.ts b/reading-platform-frontend/src/api/generated/model/classTeacherRequest.ts new file mode 100644 index 0000000..a5299d1 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/classTeacherRequest.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export interface ClassTeacherRequest { + teacherId?: string; + role?: string; + isPrimary?: boolean; +} diff --git a/reading-platform-frontend/src/api/generated/model/commonPageResponseLesson.ts b/reading-platform-frontend/src/api/generated/model/commonPageResponseLesson.ts new file mode 100644 index 0000000..c33a601 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/commonPageResponseLesson.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { Lesson } from './lesson'; + +/** + * 分页响应 + */ +export interface CommonPageResponseLesson { + /** 数据列表 */ + items?: Lesson[]; + /** 总数 */ + total?: number; + /** 当前页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/commonPageResponseTaskCompletionInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/commonPageResponseTaskCompletionInfoResponse.ts new file mode 100644 index 0000000..6f179d9 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/commonPageResponseTaskCompletionInfoResponse.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TaskCompletionInfoResponse } from './taskCompletionInfoResponse'; + +/** + * 分页响应 + */ +export interface CommonPageResponseTaskCompletionInfoResponse { + /** 数据列表 */ + items?: TaskCompletionInfoResponse[]; + /** 总数 */ + total?: number; + /** 当前页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/courseDistributionResponse.ts b/reading-platform-frontend/src/api/generated/model/courseDistributionResponse.ts new file mode 100644 index 0000000..6da4e6c --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/courseDistributionResponse.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 课程分布响应 + */ +export interface CourseDistributionResponse { + /** 课程名称 */ + name?: string; + /** 课时数量 */ + value?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/courseStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/courseStatsResponse.ts new file mode 100644 index 0000000..a4c9102 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/courseStatsResponse.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 热门课程统计响应 + */ +export interface CourseStatsResponse { + /** 课程 ID */ + id?: string; + /** 课程名称 */ + name?: string; + /** 分类 */ + category?: string; + /** 状态 */ + status?: string; + /** 使用次数 */ + usageCount?: number; + /** 教师数 */ + teacherCount?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/courseUsageStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/courseUsageStatsResponse.ts new file mode 100644 index 0000000..1578784 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/courseUsageStatsResponse.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 课程使用统计响应 + */ +export interface CourseUsageStatsResponse { + /** 课程 ID */ + courseId?: string; + /** 课程名称 */ + courseName?: string; + /** 使用次数 */ + usageCount?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/createTaskFromTemplateRequest.ts b/reading-platform-frontend/src/api/generated/model/createTaskFromTemplateRequest.ts new file mode 100644 index 0000000..f06eb9e --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/createTaskFromTemplateRequest.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 从模板创建任务请求 + */ +export interface CreateTaskFromTemplateRequest { + /** 模板 ID */ + templateId?: number; + /** 目标 ID 列表(班级 ID 或学生 ID) */ + targetIds: number[]; + /** 目标类型:CLASS-班级,STUDENT-学生 */ + targetType?: string; + /** 任务开始日期 */ + startDate?: string; + /** 任务截止日期 */ + endDate?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/fileUploadResponse.ts b/reading-platform-frontend/src/api/generated/model/fileUploadResponse.ts new file mode 100644 index 0000000..1a57333 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/fileUploadResponse.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 文件上传响应 + */ +export interface FileUploadResponse { + /** 文件 URL */ + fileUrl?: string; + /** 文件名称 */ + fileName?: string; + /** 文件大小 */ + fileSize?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/getActiveTeachersParams.ts b/reading-platform-frontend/src/api/generated/model/getActiveTeachersParams.ts new file mode 100644 index 0000000..b78fe21 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getActiveTeachersParams.ts @@ -0,0 +1,11 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetActiveTeachersParams = { +limit?: number; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getChildLessonsParams.ts b/reading-platform-frontend/src/api/generated/model/getChildLessonsParams.ts new file mode 100644 index 0000000..f8e7b46 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getChildLessonsParams.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetChildLessonsParams = { +page?: number; +pageSize?: number; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getChildTasksParams.ts b/reading-platform-frontend/src/api/generated/model/getChildTasksParams.ts new file mode 100644 index 0000000..567af52 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getChildTasksParams.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetChildTasksParams = { +page?: number; +pageSize?: number; +status?: string; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getClassStudents1Params.ts b/reading-platform-frontend/src/api/generated/model/getClassStudents1Params.ts new file mode 100644 index 0000000..1bfa49c --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getClassStudents1Params.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetClassStudents1Params = { +page?: number; +pageSize?: number; +keyword?: string; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getClassStudentsParams.ts b/reading-platform-frontend/src/api/generated/model/getClassStudentsParams.ts new file mode 100644 index 0000000..6ecb144 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getClassStudentsParams.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetClassStudentsParams = { +page?: number; +pageSize?: number; +keyword?: string; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getCompletions1Params.ts b/reading-platform-frontend/src/api/generated/model/getCompletions1Params.ts new file mode 100644 index 0000000..fec7007 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getCompletions1Params.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetCompletions1Params = { +page?: number; +pageSize?: number; +status?: string; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getCompletionsParams.ts b/reading-platform-frontend/src/api/generated/model/getCompletionsParams.ts new file mode 100644 index 0000000..da5bc99 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getCompletionsParams.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetCompletionsParams = { +page?: number; +pageSize?: number; +status?: string; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getLessonTrendParams.ts b/reading-platform-frontend/src/api/generated/model/getLessonTrendParams.ts new file mode 100644 index 0000000..b8c17a3 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getLessonTrendParams.ts @@ -0,0 +1,11 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetLessonTrendParams = { +months?: number; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getMonthlyStats1Params.ts b/reading-platform-frontend/src/api/generated/model/getMonthlyStats1Params.ts new file mode 100644 index 0000000..0fb6804 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getMonthlyStats1Params.ts @@ -0,0 +1,11 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetMonthlyStats1Params = { +months?: number; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getMonthlyStatsParams.ts b/reading-platform-frontend/src/api/generated/model/getMonthlyStatsParams.ts new file mode 100644 index 0000000..1b60ce3 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getMonthlyStatsParams.ts @@ -0,0 +1,11 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetMonthlyStatsParams = { +months?: number; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getMyNotifications2Params.ts b/reading-platform-frontend/src/api/generated/model/getMyNotifications2Params.ts new file mode 100644 index 0000000..3e3a6fc --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getMyNotifications2Params.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetMyNotifications2Params = { +page?: number; +pageSize?: number; +isRead?: number; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getRecentActivitiesParams.ts b/reading-platform-frontend/src/api/generated/model/getRecentActivitiesParams.ts new file mode 100644 index 0000000..473063a --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getRecentActivitiesParams.ts @@ -0,0 +1,11 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetRecentActivitiesParams = { +limit?: number; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getSchedulePlans1Params.ts b/reading-platform-frontend/src/api/generated/model/getSchedulePlans1Params.ts index 8ec05f2..856c1de 100644 --- a/reading-platform-frontend/src/api/generated/model/getSchedulePlans1Params.ts +++ b/reading-platform-frontend/src/api/generated/model/getSchedulePlans1Params.ts @@ -10,4 +10,6 @@ export type GetSchedulePlans1Params = { pageNum?: number; pageSize?: number; classId?: number; +startDate?: string; +endDate?: string; }; diff --git a/reading-platform-frontend/src/api/generated/model/getTeacherStudentsParams.ts b/reading-platform-frontend/src/api/generated/model/getTeacherStudentsParams.ts new file mode 100644 index 0000000..226baee --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getTeacherStudentsParams.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetTeacherStudentsParams = { +page?: number; +pageSize?: number; +keyword?: string; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getTemplates1Params.ts b/reading-platform-frontend/src/api/generated/model/getTemplates1Params.ts new file mode 100644 index 0000000..a298f5d --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getTemplates1Params.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetTemplates1Params = { +page?: number; +pageSize?: number; +keyword?: string; +type?: string; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getTemplatesParams.ts b/reading-platform-frontend/src/api/generated/model/getTemplatesParams.ts new file mode 100644 index 0000000..7e68b1c --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getTemplatesParams.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetTemplatesParams = { +page?: number; +pageSize?: number; +keyword?: string; +type?: string; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getTimetable1Params.ts b/reading-platform-frontend/src/api/generated/model/getTimetable1Params.ts new file mode 100644 index 0000000..8052241 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getTimetable1Params.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetTimetable1Params = { +startDate?: string; +endDate?: string; +classId?: string; +}; diff --git a/reading-platform-frontend/src/api/generated/model/getTimetableParams.ts b/reading-platform-frontend/src/api/generated/model/getTimetableParams.ts new file mode 100644 index 0000000..c40bc5b --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/getTimetableParams.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type GetTimetableParams = { +startDate?: string; +endDate?: string; +classId?: number; +}; diff --git a/reading-platform-frontend/src/api/generated/model/importTemplateResponse.ts b/reading-platform-frontend/src/api/generated/model/importTemplateResponse.ts new file mode 100644 index 0000000..eacf32a --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/importTemplateResponse.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 导入模板响应 + */ +export interface ImportTemplateResponse { + /** 表头 */ + headers?: string[]; + /** 示例数据 */ + example?: string[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/index.ts b/reading-platform-frontend/src/api/generated/model/index.ts index 381e4fd..b56ec5a 100644 --- a/reading-platform-frontend/src/api/generated/model/index.ts +++ b/reading-platform-frontend/src/api/generated/model/index.ts @@ -6,22 +6,50 @@ * OpenAPI spec version: 1.0.0 */ +export * from './activeTeacherStatsResponse'; +export * from './adminSettingsUpdateRequest'; +export * from './adminStatsResponse'; export * from './approveCourseParams'; +export * from './batchSaveStudentRecordResponse'; +export * from './batchStudentRecordRequest'; +export * from './batchStudentRecordRequestRecordsItem'; export * from './bindStudentParams'; export * from './changePasswordParams'; +export * from './childDetailResponse'; +export * from './childInfoResponse'; +export * from './childStats'; export * from './classCreateRequest'; +export * from './classInfo'; +export * from './classInfoResponse'; +export * from './classSimpleInfo'; +export * from './classTeacher'; +export * from './classTeacherRequest'; export * from './classUpdateRequest'; export * from './clazz'; +export * from './commonPageResponseLesson'; +export * from './commonPageResponseTaskCompletionInfoResponse'; export * from './completeTaskParams'; export * from './course'; export * from './courseCreateRequest'; +export * from './courseDistributionResponse'; export * from './courseLesson'; export * from './coursePackage'; +export * from './courseStatsResponse'; export * from './courseUpdateRequest'; +export * from './courseUsageStatsResponse'; +export * from './createTaskFromTemplateRequest'; export * from './deleteFileParams'; +export * from './fileUploadResponse'; +export * from './getActiveTeachersParams'; export * from './getActiveTenantsParams'; export * from './getActivitiesParams'; +export * from './getChildLessonsParams'; +export * from './getChildTasksParams'; export * from './getClassPageParams'; +export * from './getClassStudents1Params'; +export * from './getClassStudentsParams'; +export * from './getCompletions1Params'; +export * from './getCompletionsParams'; export * from './getCoursePage1Params'; export * from './getCoursePageParams'; export * from './getCourses1Params'; @@ -30,16 +58,21 @@ export * from './getGrowthRecordPage1Params'; export * from './getGrowthRecordPageParams'; export * from './getGrowthRecordsByStudentParams'; export * from './getItemsParams'; +export * from './getLessonTrendParams'; export * from './getLibrariesParams'; export * from './getLogs1Params'; export * from './getLogsParams'; +export * from './getMonthlyStats1Params'; +export * from './getMonthlyStatsParams'; export * from './getMyLessonsParams'; export * from './getMyNotifications1Params'; +export * from './getMyNotifications2Params'; export * from './getMyNotificationsParams'; export * from './getPackages1Params'; export * from './getPackagesParams'; export * from './getParentPageParams'; export * from './getPopularCoursesParams'; +export * from './getRecentActivitiesParams'; export * from './getRecentGrowthRecordsParams'; export * from './getReviewCoursePageParams'; export * from './getSchedulePlans1Params'; @@ -50,17 +83,33 @@ export * from './getTaskPage1Params'; export * from './getTaskPageParams'; export * from './getTasksByStudentParams'; export * from './getTeacherPageParams'; +export * from './getTeacherStudentsParams'; +export * from './getTemplates1Params'; +export * from './getTemplatesParams'; export * from './getTenantPageParams'; export * from './getThemesParams'; +export * from './getTimetable1Params'; +export * from './getTimetableParams'; export * from './growthRecord'; export * from './growthRecordCreateRequest'; export * from './growthRecordUpdateRequest'; +export * from './importTemplateResponse'; export * from './lesson'; +export * from './lessonActivityResponse'; export * from './lessonCreateRequest'; +export * from './lessonFeedback'; +export * from './lessonFeedbackRequest'; +export * from './lessonFeedbackRequestActivitiesDone'; +export * from './lessonFeedbackRequestStepFeedbacks'; +export * from './lessonFinishRequest'; +export * from './lessonSimpleInfo'; +export * from './lessonSimpleResponse'; export * from './lessonUpdateRequest'; export * from './localTime'; export * from './loginRequest'; export * from './loginResponse'; +export * from './messageResponse'; +export * from './monthlyTaskStatsResponse'; export * from './notification'; export * from './operationLog'; export * from './pageResultClazz'; @@ -76,39 +125,75 @@ export * from './pageResultSchedulePlan'; export * from './pageResultScheduleTemplate'; export * from './pageResultSchoolCourse'; export * from './pageResultStudent'; +export * from './pageResultStudentInfoResponse'; export * from './pageResultTask'; +export * from './pageResultTaskCompletion'; +export * from './pageResultTaskTemplate'; export * from './pageResultTeacher'; export * from './pageResultTenant'; export * from './parent'; export * from './parentCreateRequest'; export * from './parentUpdateRequest'; +export * from './recentActivityResponse'; export * from './rejectCourseParams'; export * from './resetPassword1Params'; export * from './resetPasswordParams'; +export * from './resetPasswordResponse'; export * from './resourceItem'; export * from './resourceLibrary'; +export * from './resultAdminStatsResponse'; +export * from './resultBatchSaveStudentRecordResponse'; +export * from './resultChildDetailResponse'; +export * from './resultClassTeacher'; export * from './resultClazz'; +export * from './resultCommonPageResponseLesson'; +export * from './resultCommonPageResponseTaskCompletionInfoResponse'; export * from './resultCourse'; export * from './resultCourseLesson'; export * from './resultCoursePackage'; +export * from './resultFileUploadResponse'; export * from './resultGrowthRecord'; +export * from './resultImportTemplateResponse'; export * from './resultLesson'; +export * from './resultLessonFeedback'; +export * from './resultListActiveTeacherStatsResponse'; +export * from './resultListChildInfoResponse'; +export * from './resultListClassInfoResponse'; +export * from './resultListClassTeacher'; +export * from './resultListClazz'; export * from './resultListCourse'; +export * from './resultListCourseDistributionResponse'; export * from './resultListCourseLesson'; +export * from './resultListCourseStatsResponse'; +export * from './resultListCourseUsageStatsResponse'; export * from './resultListGrowthRecord'; export * from './resultListLesson'; +export * from './resultListLessonActivityResponse'; +export * from './resultListLessonSimpleResponse'; export * from './resultListMapStringObject'; export * from './resultListMapStringObjectDataItem'; +export * from './resultListMonthlyTaskStatsResponse'; +export * from './resultListRecentActivityResponse'; export * from './resultListResourceLibrary'; +export * from './resultListSchedulePlan'; +export * from './resultListSchedulePlanResponse'; export * from './resultListStudent'; +export * from './resultListStudentTransferHistoryResponse'; +export * from './resultListTaskStatsByClassResponse'; +export * from './resultListTaskStatsByTypeResponse'; +export * from './resultListTeacherInfoResponse'; export * from './resultListTenantResponse'; +export * from './resultListTenantStatsResponse'; export * from './resultListTheme'; +export * from './resultListTrendDataPointResponse'; +export * from './resultListTrendDataResponse'; export * from './resultLoginResponse'; export * from './resultLong'; export * from './resultMapStringObject'; export * from './resultMapStringObjectData'; export * from './resultMapStringString'; export * from './resultMapStringStringData'; +export * from './resultMessageResponse'; export * from './resultNotification'; export * from './resultPageResultClazz'; export * from './resultPageResultCourse'; @@ -123,41 +208,90 @@ export * from './resultPageResultSchedulePlan'; export * from './resultPageResultScheduleTemplate'; export * from './resultPageResultSchoolCourse'; export * from './resultPageResultStudent'; +export * from './resultPageResultStudentInfoResponse'; export * from './resultPageResultTask'; +export * from './resultPageResultTaskCompletion'; +export * from './resultPageResultTaskTemplate'; export * from './resultPageResultTeacher'; export * from './resultPageResultTenant'; export * from './resultParent'; +export * from './resultResetPasswordResponse'; export * from './resultResourceItem'; export * from './resultResourceLibrary'; export * from './resultSchedulePlan'; export * from './resultScheduleTemplate'; export * from './resultSchoolCourse'; +export * from './resultStatsResponse'; export * from './resultStudent'; +export * from './resultStudentRecord'; +export * from './resultStudentRecordListResponse'; +export * from './resultSystemSettingsResponse'; export * from './resultTask'; +export * from './resultTaskCompletion'; +export * from './resultTaskFeedbackResponse'; +export * from './resultTaskStatsResponse'; +export * from './resultTaskTemplate'; export * from './resultTeacher'; +export * from './resultTeacherDashboardResponse'; export * from './resultTenant'; +export * from './resultTenantStatusUpdateResponse'; export * from './resultTheme'; export * from './resultUserInfoResponse'; export * from './resultVoid'; export * from './resultVoidData'; export * from './reviewPackageBody'; export * from './schedulePlan'; +export * from './schedulePlanCreateRequest'; +export * from './schedulePlanResponse'; +export * from './schedulePlanUpdateRequest'; export * from './scheduleTemplate'; +export * from './scheduleTemplateApplyRequest'; export * from './schoolCourse'; +export * from './schoolSettingsUpdateRequest'; +export * from './statsResponse'; export * from './student'; export * from './studentCreateRequest'; +export * from './studentInfoResponse'; +export * from './studentRecord'; +export * from './studentRecordListResponse'; +export * from './studentRecordRequest'; +export * from './studentRecordResponse'; +export * from './studentTransferHistoryResponse'; export * from './studentUpdateRequest'; +export * from './systemSettingsResponse'; export * from './task'; +export * from './taskCompletion'; +export * from './taskCompletionInfoResponse'; export * from './taskCreateRequest'; +export * from './taskFeedbackResponse'; +export * from './taskFeedbackUpdateRequest'; +export * from './taskSimpleInfo'; +export * from './taskStatsByClassResponse'; +export * from './taskStatsByTypeResponse'; +export * from './taskStatsResponse'; +export * from './taskTemplate'; +export * from './taskTemplateCreateRequest'; +export * from './taskTemplateUpdateRequest'; export * from './taskUpdateRequest'; export * from './teacher'; export * from './teacherCreateRequest'; +export * from './teacherDashboardResponse'; +export * from './teacherInfoResponse'; export * from './teacherUpdateRequest'; export * from './tenant'; export * from './tenantCreateRequest'; +export * from './tenantQuotaUpdateRequest'; export * from './tenantResponse'; +export * from './tenantStatsResponse'; +export * from './tenantStatusUpdateRequest'; +export * from './tenantStatusUpdateResponse'; export * from './tenantUpdateRequest'; export * from './theme'; +export * from './transferStudentRequest'; +export * from './trendDataPointResponse'; +export * from './trendDataResponse'; +export * from './updateCompletion1Params'; +export * from './updateCompletionParams'; export * from './updateSettings1Body'; export * from './updateSettingsBody'; export * from './updateTenantQuotaBody'; diff --git a/reading-platform-frontend/src/api/generated/model/lessonActivityResponse.ts b/reading-platform-frontend/src/api/generated/model/lessonActivityResponse.ts new file mode 100644 index 0000000..efd4b13 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/lessonActivityResponse.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 课时活动响应 + */ +export interface LessonActivityResponse { + /** 课时 ID */ + id?: string; + /** 课时标题 */ + title?: string; + /** 课时日期 */ + lessonDate?: string; + /** 课时状态 */ + status?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/lessonFeedback.ts b/reading-platform-frontend/src/api/generated/model/lessonFeedback.ts new file mode 100644 index 0000000..10a0e59 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/lessonFeedback.ts @@ -0,0 +1,55 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 课时反馈 + */ +export interface LessonFeedback { + /** ID */ + readonly id?: string; + /** 课时 ID */ + lessonId?: string; + /** 教师 ID */ + teacherId?: string; + /** + * 设计质量评分 (1-5) + * @minimum 1 + * @maximum 5 + */ + designQuality?: number; + /** + * 参与度评分 (1-5) + * @minimum 1 + * @maximum 5 + */ + participation?: number; + /** + * 目标达成度评分 (1-5) + * @minimum 1 + * @maximum 5 + */ + goalAchievement?: number; + /** 环节反馈 JSON */ + stepFeedbacks?: string; + /** 优点 */ + pros?: string; + /** 建议 */ + suggestions?: string; + /** 完成的活动 JSON */ + activitiesDone?: string; + /** 创建人用户名 */ + readonly createdBy?: string; + /** 创建时间 */ + readonly createdAt?: string; + /** 更新时间 */ + readonly updatedAt?: string; + /** 更新人用户名 */ + readonly updatedBy?: string; + /** 是否删除 */ + readonly deleted?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/lessonFeedbackRequest.ts b/reading-platform-frontend/src/api/generated/model/lessonFeedbackRequest.ts new file mode 100644 index 0000000..81e59c7 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/lessonFeedbackRequest.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { LessonFeedbackRequestStepFeedbacks } from './lessonFeedbackRequestStepFeedbacks'; +import type { LessonFeedbackRequestActivitiesDone } from './lessonFeedbackRequestActivitiesDone'; + +export interface LessonFeedbackRequest { + designQuality?: number; + participation?: number; + goalAchievement?: number; + stepFeedbacks?: LessonFeedbackRequestStepFeedbacks; + pros?: string; + suggestions?: string; + activitiesDone?: LessonFeedbackRequestActivitiesDone; +} diff --git a/reading-platform-frontend/src/api/generated/model/lessonFeedbackRequestActivitiesDone.ts b/reading-platform-frontend/src/api/generated/model/lessonFeedbackRequestActivitiesDone.ts new file mode 100644 index 0000000..e9f3af6 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/lessonFeedbackRequestActivitiesDone.ts @@ -0,0 +1,9 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type LessonFeedbackRequestActivitiesDone = { [key: string]: unknown }; diff --git a/reading-platform-frontend/src/api/generated/model/lessonFeedbackRequestStepFeedbacks.ts b/reading-platform-frontend/src/api/generated/model/lessonFeedbackRequestStepFeedbacks.ts new file mode 100644 index 0000000..1b4b67d --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/lessonFeedbackRequestStepFeedbacks.ts @@ -0,0 +1,9 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type LessonFeedbackRequestStepFeedbacks = { [key: string]: unknown }; diff --git a/reading-platform-frontend/src/api/generated/model/lessonFinishRequest.ts b/reading-platform-frontend/src/api/generated/model/lessonFinishRequest.ts new file mode 100644 index 0000000..47a7b58 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/lessonFinishRequest.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export interface LessonFinishRequest { + actualDuration?: number; + overallRating?: string; + participationRating?: string; + completionNote?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/lessonSimpleInfo.ts b/reading-platform-frontend/src/api/generated/model/lessonSimpleInfo.ts new file mode 100644 index 0000000..7bd0a49 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/lessonSimpleInfo.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 课程简单信息 + */ +export interface LessonSimpleInfo { + /** 课程 ID */ + id?: string; + /** 课程状态 */ + status?: string; + /** 班级名称 */ + className?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/lessonSimpleResponse.ts b/reading-platform-frontend/src/api/generated/model/lessonSimpleResponse.ts new file mode 100644 index 0000000..8146001 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/lessonSimpleResponse.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 课时简单信息响应 + */ +export interface LessonSimpleResponse { + /** 课时 ID */ + id?: string; + /** 课时标题 */ + title?: string; + /** 开始时间 */ + startTime?: string; + /** 结束时间 */ + endTime?: string; + /** 地点 */ + location?: string; + /** 课时状态 */ + status?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/messageResponse.ts b/reading-platform-frontend/src/api/generated/model/messageResponse.ts new file mode 100644 index 0000000..0abf291 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/messageResponse.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 简单消息响应 + */ +export interface MessageResponse { + /** 消息内容 */ + message?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/monthlyTaskStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/monthlyTaskStatsResponse.ts new file mode 100644 index 0000000..f0cee59 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/monthlyTaskStatsResponse.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 月度任务统计响应 + */ +export interface MonthlyTaskStatsResponse { + /** 月份 */ + month?: string; + /** 任务数 */ + tasks?: number; + /** 完成次数 */ + completions?: number; + /** 已完成数量 */ + completed?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/pageResultStudentInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/pageResultStudentInfoResponse.ts new file mode 100644 index 0000000..368eebc --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/pageResultStudentInfoResponse.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { StudentInfoResponse } from './studentInfoResponse'; + +export interface PageResultStudentInfoResponse { + total?: number; + pageSize?: number; + items?: StudentInfoResponse[]; + page?: number; + totalPages?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/pageResultTaskCompletion.ts b/reading-platform-frontend/src/api/generated/model/pageResultTaskCompletion.ts new file mode 100644 index 0000000..added07 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/pageResultTaskCompletion.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TaskCompletion } from './taskCompletion'; + +export interface PageResultTaskCompletion { + total?: number; + pageSize?: number; + items?: TaskCompletion[]; + page?: number; + totalPages?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/pageResultTaskTemplate.ts b/reading-platform-frontend/src/api/generated/model/pageResultTaskTemplate.ts new file mode 100644 index 0000000..83ebd35 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/pageResultTaskTemplate.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TaskTemplate } from './taskTemplate'; + +export interface PageResultTaskTemplate { + total?: number; + pageSize?: number; + items?: TaskTemplate[]; + page?: number; + totalPages?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/recentActivityResponse.ts b/reading-platform-frontend/src/api/generated/model/recentActivityResponse.ts new file mode 100644 index 0000000..0bc6b3c --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/recentActivityResponse.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 近期活动响应 + */ +export interface RecentActivityResponse { + /** 活动 ID */ + id?: string; + /** 活动类型/课时状态 */ + type?: string; + /** 活动标题 */ + title?: string; + /** 活动时间 */ + time?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/resetPasswordResponse.ts b/reading-platform-frontend/src/api/generated/model/resetPasswordResponse.ts new file mode 100644 index 0000000..c68bb43 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resetPasswordResponse.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 重置密码响应 + */ +export interface ResetPasswordResponse { + /** 临时密码 */ + tempPassword?: string; + /** 提示信息 */ + message?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultAdminStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/resultAdminStatsResponse.ts new file mode 100644 index 0000000..5a031a6 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultAdminStatsResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { AdminStatsResponse } from './adminStatsResponse'; + +export interface ResultAdminStatsResponse { + code?: number; + message?: string; + data?: AdminStatsResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultBatchSaveStudentRecordResponse.ts b/reading-platform-frontend/src/api/generated/model/resultBatchSaveStudentRecordResponse.ts new file mode 100644 index 0000000..4ab56e5 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultBatchSaveStudentRecordResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { BatchSaveStudentRecordResponse } from './batchSaveStudentRecordResponse'; + +export interface ResultBatchSaveStudentRecordResponse { + code?: number; + message?: string; + data?: BatchSaveStudentRecordResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultChildDetailResponse.ts b/reading-platform-frontend/src/api/generated/model/resultChildDetailResponse.ts new file mode 100644 index 0000000..5463037 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultChildDetailResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { ChildDetailResponse } from './childDetailResponse'; + +export interface ResultChildDetailResponse { + code?: number; + message?: string; + data?: ChildDetailResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultClassTeacher.ts b/reading-platform-frontend/src/api/generated/model/resultClassTeacher.ts new file mode 100644 index 0000000..3fac997 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultClassTeacher.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { ClassTeacher } from './classTeacher'; + +export interface ResultClassTeacher { + code?: number; + message?: string; + data?: ClassTeacher; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultCommonPageResponseLesson.ts b/reading-platform-frontend/src/api/generated/model/resultCommonPageResponseLesson.ts new file mode 100644 index 0000000..95a7867 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultCommonPageResponseLesson.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { CommonPageResponseLesson } from './commonPageResponseLesson'; + +export interface ResultCommonPageResponseLesson { + code?: number; + message?: string; + data?: CommonPageResponseLesson; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultCommonPageResponseTaskCompletionInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/resultCommonPageResponseTaskCompletionInfoResponse.ts new file mode 100644 index 0000000..c3674d1 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultCommonPageResponseTaskCompletionInfoResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { CommonPageResponseTaskCompletionInfoResponse } from './commonPageResponseTaskCompletionInfoResponse'; + +export interface ResultCommonPageResponseTaskCompletionInfoResponse { + code?: number; + message?: string; + data?: CommonPageResponseTaskCompletionInfoResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultFileUploadResponse.ts b/reading-platform-frontend/src/api/generated/model/resultFileUploadResponse.ts new file mode 100644 index 0000000..e40f5c3 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultFileUploadResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { FileUploadResponse } from './fileUploadResponse'; + +export interface ResultFileUploadResponse { + code?: number; + message?: string; + data?: FileUploadResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultImportTemplateResponse.ts b/reading-platform-frontend/src/api/generated/model/resultImportTemplateResponse.ts new file mode 100644 index 0000000..2baa944 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultImportTemplateResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { ImportTemplateResponse } from './importTemplateResponse'; + +export interface ResultImportTemplateResponse { + code?: number; + message?: string; + data?: ImportTemplateResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultLessonFeedback.ts b/reading-platform-frontend/src/api/generated/model/resultLessonFeedback.ts new file mode 100644 index 0000000..327926c --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultLessonFeedback.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { LessonFeedback } from './lessonFeedback'; + +export interface ResultLessonFeedback { + code?: number; + message?: string; + data?: LessonFeedback; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListActiveTeacherStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListActiveTeacherStatsResponse.ts new file mode 100644 index 0000000..5b24347 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListActiveTeacherStatsResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { ActiveTeacherStatsResponse } from './activeTeacherStatsResponse'; + +export interface ResultListActiveTeacherStatsResponse { + code?: number; + message?: string; + data?: ActiveTeacherStatsResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListChildInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListChildInfoResponse.ts new file mode 100644 index 0000000..7e1b29c --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListChildInfoResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { ChildInfoResponse } from './childInfoResponse'; + +export interface ResultListChildInfoResponse { + code?: number; + message?: string; + data?: ChildInfoResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListClassInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListClassInfoResponse.ts new file mode 100644 index 0000000..254ebf5 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListClassInfoResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { ClassInfoResponse } from './classInfoResponse'; + +export interface ResultListClassInfoResponse { + code?: number; + message?: string; + data?: ClassInfoResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListClassTeacher.ts b/reading-platform-frontend/src/api/generated/model/resultListClassTeacher.ts new file mode 100644 index 0000000..9e550ca --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListClassTeacher.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { ClassTeacher } from './classTeacher'; + +export interface ResultListClassTeacher { + code?: number; + message?: string; + data?: ClassTeacher[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListClazz.ts b/reading-platform-frontend/src/api/generated/model/resultListClazz.ts new file mode 100644 index 0000000..db17995 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListClazz.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { Clazz } from './clazz'; + +export interface ResultListClazz { + code?: number; + message?: string; + data?: Clazz[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListCourseDistributionResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListCourseDistributionResponse.ts new file mode 100644 index 0000000..64bddc8 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListCourseDistributionResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { CourseDistributionResponse } from './courseDistributionResponse'; + +export interface ResultListCourseDistributionResponse { + code?: number; + message?: string; + data?: CourseDistributionResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListCourseStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListCourseStatsResponse.ts new file mode 100644 index 0000000..95a15bc --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListCourseStatsResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { CourseStatsResponse } from './courseStatsResponse'; + +export interface ResultListCourseStatsResponse { + code?: number; + message?: string; + data?: CourseStatsResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListCourseUsageStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListCourseUsageStatsResponse.ts new file mode 100644 index 0000000..8a66976 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListCourseUsageStatsResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { CourseUsageStatsResponse } from './courseUsageStatsResponse'; + +export interface ResultListCourseUsageStatsResponse { + code?: number; + message?: string; + data?: CourseUsageStatsResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListLessonActivityResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListLessonActivityResponse.ts new file mode 100644 index 0000000..d459333 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListLessonActivityResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { LessonActivityResponse } from './lessonActivityResponse'; + +export interface ResultListLessonActivityResponse { + code?: number; + message?: string; + data?: LessonActivityResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListLessonSimpleResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListLessonSimpleResponse.ts new file mode 100644 index 0000000..be8b38c --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListLessonSimpleResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { LessonSimpleResponse } from './lessonSimpleResponse'; + +export interface ResultListLessonSimpleResponse { + code?: number; + message?: string; + data?: LessonSimpleResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListMonthlyTaskStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListMonthlyTaskStatsResponse.ts new file mode 100644 index 0000000..1e1731e --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListMonthlyTaskStatsResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { MonthlyTaskStatsResponse } from './monthlyTaskStatsResponse'; + +export interface ResultListMonthlyTaskStatsResponse { + code?: number; + message?: string; + data?: MonthlyTaskStatsResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListRecentActivityResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListRecentActivityResponse.ts new file mode 100644 index 0000000..9d85a0e --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListRecentActivityResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { RecentActivityResponse } from './recentActivityResponse'; + +export interface ResultListRecentActivityResponse { + code?: number; + message?: string; + data?: RecentActivityResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListSchedulePlan.ts b/reading-platform-frontend/src/api/generated/model/resultListSchedulePlan.ts new file mode 100644 index 0000000..a892334 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListSchedulePlan.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { SchedulePlan } from './schedulePlan'; + +export interface ResultListSchedulePlan { + code?: number; + message?: string; + data?: SchedulePlan[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListSchedulePlanResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListSchedulePlanResponse.ts new file mode 100644 index 0000000..a4ff2c8 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListSchedulePlanResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { SchedulePlanResponse } from './schedulePlanResponse'; + +export interface ResultListSchedulePlanResponse { + code?: number; + message?: string; + data?: SchedulePlanResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListStudentTransferHistoryResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListStudentTransferHistoryResponse.ts new file mode 100644 index 0000000..808f7e0 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListStudentTransferHistoryResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { StudentTransferHistoryResponse } from './studentTransferHistoryResponse'; + +export interface ResultListStudentTransferHistoryResponse { + code?: number; + message?: string; + data?: StudentTransferHistoryResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListTaskStatsByClassResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListTaskStatsByClassResponse.ts new file mode 100644 index 0000000..ccf9d11 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListTaskStatsByClassResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TaskStatsByClassResponse } from './taskStatsByClassResponse'; + +export interface ResultListTaskStatsByClassResponse { + code?: number; + message?: string; + data?: TaskStatsByClassResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListTaskStatsByTypeResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListTaskStatsByTypeResponse.ts new file mode 100644 index 0000000..c2e8b40 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListTaskStatsByTypeResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TaskStatsByTypeResponse } from './taskStatsByTypeResponse'; + +export interface ResultListTaskStatsByTypeResponse { + code?: number; + message?: string; + data?: TaskStatsByTypeResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListTeacherInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListTeacherInfoResponse.ts new file mode 100644 index 0000000..c27d85e --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListTeacherInfoResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TeacherInfoResponse } from './teacherInfoResponse'; + +export interface ResultListTeacherInfoResponse { + code?: number; + message?: string; + data?: TeacherInfoResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListTenantStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListTenantStatsResponse.ts new file mode 100644 index 0000000..46bbaa3 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListTenantStatsResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TenantStatsResponse } from './tenantStatsResponse'; + +export interface ResultListTenantStatsResponse { + code?: number; + message?: string; + data?: TenantStatsResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListTrendDataPointResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListTrendDataPointResponse.ts new file mode 100644 index 0000000..f5770e9 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListTrendDataPointResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TrendDataPointResponse } from './trendDataPointResponse'; + +export interface ResultListTrendDataPointResponse { + code?: number; + message?: string; + data?: TrendDataPointResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultListTrendDataResponse.ts b/reading-platform-frontend/src/api/generated/model/resultListTrendDataResponse.ts new file mode 100644 index 0000000..895cf87 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultListTrendDataResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TrendDataResponse } from './trendDataResponse'; + +export interface ResultListTrendDataResponse { + code?: number; + message?: string; + data?: TrendDataResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultMessageResponse.ts b/reading-platform-frontend/src/api/generated/model/resultMessageResponse.ts new file mode 100644 index 0000000..7d07e35 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultMessageResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { MessageResponse } from './messageResponse'; + +export interface ResultMessageResponse { + code?: number; + message?: string; + data?: MessageResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultPageResultStudentInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/resultPageResultStudentInfoResponse.ts new file mode 100644 index 0000000..feb3b5a --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultPageResultStudentInfoResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { PageResultStudentInfoResponse } from './pageResultStudentInfoResponse'; + +export interface ResultPageResultStudentInfoResponse { + code?: number; + message?: string; + data?: PageResultStudentInfoResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultPageResultTaskCompletion.ts b/reading-platform-frontend/src/api/generated/model/resultPageResultTaskCompletion.ts new file mode 100644 index 0000000..4f70bfe --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultPageResultTaskCompletion.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { PageResultTaskCompletion } from './pageResultTaskCompletion'; + +export interface ResultPageResultTaskCompletion { + code?: number; + message?: string; + data?: PageResultTaskCompletion; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultPageResultTaskTemplate.ts b/reading-platform-frontend/src/api/generated/model/resultPageResultTaskTemplate.ts new file mode 100644 index 0000000..f65e88e --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultPageResultTaskTemplate.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { PageResultTaskTemplate } from './pageResultTaskTemplate'; + +export interface ResultPageResultTaskTemplate { + code?: number; + message?: string; + data?: PageResultTaskTemplate; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultResetPasswordResponse.ts b/reading-platform-frontend/src/api/generated/model/resultResetPasswordResponse.ts new file mode 100644 index 0000000..d2348bd --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultResetPasswordResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { ResetPasswordResponse } from './resetPasswordResponse'; + +export interface ResultResetPasswordResponse { + code?: number; + message?: string; + data?: ResetPasswordResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/resultStatsResponse.ts new file mode 100644 index 0000000..5f09047 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultStatsResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { StatsResponse } from './statsResponse'; + +export interface ResultStatsResponse { + code?: number; + message?: string; + data?: StatsResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultStudentRecord.ts b/reading-platform-frontend/src/api/generated/model/resultStudentRecord.ts new file mode 100644 index 0000000..72e938a --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultStudentRecord.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { StudentRecord } from './studentRecord'; + +export interface ResultStudentRecord { + code?: number; + message?: string; + data?: StudentRecord; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultStudentRecordListResponse.ts b/reading-platform-frontend/src/api/generated/model/resultStudentRecordListResponse.ts new file mode 100644 index 0000000..251bde4 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultStudentRecordListResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { StudentRecordListResponse } from './studentRecordListResponse'; + +export interface ResultStudentRecordListResponse { + code?: number; + message?: string; + data?: StudentRecordListResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultSystemSettingsResponse.ts b/reading-platform-frontend/src/api/generated/model/resultSystemSettingsResponse.ts new file mode 100644 index 0000000..c0af411 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultSystemSettingsResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { SystemSettingsResponse } from './systemSettingsResponse'; + +export interface ResultSystemSettingsResponse { + code?: number; + message?: string; + data?: SystemSettingsResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultTaskCompletion.ts b/reading-platform-frontend/src/api/generated/model/resultTaskCompletion.ts new file mode 100644 index 0000000..8e6062b --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultTaskCompletion.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TaskCompletion } from './taskCompletion'; + +export interface ResultTaskCompletion { + code?: number; + message?: string; + data?: TaskCompletion; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultTaskFeedbackResponse.ts b/reading-platform-frontend/src/api/generated/model/resultTaskFeedbackResponse.ts new file mode 100644 index 0000000..36c2d09 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultTaskFeedbackResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TaskFeedbackResponse } from './taskFeedbackResponse'; + +export interface ResultTaskFeedbackResponse { + code?: number; + message?: string; + data?: TaskFeedbackResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultTaskStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/resultTaskStatsResponse.ts new file mode 100644 index 0000000..30ba1d6 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultTaskStatsResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TaskStatsResponse } from './taskStatsResponse'; + +export interface ResultTaskStatsResponse { + code?: number; + message?: string; + data?: TaskStatsResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultTaskTemplate.ts b/reading-platform-frontend/src/api/generated/model/resultTaskTemplate.ts new file mode 100644 index 0000000..126ddd6 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultTaskTemplate.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TaskTemplate } from './taskTemplate'; + +export interface ResultTaskTemplate { + code?: number; + message?: string; + data?: TaskTemplate; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultTeacherDashboardResponse.ts b/reading-platform-frontend/src/api/generated/model/resultTeacherDashboardResponse.ts new file mode 100644 index 0000000..19fc1fb --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultTeacherDashboardResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TeacherDashboardResponse } from './teacherDashboardResponse'; + +export interface ResultTeacherDashboardResponse { + code?: number; + message?: string; + data?: TeacherDashboardResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/resultTenantStatusUpdateResponse.ts b/reading-platform-frontend/src/api/generated/model/resultTenantStatusUpdateResponse.ts new file mode 100644 index 0000000..cd7eb52 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/resultTenantStatusUpdateResponse.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TenantStatusUpdateResponse } from './tenantStatusUpdateResponse'; + +export interface ResultTenantStatusUpdateResponse { + code?: number; + message?: string; + data?: TenantStatusUpdateResponse; +} diff --git a/reading-platform-frontend/src/api/generated/model/schedulePlan.ts b/reading-platform-frontend/src/api/generated/model/schedulePlan.ts index 3b044a0..fe1c587 100644 --- a/reading-platform-frontend/src/api/generated/model/schedulePlan.ts +++ b/reading-platform-frontend/src/api/generated/model/schedulePlan.ts @@ -5,14 +5,23 @@ * Reading Platform Backend Service API Documentation * OpenAPI spec version: 1.0.0 */ +import type { LocalTime } from './localTime'; export interface SchedulePlan { id?: number; tenantId?: number; name?: string; classId?: number; + courseId?: number; + teacherId?: number; + dayOfWeek?: number; + period?: number; + startTime?: LocalTime; + endTime?: LocalTime; startDate?: string; endDate?: string; + location?: string; + note?: string; status?: string; createdAt?: string; updatedAt?: string; diff --git a/reading-platform-frontend/src/api/generated/model/schedulePlanCreateRequest.ts b/reading-platform-frontend/src/api/generated/model/schedulePlanCreateRequest.ts new file mode 100644 index 0000000..02b0243 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/schedulePlanCreateRequest.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { LocalTime } from './localTime'; + +/** + * 课表计划创建请求 + */ +export interface SchedulePlanCreateRequest { + /** 班级 ID */ + classId?: number; + /** 课程 ID */ + courseId?: number; + /** 星期几:1-7 */ + dayOfWeek?: number; + /** 节次 */ + period?: number; + startTime?: LocalTime; + endTime?: LocalTime; + /** 授课教师 ID */ + teacherId?: number; + /** 开始日期 */ + startDate?: string; + /** 结束日期 */ + endDate?: string; + /** 教室/地点 */ + location?: string; + /** 备注 */ + note?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/schedulePlanResponse.ts b/reading-platform-frontend/src/api/generated/model/schedulePlanResponse.ts new file mode 100644 index 0000000..a0cb60b --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/schedulePlanResponse.ts @@ -0,0 +1,46 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { LocalTime } from './localTime'; + +/** + * 课表计划响应 + */ +export interface SchedulePlanResponse { + /** 课表 ID */ + id?: string; + /** 课表名称 */ + name?: string; + /** 班级 ID */ + classId?: string; + /** 班级名称 */ + className?: string; + /** 课程 ID */ + courseId?: string; + /** 课程名称 */ + courseName?: string; + /** 教师 ID */ + teacherId?: string; + /** 教师姓名 */ + teacherName?: string; + /** 星期几 (1-7) */ + dayOfWeek?: number; + /** 节次 */ + period?: number; + startTime?: LocalTime; + endTime?: LocalTime; + /** 开始日期 */ + startDate?: string; + /** 结束日期 */ + endDate?: string; + /** 地点 */ + location?: string; + /** 备注 */ + note?: string; + /** 状态 */ + status?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/schedulePlanUpdateRequest.ts b/reading-platform-frontend/src/api/generated/model/schedulePlanUpdateRequest.ts new file mode 100644 index 0000000..53ed649 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/schedulePlanUpdateRequest.ts @@ -0,0 +1,26 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { LocalTime } from './localTime'; + +/** + * 课表计划更新请求 + */ +export interface SchedulePlanUpdateRequest { + /** 授课教师 ID */ + teacherId?: string; + /** 开始日期 */ + startDate?: string; + /** 结束日期 */ + endDate?: string; + startTime?: LocalTime; + endTime?: LocalTime; + /** 状态 */ + status?: string; + /** 备注 */ + note?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/scheduleTemplateApplyRequest.ts b/reading-platform-frontend/src/api/generated/model/scheduleTemplateApplyRequest.ts new file mode 100644 index 0000000..bc227a6 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/scheduleTemplateApplyRequest.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 课表模板应用请求 + */ +export interface ScheduleTemplateApplyRequest { + /** 班级 ID */ + classId: number; + /** 应用开始日期 */ + startDate: string; + /** 应用周数 */ + weeks?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/schoolSettingsUpdateRequest.ts b/reading-platform-frontend/src/api/generated/model/schoolSettingsUpdateRequest.ts new file mode 100644 index 0000000..71d2802 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/schoolSettingsUpdateRequest.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 学校设置更新请求 + */ +export interface SchoolSettingsUpdateRequest { + /** 学校名称 */ + schoolName?: string; + /** 学校 Logo */ + schoolLogo?: string; + /** 地址 */ + address?: string; + /** 课时通知启用 */ + notifyOnLesson?: boolean; + /** 任务通知启用 */ + notifyOnTask?: boolean; + /** 成长记录通知启用 */ + notifyOnGrowth?: boolean; +} diff --git a/reading-platform-frontend/src/api/generated/model/statsResponse.ts b/reading-platform-frontend/src/api/generated/model/statsResponse.ts new file mode 100644 index 0000000..8d67cb0 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/statsResponse.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 统计数据响应 + */ +export interface StatsResponse { + /** 学生总数 */ + totalStudents?: number; + /** 教师总数 */ + totalTeachers?: number; + /** 班级总数 */ + totalClasses?: number; + /** 课程总数 */ + totalCourses?: number; + /** 今日课时数 */ + todayLessons?: number; + /** 本月任务数 */ + monthTasks?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/studentInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/studentInfoResponse.ts new file mode 100644 index 0000000..03c79b9 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/studentInfoResponse.ts @@ -0,0 +1,35 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { ClassSimpleInfo } from './classSimpleInfo'; + +/** + * 学生信息响应 + */ +export interface StudentInfoResponse { + /** 学生 ID */ + id?: string; + /** 学生姓名 */ + name?: string; + /** 性别 */ + gender?: string; + /** 出生日期 */ + birthDate?: string; + /** 班级 ID */ + classId?: string; + classInfo?: ClassSimpleInfo; + /** 家长姓名 */ + parentName?: string; + /** 家长手机号 */ + parentPhone?: string; + /** 课时数 */ + lessonCount?: number; + /** 阅读次数 */ + readingCount?: number; + /** 创建时间 */ + createdAt?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/studentRecord.ts b/reading-platform-frontend/src/api/generated/model/studentRecord.ts new file mode 100644 index 0000000..1db0040 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/studentRecord.ts @@ -0,0 +1,59 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 学生记录 + */ +export interface StudentRecord { + /** 记录 ID */ + readonly id?: string; + /** 课时 ID */ + lessonId: string; + /** 学生 ID */ + studentId: string; + /** 出勤状态 present/absent/late */ + attendance?: string; + /** 课堂表现评价 */ + performance?: string; + /** 备注说明 */ + notes?: string; + /** + * 专注力评分 (1-5) + * @minimum 1 + * @maximum 5 + */ + focus?: number; + /** + * 参与度评分 (1-5) + * @minimum 1 + * @maximum 5 + */ + participation?: number; + /** + * 兴趣评分 (1-5) + * @minimum 1 + * @maximum 5 + */ + interest?: number; + /** + * 理解度评分 (1-5) + * @minimum 1 + * @maximum 5 + */ + understanding?: number; + /** 创建人用户名 */ + readonly createdBy?: string; + /** 更新人用户名 */ + readonly updatedBy?: string; + /** 创建时间 */ + readonly createdAt?: string; + /** 更新时间 */ + readonly updatedAt?: string; + /** 是否删除 0-未删除 1-已删除 */ + readonly deleted?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/studentRecordListResponse.ts b/reading-platform-frontend/src/api/generated/model/studentRecordListResponse.ts new file mode 100644 index 0000000..6d9a0ae --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/studentRecordListResponse.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { LessonSimpleInfo } from './lessonSimpleInfo'; +import type { StudentRecordResponse } from './studentRecordResponse'; + +/** + * 学生记录列表响应 + */ +export interface StudentRecordListResponse { + lesson?: LessonSimpleInfo; + /** 学生记录列表 */ + students?: StudentRecordResponse[]; +} diff --git a/reading-platform-frontend/src/api/generated/model/studentRecordRequest.ts b/reading-platform-frontend/src/api/generated/model/studentRecordRequest.ts new file mode 100644 index 0000000..828e1d0 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/studentRecordRequest.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export interface StudentRecordRequest { + focus?: number; + participation?: number; + interest?: number; + understanding?: number; + notes?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/studentRecordResponse.ts b/reading-platform-frontend/src/api/generated/model/studentRecordResponse.ts new file mode 100644 index 0000000..994007c --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/studentRecordResponse.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 学生记录响应 + */ +export interface StudentRecordResponse { + /** 记录 ID */ + id?: string; + /** 学生 ID */ + studentId?: string; + /** 专注力评分 (1-5) */ + focus?: number; + /** 参与度评分 (1-5) */ + participation?: number; + /** 兴趣评分 (1-5) */ + interest?: number; + /** 理解度评分 (1-5) */ + understanding?: number; + /** 备注 */ + notes?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/studentTransferHistoryResponse.ts b/reading-platform-frontend/src/api/generated/model/studentTransferHistoryResponse.ts new file mode 100644 index 0000000..b829a58 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/studentTransferHistoryResponse.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 学生调班历史响应 + */ +export interface StudentTransferHistoryResponse { + /** 记录 ID */ + id?: string; + /** 班级 ID */ + classId?: string; + /** 班级名称 */ + className?: string; + /** 开始日期 */ + startDate?: string; + /** 结束日期 */ + endDate?: string; + /** 状态 */ + status?: string; + /** 调班原因 */ + reason?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/systemSettingsResponse.ts b/reading-platform-frontend/src/api/generated/model/systemSettingsResponse.ts new file mode 100644 index 0000000..09495d5 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/systemSettingsResponse.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 系统设置响应 + */ +export interface SystemSettingsResponse { + /** 系统名称 */ + systemName?: string; + /** 系统 Logo URL */ + systemLogo?: string; + /** 登录页背景图 URL */ + loginBackground?: string; + /** 系统公告 */ + announcement?: string; + /** 联系方式 */ + contactInfo?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/taskCompletion.ts b/reading-platform-frontend/src/api/generated/model/taskCompletion.ts new file mode 100644 index 0000000..88228b3 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/taskCompletion.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export interface TaskCompletion { + id?: number; + taskId?: number; + studentId?: number; + status?: string; + completedAt?: string; + content?: string; + attachments?: string; + rating?: number; + feedback?: string; + createdAt?: string; + updatedAt?: string; + deleted?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/taskCompletionInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/taskCompletionInfoResponse.ts new file mode 100644 index 0000000..c4c6739 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/taskCompletionInfoResponse.ts @@ -0,0 +1,29 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ +import type { TaskSimpleInfo } from './taskSimpleInfo'; + +/** + * 任务完成信息响应 + */ +export interface TaskCompletionInfoResponse { + /** 完成记录 ID */ + id?: string; + /** 任务 ID */ + taskId?: string; + /** 学生 ID */ + studentId?: string; + /** 状态 */ + status?: string; + /** 完成时间 */ + completedAt?: string; + /** 反馈 */ + feedback?: string; + /** 家长反馈 */ + parentFeedback?: string; + task?: TaskSimpleInfo; +} diff --git a/reading-platform-frontend/src/api/generated/model/taskFeedbackResponse.ts b/reading-platform-frontend/src/api/generated/model/taskFeedbackResponse.ts new file mode 100644 index 0000000..442f0cc --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/taskFeedbackResponse.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 任务反馈响应 + */ +export interface TaskFeedbackResponse { + /** 完成记录 ID */ + id?: string; + /** 任务 ID */ + taskId?: string; + /** 学生 ID */ + studentId?: string; + /** 状态 */ + status?: string; + /** 家长反馈 */ + parentFeedback?: string; + /** 消息(未找到记录时返回) */ + message?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/taskFeedbackUpdateRequest.ts b/reading-platform-frontend/src/api/generated/model/taskFeedbackUpdateRequest.ts new file mode 100644 index 0000000..94d75a7 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/taskFeedbackUpdateRequest.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 任务家长反馈更新请求 + */ +export interface TaskFeedbackUpdateRequest { + /** 家长反馈内容 */ + feedback?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/taskSimpleInfo.ts b/reading-platform-frontend/src/api/generated/model/taskSimpleInfo.ts new file mode 100644 index 0000000..ef22dec --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/taskSimpleInfo.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 任务简单信息 + */ +export interface TaskSimpleInfo { + /** 任务 ID */ + id?: string; + /** 任务名称 */ + name?: string; + /** 任务类型 */ + type?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/taskStatsByClassResponse.ts b/reading-platform-frontend/src/api/generated/model/taskStatsByClassResponse.ts new file mode 100644 index 0000000..f8b94ab --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/taskStatsByClassResponse.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 按班级任务统计响应 + */ +export interface TaskStatsByClassResponse { + /** 班级 ID */ + classId?: string; + /** 班级名称 */ + className?: string; + /** 年级 */ + grade?: string; + /** 总任务数 */ + total?: number; + /** 已完成任务数 */ + completed?: number; + /** 完成率 */ + rate?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/taskStatsByTypeResponse.ts b/reading-platform-frontend/src/api/generated/model/taskStatsByTypeResponse.ts new file mode 100644 index 0000000..c306c94 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/taskStatsByTypeResponse.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 按类型统计的任务响应 + */ +export interface TaskStatsByTypeResponse { + /** 任务类型 */ + type?: string; + /** 总任务数 */ + total?: number; + /** 已完成任务数 */ + completed?: number; + /** 完成率 */ + rate?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/taskStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/taskStatsResponse.ts new file mode 100644 index 0000000..5335267 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/taskStatsResponse.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 任务统计响应 + */ +export interface TaskStatsResponse { + /** 任务总数 */ + totalTasks?: number; + /** 已发布任务数 */ + publishedTasks?: number; + /** 已完成任务数 */ + completedTasks?: number; + /** 进行中任务数 */ + inProgressTasks?: number; + /** 待完成数量 */ + pendingCount?: number; + /** 总完成次数 */ + totalCompletions?: number; + /** 完成率 */ + completionRate?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/taskTemplate.ts b/reading-platform-frontend/src/api/generated/model/taskTemplate.ts new file mode 100644 index 0000000..e428f0c --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/taskTemplate.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export interface TaskTemplate { + id?: number; + tenantId?: number; + name?: string; + description?: string; + type?: string; + content?: string; + isPublic?: number; + createdAt?: string; + updatedAt?: string; + deleted?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/taskTemplateCreateRequest.ts b/reading-platform-frontend/src/api/generated/model/taskTemplateCreateRequest.ts new file mode 100644 index 0000000..3bce611 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/taskTemplateCreateRequest.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 任务模板创建请求 + */ +export interface TaskTemplateCreateRequest { + /** 模板名称 */ + name: string; + /** 模板描述 */ + description?: string; + /** 任务类型:阅读、作业、活动 */ + type?: string; + /** 任务内容模板 */ + content?: string; + /** 是否公共模板:0-私有,1-公共 */ + isPublic?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/taskTemplateUpdateRequest.ts b/reading-platform-frontend/src/api/generated/model/taskTemplateUpdateRequest.ts new file mode 100644 index 0000000..2b1aed8 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/taskTemplateUpdateRequest.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 任务模板更新请求 + */ +export interface TaskTemplateUpdateRequest { + /** 模板名称 */ + name?: string; + /** 模板描述 */ + description?: string; + /** 任务类型:阅读、作业、活动 */ + type?: string; + /** 任务内容模板 */ + content?: string; + /** 是否公共模板:0-私有,1-公共 */ + isPublic?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/teacherDashboardResponse.ts b/reading-platform-frontend/src/api/generated/model/teacherDashboardResponse.ts new file mode 100644 index 0000000..307747a --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/teacherDashboardResponse.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 教师仪表盘概览响应 + */ +export interface TeacherDashboardResponse { + /** 课时数 */ + lessonCount?: number; + /** 任务数 */ + taskCount?: number; + /** 成长记录数 */ + growthRecordCount?: number; + /** 未读通知数 */ + unreadNotifications?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/teacherInfoResponse.ts b/reading-platform-frontend/src/api/generated/model/teacherInfoResponse.ts new file mode 100644 index 0000000..254d6c9 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/teacherInfoResponse.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 教师信息响应 + */ +export interface TeacherInfoResponse { + /** 教师 ID */ + teacherId?: string; + /** 教师姓名 */ + teacherName?: string; + /** 教师手机号 */ + teacherPhone?: string; + /** 角色 */ + role?: string; + /** 是否主教 */ + isPrimary?: boolean; +} diff --git a/reading-platform-frontend/src/api/generated/model/tenantQuotaUpdateRequest.ts b/reading-platform-frontend/src/api/generated/model/tenantQuotaUpdateRequest.ts new file mode 100644 index 0000000..5977f6b --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/tenantQuotaUpdateRequest.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 租户配额更新请求 + */ +export interface TenantQuotaUpdateRequest { + /** 套餐类型 */ + packageType?: string; + /** 教师配额 */ + teacherQuota?: number; + /** 学生配额 */ + studentQuota?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/tenantStatsResponse.ts b/reading-platform-frontend/src/api/generated/model/tenantStatsResponse.ts new file mode 100644 index 0000000..efa5e7b --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/tenantStatsResponse.ts @@ -0,0 +1,29 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 活跃租户统计响应 + */ +export interface TenantStatsResponse { + /** 租户 ID */ + id?: string; + /** 租户名称 */ + name?: string; + /** 租户编码 */ + code?: string; + /** 状态 */ + status?: string; + /** 过期时间 */ + expireAt?: string; + /** 教师数 */ + teacherCount?: number; + /** 学生数 */ + studentCount?: number; + /** 课时数 */ + lessonCount?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/tenantStatusUpdateRequest.ts b/reading-platform-frontend/src/api/generated/model/tenantStatusUpdateRequest.ts new file mode 100644 index 0000000..b8f941a --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/tenantStatusUpdateRequest.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 租户状态更新请求 + */ +export interface TenantStatusUpdateRequest { + /** 状态:active/inactive */ + status?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/tenantStatusUpdateResponse.ts b/reading-platform-frontend/src/api/generated/model/tenantStatusUpdateResponse.ts new file mode 100644 index 0000000..3bdaad1 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/tenantStatusUpdateResponse.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 租户状态更新响应 + */ +export interface TenantStatusUpdateResponse { + /** 租户 ID */ + id?: string; + /** 租户名称 */ + name?: string; + /** 状态 */ + status?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/transferStudentRequest.ts b/reading-platform-frontend/src/api/generated/model/transferStudentRequest.ts new file mode 100644 index 0000000..75e76a2 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/transferStudentRequest.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export interface TransferStudentRequest { + toClassId?: string; + reason?: string; +} diff --git a/reading-platform-frontend/src/api/generated/model/trendDataPointResponse.ts b/reading-platform-frontend/src/api/generated/model/trendDataPointResponse.ts new file mode 100644 index 0000000..1315441 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/trendDataPointResponse.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 趋势数据点响应 + */ +export interface TrendDataPointResponse { + /** 月份 */ + month?: string; + /** 租户数 */ + tenantCount?: number; + /** 课时数 */ + lessonCount?: number; + /** 学生数 */ + studentCount?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/trendDataResponse.ts b/reading-platform-frontend/src/api/generated/model/trendDataResponse.ts new file mode 100644 index 0000000..fb48c24 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/trendDataResponse.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +/** + * 趋势数据响应 + */ +export interface TrendDataResponse { + /** 月份 */ + month?: string; + /** 课时数 */ + lessonCount?: number; + /** 学生数 */ + studentCount?: number; +} diff --git a/reading-platform-frontend/src/api/generated/model/updateCompletion1Params.ts b/reading-platform-frontend/src/api/generated/model/updateCompletion1Params.ts new file mode 100644 index 0000000..9f6e41d --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/updateCompletion1Params.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type UpdateCompletion1Params = { +status: string; +feedback?: string; +}; diff --git a/reading-platform-frontend/src/api/generated/model/updateCompletionParams.ts b/reading-platform-frontend/src/api/generated/model/updateCompletionParams.ts new file mode 100644 index 0000000..0f8ddb0 --- /dev/null +++ b/reading-platform-frontend/src/api/generated/model/updateCompletionParams.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.13.2 🍺 + * Do not edit manually. + * Reading Platform API + * Reading Platform Backend Service API Documentation + * OpenAPI spec version: 1.0.0 + */ + +export type UpdateCompletionParams = { +status: string; +feedback?: string; +}; diff --git a/reading-platform-frontend/src/api/parent.ts b/reading-platform-frontend/src/api/parent.ts index c261006..5d69292 100644 --- a/reading-platform-frontend/src/api/parent.ts +++ b/reading-platform-frontend/src/api/parent.ts @@ -108,6 +108,10 @@ export const getChildLessons = ( // ==================== 任务 API ==================== +export interface TaskFeedbackUpdateRequest { + feedback: string; +} + export const getChildTasks = ( childId: number, params?: { page?: number; pageSize?: number; status?: string } @@ -117,9 +121,9 @@ export const getChildTasks = ( export const submitTaskFeedback = ( childId: number, taskId: number, - feedback: string + data: TaskFeedbackUpdateRequest ): Promise => - http.put(`/parent/children/${childId}/tasks/${taskId}/feedback`, { feedback }); + http.put(`/parent/children/${childId}/tasks/${taskId}/feedback`, data); // ==================== 成长档案 API ==================== diff --git a/reading-platform-frontend/src/api/teacher.ts b/reading-platform-frontend/src/api/teacher.ts index 1d6edeb..f73b63b 100644 --- a/reading-platform-frontend/src/api/teacher.ts +++ b/reading-platform-frontend/src/api/teacher.ts @@ -435,6 +435,16 @@ export interface CreateTeacherScheduleDto { note?: string; } +export interface SchedulePlanUpdateRequest { + teacherId?: number; + startDate?: string; + endDate?: string; + startTime?: string; + endTime?: string; + status?: string; + note?: string; +} + export interface TeacherTimetableItem { date: string; weekDay: number; @@ -458,7 +468,7 @@ export const getTodayTeacherSchedules = () => export const createTeacherSchedule = (data: CreateTeacherScheduleDto) => http.post('/teacher/schedules', data); -export const updateTeacherSchedule = (id: number, data: Partial & { status?: string }) => +export const updateTeacherSchedule = (id: number, data: SchedulePlanUpdateRequest) => http.put(`/teacher/schedules/${id}`, data); export const cancelTeacherSchedule = (id: number) => diff --git a/reading-platform-frontend/src/api/teacher.ts.tmp.13484.1773123085155 b/reading-platform-frontend/src/api/teacher.ts.tmp.13484.1773123085155 new file mode 100644 index 0000000..f73b63b --- /dev/null +++ b/reading-platform-frontend/src/api/teacher.ts.tmp.13484.1773123085155 @@ -0,0 +1,670 @@ +import { http } from './index'; + +// ==================== 教师课程 API ==================== + +export interface TeacherCourseQueryParams { + page?: number; + pageSize?: number; + grade?: string; + keyword?: string; +} + +export interface TeacherCourse { + id: number; + name: string; + pictureBookName?: string; + coverImagePath?: string; + gradeTags: string[]; + domainTags: string[]; + duration: number; + avgRating: number; + usageCount: number; + publishedAt: string; +} + +// 教师班级信息(更新:新增角色字段) +export interface TeacherClass { + id: number; + name: string; + grade: string; + studentCount: number; + lessonCount: number; + myRole: 'MAIN' | 'ASSIST' | 'CARE'; // 我在该班级的角色 + isPrimary: boolean; // 是否班主任 +} + +// 班级教师信息 +export interface TeacherClassTeacher { + teacherId: number; + teacherName: string; + teacherPhone?: string; + role: 'MAIN' | 'ASSIST' | 'CARE'; + isPrimary: boolean; +} + +// 获取教师可用的课程列表 +export function getTeacherCourses(params: TeacherCourseQueryParams): Promise<{ + items: TeacherCourse[]; + total: number; + page: number; + pageSize: number; +}> { + return http.get('/teacher/courses', { params }); +} + +// 获取课程详情 +export function getTeacherCourse(id: number): Promise { + return http.get(`/teacher/courses/${id}`); +} + +// 获取教师的班级列表 +export function getTeacherClasses(): Promise { + return http.get('/teacher/courses/classes'); +} + +// 获取教师所有学生列表(跨班级) +export function getTeacherStudents(params?: { page?: number; pageSize?: number; keyword?: string }): Promise<{ + items: Array<{ + id: number; + name: string; + gender?: string; + birthDate?: string; + classId: number; + class?: { + id: number; + name: string; + grade: string; + }; + parentName?: string; + parentPhone?: string; + createdAt: string; + }>; + total: number; + page: number; + pageSize: number; +}> { + return http.get('/teacher/students', { params }); +} + +// 获取班级学生列表 +export function getTeacherClassStudents(classId: number, params?: { page?: number; pageSize?: number; keyword?: string }): Promise<{ + items: Array<{ + id: number; + name: string; + gender?: string; + birthDate?: string; + parentName?: string; + parentPhone?: string; + lessonCount?: number; + readingCount?: number; + createdAt: string; + }>; + total: number; + page: number; + pageSize: number; + class?: { + id: number; + name: string; + grade: string; + studentCount: number; + lessonCount: number; + }; +}> { + return http.get(`/teacher/classes/${classId}/students`, { params }); +} + +// 获取班级教师列表 +export function getClassTeachers(classId: number): Promise { + return http.get(`/teacher/classes/${classId}/teachers`); +} + +// ==================== 授课记录 API ==================== + +export interface CreateLessonDto { + courseId: number; + classId: number; + plannedDatetime?: string; +} + +export interface FinishLessonDto { + overallRating?: string; + participationRating?: string; + completionNote?: string; + actualDuration?: number; +} + +export interface StudentRecordDto { + focus?: number; + participation?: number; + interest?: number; + understanding?: number; + notes?: string; +} + +// 获取授课记录列表 +export function getLessons(params?: { + page?: number; + pageSize?: number; + status?: string; + courseId?: number; +}): Promise<{ + items: any[]; + total: number; + page: number; + pageSize: number; +}> { + return http.get('/teacher/lessons', { params }); +} + +// 获取单个授课记录详情 +export function getLesson(id: number): Promise { + return http.get(`/teacher/lessons/${id}`); +} + +// 创建授课记录(备课) +export function createLesson(data: CreateLessonDto): Promise { + return http.post('/teacher/lessons', data); +} + +// 开始上课 +export function startLesson(id: number): Promise { + return http.post(`/teacher/lessons/${id}/start`); +} + +// 结束上课 +export function finishLesson(id: number, data: FinishLessonDto): Promise { + return http.post(`/teacher/lessons/${id}/finish`, data); +} + +// 取消课程 +export function cancelLesson(id: number): Promise { + return http.post(`/teacher/lessons/${id}/cancel`); +} + +// 保存学生评价记录 +export function saveStudentRecord( + lessonId: number, + studentId: number, + data: StudentRecordDto +): Promise { + return http.post(`/teacher/lessons/${lessonId}/students/${studentId}/record`, data); +} + +// 获取课程所有学生记录 +export interface StudentWithRecord { + id: number; + name: string; + gender?: string; + record: { + id: number; + focus?: number; + participation?: number; + interest?: number; + understanding?: number; + notes?: string; + } | null; +} + +export interface StudentRecordsResponse { + lesson: { + id: number; + status: string; + className: string; + }; + students: StudentWithRecord[]; +} + +export function getStudentRecords(lessonId: number): Promise { + return http.get(`/teacher/lessons/${lessonId}/student-records`); +} + +// 批量保存学生评价记录 +export function batchSaveStudentRecords( + lessonId: number, + records: Array<{ studentId: number } & StudentRecordDto> +): Promise<{ count: number; records: any[] }> { + return http.post(`/teacher/lessons/${lessonId}/student-records/batch`, { records }); +} + +// ==================== 教师首页 API ==================== + +export interface DashboardData { + stats: { + classCount: number; + studentCount: number; + lessonCount: number; + courseCount: number; + }; + todayLessons: Array<{ + id: number; + courseId: number; + courseName: string; + pictureBookName?: string; + classId: number; + className: string; + plannedDatetime: string; + status: string; + duration: number; + }>; + recommendedCourses: Array<{ + id: number; + name: string; + pictureBookName?: string; + coverImagePath?: string; + duration: number; + usageCount: number; + avgRating: number; + gradeTags: string[]; + }>; + weeklyStats: { + lessonCount: number; + studentParticipation: number; + avgRating: number; + totalDuration: number; + }; + recentActivities: Array<{ + id: number; + type: string; + description: string; + time: string; + }>; +} + +export const getTeacherDashboard = () => + http.get('/teacher/dashboard'); + +export const getTodayLessons = () => + http.get('/teacher/dashboard/today'); + +export const getRecommendedCourses = () => + http.get('/teacher/dashboard/recommend'); + +export const getWeeklyStats = () => + http.get('/teacher/dashboard/weekly'); + +// ==================== 教师统计趋势 ==================== + +export interface TeacherLessonTrendItem { + month: string; + lessonCount: number; + avgRating: number; +} + +export interface TeacherCourseUsageItem { + name: string; + value: number; +} + +export const getTeacherLessonTrend = (months?: number) => + http.get('/teacher/dashboard/lesson-trend', { params: { months } }); + +export const getTeacherCourseUsage = () => + http.get('/teacher/dashboard/course-usage'); + +// ==================== 课程反馈 API ==================== + +export interface FeedbackDto { + designQuality?: number; + participation?: number; + goalAchievement?: number; + stepFeedbacks?: any; + pros?: string; + suggestions?: string; + activitiesDone?: any; +} + +export interface LessonFeedback { + id: number; + lessonId: number; + teacherId: number; + designQuality?: number; + participation?: number; + goalAchievement?: number; + stepFeedbacks?: any; + pros?: string; + suggestions?: string; + activitiesDone?: any; + createdAt: string; + updatedAt: string; + teacher?: { + id: number; + name: string; + }; + lesson?: { + id: number; + startDatetime?: string; + course: { + id: number; + name: string; + pictureBookName?: string; + }; + class: { + id: number; + name: string; + }; + }; +} + +// 提交课程反馈 +export function submitFeedback(lessonId: number, data: FeedbackDto): Promise { + return http.post(`/teacher/lessons/${lessonId}/feedback`, data); +} + +// 获取课程反馈 +export function getFeedback(lessonId: number): Promise { + return http.get(`/teacher/lessons/${lessonId}/feedback`); +} + +// ==================== 学校端反馈 API ==================== + +export interface FeedbackQueryParams { + page?: number; + pageSize?: number; + teacherId?: number; + courseId?: number; +} + +export interface FeedbackStats { + totalFeedbacks: number; + avgDesignQuality: number; + avgParticipation: number; + avgGoalAchievement: number; + courseStats: Record; +} + +// 获取学校端反馈列表 +export function getSchoolFeedbacks(params: FeedbackQueryParams): Promise<{ + items: LessonFeedback[]; + total: number; + page: number; + pageSize: number; +}> { + return http.get('/school/feedbacks', { params }); +} + +// 获取反馈统计 +export function getFeedbackStats(): Promise { + return http.get('/school/feedbacks/stats'); +} + +// 获取教师自己的反馈列表 +export function getTeacherFeedbacks(params: FeedbackQueryParams): Promise<{ + items: LessonFeedback[]; + total: number; + page: number; + pageSize: number; +}> { + return http.get('/teacher/feedbacks', { params }); +} + +// 获取教师自己的反馈统计 +export function getTeacherFeedbackStats(): Promise { + return http.get('/teacher/feedbacks/stats'); +} + +// ==================== 排课管理 API ==================== + +export interface TeacherSchedule { + id: number; + classId: number; + className: string; + courseId: number; + courseName: string; + teacherId?: number; + scheduledDate?: string; + scheduledTime?: string; + weekDay?: number; + repeatType: 'NONE' | 'DAILY' | 'WEEKLY'; + source: 'SCHOOL' | 'TEACHER'; + status: 'ACTIVE' | 'CANCELLED'; + note?: string; + hasLesson: boolean; + lessonId?: number; + lessonStatus?: string; + createdAt: string; +} + +export interface CreateTeacherScheduleDto { + classId: number; + courseId: number; + scheduledDate?: string; + scheduledTime?: string; + weekDay?: number; + repeatType?: 'NONE' | 'DAILY' | 'WEEKLY'; + repeatEndDate?: string; + note?: string; +} + +export interface SchedulePlanUpdateRequest { + teacherId?: number; + startDate?: string; + endDate?: string; + startTime?: string; + endTime?: string; + status?: string; + note?: string; +} + +export interface TeacherTimetableItem { + date: string; + weekDay: number; + schedules: TeacherSchedule[]; +} + +export const getTeacherSchedules = (params?: { + startDate?: string; + endDate?: string; + status?: string; + page?: number; + pageSize?: number; +}) => http.get<{ items: TeacherSchedule[]; total: number; page: number; pageSize: number }>('/teacher/schedules', { params }); + +export const getTeacherTimetable = (params: { startDate: string; endDate: string }) => + http.get('/teacher/schedules/timetable', { params }); + +export const getTodayTeacherSchedules = () => + http.get('/teacher/schedules/today'); + +export const createTeacherSchedule = (data: CreateTeacherScheduleDto) => + http.post('/teacher/schedules', data); + +export const updateTeacherSchedule = (id: number, data: SchedulePlanUpdateRequest) => + http.put(`/teacher/schedules/${id}`, data); + +export const cancelTeacherSchedule = (id: number) => + http.delete<{ message: string }>(`/teacher/schedules/${id}`); + +// ==================== 阅读任务 API ==================== + +export interface TeacherTask { + id: number; + tenantId: number; + title: string; + description?: string; + taskType: 'READING' | 'ACTIVITY' | 'HOMEWORK'; + targetType: 'CLASS' | 'STUDENT'; + status: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED'; + relatedCourseId?: number; + startDate: string; + endDate: string; + createdBy: number; + createdAt: string; + updatedAt: string; + course?: { + id: number; + name: string; + }; + targetCount?: number; + completionCount?: number; +} + +export interface TaskCompletion { + id: number; + taskId: number; + studentId: number; + status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED'; + completedAt?: string; + feedback?: string; + parentFeedback?: string; + createdAt: string; + student: { + id: number; + name: string; + gender?: string; + class?: { + id: number; + name: string; + }; + }; +} + +export interface CreateTeacherTaskDto { + title: string; + description?: string; + taskType: 'READING' | 'ACTIVITY' | 'HOMEWORK'; + targetType: 'CLASS' | 'STUDENT'; + targetIds: number[]; + relatedCourseId?: number; + startDate: string; + endDate: string; +} + +export interface UpdateTaskCompletionDto { + status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED'; + feedback?: string; +} + +export const getTeacherTasks = (params?: { + page?: number; + pageSize?: number; + status?: string; + taskType?: string; + keyword?: string; +}) => http.get<{ items: TeacherTask[]; total: number; page: number; pageSize: number }>('/teacher/tasks', { params }); + +export const getTeacherTask = (id: number) => + http.get(`/teacher/tasks/${id}`); + +export const getTeacherTaskCompletions = (taskId: number, params?: { + page?: number; + pageSize?: number; + status?: string; +}) => http.get<{ items: TaskCompletion[]; total: number; page: number; pageSize: number }>(`/teacher/tasks/${taskId}/completions`, { params }); + +export const createTeacherTask = (data: CreateTeacherTaskDto) => + http.post('/teacher/tasks', data); + +export const updateTeacherTask = (id: number, data: Partial & { status?: string }) => + http.put(`/teacher/tasks/${id}`, data); + +export const deleteTeacherTask = (id: number) => + http.delete<{ message: string }>(`/teacher/tasks/${id}`); + +export const updateTaskCompletion = (taskId: number, studentId: number, data: UpdateTaskCompletionDto) => + http.put(`/teacher/tasks/${taskId}/completions/${studentId}`, data); + +export const sendTaskReminder = (taskId: number) => + http.post<{ message: string }>(`/teacher/tasks/${taskId}/remind`); + +// ==================== 任务模板 API ==================== + +export interface TaskTemplate { + id: number; + tenantId: number; + name: string; + description?: string; + taskType: 'READING' | 'ACTIVITY' | 'HOMEWORK'; + relatedCourseId?: number; + defaultDuration: number; + isDefault: boolean; + status: string; + createdBy: number; + createdAt: string; + updatedAt: string; + course?: { + id: number; + name: string; + pictureBookName?: string; + }; +} + +export interface CreateTaskTemplateDto { + name: string; + description?: string; + taskType: 'READING' | 'ACTIVITY' | 'HOMEWORK'; + relatedCourseId?: number; + defaultDuration?: number; + isDefault?: boolean; +} + +export interface CreateTaskFromTemplateDto { + templateId: number; + targetIds: number[]; + targetType: 'CLASS' | 'STUDENT'; + startDate?: string; +} + +export const getTaskTemplates = (params?: { + page?: number; + pageSize?: number; + taskType?: string; + keyword?: string; +}) => http.get<{ items: TaskTemplate[]; total: number; page: number; pageSize: number }>('/teacher/task-templates', { params }); + +export const getTaskTemplate = (id: number) => + http.get(`/teacher/task-templates/${id}`); + +export const getDefaultTaskTemplate = (taskType: string) => + http.get(`/teacher/task-templates/default/${taskType}`); + +export const createTaskFromTemplate = (data: CreateTaskFromTemplateDto) => + http.post('/teacher/tasks/from-template', data); + +// ==================== 任务统计 API ==================== + +export interface TaskStats { + totalTasks: number; + publishedTasks: number; + completedTasks: number; + inProgressTasks: number; + pendingCount: number; + totalCompletions: number; + completionRate: number; +} + +export interface TaskStatsByType { + [key: string]: { + total: number; + completed: number; + rate: number; + }; +} + +export interface TaskStatsByClass { + classId: number; + className: string; + grade: string; + total: number; + completed: number; + rate: number; +} + +export interface MonthlyTaskStats { + month: string; + tasks: number; + completions: number; + completed: number; + rate: number; +} + +export const getTaskStats = () => + http.get('/teacher/tasks/stats'); + +export const getTaskStatsByType = () => + http.get('/teacher/tasks/stats/by-type'); + +export const getTaskStatsByClass = () => + http.get('/teacher/tasks/stats/by-class'); + +export const getMonthlyTaskStats = (months?: number) => + http.get('/teacher/tasks/stats/monthly', { params: { months } }); diff --git a/reading-platform-frontend/src/components.d.ts b/reading-platform-frontend/src/components.d.ts index 52cfbdf..9b0b9d8 100644 --- a/reading-platform-frontend/src/components.d.ts +++ b/reading-platform-frontend/src/components.d.ts @@ -15,11 +15,17 @@ declare module 'vue' { ACheckbox: typeof import('ant-design-vue/es')['Checkbox'] ACol: typeof import('ant-design-vue/es')['Col'] ADatePicker: typeof import('ant-design-vue/es')['DatePicker'] + ADescriptions: typeof import('ant-design-vue/es')['Descriptions'] + ADescriptionsItem: typeof import('ant-design-vue/es')['DescriptionsItem'] + ADivider: typeof import('ant-design-vue/es')['Divider'] ADropdown: typeof import('ant-design-vue/es')['Dropdown'] AEmpty: typeof import('ant-design-vue/es')['Empty'] AForm: typeof import('ant-design-vue/es')['Form'] AFormItem: typeof import('ant-design-vue/es')['FormItem'] + AImage: typeof import('ant-design-vue/es')['Image'] + AImagePreviewGroup: typeof import('ant-design-vue/es')['ImagePreviewGroup'] AInput: typeof import('ant-design-vue/es')['Input'] + AInputNumber: typeof import('ant-design-vue/es')['InputNumber'] AInputPassword: typeof import('ant-design-vue/es')['InputPassword'] AInputSearch: typeof import('ant-design-vue/es')['InputSearch'] ALayout: typeof import('ant-design-vue/es')['Layout'] @@ -35,20 +41,28 @@ declare module 'vue' { AModal: typeof import('ant-design-vue/es')['Modal'] APagination: typeof import('ant-design-vue/es')['Pagination'] APopconfirm: typeof import('ant-design-vue/es')['Popconfirm'] + AProgress: typeof import('ant-design-vue/es')['Progress'] ARadio: typeof import('ant-design-vue/es')['Radio'] ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup'] ARangePicker: typeof import('ant-design-vue/es')['RangePicker'] + ARate: typeof import('ant-design-vue/es')['Rate'] ARow: typeof import('ant-design-vue/es')['Row'] ASelect: typeof import('ant-design-vue/es')['Select'] ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] ASpace: typeof import('ant-design-vue/es')['Space'] ASpin: typeof import('ant-design-vue/es')['Spin'] + AStatistic: typeof import('ant-design-vue/es')['Statistic'] ASubMenu: typeof import('ant-design-vue/es')['SubMenu'] + ASwitch: typeof import('ant-design-vue/es')['Switch'] ATable: typeof import('ant-design-vue/es')['Table'] + ATabPane: typeof import('ant-design-vue/es')['TabPane'] + ATabs: typeof import('ant-design-vue/es')['Tabs'] ATag: typeof import('ant-design-vue/es')['Tag'] ATextarea: typeof import('ant-design-vue/es')['Textarea'] + ATimeRangePicker: typeof import('ant-design-vue/es')['TimeRangePicker'] ATooltip: typeof import('ant-design-vue/es')['Tooltip'] ATypographyText: typeof import('ant-design-vue/es')['TypographyText'] + AUpload: typeof import('ant-design-vue/es')['Upload'] AUploadDragger: typeof import('ant-design-vue/es')['UploadDragger'] FilePreviewModal: typeof import('./components/FilePreviewModal.vue')['default'] FileUploader: typeof import('./components/course/FileUploader.vue')['default'] diff --git a/reading-platform-java/Fapache-maven-3.8.4confjvm.config b/reading-platform-java/Fapache-maven-3.8.4confjvm.config new file mode 100644 index 0000000..69d3c7f --- /dev/null +++ b/reading-platform-java/Fapache-maven-3.8.4confjvm.config @@ -0,0 +1 @@ +JAVA_HOME=C:\Program Files\Java\jdk-17 diff --git a/reading-platform-java/pom.xml b/reading-platform-java/pom.xml index 7a1cf18..ed6f88e 100644 --- a/reading-platform-java/pom.xml +++ b/reading-platform-java/pom.xml @@ -20,6 +20,9 @@ 17 + 17 + 17 + 17 3.5.5 0.12.5 4.4.0 @@ -139,6 +142,16 @@ + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + 17 + 17 + UTF-8 + + org.springframework.boot spring-boot-maven-plugin @@ -149,6 +162,7 @@ lombok + -Dfile.encoding=UTF-8 diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/annotation/RateLimit.java b/reading-platform-java/src/main/java/com/reading/platform/common/annotation/RateLimit.java new file mode 100644 index 0000000..6b4737c --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/common/annotation/RateLimit.java @@ -0,0 +1,50 @@ +package com.reading.platform.common.annotation; + +import java.lang.annotation.*; +import java.util.concurrent.TimeUnit; + +/** + * 限流注解 + * 用于对特定接口或方法进行限流控制 + * 优先级高于配置文件的限流规则 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RateLimit { + + /** + * 限流键的前缀 + * 默认使用方法名作为前缀 + */ + String keyPrefix() default ""; + + /** + * 时间窗口大小 + * 默认 60 秒 + */ + long time() default 60; + + /** + * 时间单位 + * 默认秒 + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; + + /** + * 时间窗口内最大请求数 + * 默认 100 次 + */ + long maxRequests() default 100; + + /** + * 限流提示信息 + */ + String message() default "请求过于频繁,请稍后再试"; + + /** + * 是否启用限流 + * 默认启用 + */ + boolean enabled() default true; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/aspect/RateLimitAspect.java b/reading-platform-java/src/main/java/com/reading/platform/common/aspect/RateLimitAspect.java new file mode 100644 index 0000000..117a8fb --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/common/aspect/RateLimitAspect.java @@ -0,0 +1,115 @@ +package com.reading.platform.common.aspect; + +import com.reading.platform.common.annotation.RateLimit; +import com.reading.platform.common.config.RateLimitProperties; +import com.reading.platform.common.enums.ErrorCode; +import com.reading.platform.common.exception.BusinessException; +import com.reading.platform.common.util.RateLimiter; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +/** + * 限流切面 + * 支持配置化限流和注解限流两种方式 + * 注解限流优先级高于配置化限流 + */ +@Slf4j +@Aspect +@Component +public class RateLimitAspect { + + private final RateLimiter rateLimiter; + private final RateLimitProperties rateLimitProperties; + + public RateLimitAspect(RateLimiter rateLimiter, RateLimitProperties rateLimitProperties) { + this.rateLimiter = rateLimiter; + this.rateLimitProperties = rateLimitProperties; + } + + @Around("@annotation(rateLimit)") + public Object aroundAnnotation(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable { + // 如果限流未启用,直接放行 + if (!rateLimitProperties.isEnabled() || !rateLimit.enabled()) { + return joinPoint.proceed(); + } + + // 获取限流键 + String key = buildRateLimitKey(joinPoint, rateLimit); + + // 检查是否允许请求 + boolean allowed = rateLimiter.tryAcquire( + key, + rateLimit.maxRequests(), + rateLimit.time(), + rateLimit.timeUnit() + ); + + if (!allowed) { + long remaining = rateLimiter.getRemainingRequests( + key, + rateLimit.maxRequests(), + rateLimit.time(), + rateLimit.timeUnit() + ); + log.warn("请求被限流拦截:key={}, 剩余次数={}, 最大请求数={}", key, remaining, rateLimit.maxRequests()); + throw new BusinessException(ErrorCode.RATE_LIMIT_EXCEEDED, rateLimit.message()); + } + + log.debug("请求通过限流检查:key={}", key); + return joinPoint.proceed(); + } + + /** + * 构建限流键 + * 优先级:自定义 keyPrefix > 类名。方法名 > IP 地址。类名。方法名 + */ + private String buildRateLimitKey(ProceedingJoinPoint joinPoint, RateLimit rateLimit) { + StringBuilder key = new StringBuilder(); + + // 添加自定义前缀 + if (StringUtils.hasText(rateLimit.keyPrefix())) { + key.append(rateLimit.keyPrefix()); + } else { + // 默认使用 IP 地址 + 类名。方法名 + String clientIp = getClientIp(); + if (StringUtils.hasText(clientIp)) { + key.append(clientIp).append(":"); + } + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + key.append(signature.getDeclaringTypeName()) + .append(".") + .append(signature.getName()); + } + + return key.toString(); + } + + /** + * 获取客户端 IP 地址 + */ + private String getClientIp() { + try { + ServletRequestAttributes attributes = + (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (attributes != null) { + HttpServletRequest request = attributes.getRequest(); + String xForwardedFor = request.getHeader("X-Forwarded-For"); + if (StringUtils.hasText(xForwardedFor)) { + return xForwardedFor.split(",")[0].trim(); + } + return request.getRemoteAddr(); + } + } catch (Exception e) { + log.debug("获取客户端 IP 失败", e); + } + return "unknown"; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/config/MybatisPlusConfig.java b/reading-platform-java/src/main/java/com/reading/platform/common/config/MybatisPlusConfig.java index 4490f5c..88bdb32 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/common/config/MybatisPlusConfig.java +++ b/reading-platform-java/src/main/java/com/reading/platform/common/config/MybatisPlusConfig.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.reading.platform.common.security.SecurityUtils; import org.apache.ibatis.reflection.MetaObject; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -28,13 +29,30 @@ public class MybatisPlusConfig { return new MetaObjectHandler() { @Override public void insertFill(MetaObject metaObject) { + // 时间字段自动填充 this.strictInsertFill(metaObject, "createdAt", LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, "updatedAt", LocalDateTime.class, LocalDateTime.now()); + // 审计用户字段自动填充(从 Security 上下文获取当前用户名) + try { + String username = SecurityUtils.getCurrentUsername(); + this.strictInsertFill(metaObject, "createdBy", String.class, username); + this.strictInsertFill(metaObject, "updatedBy", String.class, username); + } catch (Exception e) { + // 如果无法获取当前用户(如异步线程、测试等),则不填充 + } } @Override public void updateFill(MetaObject metaObject) { + // 时间字段自动填充 this.strictUpdateFill(metaObject, "updatedAt", LocalDateTime.class, LocalDateTime.now()); + // 审计用户字段自动填充(从 Security 上下文获取当前用户名) + try { + String username = SecurityUtils.getCurrentUsername(); + this.strictUpdateFill(metaObject, "updatedBy", String.class, username); + } catch (Exception e) { + // 如果无法获取当前用户(如异步线程、测试等),则不填充 + } } }; } diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/config/RateLimitInterceptor.java b/reading-platform-java/src/main/java/com/reading/platform/common/config/RateLimitInterceptor.java new file mode 100644 index 0000000..4e303c8 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/common/config/RateLimitInterceptor.java @@ -0,0 +1,174 @@ +package com.reading.platform.common.config; + +import com.reading.platform.common.util.RateLimiter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.servlet.HandlerInterceptor; + +import java.io.IOException; +import java.util.List; + +/** + * 限流拦截器 + * 基于配置文件中的限流规则进行拦截 + * 优先级低于注解限流 + */ +@Slf4j +@Component +public class RateLimitInterceptor implements HandlerInterceptor { + + private final RateLimiter rateLimiter; + private final RateLimitProperties rateLimitProperties; + private final AntPathMatcher antPathMatcher = new AntPathMatcher(); + + public RateLimitInterceptor(RateLimiter rateLimiter, RateLimitProperties rateLimitProperties) { + this.rateLimiter = rateLimiter; + this.rateLimitProperties = rateLimitProperties; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + // 如果限流未启用,直接放行 + if (!rateLimitProperties.isEnabled()) { + return true; + } + + String requestURI = request.getRequestURI(); + + // 检查是否在排除列表中 + List excludePatterns = rateLimitProperties.getExcludePatterns(); + if (excludePatterns != null) { + for (String pattern : excludePatterns) { + if (antPathMatcher.match(pattern, requestURI)) { + log.debug("请求在排除列表中,跳过限流:{}", requestURI); + return true; + } + } + } + + // 查找匹配的限流规则 + RateLimitProperties.RateLimitRule matchedRule = findMatchedRule(requestURI); + if (matchedRule == null) { + // 没有匹配的规则,使用默认限流配置 + applyDefaultRateLimit(request, response, requestURI); + return true; + } + + // 应用匹配的限流规则 + return applyRateLimitRule(request, response, requestURI, matchedRule); + } + + /** + * 查找匹配的限流规则 + */ + private RateLimitProperties.RateLimitRule findMatchedRule(String requestURI) { + List rules = rateLimitProperties.getRules(); + if (rules == null || rules.isEmpty()) { + return null; + } + + for (RateLimitProperties.RateLimitRule rule : rules) { + if (antPathMatcher.match(rule.getPattern(), requestURI)) { + log.debug("请求匹配限流规则:pattern={}, timeWindow={}, maxRequests={}", + rule.getPattern(), rule.getTimeWindow(), rule.getMaxRequests()); + return rule; + } + } + + return null; + } + + /** + * 应用匹配的限流规则 + */ + private boolean applyRateLimitRule(HttpServletRequest request, HttpServletResponse response, String requestURI, + RateLimitProperties.RateLimitRule rule) { + String key = buildRateLimitKey(request, rule.getPattern()); + + boolean allowed = rateLimiter.tryAcquire( + key, + rule.getMaxRequests(), + rule.getTimeWindow(), + java.util.concurrent.TimeUnit.SECONDS + ); + + if (!allowed) { + log.warn("请求被限流拦截:URI={}, 规则={}, 最大请求数={}", requestURI, rule.getPattern(), rule.getMaxRequests()); + sendRateLimitResponse(response); + return false; + } + + log.debug("请求通过限流检查:URI={}, 规则={}", requestURI, rule.getPattern()); + return true; + } + + /** + * 应用默认限流配置 + */ + private void applyDefaultRateLimit(HttpServletRequest request, HttpServletResponse response, String requestURI) { + String key = buildRateLimitKey(request, "default"); + + boolean allowed = rateLimiter.tryAcquire( + key, + rateLimitProperties.getDefaultMaxRequests(), + rateLimitProperties.getDefaultTimeWindow(), + java.util.concurrent.TimeUnit.SECONDS + ); + + if (!allowed) { + log.warn("请求被默认限流拦截:URI={}, 最大请求数={}", requestURI, rateLimitProperties.getDefaultMaxRequests()); + sendRateLimitResponse(response); + } + } + + /** + * 构建限流键 + * 格式:IP:Pattern + */ + private String buildRateLimitKey(HttpServletRequest request, String pattern) { + String clientIp = getClientIp(request); + return clientIp + ":" + pattern; + } + + /** + * 获取客户端 IP 地址 + */ + private String getClientIp(HttpServletRequest request) { + String xForwardedFor = request.getHeader("X-Forwarded-For"); + if (xForwardedFor != null && !xForwardedFor.isEmpty()) { + return xForwardedFor.split(",")[0].trim(); + } + + String xRealIp = request.getHeader("X-Real-IP"); + if (xRealIp != null && !xRealIp.isEmpty()) { + return xRealIp; + } + + return request.getRemoteAddr(); + } + + /** + * 发送限流响应 + */ + private void sendRateLimitResponse(HttpServletResponse response) { + response.setStatus(429); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding("UTF-8"); + + // 添加限流响应头 + response.setHeader("X-RateLimit-Limit", "1"); + response.setHeader("X-RateLimit-Remaining", "0"); + response.setHeader("Retry-After", "60"); + + try { + String jsonResponse = "{\"code\":5001,\"message\":\"请求过于频繁,请稍后再试\",\"data\":null}"; + response.getWriter().write(jsonResponse); + } catch (IOException e) { + log.error("发送限流响应失败", e); + } + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/config/RateLimitProperties.java b/reading-platform-java/src/main/java/com/reading/platform/common/config/RateLimitProperties.java new file mode 100644 index 0000000..58617f1 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/common/config/RateLimitProperties.java @@ -0,0 +1,64 @@ +package com.reading.platform.common.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 限流配置属性 + * 支持通过配置文件配置全局限流规则 + */ +@Data +@Component +@ConfigurationProperties(prefix = "rate-limit") +public class RateLimitProperties { + + /** + * 是否启用限流 + * 默认启用 + */ + private boolean enabled = true; + + /** + * 默认时间窗口大小(秒) + */ + private long defaultTimeWindow = 60; + + /** + * 默认时间窗口内最大请求数 + */ + private long defaultMaxRequests = 1000; + + /** + * 限流规则列表 + */ + private List rules; + + /** + * 排除限流的接口路径 + */ + private List excludePatterns; + + /** + * 限流规则 + */ + @Data + public static class RateLimitRule { + /** + * 接口路径_pattern(支持 Ant 风格通配符) + */ + private String pattern; + + /** + * 时间窗口大小 + */ + private long timeWindow = 60; + + /** + * 时间窗口内最大请求数 + */ + private long maxRequests = 100; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/config/RedisConfig.java b/reading-platform-java/src/main/java/com/reading/platform/common/config/RedisConfig.java new file mode 100644 index 0000000..9a1e1d1 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/common/config/RedisConfig.java @@ -0,0 +1,32 @@ +package com.reading.platform.common.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * Redis 配置类 + */ +@Configuration +public class RedisConfig { + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(connectionFactory); + + // Key 序列化 + template.setKeySerializer(new StringRedisSerializer()); + template.setHashKeySerializer(new StringRedisSerializer()); + + // Value 序列化 + template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); + template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); + + template.afterPropertiesSet(); + return template; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/config/WebMvcConfig.java b/reading-platform-java/src/main/java/com/reading/platform/common/config/WebMvcConfig.java index 8659597..07077ca 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/common/config/WebMvcConfig.java +++ b/reading-platform-java/src/main/java/com/reading/platform/common/config/WebMvcConfig.java @@ -2,12 +2,19 @@ package com.reading.platform.common.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer { + private final RateLimitInterceptor rateLimitInterceptor; + + public WebMvcConfig(RateLimitInterceptor rateLimitInterceptor) { + this.rateLimitInterceptor = rateLimitInterceptor; + } + @Value("${file.upload.path:/app/uploads/}") private String uploadPath; @@ -16,4 +23,17 @@ public class WebMvcConfig implements WebMvcConfigurer { registry.addResourceHandler("/uploads/**") .addResourceLocations("file:" + uploadPath); } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(rateLimitInterceptor) + .addPathPatterns("/api/**") + .excludePathPatterns( + "/doc.html", + "/swagger-resources/**", + "/v3/api-docs/**", + "/webjars/**", + "/uploads/**" + ); + } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/enums/ErrorCode.java b/reading-platform-java/src/main/java/com/reading/platform/common/enums/ErrorCode.java index 25cdde8..646275b 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/common/enums/ErrorCode.java +++ b/reading-platform-java/src/main/java/com/reading/platform/common/enums/ErrorCode.java @@ -38,7 +38,10 @@ public enum ErrorCode { USER_NOT_FOUND(4001, "User not found"), USER_ALREADY_EXISTS(4002, "User already exists"), PASSWORD_MISMATCH(4003, "Password mismatch"), - OLD_PASSWORD_ERROR(4004, "Old password is incorrect"); + OLD_PASSWORD_ERROR(4004, "Old password is incorrect"), + + // Rate Limit Errors (5000+) + RATE_LIMIT_EXCEEDED(5001, "请求过于频繁,请稍后再试"); private final Integer code; private final String message; diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/security/JwtPayload.java b/reading-platform-java/src/main/java/com/reading/platform/common/security/JwtPayload.java index 6c59233..4fd4248 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/common/security/JwtPayload.java +++ b/reading-platform-java/src/main/java/com/reading/platform/common/security/JwtPayload.java @@ -18,10 +18,10 @@ public class JwtPayload implements Serializable { private static final long serialVersionUID = 1L; - private Long userId; + private String userId; private String username; private String role; - private Long tenantId; + private String tenantId; private String name; } diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/security/JwtTokenProvider.java b/reading-platform-java/src/main/java/com/reading/platform/common/security/JwtTokenProvider.java index e7d6bda..0125b9c 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/common/security/JwtTokenProvider.java +++ b/reading-platform-java/src/main/java/com/reading/platform/common/security/JwtTokenProvider.java @@ -56,10 +56,10 @@ public class JwtTokenProvider { .getPayload(); return JwtPayload.builder() - .userId(claims.get("userId", Long.class)) + .userId(claims.get("userId", String.class)) .username(claims.get("username", String.class)) .role(claims.get("role", String.class)) - .tenantId(claims.get("tenantId", Long.class)) + .tenantId(claims.get("tenantId", String.class)) .name(claims.get("name", String.class)) .build(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/security/SecurityUtils.java b/reading-platform-java/src/main/java/com/reading/platform/common/security/SecurityUtils.java index 3377ca9..cc622e4 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/common/security/SecurityUtils.java +++ b/reading-platform-java/src/main/java/com/reading/platform/common/security/SecurityUtils.java @@ -21,7 +21,7 @@ public class SecurityUtils { return (JwtPayload) authentication.getPrincipal(); } - public static Long getCurrentUserId() { + public static String getCurrentUserId() { return getCurrentUser().getUserId(); } @@ -33,7 +33,7 @@ public class SecurityUtils { return getCurrentUser().getRole(); } - public static Long getCurrentTenantId() { + public static String getCurrentTenantId() { return getCurrentUser().getTenantId(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/util/RateLimiter.java b/reading-platform-java/src/main/java/com/reading/platform/common/util/RateLimiter.java new file mode 100644 index 0000000..179e1e1 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/common/util/RateLimiter.java @@ -0,0 +1,135 @@ +package com.reading.platform.common.util; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +/** + * Redis 限流工具类 + * 基于滑动窗口算法实现限流 + */ +@Slf4j +@Component +public class RateLimiter { + + private final RedisTemplate redisTemplate; + + public RateLimiter(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + /** + * 尝试获取请求许可 + * + * @param key 限流键 + * @param maxRequests 时间窗口内最大请求数 + * @param timeWindow 时间窗口大小 + * @param timeUnit 时间单位 + * @return true-允许请求,false-拒绝请求 + */ + public boolean tryAcquire(String key, long maxRequests, long timeWindow, TimeUnit timeUnit) { + long currentTime = System.currentTimeMillis(); + long windowStart = currentTime - timeUnit.toMillis(timeWindow); + + String redisKey = "rate_limit:" + key; + + try { + // 使用 Redis 事务保证原子性 + Boolean result = redisTemplate.execute(connection -> { + try { + // 移除窗口外的请求记录 + connection.zSetCommands().zRemRangeByScore( + redisKey.getBytes(), + 0, + windowStart + ); + + // 获取当前窗口内的请求数 + Long count = connection.zSetCommands().zCard(redisKey.getBytes()); + + if (count != null && count >= maxRequests) { + // 超过限流阈值 + return false; + } + + // 添加当前请求记录 + connection.zSetCommands().zAdd( + redisKey.getBytes(), + currentTime, + String.valueOf(currentTime).getBytes() + ); + + // 设置过期时间 + connection.expire(redisKey.getBytes(), timeWindow); + + return true; + } catch (Exception e) { + log.error("限流检查失败,key: {}", key, e); + // 异常情况放行 + return true; + } + }, false); + + return Boolean.TRUE.equals(result); + } catch (Exception e) { + log.error("限流检查异常,key: {}", key, e); + // 异常情况放行 + return true; + } + } + + /** + * 获取剩余请求次数 + * + * @param key 限流键 + * @param maxRequests 时间窗口内最大请求数 + * @param timeWindow 时间窗口大小 + * @param timeUnit 时间单位 + * @return 剩余请求次数 + */ + public long getRemainingRequests(String key, long maxRequests, long timeWindow, TimeUnit timeUnit) { + long currentTime = System.currentTimeMillis(); + long windowStart = currentTime - timeUnit.toMillis(timeWindow); + + String redisKey = "rate_limit:" + key; + + try { + Long count = redisTemplate.execute(connection -> { + // 先清理过期数据 + connection.zSetCommands().zRemRangeByScore( + redisKey.getBytes(), + 0, + windowStart + ); + // 获取当前窗口内的请求数 + return connection.zSetCommands().zCard(redisKey.getBytes()); + }, false); + + if (count == null) { + return maxRequests; + } + + return Math.max(0, maxRequests - count); + } catch (Exception e) { + log.error("获取剩余请求次数失败,key: {}", key, e); + return maxRequests; + } + } + + /** + * 重置限流计数器 + * + * @param key 限流键 + */ + public void reset(String key) { + String redisKey = "rate_limit:" + key; + try { + redisTemplate.delete(redisKey); + log.debug("限流计数器已重置,key: {}", key); + } catch (Exception e) { + log.error("重置限流计数器失败,key: {}", key, e); + } + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/FileUploadController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/FileUploadController.java index 9e0256c..2e17035 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/FileUploadController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/FileUploadController.java @@ -1,6 +1,7 @@ package com.reading.platform.controller; import com.reading.platform.common.response.Result; +import com.reading.platform.dto.response.FileUploadResponse; import com.reading.platform.service.FileUploadService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -8,9 +9,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import java.util.HashMap; -import java.util.Map; - @Tag(name = "文件上传", description = "文件上传接口") @RestController @RequestMapping("/api/v1/files") @@ -21,12 +19,9 @@ public class FileUploadController { @Operation(summary = "上传文件") @PostMapping("/upload") - public Result> uploadFile(@RequestParam("file") MultipartFile file) { + public Result uploadFile(@RequestParam("file") MultipartFile file) { String url = fileUploadService.uploadFile(file); - Map result = new HashMap<>(); - result.put("url", url); - result.put("filename", file.getOriginalFilename()); - return Result.success(result); + return Result.success(FileUploadResponse.of(url, file.getOriginalFilename(), file.getSize())); } @Operation(summary = "删除文件") diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseController.java index 9daba15..9dfbc77 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseController.java @@ -33,13 +33,13 @@ public class AdminCourseController { @Operation(summary = "更新课程") @PutMapping("/{id}") - public Result updateCourse(@PathVariable Long id, @RequestBody CourseUpdateRequest request) { + public Result updateCourse(@PathVariable String id, @RequestBody CourseUpdateRequest request) { return Result.success(courseService.updateCourse(id, request)); } @Operation(summary = "根据ID获取课程") @GetMapping("/{id}") - public Result getCourse(@PathVariable Long id) { + public Result getCourse(@PathVariable String id) { return Result.success(courseService.getCourseById(id)); } @@ -66,21 +66,21 @@ public class AdminCourseController { @Operation(summary = "删除课程") @DeleteMapping("/{id}") - public Result deleteCourse(@PathVariable Long id) { + public Result deleteCourse(@PathVariable String id) { courseService.deleteCourse(id); return Result.success(); } @Operation(summary = "提交课程审核") @PostMapping("/{id}/submit") - public Result submitCourse(@PathVariable Long id) { + public Result submitCourse(@PathVariable String id) { courseService.submitCourse(id); return Result.success(); } @Operation(summary = "撤销课程审核") @PostMapping("/{id}/withdraw") - public Result withdrawCourse(@PathVariable Long id) { + public Result withdrawCourse(@PathVariable String id) { courseService.withdrawCourse(id); return Result.success(); } @@ -88,7 +88,7 @@ public class AdminCourseController { @Operation(summary = "审批课程") @PostMapping("/{id}/approve") public Result approveCourse( - @PathVariable Long id, + @PathVariable String id, @RequestParam(required = false) String comment) { courseService.approveCourse(id, comment); return Result.success(); @@ -97,7 +97,7 @@ public class AdminCourseController { @Operation(summary = "驳回课程") @PostMapping("/{id}/reject") public Result rejectCourse( - @PathVariable Long id, + @PathVariable String id, @RequestParam(required = false) String comment) { courseService.rejectCourse(id, comment); return Result.success(); @@ -105,35 +105,35 @@ public class AdminCourseController { @Operation(summary = "发布课程") @PostMapping("/{id}/publish") - public Result publishCourse(@PathVariable Long id) { + public Result publishCourse(@PathVariable String id) { courseService.publishCourse(id); return Result.success(); } @Operation(summary = "直接发布课程(跳过审核)") @PostMapping("/{id}/direct-publish") - public Result directPublishCourse(@PathVariable Long id) { + public Result directPublishCourse(@PathVariable String id) { courseService.publishCourse(id); return Result.success(); } @Operation(summary = "取消发布(归档)课程") @PostMapping("/{id}/unpublish") - public Result unpublishCourse(@PathVariable Long id) { + public Result unpublishCourse(@PathVariable String id) { courseService.archiveCourse(id); return Result.success(); } @Operation(summary = "重新发布课程") @PostMapping("/{id}/republish") - public Result republishCourse(@PathVariable Long id) { + public Result republishCourse(@PathVariable String id) { courseService.publishCourse(id); return Result.success(); } @Operation(summary = "归档课程") @PostMapping("/{id}/archive") - public Result archiveCourse(@PathVariable Long id) { + public Result archiveCourse(@PathVariable String id) { courseService.archiveCourse(id); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseLessonController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseLessonController.java index ed085d2..f994ce8 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseLessonController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseLessonController.java @@ -23,32 +23,32 @@ public class AdminCourseLessonController { @Operation(summary = "获取课程的课时列表") @GetMapping - public Result> getLessons(@PathVariable Long courseId) { + public Result> getLessons(@PathVariable String courseId) { return Result.success(courseLessonService.getLessonsByCourse(courseId)); } @Operation(summary = "根据ID获取课时") @GetMapping("/{id}") - public Result getLesson(@PathVariable Long courseId, @PathVariable Long id) { + public Result getLesson(@PathVariable String courseId, @PathVariable String id) { return Result.success(courseLessonService.getLessonById(id)); } @Operation(summary = "创建课程课时") @PostMapping - public Result createLesson(@PathVariable Long courseId, @RequestBody CourseLesson lesson) { + public Result createLesson(@PathVariable String courseId, @RequestBody CourseLesson lesson) { lesson.setCourseId(courseId); return Result.success(courseLessonService.createLesson(lesson)); } @Operation(summary = "更新课程课时") @PutMapping("/{id}") - public Result updateLesson(@PathVariable Long courseId, @PathVariable Long id, @RequestBody CourseLesson lesson) { + public Result updateLesson(@PathVariable String courseId, @PathVariable String id, @RequestBody CourseLesson lesson) { return Result.success(courseLessonService.updateLesson(id, lesson)); } @Operation(summary = "删除课程课时") @DeleteMapping("/{id}") - public Result deleteLesson(@PathVariable Long courseId, @PathVariable Long id) { + public Result deleteLesson(@PathVariable String courseId, @PathVariable String id) { courseLessonService.deleteLesson(id); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCoursePackageController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCoursePackageController.java index aef3347..263ffc2 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCoursePackageController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCoursePackageController.java @@ -34,7 +34,7 @@ public class AdminCoursePackageController { @Operation(summary = "根据ID获取课程包") @GetMapping("/{id}") - public Result getPackage(@PathVariable Long id) { + public Result getPackage(@PathVariable String id) { return Result.success(coursePackageService.getPackageById(id)); } @@ -46,20 +46,20 @@ public class AdminCoursePackageController { @Operation(summary = "更新课程包") @PutMapping("/{id}") - public Result updatePackage(@PathVariable Long id, @RequestBody CoursePackage pkg) { + public Result updatePackage(@PathVariable String id, @RequestBody CoursePackage pkg) { return Result.success(coursePackageService.updatePackage(id, pkg)); } @Operation(summary = "删除课程包") @DeleteMapping("/{id}") - public Result deletePackage(@PathVariable Long id) { + public Result deletePackage(@PathVariable String id) { coursePackageService.deletePackage(id); return Result.success(); } @Operation(summary = "提交课程包审核") @PostMapping("/{id}/submit") - public Result submitPackage(@PathVariable Long id) { + public Result submitPackage(@PathVariable String id) { coursePackageService.submitPackage(id); return Result.success(); } @@ -67,7 +67,7 @@ public class AdminCoursePackageController { @Operation(summary = "审核课程包(通过或拒绝)") @PostMapping("/{id}/review") public Result reviewPackage( - @PathVariable Long id, + @PathVariable String id, @RequestBody java.util.Map body) { boolean approved = Boolean.TRUE.equals(body.get("approved")); String comment = (String) body.get("comment"); @@ -77,14 +77,14 @@ public class AdminCoursePackageController { @Operation(summary = "发布课程包") @PostMapping("/{id}/publish") - public Result publishPackage(@PathVariable Long id) { + public Result publishPackage(@PathVariable String id) { coursePackageService.publishPackage(id); return Result.success(); } @Operation(summary = "下架课程包") @PostMapping("/{id}/offline") - public Result offlinePackage(@PathVariable Long id) { + public Result offlinePackage(@PathVariable String id) { coursePackageService.offlinePackage(id); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminOperationLogController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminOperationLogController.java index 806b5dd..b12f481 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminOperationLogController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminOperationLogController.java @@ -26,7 +26,7 @@ public class AdminOperationLogController { public Result> getLogs( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "20") int pageSize, - @RequestParam(required = false) Long tenantId, + @RequestParam(required = false) String tenantId, @RequestParam(required = false) String module) { Page page = operationLogService.getLogs(pageNum, pageSize, tenantId, module); return Result.success(PageResult.of(page)); diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminResourceController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminResourceController.java index 47d508c..0c0494f 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminResourceController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminResourceController.java @@ -26,7 +26,7 @@ public class AdminResourceController { @Operation(summary = "获取所有资源库") @GetMapping("/libraries") - public Result> getLibraries(@RequestParam(required = false) Long tenantId) { + public Result> getLibraries(@RequestParam(required = false) String tenantId) { return Result.success(resourceService.getLibraries(tenantId)); } @@ -38,13 +38,13 @@ public class AdminResourceController { @Operation(summary = "更新资源库") @PutMapping("/libraries/{id}") - public Result updateLibrary(@PathVariable Long id, @RequestBody ResourceLibrary library) { + public Result updateLibrary(@PathVariable String id, @RequestBody ResourceLibrary library) { return Result.success(resourceService.updateLibrary(id, library)); } @Operation(summary = "删除资源库") @DeleteMapping("/libraries/{id}") - public Result deleteLibrary(@PathVariable Long id) { + public Result deleteLibrary(@PathVariable String id) { resourceService.deleteLibrary(id); return Result.success(); } @@ -54,7 +54,7 @@ public class AdminResourceController { public Result> getItems( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "20") int pageSize, - @RequestParam(required = false) Long libraryId, + @RequestParam(required = false) String libraryId, @RequestParam(required = false) String keyword) { Page page = resourceService.getItems(pageNum, pageSize, libraryId, keyword); return Result.success(PageResult.of(page)); @@ -68,13 +68,13 @@ public class AdminResourceController { @Operation(summary = "更新资源项") @PutMapping("/items/{id}") - public Result updateItem(@PathVariable Long id, @RequestBody ResourceItem item) { + public Result updateItem(@PathVariable String id, @RequestBody ResourceItem item) { return Result.success(resourceService.updateItem(id, item)); } @Operation(summary = "删除资源项") @DeleteMapping("/items/{id}") - public Result deleteItem(@PathVariable Long id) { + public Result deleteItem(@PathVariable String id) { resourceService.deleteItem(id); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminSettingsController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminSettingsController.java index d56c203..8a03cc9 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminSettingsController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminSettingsController.java @@ -3,6 +3,8 @@ package com.reading.platform.controller.admin; import com.reading.platform.common.annotation.RequireRole; import com.reading.platform.common.enums.UserRole; import com.reading.platform.common.response.Result; +import com.reading.platform.dto.request.AdminSettingsUpdateRequest; +import com.reading.platform.dto.response.SystemSettingsResponse; import com.reading.platform.service.SystemSettingService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -18,26 +20,50 @@ import java.util.Map; @RequireRole(UserRole.ADMIN) public class AdminSettingsController { - // Use tenantId=0 for global admin settings - private static final Long ADMIN_TENANT_ID = 0L; + // Use tenantId="0" for global admin settings + private static final String ADMIN_TENANT_ID = "0"; private final SystemSettingService systemSettingService; @Operation(summary = "获取管理员系统设置") @GetMapping - public Result> getSettings() { - return Result.success(systemSettingService.getSettings(ADMIN_TENANT_ID)); + public Result getSettings() { + Map settings = systemSettingService.getSettings(ADMIN_TENANT_ID); + + SystemSettingsResponse response = new SystemSettingsResponse(); + response.setSystemName(settings.get("systemName")); + response.setSystemLogo(settings.get("systemLogo")); + response.setLoginBackground(settings.get("loginBackground")); + response.setAnnouncement(settings.get("announcement")); + response.setContactInfo(settings.get("contactInfo")); + + return Result.success(response); } @Operation(summary = "更新管理员系统设置") @PutMapping - public Result updateSettings(@RequestBody Map settings) { + public Result updateSettings(@RequestBody AdminSettingsUpdateRequest request) { Map stringSettings = new java.util.HashMap<>(); - settings.forEach((k, v) -> { - if (v != null) { - stringSettings.put(k, v.toString()); - } - }); + + if (request.getSystemName() != null) stringSettings.put("systemName", request.getSystemName()); + if (request.getSystemDesc() != null) stringSettings.put("systemDesc", request.getSystemDesc()); + if (request.getContactPhone() != null) stringSettings.put("contactPhone", request.getContactPhone()); + if (request.getContactEmail() != null) stringSettings.put("contactEmail", request.getContactEmail()); + if (request.getSystemLogo() != null) stringSettings.put("systemLogo", request.getSystemLogo()); + if (request.getPasswordStrength() != null) stringSettings.put("passwordStrength", request.getPasswordStrength()); + if (request.getMaxLoginAttempts() != null) stringSettings.put("maxLoginAttempts", request.getMaxLoginAttempts().toString()); + if (request.getTokenExpire() != null) stringSettings.put("tokenExpire", request.getTokenExpire()); + if (request.getForceHttps() != null) stringSettings.put("forceHttps", request.getForceHttps().toString()); + if (request.getEmailEnabled() != null) stringSettings.put("emailEnabled", request.getEmailEnabled().toString()); + if (request.getSmsEnabled() != null) stringSettings.put("smsEnabled", request.getSmsEnabled().toString()); + if (request.getStorageType() != null) stringSettings.put("storageType", request.getStorageType()); + if (request.getMaxFileSize() != null) stringSettings.put("maxFileSize", request.getMaxFileSize().toString()); + if (request.getAllowedTypes() != null) stringSettings.put("allowedTypes", request.getAllowedTypes()); + if (request.getDefaultTeacherQuota() != null) stringSettings.put("defaultTeacherQuota", request.getDefaultTeacherQuota().toString()); + if (request.getDefaultStudentQuota() != null) stringSettings.put("defaultStudentQuota", request.getDefaultStudentQuota().toString()); + if (request.getEnableAutoExpire() != null) stringSettings.put("enableAutoExpire", request.getEnableAutoExpire().toString()); + if (request.getNotifyBeforeDays() != null) stringSettings.put("notifyBeforeDays", request.getNotifyBeforeDays().toString()); + systemSettingService.updateSettings(ADMIN_TENANT_ID, stringSettings); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminStatsController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminStatsController.java index ede4206..38c1dc6 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminStatsController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminStatsController.java @@ -3,6 +3,7 @@ package com.reading.platform.controller.admin; import com.reading.platform.common.annotation.RequireRole; import com.reading.platform.common.enums.UserRole; import com.reading.platform.common.response.Result; +import com.reading.platform.dto.response.*; import com.reading.platform.service.AdminStatsService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -11,6 +12,7 @@ import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Map; +import java.util.ArrayList; @Tag(name = "管理员 - 统计", description = "管理员统计仪表盘") @RestController @@ -23,34 +25,96 @@ public class AdminStatsController { @Operation(summary = "获取整体统计数据") @GetMapping - public Result> getStats() { - return Result.success(adminStatsService.getStats()); + public Result getStats() { + Map stats = adminStatsService.getStats(); + + AdminStatsResponse response = new AdminStatsResponse(); + response.setTenantCount((Integer) stats.get("tenantCount")); + response.setActiveTenantCount((Integer) stats.get("activeTenantCount")); + response.setTeacherCount((Integer) stats.get("teacherCount")); + response.setStudentCount((Integer) stats.get("studentCount")); + response.setCourseCount((Integer) stats.get("courseCount")); + response.setPublishedCourseCount((Integer) stats.get("publishedCourseCount")); + response.setLessonCount((Integer) stats.get("lessonCount")); + response.setMonthlyLessons((Integer) stats.get("monthlyLessons")); + + return Result.success(response); } @Operation(summary = "获取趋势数据(近6个月)") @GetMapping("/trend") - public Result>> getTrendData() { - return Result.success(adminStatsService.getTrendData()); + public Result> getTrendData() { + List> trend = adminStatsService.getTrendData(); + + List result = new ArrayList<>(); + for (Map item : trend) { + TrendDataPointResponse response = new TrendDataPointResponse(); + response.setMonth((String) item.get("month")); + response.setTenantCount((Integer) item.get("tenantCount")); + response.setLessonCount((Integer) item.get("lessonCount")); + response.setStudentCount((Integer) item.get("studentCount")); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取活跃租户") @GetMapping("/tenants/active") - public Result>> getActiveTenants( + public Result> getActiveTenants( @RequestParam(defaultValue = "10") int limit) { - return Result.success(adminStatsService.getActiveTenants(limit)); + List> tenants = adminStatsService.getActiveTenants(limit); + + List result = new ArrayList<>(); + for (Map item : tenants) { + TenantStatsResponse response = new TenantStatsResponse(); + response.setId(item.get("id") != null ? item.get("id") != null ? item.get("id").toString() : null : null); + response.setName((String) item.get("name")); + response.setCode((String) item.get("code")); + response.setStatus((String) item.get("status")); + response.setExpireAt(item.get("expireAt") != null ? item.get("expireAt").toString() : null); + response.setTeacherCount((Integer) item.get("teacherCount")); + response.setStudentCount((Integer) item.get("studentCount")); + response.setLessonCount((Integer) item.get("lessonCount")); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取热门课程") @GetMapping("/courses/popular") - public Result>> getPopularCourses( + public Result> getPopularCourses( @RequestParam(defaultValue = "10") int limit) { - return Result.success(adminStatsService.getPopularCourses(limit)); + List> courses = adminStatsService.getPopularCourses(limit); + + List result = new ArrayList<>(); + for (Map item : courses) { + CourseStatsResponse response = new CourseStatsResponse(); + response.setId(item.get("id") != null ? item.get("id") != null ? item.get("id").toString() : null : null); + response.setName((String) item.get("name")); + response.setCategory((String) item.get("category")); + response.setStatus((String) item.get("status")); + response.setUsageCount((Integer) item.get("usageCount")); + response.setTeacherCount((Integer) item.get("teacherCount")); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取最近活动") @GetMapping("/activities") - public Result>> getActivities( + public Result> getActivities( @RequestParam(defaultValue = "10") int limit) { - return Result.success(adminStatsService.getRecentActivities(limit)); + List> activities = adminStatsService.getRecentActivities(limit); + + List result = new ArrayList<>(); + for (Map item : activities) { + LessonActivityResponse response = new LessonActivityResponse(); + response.setId(item.get("id") != null ? item.get("id") != null ? item.get("id").toString() : null : null); + response.setTitle((String) item.get("title")); + response.setLessonDate(item.get("lessonDate") != null ? item.get("lessonDate").toString() : null); + response.setStatus((String) item.get("status")); + result.add(response); + } + return Result.success(result); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminTenantController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminTenantController.java index 0904051..6f98ade 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminTenantController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminTenantController.java @@ -7,7 +7,11 @@ import com.reading.platform.common.response.PageResult; import com.reading.platform.common.response.Result; import com.reading.platform.dto.request.TenantCreateRequest; import com.reading.platform.dto.request.TenantUpdateRequest; +import com.reading.platform.dto.request.TenantStatusUpdateRequest; +import com.reading.platform.dto.request.TenantQuotaUpdateRequest; import com.reading.platform.dto.response.TenantResponse; +import com.reading.platform.dto.response.TenantStatusUpdateResponse; +import com.reading.platform.dto.response.ResetPasswordResponse; import com.reading.platform.entity.Tenant; import com.reading.platform.service.TenantService; import io.swagger.v3.oas.annotations.Operation; @@ -18,7 +22,6 @@ import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.List; -import java.util.Map; @Tag(name = "管理员 - 租户", description = "租户管理接口(管理员专用)") @RestController @@ -37,13 +40,13 @@ public class AdminTenantController { @Operation(summary = "更新租户") @PutMapping("/{id}") - public Result updateTenant(@PathVariable Long id, @RequestBody TenantUpdateRequest request) { + public Result updateTenant(@PathVariable String id, @RequestBody TenantUpdateRequest request) { return Result.success(tenantService.updateTenant(id, request)); } @Operation(summary = "根据ID获取租户") @GetMapping("/{id}") - public Result getTenant(@PathVariable Long id) { + public Result getTenant(@PathVariable String id) { return Result.success(tenantService.getTenantById(id)); } @@ -61,7 +64,7 @@ public class AdminTenantController { @Operation(summary = "删除租户") @DeleteMapping("/{id}") - public Result deleteTenant(@PathVariable Long id) { + public Result deleteTenant(@PathVariable String id) { tenantService.deleteTenant(id); return Result.success(); } @@ -74,41 +77,44 @@ public class AdminTenantController { @Operation(summary = "更新租户状态") @PutMapping("/{id}/status") - public Result> updateTenantStatus(@PathVariable Long id, @RequestBody Map body) { - String status = body.get("status"); + public Result updateTenantStatus( + @PathVariable String id, + @RequestBody TenantStatusUpdateRequest request) { // Normalize status to lowercase for DB - String dbStatus = status != null ? status.toLowerCase() : "active"; + String dbStatus = request.getStatus() != null ? request.getStatus().toLowerCase() : "active"; TenantUpdateRequest req = new TenantUpdateRequest(); req.setStatus(dbStatus); Tenant tenant = tenantService.updateTenant(id, req); - Map result = new HashMap<>(); - result.put("id", tenant.getId()); - result.put("name", tenant.getName()); - result.put("status", tenant.getStatus()); - return Result.success(result); + + TenantStatusUpdateResponse response = new TenantStatusUpdateResponse(); + response.setId(tenant.getId()); + response.setName(tenant.getName()); + response.setStatus(tenant.getStatus()); + return Result.success(response); } @Operation(summary = "重置租户学校账号密码") @PostMapping("/{id}/reset-password") - public Result> resetTenantPassword(@PathVariable Long id) { + public Result resetTenantPassword(@PathVariable String id) { String tempPassword = tenantService.resetSchoolAccountPassword(id); - Map result = new HashMap<>(); - result.put("tempPassword", tempPassword); - return Result.success(result); + ResetPasswordResponse response = ResetPasswordResponse.of(tempPassword, "请通知用户及时修改密码"); + return Result.success(response); } @Operation(summary = "更新租户配额") @PutMapping("/{id}/quota") - public Result updateTenantQuota(@PathVariable Long id, @RequestBody Map body) { + public Result updateTenantQuota( + @PathVariable String id, + @RequestBody TenantQuotaUpdateRequest request) { TenantUpdateRequest req = new TenantUpdateRequest(); - if (body.get("teacherQuota") != null) { - req.setMaxTeachers(Integer.parseInt(body.get("teacherQuota").toString())); + if (request.getTeacherQuota() != null) { + req.setMaxTeachers(request.getTeacherQuota()); } - if (body.get("studentQuota") != null) { - req.setMaxStudents(Integer.parseInt(body.get("studentQuota").toString())); + if (request.getStudentQuota() != null) { + req.setMaxStudents(request.getStudentQuota()); } - if (body.get("packageType") != null) { - req.setPackageType(body.get("packageType").toString()); + if (request.getPackageType() != null) { + req.setPackageType(request.getPackageType()); } return Result.success(tenantService.updateTenant(id, req)); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminThemeController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminThemeController.java index 46c4adf..718185c 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminThemeController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminThemeController.java @@ -29,7 +29,7 @@ public class AdminThemeController { @Operation(summary = "根据ID获取主题") @GetMapping("/{id}") - public Result getTheme(@PathVariable Long id) { + public Result getTheme(@PathVariable String id) { return Result.success(themeService.getThemeById(id)); } @@ -41,13 +41,13 @@ public class AdminThemeController { @Operation(summary = "更新主题") @PutMapping("/{id}") - public Result updateTheme(@PathVariable Long id, @RequestBody Theme theme) { + public Result updateTheme(@PathVariable String id, @RequestBody Theme theme) { return Result.success(themeService.updateTheme(id, theme)); } @Operation(summary = "删除主题") @DeleteMapping("/{id}") - public Result deleteTheme(@PathVariable Long id) { + public Result deleteTheme(@PathVariable String id) { themeService.deleteTheme(id); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentChildController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentChildController.java index 3dd0e0c..686ec9a 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentChildController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentChildController.java @@ -1,15 +1,22 @@ package com.reading.platform.controller.parent; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.reading.platform.common.response.PageResult; import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; +import com.reading.platform.dto.response.*; +import com.reading.platform.entity.Lesson; import com.reading.platform.entity.Student; +import com.reading.platform.entity.TaskCompletion; +import com.reading.platform.service.LessonService; import com.reading.platform.service.StudentService; +import com.reading.platform.service.TaskService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import java.util.List; +import java.util.*; @Tag(name = "家长 - 孩子", description = "孩子信息接口(家长专用)") @RestController @@ -18,18 +25,98 @@ import java.util.List; public class ParentChildController { private final StudentService studentService; + private final LessonService lessonService; + private final TaskService taskService; @Operation(summary = "获取我的孩子") @GetMapping - public Result> getMyChildren() { - Long parentId = SecurityUtils.getCurrentUserId(); - return Result.success(studentService.getStudentsByParentId(parentId)); + public Result> getMyChildren() { + String parentId = SecurityUtils.getCurrentUserId(); + List students = studentService.getStudentsByParentId(parentId); + + List result = new ArrayList<>(); + for (Student student : students) { + ChildInfoResponse response = new ChildInfoResponse(); + response.setId(student.getId()); + response.setName(student.getName()); + response.setGender(student.getGender()); + response.setBirthDate(student.getBirthDate() != null ? student.getBirthDate().toString() : null); + response.setReadingCount(student.getReadingCount() != null ? student.getReadingCount() : 0); + response.setLessonCount(student.getLessonCount() != null ? student.getLessonCount() : 0); + response.setClassInfo(new ChildInfoResponse.ClassInfo()); + response.setRelationship("parent"); + result.add(response); + } + return Result.success(result); } - @Operation(summary = "根据ID获取孩子") + @Operation(summary = "根据 ID 获取孩子详情") @GetMapping("/{id}") - public Result getChild(@PathVariable Long id) { - return Result.success(studentService.getStudentById(id)); + public Result getChild(@PathVariable String id) { + Student student = studentService.getStudentById(id); + + ChildDetailResponse response = new ChildDetailResponse(); + response.setId(student.getId()); + response.setName(student.getName()); + response.setGender(student.getGender()); + response.setBirthDate(student.getBirthDate() != null ? student.getBirthDate().toString() : null); + response.setReadingCount(student.getReadingCount() != null ? student.getReadingCount() : 0); + response.setLessonCount(student.getLessonCount() != null ? student.getLessonCount() : 0); + + ChildDetailResponse.ChildStats stats = new ChildDetailResponse.ChildStats(); + stats.setLessonRecords(student.getLessonCount() != null ? student.getLessonCount() : 0); + stats.setGrowthRecords(0); + stats.setTaskCompletions(0); + response.setStats(stats); + + response.setClassInfo(new ChildDetailResponse.ClassInfo()); + response.setRelationship("parent"); + + return Result.success(response); + } + + @Operation(summary = "获取孩子的课时记录") + @GetMapping("/{childId}/lessons") + public Result> getChildLessons( + @PathVariable String childId, + @RequestParam(value = "page", required = false) Integer pageNum, + @RequestParam(required = false) Integer pageSize) { + + if (pageNum == null) pageNum = 1; + if (pageSize == null) pageSize = 10; + + Page page = lessonService.getLessonPage(null, pageNum, pageSize, null, null, "completed", null, null); + + return Result.success(CommonPageResponse.of(page.getRecords(), page.getTotal(), (int) page.getCurrent(), (int) page.getSize())); + } + + @Operation(summary = "获取孩子的任务") + @GetMapping("/{childId}/tasks") + public Result> getChildTasks( + @PathVariable String childId, + @RequestParam(value = "page", required = false) Integer pageNum, + @RequestParam(required = false) Integer pageSize, + @RequestParam(required = false) String status) { + + if (pageNum == null) pageNum = 1; + if (pageSize == null) pageSize = 10; + + Page completionsPage = taskService.getTaskCompletions(null, childId, pageNum, pageSize, status); + + List items = new ArrayList<>(); + for (TaskCompletion completion : completionsPage.getRecords()) { + TaskCompletionInfoResponse response = new TaskCompletionInfoResponse(); + response.setId(completion.getId()); + response.setTaskId(completion.getTaskId()); + response.setStudentId(completion.getStudentId()); + response.setStatus(completion.getStatus()); + response.setCompletedAt(completion.getCreatedAt() != null ? completion.getCreatedAt().toString() : null); + response.setFeedback(completion.getFeedback()); + response.setParentFeedback(completion.getFeedback()); + items.add(response); + } + + return Result.success(CommonPageResponse.of(items, completionsPage.getTotal(), (int) completionsPage.getCurrent(), (int) completionsPage.getSize())); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentGrowthController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentGrowthController.java index b334b6a..27a2062 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentGrowthController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentGrowthController.java @@ -27,27 +27,27 @@ public class ParentGrowthController { @Operation(summary = "创建成长档案") @PostMapping public Result createGrowthRecord(@Valid @RequestBody GrowthRecordCreateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Long userId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); return Result.success(growthRecordService.createGrowthRecord(tenantId, userId, "parent", request)); } @Operation(summary = "更新成长档案") @PutMapping("/{id}") - public Result updateGrowthRecord(@PathVariable Long id, @RequestBody GrowthRecordUpdateRequest request) { + public Result updateGrowthRecord(@PathVariable String id, @RequestBody GrowthRecordUpdateRequest request) { return Result.success(growthRecordService.updateGrowthRecord(id, request)); } @Operation(summary = "根据ID获取成长档案") @GetMapping("/{id}") - public Result getGrowthRecord(@PathVariable Long id) { + public Result getGrowthRecord(@PathVariable String id) { return Result.success(growthRecordService.getGrowthRecordById(id)); } @Operation(summary = "根据学生ID获取成长档案") @GetMapping("/student/{studentId}") public Result> getGrowthRecordsByStudent( - @PathVariable Long studentId, + @PathVariable String studentId, @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String type) { @@ -58,14 +58,14 @@ public class ParentGrowthController { @Operation(summary = "获取最近成长档案") @GetMapping("/student/{studentId}/recent") public Result> getRecentGrowthRecords( - @PathVariable Long studentId, + @PathVariable String studentId, @RequestParam(required = false, defaultValue = "10") Integer limit) { return Result.success(growthRecordService.getRecentGrowthRecords(studentId, limit)); } @Operation(summary = "删除成长档案") @DeleteMapping("/{id}") - public Result deleteGrowthRecord(@PathVariable Long id) { + public Result deleteGrowthRecord(@PathVariable String id) { growthRecordService.deleteGrowthRecord(id); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentNotificationController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentNotificationController.java index b7b3d13..aea4db1 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentNotificationController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentNotificationController.java @@ -21,7 +21,7 @@ public class ParentNotificationController { @Operation(summary = "根据ID获取通知") @GetMapping("/{id}") - public Result getNotification(@PathVariable Long id) { + public Result getNotification(@PathVariable String id) { return Result.success(notificationService.getNotificationById(id)); } @@ -31,14 +31,14 @@ public class ParentNotificationController { @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) Integer isRead) { - Long userId = SecurityUtils.getCurrentUserId(); + String userId = SecurityUtils.getCurrentUserId(); Page page = notificationService.getMyNotifications(userId, "parent", pageNum, pageSize, isRead); return Result.success(PageResult.of(page)); } @Operation(summary = "标记通知为已读") @PostMapping("/{id}/read") - public Result markAsRead(@PathVariable Long id) { + public Result markAsRead(@PathVariable String id) { notificationService.markAsRead(id); return Result.success(); } @@ -46,7 +46,7 @@ public class ParentNotificationController { @Operation(summary = "标记所有通知为已读") @PostMapping("/read-all") public Result markAllAsRead() { - Long userId = SecurityUtils.getCurrentUserId(); + String userId = SecurityUtils.getCurrentUserId(); notificationService.markAllAsRead(userId, "parent"); return Result.success(); } @@ -54,7 +54,7 @@ public class ParentNotificationController { @Operation(summary = "获取未读通知数量") @GetMapping("/unread-count") public Result getUnreadCount() { - Long userId = SecurityUtils.getCurrentUserId(); + String userId = SecurityUtils.getCurrentUserId(); return Result.success(notificationService.getUnreadCount(userId, "parent")); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentTaskController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentTaskController.java index 7547649..cae4c12 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentTaskController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentTaskController.java @@ -3,8 +3,10 @@ package com.reading.platform.controller.parent; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.reading.platform.common.response.PageResult; import com.reading.platform.common.response.Result; -import com.reading.platform.common.security.SecurityUtils; +import com.reading.platform.dto.request.TaskFeedbackUpdateRequest; +import com.reading.platform.dto.response.TaskFeedbackResponse; import com.reading.platform.entity.Task; +import com.reading.platform.entity.TaskCompletion; import com.reading.platform.service.TaskService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -19,16 +21,16 @@ public class ParentTaskController { private final TaskService taskService; - @Operation(summary = "根据ID获取任务") + @Operation(summary = "根据 ID 获取任务") @GetMapping("/{id}") - public Result getTask(@PathVariable Long id) { + public Result getTask(@PathVariable String id) { return Result.success(taskService.getTaskById(id)); } - @Operation(summary = "根据学生ID获取任务") + @Operation(summary = "根据学生 ID 获取任务") @GetMapping("/student/{studentId}") public Result> getTasksByStudent( - @PathVariable Long studentId, + @PathVariable String studentId, @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String status) { @@ -39,12 +41,37 @@ public class ParentTaskController { @Operation(summary = "完成任务") @PostMapping("/{taskId}/complete") public Result completeTask( - @PathVariable Long taskId, - @RequestParam Long studentId, + @PathVariable String taskId, + @RequestParam String studentId, @RequestParam(required = false) String content, @RequestParam(required = false) String attachments) { taskService.completeTask(taskId, studentId, content, attachments); return Result.success(); } + @Operation(summary = "提交任务家长反馈") + @PutMapping("/{childId}/tasks/{taskId}/feedback") + public Result submitParentFeedback( + @PathVariable String childId, + @PathVariable String taskId, + @RequestBody TaskFeedbackUpdateRequest request) { + String feedback = request.getFeedback(); + + TaskCompletion completion = taskService.getTaskCompletion(taskId, childId); + + if (completion != null) { + TaskFeedbackResponse response = new TaskFeedbackResponse(); + response.setId(completion.getId()); + response.setTaskId(completion.getTaskId()); + response.setStudentId(completion.getStudentId()); + response.setStatus(completion.getStatus()); + response.setParentFeedback(feedback); + return Result.success(response); + } else { + TaskFeedbackResponse response = new TaskFeedbackResponse(); + response.setMessage("未找到任务完成记录"); + return Result.success(response); + } + } + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolClassController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolClassController.java index 5f8352d..d694502 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolClassController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolClassController.java @@ -6,7 +6,9 @@ import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; import com.reading.platform.dto.request.ClassCreateRequest; import com.reading.platform.dto.request.ClassUpdateRequest; +import com.reading.platform.entity.ClassTeacher; import com.reading.platform.entity.Clazz; +import com.reading.platform.entity.Student; import com.reading.platform.service.ClassService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -27,22 +29,29 @@ public class SchoolClassController { @Operation(summary = "创建班级") @PostMapping public Result createClass(@Valid @RequestBody ClassCreateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(classService.createClass(tenantId, request)); } @Operation(summary = "更新班级") @PutMapping("/{id}") - public Result updateClass(@PathVariable Long id, @RequestBody ClassUpdateRequest request) { + public Result updateClass(@PathVariable String id, @RequestBody ClassUpdateRequest request) { return Result.success(classService.updateClass(id, request)); } @Operation(summary = "Get class by ID") @GetMapping("/{id}") - public Result getClass(@PathVariable Long id) { + public Result getClass(@PathVariable String id) { return Result.success(classService.getClassById(id)); } + @Operation(summary = "获取班级列表(无分页)") + @GetMapping("/list") + public Result> getClassList() { + String tenantId = SecurityUtils.getCurrentTenantId(); + return Result.success(classService.getClassList(tenantId)); + } + @Operation(summary = "Get class page") @GetMapping public Result> getClassPage( @@ -51,44 +60,121 @@ public class SchoolClassController { @RequestParam(required = false) String keyword, @RequestParam(required = false) String grade, @RequestParam(required = false) String status) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = classService.getClassPage(tenantId, pageNum, pageSize, keyword, grade, status); return Result.success(PageResult.of(page)); } @Operation(summary = "删除班级") @DeleteMapping("/{id}") - public Result deleteClass(@PathVariable Long id) { + public Result deleteClass(@PathVariable String id) { classService.deleteClass(id); return Result.success(); } - @Operation(summary = "分配教师到班级") + @Operation(summary = "获取班级学生分页") + @GetMapping("/{id}/students") + public Result> getClassStudents( + @PathVariable String id, + @RequestParam(value = "page", required = false) Integer pageNum, + @RequestParam(required = false) Integer pageSize, + @RequestParam(required = false) String keyword) { + Page page = classService.getClassStudents(id, pageNum, pageSize, keyword); + return Result.success(PageResult.of(page)); + } + + @Operation(summary = "获取班级教师列表") + @GetMapping("/{id}/teachers") + public Result> getClassTeachers(@PathVariable String id) { + return Result.success(classService.getClassTeachers(id)); + } + + @Operation(summary = "添加班级教师") @PostMapping("/{id}/teachers") - public Result assignTeachers(@PathVariable Long id, @RequestBody List teacherIds) { + public Result addClassTeacher( + @PathVariable String id, + @RequestBody ClassTeacherRequest request) { + String tenantId = SecurityUtils.getCurrentTenantId(); + return Result.success(classService.addClassTeacher(tenantId, id, request.getTeacherId(), request.getRole(), request.getIsPrimary())); + } + + @Operation(summary = "更新班级教师角色") + @PutMapping("/{id}/teachers/{teacherId}") + public Result updateClassTeacher( + @PathVariable String id, + @PathVariable String teacherId, + @RequestBody ClassTeacherRequest request) { + String tenantId = SecurityUtils.getCurrentTenantId(); + return Result.success(classService.updateClassTeacher(tenantId, id, teacherId, request.getRole(), request.getIsPrimary())); + } + + @Operation(summary = "移除班级教师") + @DeleteMapping("/{id}/teachers/{teacherId}") + public Result removeClassTeacher(@PathVariable String id, @PathVariable String teacherId) { + String tenantId = SecurityUtils.getCurrentTenantId(); + classService.removeClassTeacher(tenantId, id, teacherId); + return Result.success(); + } + + @Operation(summary = "分配教师到班级") + @PostMapping("/{id}/teachers/batch") + public Result assignTeachers(@PathVariable String id, @RequestBody List teacherIds) { classService.assignTeachers(id, teacherIds); return Result.success(); } @Operation(summary = "分配学生到班级") - @PostMapping("/{id}/students") - public Result assignStudents(@PathVariable Long id, @RequestBody List studentIds) { + @PostMapping("/{id}/students/batch") + public Result assignStudents(@PathVariable String id, @RequestBody List studentIds) { classService.assignStudents(id, studentIds); return Result.success(); } - @Operation(summary = "移除班级教师") - @DeleteMapping("/{id}/teachers/{teacherId}") - public Result removeTeacher(@PathVariable Long id, @PathVariable Long teacherId) { + @Operation(summary = "移除班级教师(旧接口)") + @DeleteMapping("/{id}/teachers/remove/{teacherId}") + public Result removeTeacher(@PathVariable String id, @PathVariable String teacherId) { classService.removeTeacher(id, teacherId); return Result.success(); } - @Operation(summary = "移除班级学生") - @DeleteMapping("/{id}/students/{studentId}") - public Result removeStudent(@PathVariable Long id, @PathVariable Long studentId) { + @Operation(summary = "移除班级学生(旧接口)") + @DeleteMapping("/{id}/students/remove/{studentId}") + public Result removeStudent(@PathVariable String id, @PathVariable String studentId) { classService.removeStudent(id, studentId); return Result.success(); } + /** + * 班级教师请求 DTO + */ + public static class ClassTeacherRequest { + private String teacherId; + private String role; + private Boolean isPrimary; + + public String getTeacherId() { + return teacherId; + } + + public void setTeacherId(String teacherId) { + this.teacherId = teacherId; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public Boolean getIsPrimary() { + return isPrimary; + } + + public void setIsPrimary(Boolean isPrimary) { + this.isPrimary = isPrimary; + } + } + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolCourseController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolCourseController.java index 8588392..4b7a680 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolCourseController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolCourseController.java @@ -28,34 +28,34 @@ public class SchoolCourseController { @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "20") int pageSize, @RequestParam(required = false) String keyword) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = schoolCourseService.getCourses(pageNum, pageSize, tenantId, keyword); return Result.success(PageResult.of(page)); } @Operation(summary = "根据ID获取校本课程") @GetMapping("/{id}") - public Result getCourse(@PathVariable Long id) { + public Result getCourse(@PathVariable String id) { return Result.success(schoolCourseService.getCourseById(id)); } @Operation(summary = "创建校本课程") @PostMapping public Result createCourse(@RequestBody SchoolCourse course) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Long userId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); return Result.success(schoolCourseService.createCourse(tenantId, userId, course)); } @Operation(summary = "更新校本课程") @PutMapping("/{id}") - public Result updateCourse(@PathVariable Long id, @RequestBody SchoolCourse course) { + public Result updateCourse(@PathVariable String id, @RequestBody SchoolCourse course) { return Result.success(schoolCourseService.updateCourse(id, course)); } @Operation(summary = "删除校本课程") @DeleteMapping("/{id}") - public Result deleteCourse(@PathVariable Long id) { + public Result deleteCourse(@PathVariable String id) { schoolCourseService.deleteCourse(id); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolCoursePackageController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolCoursePackageController.java index 9095447..b3f9cce 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolCoursePackageController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolCoursePackageController.java @@ -33,7 +33,7 @@ public class SchoolCoursePackageController { @Operation(summary = "根据ID获取课程包") @GetMapping("/{id}") - public Result getPackage(@PathVariable Long id) { + public Result getPackage(@PathVariable String id) { return Result.success(coursePackageService.getPackageById(id)); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolExportController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolExportController.java index 260553f..9d24e9f 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolExportController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolExportController.java @@ -27,7 +27,7 @@ public class SchoolExportController { @Operation(summary = "导出教师信息到Excel") @GetMapping("/teachers") public ResponseEntity exportTeachers() throws IOException { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); byte[] data = exportService.exportTeachers(tenantId); return buildResponse(data, "teachers_" + LocalDate.now() + ".xlsx"); } @@ -35,7 +35,7 @@ public class SchoolExportController { @Operation(summary = "导出学生信息到Excel") @GetMapping("/students") public ResponseEntity exportStudents() throws IOException { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); byte[] data = exportService.exportStudents(tenantId); return buildResponse(data, "students_" + LocalDate.now() + ".xlsx"); } @@ -43,7 +43,7 @@ public class SchoolExportController { @Operation(summary = "导出课时信息到Excel") @GetMapping("/lessons") public ResponseEntity exportLessons() throws IOException { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); byte[] data = exportService.exportLessons(tenantId); return buildResponse(data, "lessons_" + LocalDate.now() + ".xlsx"); } @@ -51,7 +51,7 @@ public class SchoolExportController { @Operation(summary = "导出成长档案到Excel") @GetMapping("/growth-records") public ResponseEntity exportGrowthRecords() throws IOException { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); byte[] data = exportService.exportGrowthRecords(tenantId); return buildResponse(data, "growth_records_" + LocalDate.now() + ".xlsx"); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolGrowthController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolGrowthController.java index 757466c..95208a4 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolGrowthController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolGrowthController.java @@ -25,21 +25,21 @@ public class SchoolGrowthController { @Operation(summary = "创建成长档案") @PostMapping public Result createGrowthRecord(@Valid @RequestBody GrowthRecordCreateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Long userId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); String role = SecurityUtils.getCurrentRole(); return Result.success(growthRecordService.createGrowthRecord(tenantId, userId, role, request)); } @Operation(summary = "更新成长档案") @PutMapping("/{id}") - public Result updateGrowthRecord(@PathVariable Long id, @RequestBody GrowthRecordUpdateRequest request) { + public Result updateGrowthRecord(@PathVariable String id, @RequestBody GrowthRecordUpdateRequest request) { return Result.success(growthRecordService.updateGrowthRecord(id, request)); } @Operation(summary = "根据ID获取成长档案") @GetMapping("/{id}") - public Result getGrowthRecord(@PathVariable Long id) { + public Result getGrowthRecord(@PathVariable String id) { return Result.success(growthRecordService.getGrowthRecordById(id)); } @@ -48,16 +48,16 @@ public class SchoolGrowthController { public Result> getGrowthRecordPage( @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, - @RequestParam(required = false) Long studentId, + @RequestParam(required = false) String studentId, @RequestParam(required = false) String type) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = growthRecordService.getGrowthRecordPage(tenantId, pageNum, pageSize, studentId, type); return Result.success(PageResult.of(page)); } @Operation(summary = "删除成长档案") @DeleteMapping("/{id}") - public Result deleteGrowthRecord(@PathVariable Long id) { + public Result deleteGrowthRecord(@PathVariable String id) { growthRecordService.deleteGrowthRecord(id); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolNotificationController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolNotificationController.java index f20b15c..347a95a 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolNotificationController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolNotificationController.java @@ -24,7 +24,7 @@ public class SchoolNotificationController { @Operation(summary = "根据 ID 获取通知") @GetMapping("/{id}") - public Result getNotification(@PathVariable Long id) { + public Result getNotification(@PathVariable String id) { return Result.success(notificationService.getNotificationById(id)); } @@ -34,14 +34,14 @@ public class SchoolNotificationController { @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) Integer isRead) { - Long userId = SecurityUtils.getCurrentUserId(); + String userId = SecurityUtils.getCurrentUserId(); Page page = notificationService.getMyNotifications(userId, "school", pageNum, pageSize, isRead); return Result.success(PageResult.of(page)); } @Operation(summary = "标记通知为已读") @PostMapping("/{id}/read") - public Result markAsRead(@PathVariable Long id) { + public Result markAsRead(@PathVariable String id) { notificationService.markAsRead(id); return Result.success(); } @@ -49,7 +49,7 @@ public class SchoolNotificationController { @Operation(summary = "标记所有通知为已读") @PostMapping("/read-all") public Result markAllAsRead() { - Long userId = SecurityUtils.getCurrentUserId(); + String userId = SecurityUtils.getCurrentUserId(); notificationService.markAllAsRead(userId, "school"); return Result.success(); } @@ -57,7 +57,7 @@ public class SchoolNotificationController { @Operation(summary = "获取未读通知数量") @GetMapping("/unread-count") public Result getUnreadCount() { - Long userId = SecurityUtils.getCurrentUserId(); + String userId = SecurityUtils.getCurrentUserId(); return Result.success(notificationService.getUnreadCount(userId, "school")); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolOperationLogController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolOperationLogController.java index e08592d..c46a38e 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolOperationLogController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolOperationLogController.java @@ -28,7 +28,7 @@ public class SchoolOperationLogController { @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "20") int pageSize, @RequestParam(required = false) String module) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = operationLogService.getLogs(pageNum, pageSize, tenantId, module); return Result.success(PageResult.of(page)); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolParentController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolParentController.java index 297455d..8afee30 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolParentController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolParentController.java @@ -25,19 +25,19 @@ public class SchoolParentController { @Operation(summary = "创建家长") @PostMapping public Result createParent(@Valid @RequestBody ParentCreateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(parentService.createParent(tenantId, request)); } @Operation(summary = "更新家长") @PutMapping("/{id}") - public Result updateParent(@PathVariable Long id, @RequestBody ParentUpdateRequest request) { + public Result updateParent(@PathVariable String id, @RequestBody ParentUpdateRequest request) { return Result.success(parentService.updateParent(id, request)); } @Operation(summary = "Get parent by ID") @GetMapping("/{id}") - public Result getParent(@PathVariable Long id) { + public Result getParent(@PathVariable String id) { return Result.success(parentService.getParentById(id)); } @@ -48,21 +48,21 @@ public class SchoolParentController { @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String status) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = parentService.getParentPage(tenantId, pageNum, pageSize, keyword, status); return Result.success(PageResult.of(page)); } @Operation(summary = "删除家长") @DeleteMapping("/{id}") - public Result deleteParent(@PathVariable Long id) { + public Result deleteParent(@PathVariable String id) { parentService.deleteParent(id); return Result.success(); } @Operation(summary = "重置家长密码") @PostMapping("/{id}/reset-password") - public Result resetPassword(@PathVariable Long id, @RequestParam String newPassword) { + public Result resetPassword(@PathVariable String id, @RequestParam String newPassword) { parentService.resetPassword(id, newPassword); return Result.success(); } @@ -70,8 +70,8 @@ public class SchoolParentController { @Operation(summary = "绑定学生到家长") @PostMapping("/{parentId}/students/{studentId}") public Result bindStudent( - @PathVariable Long parentId, - @PathVariable Long studentId, + @PathVariable String parentId, + @PathVariable String studentId, @RequestParam(required = false) String relationship, @RequestParam(required = false) Boolean isPrimary) { parentService.bindStudent(parentId, studentId, relationship, isPrimary); @@ -80,7 +80,7 @@ public class SchoolParentController { @Operation(summary = "解绑家长与学生关系") @DeleteMapping("/{parentId}/students/{studentId}") - public Result unbindStudent(@PathVariable Long parentId, @PathVariable Long studentId) { + public Result unbindStudent(@PathVariable String parentId, @PathVariable String studentId) { parentService.unbindStudent(parentId, studentId); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolScheduleController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolScheduleController.java index a1575d1..85b5d2e 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolScheduleController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolScheduleController.java @@ -8,6 +8,7 @@ import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; import com.reading.platform.dto.request.SchedulePlanCreateRequest; import com.reading.platform.dto.request.ScheduleTemplateApplyRequest; +import com.reading.platform.dto.response.SchedulePlanResponse; import com.reading.platform.entity.SchedulePlan; import com.reading.platform.entity.ScheduleTemplate; import com.reading.platform.service.ScheduleService; @@ -20,6 +21,7 @@ import org.springframework.web.bind.annotation.*; import java.time.LocalDate; import java.util.List; +import java.util.ArrayList; import java.util.Map; @Tag(name = "学校 - 课表", description = "课表管理接口(学校管理员专用)") @@ -36,47 +38,59 @@ public class SchoolScheduleController { public Result> getSchedulePlans( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "20") int pageSize, - @RequestParam(required = false) Long classId, + @RequestParam(required = false) String classId, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = scheduleService.getSchedulePlans(pageNum, pageSize, tenantId, classId, startDate, endDate); return Result.success(PageResult.of(page)); } @Operation(summary = "获取课表(按日期范围)") @GetMapping("/timetable") - public Result>> getTimetable( + public Result> getTimetable( @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate, - @RequestParam(required = false) Long classId) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(scheduleService.getTimetable(tenantId, startDate, endDate, classId)); + @RequestParam(required = false) String classId) { + String tenantId = SecurityUtils.getCurrentTenantId(); + List> timetable = scheduleService.getTimetable(tenantId, startDate, endDate, classId); + + List result = new ArrayList<>(); + for (Map item : timetable) { + SchedulePlanResponse response = new SchedulePlanResponse(); + response.setId(item.get("id") != null ? item.get("id") != null ? item.get("id").toString() : null : null); + response.setName((String) item.get("name")); + response.setClassName((String) item.get("className")); + response.setCourseName((String) item.get("courseName")); + response.setTeacherName((String) item.get("teacherName")); + result.add(response); + } + return Result.success(result); } @Operation(summary = "根据 ID 获取课表计划") @GetMapping("/{id}") - public Result getSchedulePlan(@PathVariable Long id) { + public Result getSchedulePlan(@PathVariable String id) { return Result.success(scheduleService.getSchedulePlanById(id)); } @Operation(summary = "创建课表计划") @PostMapping public Result createSchedulePlan(@Valid @RequestBody SchedulePlanCreateRequest plan) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Long userId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); return Result.success(scheduleService.createSchedulePlan(tenantId, userId, plan)); } @Operation(summary = "更新课表计划") @PutMapping("/{id}") - public Result updateSchedulePlan(@PathVariable Long id, @RequestBody SchedulePlan plan) { + public Result updateSchedulePlan(@PathVariable String id, @RequestBody SchedulePlan plan) { return Result.success(scheduleService.updateSchedulePlan(id, plan)); } @Operation(summary = "删除课表计划") @DeleteMapping("/{id}") - public Result deleteSchedulePlan(@PathVariable Long id) { + public Result deleteSchedulePlan(@PathVariable String id) { scheduleService.deleteSchedulePlan(id); return Result.success(); } @@ -84,8 +98,8 @@ public class SchoolScheduleController { @Operation(summary = "批量创建排课") @PostMapping("/batch") public Result> batchCreateSchedules(@RequestBody List plans) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Long userId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); return Result.success(scheduleService.batchCreateSchedules(tenantId, userId, plans)); } @@ -96,33 +110,33 @@ public class SchoolScheduleController { public Result> getScheduleTemplates( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "20") int pageSize) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = scheduleService.getScheduleTemplates(pageNum, pageSize, tenantId); return Result.success(PageResult.of(page)); } @Operation(summary = "根据 ID 获取课表模板") @GetMapping("/templates/{id}") - public Result getScheduleTemplate(@PathVariable Long id) { + public Result getScheduleTemplate(@PathVariable String id) { return Result.success(scheduleService.getScheduleTemplateById(id)); } @Operation(summary = "创建课表模板") @PostMapping("/templates") public Result createScheduleTemplate(@RequestBody ScheduleTemplate template) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(scheduleService.createScheduleTemplate(tenantId, template)); } @Operation(summary = "更新课表模板") @PutMapping("/templates/{id}") - public Result updateScheduleTemplate(@PathVariable Long id, @RequestBody ScheduleTemplate template) { + public Result updateScheduleTemplate(@PathVariable String id, @RequestBody ScheduleTemplate template) { return Result.success(scheduleService.updateScheduleTemplate(id, template)); } @Operation(summary = "删除课表模板") @DeleteMapping("/templates/{id}") - public Result deleteScheduleTemplate(@PathVariable Long id) { + public Result deleteScheduleTemplate(@PathVariable String id) { scheduleService.deleteScheduleTemplate(id); return Result.success(); } @@ -130,9 +144,9 @@ public class SchoolScheduleController { @Operation(summary = "应用课表模板") @PostMapping("/templates/{id}/apply") public Result> applyScheduleTemplate( - @PathVariable Long id, + @PathVariable String id, @Valid @RequestBody ScheduleTemplateApplyRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(scheduleService.applyScheduleTemplate(tenantId, id, request)); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolSettingsController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolSettingsController.java index 6140fb9..ef87fd3 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolSettingsController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolSettingsController.java @@ -4,6 +4,8 @@ import com.reading.platform.common.annotation.RequireRole; import com.reading.platform.common.enums.UserRole; import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; +import com.reading.platform.dto.request.SchoolSettingsUpdateRequest; +import com.reading.platform.dto.response.SystemSettingsResponse; import com.reading.platform.service.SystemSettingService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -23,15 +25,33 @@ public class SchoolSettingsController { @Operation(summary = "Get school settings") @GetMapping - public Result> getSettings() { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(systemSettingService.getSettings(tenantId)); + public Result getSettings() { + String tenantId = SecurityUtils.getCurrentTenantId(); + Map settings = systemSettingService.getSettings(tenantId); + + SystemSettingsResponse response = new SystemSettingsResponse(); + response.setSystemName(settings.get("systemName")); + response.setSystemLogo(settings.get("systemLogo")); + response.setLoginBackground(settings.get("loginBackground")); + response.setAnnouncement(settings.get("announcement")); + response.setContactInfo(settings.get("contactInfo")); + + return Result.success(response); } @Operation(summary = "Update school settings") @PutMapping - public Result updateSettings(@RequestBody Map settings) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + public Result updateSettings(@RequestBody SchoolSettingsUpdateRequest request) { + String tenantId = SecurityUtils.getCurrentTenantId(); + Map settings = new java.util.HashMap<>(); + + if (request.getSchoolName() != null) settings.put("schoolName", request.getSchoolName()); + if (request.getSchoolLogo() != null) settings.put("schoolLogo", request.getSchoolLogo()); + if (request.getAddress() != null) settings.put("address", request.getAddress()); + if (request.getNotifyOnLesson() != null) settings.put("notifyOnLesson", request.getNotifyOnLesson().toString()); + if (request.getNotifyOnTask() != null) settings.put("notifyOnTask", request.getNotifyOnTask().toString()); + if (request.getNotifyOnGrowth() != null) settings.put("notifyOnGrowth", request.getNotifyOnGrowth().toString()); + systemSettingService.updateSettings(tenantId, settings); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStatsController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStatsController.java index 79fffd7..e20600d 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStatsController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStatsController.java @@ -4,6 +4,7 @@ import com.reading.platform.common.annotation.RequireRole; import com.reading.platform.common.enums.UserRole; import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; +import com.reading.platform.dto.response.*; import com.reading.platform.service.SchoolStatsService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -12,6 +13,7 @@ import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Map; +import java.util.ArrayList; @Tag(name = "学校 - 统计", description = "学校统计仪表盘接口(学校管理员专用)") @RestController @@ -24,46 +26,104 @@ public class SchoolStatsController { @Operation(summary = "获取学校统计数据") @GetMapping - public Result> getStats() { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(schoolStatsService.getStats(tenantId)); + public Result getStats() { + String tenantId = SecurityUtils.getCurrentTenantId(); + Map stats = schoolStatsService.getStats(tenantId); + + StatsResponse response = new StatsResponse(); + response.setTotalTeachers((Integer) stats.get("teacherCount")); + response.setTotalStudents((Integer) stats.get("studentCount")); + response.setTotalClasses((Integer) stats.get("classCount")); + response.setTotalCourses((Integer) stats.get("courseCount")); + + return Result.success(response); } @Operation(summary = "获取活跃教师统计") @GetMapping("/teachers") - public Result>> getActiveTeachers( + public Result> getActiveTeachers( @RequestParam(value = "limit", required = false, defaultValue = "5") Integer limit) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(schoolStatsService.getActiveTeachers(tenantId, limit)); + String tenantId = SecurityUtils.getCurrentTenantId(); + List> teachers = schoolStatsService.getActiveTeachers(tenantId, limit); + + List result = new ArrayList<>(); + for (Map item : teachers) { + ActiveTeacherStatsResponse response = new ActiveTeacherStatsResponse(); + response.setId(item.get("id") != null ? item.get("id") != null ? item.get("id").toString() : null : null); + response.setName((String) item.get("name")); + response.setLessonCount((Integer) item.get("lessonCount")); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取课程使用统计") @GetMapping("/courses") - public Result>> getCourseUsageStats() { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(schoolStatsService.getCourseUsageStats(tenantId)); + public Result> getCourseUsageStats() { + String tenantId = SecurityUtils.getCurrentTenantId(); + List> stats = schoolStatsService.getCourseUsageStats(tenantId); + + List result = new ArrayList<>(); + for (Map item : stats) { + CourseUsageStatsResponse response = new CourseUsageStatsResponse(); + response.setCourseId(item.get("courseId") != null ? item.get("courseId") != null ? item.get("courseId").toString() : null : null); + response.setCourseName((String) item.get("courseName")); + response.setUsageCount((Integer) item.get("usageCount")); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取最近活动记录") @GetMapping("/activities") - public Result>> getRecentActivities( + public Result> getRecentActivities( @RequestParam(value = "limit", required = false, defaultValue = "10") Integer limit) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(schoolStatsService.getRecentActivities(tenantId, limit)); + String tenantId = SecurityUtils.getCurrentTenantId(); + List> activities = schoolStatsService.getRecentActivities(tenantId, limit); + + List result = new ArrayList<>(); + for (Map item : activities) { + RecentActivityResponse response = new RecentActivityResponse(); + response.setId(item.get("id") != null ? item.get("id") != null ? item.get("id").toString() : null : null); + response.setType((String) item.get("type")); + response.setTitle((String) item.get("title")); + response.setTime(item.get("time") != null ? item.get("time").toString() : null); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取课时趋势(最近 N 个月)") @GetMapping("/lesson-trend") - public Result>> getLessonTrend( + public Result> getLessonTrend( @RequestParam(value = "months", required = false, defaultValue = "6") Integer months) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(schoolStatsService.getLessonTrend(tenantId, months)); + String tenantId = SecurityUtils.getCurrentTenantId(); + List> trend = schoolStatsService.getLessonTrend(tenantId, months); + + List result = new ArrayList<>(); + for (Map item : trend) { + TrendDataResponse response = new TrendDataResponse(); + response.setMonth((String) item.get("month")); + response.setLessonCount((Integer) item.get("lessonCount")); + response.setStudentCount((Integer) item.get("studentCount")); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取课程分布统计(饼图数据)") @GetMapping("/course-distribution") - public Result>> getCourseDistribution() { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(schoolStatsService.getCourseDistribution(tenantId)); + public Result> getCourseDistribution() { + String tenantId = SecurityUtils.getCurrentTenantId(); + List> distribution = schoolStatsService.getCourseDistribution(tenantId); + + List result = new ArrayList<>(); + for (Map item : distribution) { + CourseDistributionResponse response = new CourseDistributionResponse(); + response.setName((String) item.get("name")); + response.setValue((Integer) item.get("value")); + result.add(response); + } + return Result.success(result); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java index 02ae6b9..b606a00 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java @@ -6,6 +6,9 @@ import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; import com.reading.platform.dto.request.StudentCreateRequest; import com.reading.platform.dto.request.StudentUpdateRequest; +import com.reading.platform.dto.response.ImportTemplateResponse; +import com.reading.platform.dto.response.MessageResponse; +import com.reading.platform.dto.response.StudentTransferHistoryResponse; import com.reading.platform.entity.Student; import com.reading.platform.service.StudentService; import io.swagger.v3.oas.annotations.Operation; @@ -14,9 +17,7 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import java.util.HashMap; import java.util.List; -import java.util.Map; @Tag(name = "学校 - 学生", description = "学生管理接口(学校管理员专用)") @RestController @@ -29,19 +30,19 @@ public class SchoolStudentController { @Operation(summary = "创建学生") @PostMapping public Result createStudent(@Valid @RequestBody StudentCreateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(studentService.createStudent(tenantId, request)); } @Operation(summary = "更新学生") @PutMapping("/{id}") - public Result updateStudent(@PathVariable Long id, @RequestBody StudentUpdateRequest request) { + public Result updateStudent(@PathVariable String id, @RequestBody StudentUpdateRequest request) { return Result.success(studentService.updateStudent(id, request)); } @Operation(summary = "根据ID获取学生") @GetMapping("/{id}") - public Result getStudent(@PathVariable Long id) { + public Result getStudent(@PathVariable String id) { return Result.success(studentService.getStudentById(id)); } @@ -53,14 +54,14 @@ public class SchoolStudentController { @RequestParam(required = false) String keyword, @RequestParam(required = false) String grade, @RequestParam(required = false) String status) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = studentService.getStudentPage(tenantId, pageNum, pageSize, keyword, grade, status); return Result.success(PageResult.of(page)); } @Operation(summary = "删除学生") @DeleteMapping("/{id}") - public Result deleteStudent(@PathVariable Long id) { + public Result deleteStudent(@PathVariable String id) { studentService.deleteStudent(id); return Result.success(); } @@ -68,17 +69,44 @@ public class SchoolStudentController { @Operation(summary = "批量导入学生") @PostMapping("/import") public Result> importStudents(@RequestBody List requests) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(studentService.importStudents(tenantId, requests)); } @Operation(summary = "获取导入模板") @GetMapping("/import/template") - public Result> getImportTemplate() { - Map template = new HashMap<>(); - template.put("headers", new String[]{"姓名", "性别", "出生日期", "家长手机号", "家长姓名", "备注"}); - template.put("example", new String[]{"张三", "男", "2018-01-01", "13800138000", "张父", "示例数据"}); - return Result.success(template); + public Result getImportTemplate() { + return Result.success(ImportTemplateResponse.studentTemplate()); + } + + @Operation(summary = "学生调班") + @PostMapping("/{id}/transfer") + public Result transferStudent( + @PathVariable String id, + @RequestBody TransferStudentRequest request) { + String tenantId = SecurityUtils.getCurrentTenantId(); + studentService.transferStudent(tenantId, id, request.getToClassId(), request.getReason()); + return Result.success(MessageResponse.of("调班成功")); + } + + @Operation(summary = "获取学生调班历史") + @GetMapping("/{id}/history") + public Result> getStudentHistory(@PathVariable String id) { + List history = studentService.getStudentClassHistory(id); + return Result.success(history); + } + + /** + * 调班请求 DTO + */ + public static class TransferStudentRequest { + private String toClassId; + private String reason; + + public String getToClassId() { return toClassId; } + public void setToClassId(String toClassId) { this.toClassId = toClassId; } + public String getReason() { return reason; } + public void setReason(String reason) { this.reason = reason; } } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTaskController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTaskController.java index 488f5d3..8be4b11 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTaskController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTaskController.java @@ -5,6 +5,10 @@ import com.reading.platform.common.response.PageResult; import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; import com.reading.platform.dto.request.*; +import com.reading.platform.dto.response.TaskStatsResponse; +import com.reading.platform.dto.response.TaskStatsByClassResponse; +import com.reading.platform.dto.response.TaskStatsByTypeResponse; +import com.reading.platform.dto.response.MonthlyTaskStatsResponse; import com.reading.platform.entity.Task; import com.reading.platform.entity.TaskCompletion; import com.reading.platform.entity.TaskTemplate; @@ -17,6 +21,7 @@ import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Map; +import java.util.ArrayList; @Tag(name = "学校 - 任务", description = "任务管理接口(学校管理员专用)") @RestController @@ -29,21 +34,21 @@ public class SchoolTaskController { @Operation(summary = "创建任务") @PostMapping public Result createTask(@Valid @RequestBody TaskCreateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Long userId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); String role = SecurityUtils.getCurrentRole(); return Result.success(taskService.createTask(tenantId, userId, role, request)); } @Operation(summary = "更新任务") @PutMapping("/{id}") - public Result updateTask(@PathVariable Long id, @RequestBody TaskUpdateRequest request) { + public Result updateTask(@PathVariable String id, @RequestBody TaskUpdateRequest request) { return Result.success(taskService.updateTask(id, request)); } @Operation(summary = "根据 ID 获取任务") @GetMapping("/{id}") - public Result getTask(@PathVariable Long id) { + public Result getTask(@PathVariable String id) { return Result.success(taskService.getTaskById(id)); } @@ -55,14 +60,14 @@ public class SchoolTaskController { @RequestParam(required = false) String keyword, @RequestParam(required = false) String type, @RequestParam(required = false) String status) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = taskService.getTaskPage(tenantId, pageNum, pageSize, keyword, type, status); return Result.success(PageResult.of(page)); } @Operation(summary = "删除任务") @DeleteMapping("/{id}") - public Result deleteTask(@PathVariable Long id) { + public Result deleteTask(@PathVariable String id) { taskService.deleteTask(id); return Result.success(); } @@ -71,41 +76,90 @@ public class SchoolTaskController { @Operation(summary = "获取任务统计数据") @GetMapping("/stats") - public Result> getStats() { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(taskService.getTaskStats(tenantId)); + public Result getStats() { + String tenantId = SecurityUtils.getCurrentTenantId(); + Map stats = taskService.getTaskStats(tenantId); + + TaskStatsResponse response = new TaskStatsResponse(); + response.setTotalTasks((Integer) stats.get("totalTasks")); + response.setPublishedTasks((Integer) stats.get("publishedTasks")); + response.setCompletedTasks((Integer) stats.get("completedTasks")); + response.setInProgressTasks((Integer) stats.get("inProgressTasks")); + response.setPendingCount((Integer) stats.get("pendingCount")); + response.setTotalCompletions((Integer) stats.get("totalCompletions")); + response.setCompletionRate((Integer) stats.get("completionRate")); + + return Result.success(response); } @Operation(summary = "按任务类型统计") @GetMapping("/stats/by-type") - public Result> getStatsByType() { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(taskService.getStatsByType(tenantId)); + public Result> getStatsByType() { + String tenantId = SecurityUtils.getCurrentTenantId(); + Map stats = taskService.getStatsByType(tenantId); + + List result = new ArrayList<>(); + for (Map.Entry entry : stats.entrySet()) { + TaskStatsByTypeResponse response = new TaskStatsByTypeResponse(); + response.setType(entry.getKey()); + if (entry.getValue() instanceof Map) { + Map typeData = (Map) entry.getValue(); + response.setTotal(typeData.get("total") != null ? ((Number) typeData.get("total")).intValue() : null); + response.setCompleted(typeData.get("completed") != null ? ((Number) typeData.get("completed")).intValue() : null); + response.setRate(typeData.get("rate") != null ? ((Number) typeData.get("rate")).intValue() : null); + } + result.add(response); + } + return Result.success(result); } @Operation(summary = "按班级统计") @GetMapping("/stats/by-class") - public Result>> getStatsByClass() { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(taskService.getStatsByClass(tenantId)); + public Result> getStatsByClass() { + String tenantId = SecurityUtils.getCurrentTenantId(); + List> stats = taskService.getStatsByClass(tenantId); + + List result = new ArrayList<>(); + for (Map item : stats) { + TaskStatsByClassResponse response = new TaskStatsByClassResponse(); + response.setClassId(item.get("classId") != null ? item.get("classId") != null ? item.get("classId").toString() : null : null); + response.setClassName((String) item.get("className")); + response.setGrade((String) item.get("grade")); + response.setTotal(item.get("total") != null ? ((Number) item.get("total")).intValue() : null); + response.setCompleted(item.get("completed") != null ? ((Number) item.get("completed")).intValue() : null); + response.setRate(item.get("rate") != null ? ((Number) item.get("rate")).intValue() : null); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取月度统计趋势") @GetMapping("/stats/monthly") - public Result>> getMonthlyStats( + public Result> getMonthlyStats( @RequestParam(value = "months", required = false, defaultValue = "6") Integer months) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(taskService.getMonthlyStats(tenantId, months)); + String tenantId = SecurityUtils.getCurrentTenantId(); + List> stats = taskService.getMonthlyStats(tenantId, months); + + List result = new ArrayList<>(); + for (Map item : stats) { + MonthlyTaskStatsResponse response = new MonthlyTaskStatsResponse(); + response.setMonth((String) item.get("month")); + response.setTasks(item.get("tasks") != null ? ((Number) item.get("tasks")).intValue() : null); + response.setCompletions(item.get("completions") != null ? ((Number) item.get("completions")).intValue() : null); + response.setCompleted(item.get("completed") != null ? ((Number) item.get("completed")).intValue() : null); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取任务完成情况分页") @GetMapping("/{id}/completions") public Result> getCompletions( - @PathVariable Long id, + @PathVariable String id, @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String status) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = taskService.getTaskCompletions(tenantId, id, pageNum, pageSize, status); return Result.success(PageResult.of(page)); } @@ -113,11 +167,11 @@ public class SchoolTaskController { @Operation(summary = "更新任务完成状态") @PutMapping("/{taskId}/completions/{studentId}") public Result updateCompletion( - @PathVariable Long taskId, - @PathVariable Long studentId, + @PathVariable String taskId, + @PathVariable String studentId, @RequestParam String status, @RequestParam(required = false) String feedback) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(taskService.updateTaskCompletion(tenantId, taskId, studentId, status, feedback)); } @@ -130,46 +184,46 @@ public class SchoolTaskController { @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String type) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = taskService.getTemplatePage(tenantId, pageNum, pageSize, keyword, type); return Result.success(PageResult.of(page)); } @Operation(summary = "根据 ID 获取任务模板") @GetMapping("/task-templates/{id}") - public Result getTemplate(@PathVariable Long id) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + public Result getTemplate(@PathVariable String id) { + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(taskService.getTemplateById(tenantId, id)); } @Operation(summary = "获取默认模板(按类型)") @GetMapping("/task-templates/default/{taskType}") public Result getDefaultTemplate(@PathVariable String taskType) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(taskService.getDefaultTemplate(tenantId, taskType)); } @Operation(summary = "创建任务模板") @PostMapping("/task-templates") public Result createTemplate(@Valid @RequestBody TaskTemplateCreateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Long userId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); return Result.success(taskService.createTemplate(tenantId, userId, request)); } @Operation(summary = "更新任务模板") @PutMapping("/task-templates/{id}") public Result updateTemplate( - @PathVariable Long id, + @PathVariable String id, @RequestBody TaskTemplateUpdateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(taskService.updateTemplate(tenantId, id, request)); } @Operation(summary = "删除任务模板") @DeleteMapping("/task-templates/{id}") - public Result deleteTemplate(@PathVariable Long id) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + public Result deleteTemplate(@PathVariable String id) { + String tenantId = SecurityUtils.getCurrentTenantId(); taskService.deleteTemplate(tenantId, id); return Result.success(); } @@ -177,8 +231,8 @@ public class SchoolTaskController { @Operation(summary = "从模板创建任务") @PostMapping("/from-template") public Result createFromTemplate(@Valid @RequestBody CreateTaskFromTemplateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Long userId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); String role = SecurityUtils.getCurrentRole(); return Result.success(taskService.createTaskFromTemplate(tenantId, userId, role, request)); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTeacherController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTeacherController.java index 9244573..cc9d14e 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTeacherController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTeacherController.java @@ -25,19 +25,19 @@ public class SchoolTeacherController { @Operation(summary = "创建教师") @PostMapping public Result createTeacher(@Valid @RequestBody TeacherCreateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(teacherService.createTeacher(tenantId, request)); } @Operation(summary = "更新教师") @PutMapping("/{id}") - public Result updateTeacher(@PathVariable Long id, @RequestBody TeacherUpdateRequest request) { + public Result updateTeacher(@PathVariable String id, @RequestBody TeacherUpdateRequest request) { return Result.success(teacherService.updateTeacher(id, request)); } @Operation(summary = "根据ID获取教师") @GetMapping("/{id}") - public Result getTeacher(@PathVariable Long id) { + public Result getTeacher(@PathVariable String id) { return Result.success(teacherService.getTeacherById(id)); } @@ -48,21 +48,21 @@ public class SchoolTeacherController { @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String status) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = teacherService.getTeacherPage(tenantId, pageNum, pageSize, keyword, status); return Result.success(PageResult.of(page)); } @Operation(summary = "删除教师") @DeleteMapping("/{id}") - public Result deleteTeacher(@PathVariable Long id) { + public Result deleteTeacher(@PathVariable String id) { teacherService.deleteTeacher(id); return Result.success(); } @Operation(summary = "重置教师密码") @PostMapping("/{id}/reset-password") - public Result resetPassword(@PathVariable Long id, @RequestParam String newPassword) { + public Result resetPassword(@PathVariable String id, @RequestParam String newPassword) { teacherService.resetPassword(id, newPassword); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseController.java index 463f68c..ef8b21e 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseController.java @@ -1,16 +1,22 @@ package com.reading.platform.controller.teacher; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.reading.platform.common.response.PageResult; import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; +import com.reading.platform.dto.response.ClassInfoResponse; +import com.reading.platform.dto.response.StudentInfoResponse; +import com.reading.platform.dto.response.TeacherInfoResponse; import com.reading.platform.entity.Course; +import com.reading.platform.entity.Student; +import com.reading.platform.service.ClassService; import com.reading.platform.service.CourseService; +import com.reading.platform.service.StudentService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.util.ArrayList; import java.util.List; @Tag(name = "教师 - 课程", description = "课程接口(教师专用)") @@ -20,10 +26,12 @@ import java.util.List; public class TeacherCourseController { private final CourseService courseService; + private final ClassService classService; + private final StudentService studentService; - @Operation(summary = "根据ID获取课程") + @Operation(summary = "根据 ID 获取课程") @GetMapping("/{id}") - public Result getCourse(@PathVariable Long id) { + public Result getCourse(@PathVariable String id) { return Result.success(courseService.getCourseById(id)); } @@ -33,17 +41,121 @@ public class TeacherCourseController { @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, - @RequestParam(required = false) String category) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Page page = courseService.getCoursePage(tenantId, pageNum, pageSize, keyword, category, "published"); - return Result.success(PageResult.of(page)); + @RequestParam(required = false) String grade) { + String tenantId = SecurityUtils.getCurrentTenantId(); + return Result.success(PageResult.of(courseService.getCoursePage(tenantId, pageNum, pageSize, keyword, null, "published"))); } @Operation(summary = "获取所有课程") @GetMapping("/all") public Result> getAllCourses() { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(courseService.getCoursesByTenantId(tenantId)); } + @Operation(summary = "获取教师的班级列表") + @GetMapping("/classes") + public Result> getTeacherClasses() { + String tenantId = SecurityUtils.getCurrentTenantId(); + List classes = classService.getClassList(tenantId); + + List result = new ArrayList<>(); + for (com.reading.platform.entity.Clazz clazz : classes) { + ClassInfoResponse response = new ClassInfoResponse(); + response.setId(clazz.getId()); + response.setName(clazz.getName()); + response.setGrade(clazz.getGrade()); + response.setStudentCount(0); + response.setLessonCount(0); + response.setMyRole("MAIN"); + response.setIsPrimary(true); + result.add(response); + } + return Result.success(result); + } + + @Operation(summary = "获取教师所有学生分页") + @GetMapping("/students") + public Result> getTeacherStudents( + @RequestParam(value = "page", required = false) Integer pageNum, + @RequestParam(required = false) Integer pageSize, + @RequestParam(required = false) String keyword) { + + if (pageNum == null) pageNum = 1; + if (pageSize == null) pageSize = 10; + + String tenantId = SecurityUtils.getCurrentTenantId(); + var page = studentService.getStudentPage(tenantId, pageNum, pageSize, keyword, null, null); + + List result = new ArrayList<>(); + for (Student student : page.getRecords()) { + StudentInfoResponse response = new StudentInfoResponse(); + response.setId(student.getId()); + response.setName(student.getName()); + response.setGender(student.getGender()); + response.setBirthDate(student.getBirthDate() != null ? student.getBirthDate().toString() : null); + response.setClassId(student.getClassId()); + + if (student.getClassId() != null) { + var clazz = classService.getClassById(student.getClassId()); + if (clazz != null) { + StudentInfoResponse.ClassSimpleInfo classInfo = new StudentInfoResponse.ClassSimpleInfo(); + classInfo.setId(clazz.getId()); + classInfo.setName(clazz.getName()); + classInfo.setGrade(clazz.getGrade()); + response.setClassInfo(classInfo); + } + } + + response.setParentName(student.getParentName()); + response.setParentPhone(student.getParentPhone()); + response.setCreatedAt(student.getCreatedAt() != null ? student.getCreatedAt().toString() : null); + result.add(response); + } + + return Result.success(PageResult.of(result, page.getTotal(), page.getCurrent(), page.getSize())); + } + + @Operation(summary = "获取班级学生分页") + @GetMapping("/classes/{classId}/students") + public Result> getClassStudents( + @PathVariable String classId, + @RequestParam(value = "page", required = false) Integer pageNum, + @RequestParam(required = false) Integer pageSize, + @RequestParam(required = false) String keyword) { + + var page = classService.getClassStudents(classId, pageNum, pageSize, keyword); + + List result = new ArrayList<>(); + for (Student student : page.getRecords()) { + StudentInfoResponse response = new StudentInfoResponse(); + response.setId(student.getId()); + response.setName(student.getName()); + response.setGender(student.getGender()); + response.setBirthDate(student.getBirthDate() != null ? student.getBirthDate().toString() : null); + response.setParentName(student.getParentName()); + response.setParentPhone(student.getParentPhone()); + response.setLessonCount(student.getLessonCount() != null ? student.getLessonCount() : 0); + response.setReadingCount(student.getReadingCount() != null ? student.getReadingCount() : 0); + response.setCreatedAt(student.getCreatedAt() != null ? student.getCreatedAt().toString() : null); + result.add(response); + } + + return Result.success(PageResult.of(result, page.getTotal(), page.getCurrent(), page.getSize())); + } + + @Operation(summary = "获取班级教师列表") + @GetMapping("/classes/{classId}/teachers") + public Result> getClassTeachers(@PathVariable String classId) { + List result = classService.getClassTeachers(classId).stream().map(ct -> { + TeacherInfoResponse response = new TeacherInfoResponse(); + response.setTeacherId(ct.getTeacherId()); + response.setRole(ct.getRole()); + response.setIsPrimary(ct.getIsPrimary()); + return response; + }).toList(); + + return Result.success(result); + } + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseLessonController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseLessonController.java index 15b2249..61f3ae4 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseLessonController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseLessonController.java @@ -23,13 +23,13 @@ public class TeacherCourseLessonController { @Operation(summary = "获取课程的课时列表") @GetMapping - public Result> getLessons(@PathVariable Long courseId) { + public Result> getLessons(@PathVariable String courseId) { return Result.success(courseLessonService.getLessonsByCourse(courseId)); } @Operation(summary = "根据ID获取课时") @GetMapping("/{id}") - public Result getLesson(@PathVariable Long courseId, @PathVariable Long id) { + public Result getLesson(@PathVariable String courseId, @PathVariable String id) { return Result.success(courseLessonService.getLessonById(id)); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherDashboardController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherDashboardController.java index 3205ba3..3ca2486 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherDashboardController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherDashboardController.java @@ -4,6 +4,8 @@ import com.reading.platform.common.annotation.RequireRole; import com.reading.platform.common.enums.UserRole; import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; +import com.reading.platform.dto.response.LessonSimpleResponse; +import com.reading.platform.dto.response.TeacherDashboardResponse; import com.reading.platform.service.TeacherDashboardService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -12,6 +14,7 @@ import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Map; +import java.util.ArrayList; @Tag(name = "教师 - 仪表盘", description = "教师仪表盘") @RestController @@ -24,25 +27,59 @@ public class TeacherDashboardController { @Operation(summary = "获取教师仪表盘概览") @GetMapping - public Result> getDashboard() { - Long teacherId = SecurityUtils.getCurrentUserId(); - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(teacherDashboardService.getDashboard(teacherId, tenantId)); + public Result getDashboard() { + String teacherId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + Map dashboard = teacherDashboardService.getDashboard(teacherId, tenantId); + + TeacherDashboardResponse response = new TeacherDashboardResponse(); + response.setLessonCount((Integer) dashboard.get("lessonCount")); + response.setTaskCount((Integer) dashboard.get("taskCount")); + response.setGrowthRecordCount((Integer) dashboard.get("growthRecordCount")); + response.setUnreadNotifications((Integer) dashboard.get("unreadNotifications")); + + return Result.success(response); } @Operation(summary = "获取今天课时") @GetMapping("/today") - public Result>> getTodayLessons() { - Long teacherId = SecurityUtils.getCurrentUserId(); - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(teacherDashboardService.getTodayLessons(teacherId, tenantId)); + public Result> getTodayLessons() { + String teacherId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + List> lessons = teacherDashboardService.getTodayLessons(teacherId, tenantId); + + List result = new ArrayList<>(); + for (Map item : lessons) { + LessonSimpleResponse response = new LessonSimpleResponse(); + response.setId(item.get("id") != null ? item.get("id").toString() : null); + response.setTitle((String) item.get("title")); + response.setStartTime(item.get("startTime") != null ? item.get("startTime").toString() : null); + response.setEndTime(item.get("endTime") != null ? item.get("endTime").toString() : null); + response.setLocation((String) item.get("location")); + response.setStatus((String) item.get("status")); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取本周课时") @GetMapping("/weekly") - public Result>> getWeeklyLessons() { - Long teacherId = SecurityUtils.getCurrentUserId(); - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(teacherDashboardService.getWeeklyLessons(teacherId, tenantId)); + public Result> getWeeklyLessons() { + String teacherId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + List> lessons = teacherDashboardService.getWeeklyLessons(teacherId, tenantId); + + List result = new ArrayList<>(); + for (Map item : lessons) { + LessonSimpleResponse response = new LessonSimpleResponse(); + response.setId(item.get("id") != null ? item.get("id").toString() : null); + response.setTitle((String) item.get("title")); + response.setStartTime(item.get("startTime") != null ? item.get("startTime").toString() : null); + response.setEndTime(item.get("endTime") != null ? item.get("endTime").toString() : null); + response.setLocation((String) item.get("location")); + response.setStatus((String) item.get("status")); + result.add(response); + } + return Result.success(result); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherGrowthController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherGrowthController.java index 526b5aa..12ae102 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherGrowthController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherGrowthController.java @@ -25,20 +25,20 @@ public class TeacherGrowthController { @Operation(summary = "创建成长档案") @PostMapping public Result createGrowthRecord(@Valid @RequestBody GrowthRecordCreateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Long userId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); return Result.success(growthRecordService.createGrowthRecord(tenantId, userId, "teacher", request)); } @Operation(summary = "更新成长档案") @PutMapping("/{id}") - public Result updateGrowthRecord(@PathVariable Long id, @RequestBody GrowthRecordUpdateRequest request) { + public Result updateGrowthRecord(@PathVariable String id, @RequestBody GrowthRecordUpdateRequest request) { return Result.success(growthRecordService.updateGrowthRecord(id, request)); } @Operation(summary = "根据ID获取成长档案") @GetMapping("/{id}") - public Result getGrowthRecord(@PathVariable Long id) { + public Result getGrowthRecord(@PathVariable String id) { return Result.success(growthRecordService.getGrowthRecordById(id)); } @@ -47,16 +47,16 @@ public class TeacherGrowthController { public Result> getGrowthRecordPage( @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, - @RequestParam(required = false) Long studentId, + @RequestParam(required = false) String studentId, @RequestParam(required = false) String type) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = growthRecordService.getGrowthRecordPage(tenantId, pageNum, pageSize, studentId, type); return Result.success(PageResult.of(page)); } @Operation(summary = "删除成长档案") @DeleteMapping("/{id}") - public Result deleteGrowthRecord(@PathVariable Long id) { + public Result deleteGrowthRecord(@PathVariable String id) { growthRecordService.deleteGrowthRecord(id); return Result.success(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java index bcd6238..38b6eba 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java @@ -6,7 +6,12 @@ import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; import com.reading.platform.dto.request.LessonCreateRequest; import com.reading.platform.dto.request.LessonUpdateRequest; +import com.reading.platform.dto.response.BatchSaveStudentRecordResponse; +import com.reading.platform.dto.response.StudentRecordListResponse; +import com.reading.platform.dto.response.StudentRecordResponse; import com.reading.platform.entity.Lesson; +import com.reading.platform.entity.LessonFeedback; +import com.reading.platform.entity.StudentRecord; import com.reading.platform.service.LessonService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -16,7 +21,7 @@ import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; import java.time.LocalDate; -import java.util.List; +import java.util.*; @Tag(name = "教师 - 课时", description = "课时接口(教师专用)") @RestController @@ -29,19 +34,19 @@ public class TeacherLessonController { @Operation(summary = "创建课时") @PostMapping public Result createLesson(@Valid @RequestBody LessonCreateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(lessonService.createLesson(tenantId, request)); } @Operation(summary = "更新课时") @PutMapping("/{id}") - public Result updateLesson(@PathVariable Long id, @RequestBody LessonUpdateRequest request) { + public Result updateLesson(@PathVariable String id, @RequestBody LessonUpdateRequest request) { return Result.success(lessonService.updateLesson(id, request)); } @Operation(summary = "根据ID获取课时") @GetMapping("/{id}") - public Result getLesson(@PathVariable Long id) { + public Result getLesson(@PathVariable String id) { return Result.success(lessonService.getLessonById(id)); } @@ -53,28 +58,27 @@ public class TeacherLessonController { @RequestParam(required = false) String status, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) { - Long teacherId = SecurityUtils.getCurrentUserId(); + String teacherId = SecurityUtils.getCurrentUserId(); Page page = lessonService.getTeacherLessons(teacherId, pageNum, pageSize, status, startDate, endDate); return Result.success(PageResult.of(page)); } @Operation(summary = "开始课时") @PostMapping("/{id}/start") - public Result startLesson(@PathVariable Long id) { + public Result startLesson(@PathVariable String id) { lessonService.startLesson(id); return Result.success(); } - @Operation(summary = "Complete lesson") - @PostMapping("/{id}/complete") - public Result completeLesson(@PathVariable Long id) { - lessonService.completeLesson(id); - return Result.success(); + @Operation(summary = "结束课时") + @PostMapping("/{id}/finish") + public Result finishLesson(@PathVariable String id, @RequestBody LessonFinishRequest request) { + return Result.success(lessonService.finishLesson(id, request.getActualDuration(), request.getOverallRating(), request.getParticipationRating(), request.getCompletionNote())); } @Operation(summary = "取消课时") @PostMapping("/{id}/cancel") - public Result cancelLesson(@PathVariable Long id) { + public Result cancelLesson(@PathVariable String id) { lessonService.cancelLesson(id); return Result.success(); } @@ -82,8 +86,178 @@ public class TeacherLessonController { @Operation(summary = "获取今天课时") @GetMapping("/today") public Result> getTodayLessons() { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(lessonService.getTodayLessons(tenantId)); } + @Operation(summary = "保存学生评价记录") + @PostMapping("/{lessonId}/students/{studentId}/record") + public Result saveStudentRecord( + @PathVariable String lessonId, + @PathVariable String studentId, + @RequestBody StudentRecordRequest request) { + return Result.success(lessonService.saveStudentRecord(lessonId, studentId, request.getFocus(), request.getParticipation(), request.getInterest(), request.getUnderstanding(), request.getNotes())); + } + + @Operation(summary = "获取课程所有学生记录") + @GetMapping("/{lessonId}/student-records") + public Result getStudentRecords(@PathVariable String lessonId) { + Lesson lesson = lessonService.getLessonById(lessonId); + List records = lessonService.getStudentRecords(lessonId); + + StudentRecordListResponse response = new StudentRecordListResponse(); + + StudentRecordListResponse.LessonSimpleInfo lessonInfo = new StudentRecordListResponse.LessonSimpleInfo(); + lessonInfo.setId(lesson.getId()); + lessonInfo.setStatus(lesson.getStatus()); + lessonInfo.setClassName(""); // TODO: 需要关联班级表获取班级名称 + response.setLesson(lessonInfo); + + List studentRecords = new ArrayList<>(); + for (StudentRecord record : records) { + StudentRecordResponse item = new StudentRecordResponse(); + item.setId(record.getId()); + item.setStudentId(record.getStudentId()); + item.setFocus(record.getFocus()); + item.setParticipation(record.getParticipation()); + item.setInterest(record.getInterest()); + item.setUnderstanding(record.getUnderstanding()); + item.setNotes(record.getNotes()); + studentRecords.add(item); + } + response.setStudents(studentRecords); + + return Result.success(response); + } + + @Operation(summary = "批量保存学生评价记录") + @PostMapping("/{lessonId}/student-records/batch") + public Result batchSaveStudentRecords( + @PathVariable String lessonId, + @RequestBody BatchStudentRecordRequest request) { + int count = lessonService.batchSaveStudentRecords(lessonId, request.getRecords()); + + List records = lessonService.getStudentRecords(lessonId); + List studentRecords = new ArrayList<>(); + for (StudentRecord record : records) { + StudentRecordResponse item = new StudentRecordResponse(); + item.setId(record.getId()); + item.setStudentId(record.getStudentId()); + item.setFocus(record.getFocus()); + item.setParticipation(record.getParticipation()); + item.setInterest(record.getInterest()); + item.setUnderstanding(record.getUnderstanding()); + item.setNotes(record.getNotes()); + studentRecords.add(item); + } + + BatchSaveStudentRecordResponse response = new BatchSaveStudentRecordResponse(); + response.setCount(count); + response.setRecords(studentRecords); + return Result.success(response); + } + + @Operation(summary = "提交课程反馈") + @PostMapping("/{lessonId}/feedback") + public Result submitFeedback( + @PathVariable String lessonId, + @RequestBody LessonFeedbackRequest request) { + String tenantId = SecurityUtils.getCurrentTenantId(); + String teacherId = SecurityUtils.getCurrentUserId(); + Map feedbackData = new HashMap<>(); + feedbackData.put("designQuality", request.getDesignQuality()); + feedbackData.put("participation", request.getParticipation()); + feedbackData.put("goalAchievement", request.getGoalAchievement()); + feedbackData.put("stepFeedbacks", request.getStepFeedbacks() != null ? request.getStepFeedbacks().toString() : null); + feedbackData.put("pros", request.getPros()); + feedbackData.put("suggestions", request.getSuggestions()); + feedbackData.put("activitiesDone", request.getActivitiesDone() != null ? request.getActivitiesDone().toString() : null); + return Result.success(lessonService.saveLessonFeedback(tenantId, lessonId, teacherId, feedbackData)); + } + + @Operation(summary = "获取课程反馈") + @GetMapping("/{lessonId}/feedback") + public Result getFeedback(@PathVariable String lessonId) { + return Result.success(lessonService.getLessonFeedback(lessonId)); + } + + /** + * 课程结束请求 DTO + */ + public static class LessonFinishRequest { + private Integer actualDuration; + private String overallRating; + private String participationRating; + private String completionNote; + + public Integer getActualDuration() { return actualDuration; } + public void setActualDuration(Integer actualDuration) { this.actualDuration = actualDuration; } + public String getOverallRating() { return overallRating; } + public void setOverallRating(String overallRating) { this.overallRating = overallRating; } + public String getParticipationRating() { return participationRating; } + public void setParticipationRating(String participationRating) { this.participationRating = participationRating; } + public String getCompletionNote() { return completionNote; } + public void setCompletionNote(String completionNote) { this.completionNote = completionNote; } + } + + /** + * 学生记录请求 DTO + */ + public static class StudentRecordRequest { + private Integer focus; + private Integer participation; + private Integer interest; + private Integer understanding; + private String notes; + + public Integer getFocus() { return focus; } + public void setFocus(Integer focus) { this.focus = focus; } + public Integer getParticipation() { return participation; } + public void setParticipation(Integer participation) { this.participation = participation; } + public Integer getInterest() { return interest; } + public void setInterest(Integer interest) { this.interest = interest; } + public Integer getUnderstanding() { return understanding; } + public void setUnderstanding(Integer understanding) { this.understanding = understanding; } + public String getNotes() { return notes; } + public void setNotes(String notes) { this.notes = notes; } + } + + /** + * 批量学生记录请求 DTO + */ + public static class BatchStudentRecordRequest { + private List> records; + + public List> getRecords() { return records; } + public void setRecords(List> records) { this.records = records; } + } + + /** + * 课程反馈请求 DTO + */ + public static class LessonFeedbackRequest { + private Integer designQuality; + private Integer participation; + private Integer goalAchievement; + private Object stepFeedbacks; + private String pros; + private String suggestions; + private Object activitiesDone; + + public Integer getDesignQuality() { return designQuality; } + public void setDesignQuality(Integer designQuality) { this.designQuality = designQuality; } + public Integer getParticipation() { return participation; } + public void setParticipation(Integer participation) { this.participation = participation; } + public Integer getGoalAchievement() { return goalAchievement; } + public void setGoalAchievement(Integer goalAchievement) { this.goalAchievement = goalAchievement; } + public Object getStepFeedbacks() { return stepFeedbacks; } + public void setStepFeedbacks(Object stepFeedbacks) { this.stepFeedbacks = stepFeedbacks; } + public String getPros() { return pros; } + public void setPros(String pros) { this.pros = pros; } + public String getSuggestions() { return suggestions; } + public void setSuggestions(String suggestions) { this.suggestions = suggestions; } + public Object getActivitiesDone() { return activitiesDone; } + public void setActivitiesDone(Object activitiesDone) { this.activitiesDone = activitiesDone; } + } + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherNotificationController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherNotificationController.java index ed39041..87e89e1 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherNotificationController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherNotificationController.java @@ -21,7 +21,7 @@ public class TeacherNotificationController { @Operation(summary = "根据ID获取通知") @GetMapping("/{id}") - public Result getNotification(@PathVariable Long id) { + public Result getNotification(@PathVariable String id) { return Result.success(notificationService.getNotificationById(id)); } @@ -31,14 +31,14 @@ public class TeacherNotificationController { @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) Integer isRead) { - Long userId = SecurityUtils.getCurrentUserId(); + String userId = SecurityUtils.getCurrentUserId(); Page page = notificationService.getMyNotifications(userId, "teacher", pageNum, pageSize, isRead); return Result.success(PageResult.of(page)); } @Operation(summary = "标记通知为已读") @PostMapping("/{id}/read") - public Result markAsRead(@PathVariable Long id) { + public Result markAsRead(@PathVariable String id) { notificationService.markAsRead(id); return Result.success(); } @@ -46,7 +46,7 @@ public class TeacherNotificationController { @Operation(summary = "标记所有通知为已读") @PostMapping("/read-all") public Result markAllAsRead() { - Long userId = SecurityUtils.getCurrentUserId(); + String userId = SecurityUtils.getCurrentUserId(); notificationService.markAllAsRead(userId, "teacher"); return Result.success(); } @@ -54,7 +54,7 @@ public class TeacherNotificationController { @Operation(summary = "获取未读通知数量") @GetMapping("/unread-count") public Result getUnreadCount() { - Long userId = SecurityUtils.getCurrentUserId(); + String userId = SecurityUtils.getCurrentUserId(); return Result.success(notificationService.getUnreadCount(userId, "teacher")); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherScheduleController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherScheduleController.java index 48c04b8..5c88ca0 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherScheduleController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherScheduleController.java @@ -1,23 +1,31 @@ package com.reading.platform.controller.teacher; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.reading.platform.common.annotation.RequireRole; -import com.reading.platform.common.enums.UserRole; import com.reading.platform.common.response.PageResult; import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; +import com.reading.platform.dto.response.MessageResponse; +import com.reading.platform.dto.response.SchedulePlanResponse; +import com.reading.platform.dto.request.SchedulePlanCreateRequest; +import com.reading.platform.dto.request.SchedulePlanUpdateRequest; import com.reading.platform.entity.SchedulePlan; import com.reading.platform.service.ScheduleService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + @Tag(name = "教师 - 课表", description = "教师课表视图") @RestController @RequestMapping("/api/v1/teacher/schedules") @RequiredArgsConstructor -@RequireRole(UserRole.TEACHER) public class TeacherScheduleController { private final ScheduleService scheduleService; @@ -27,14 +35,88 @@ public class TeacherScheduleController { public Result> getSchedulePlans( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "20") int pageSize) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Page page = scheduleService.getSchedulePlans(pageNum, pageSize, tenantId, null); + String tenantId = SecurityUtils.getCurrentTenantId(); + var page = scheduleService.getSchedulePlans(pageNum, pageSize, tenantId, null); return Result.success(PageResult.of(page)); } - @Operation(summary = "根据ID获取课表计划") + @Operation(summary = "根据 ID 获取课表计划") @GetMapping("/{id}") - public Result getSchedulePlan(@PathVariable Long id) { + public Result getSchedulePlan(@PathVariable String id) { return Result.success(scheduleService.getSchedulePlanById(id)); } + + @Operation(summary = "获取课表(按日期范围)") + @GetMapping("/timetable") + public Result> getTimetable( + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) { + String tenantId = SecurityUtils.getCurrentTenantId(); + List> timetable = scheduleService.getTimetable(tenantId, startDate, endDate, null); + + List result = new ArrayList<>(); + for (Map item : timetable) { + SchedulePlanResponse response = new SchedulePlanResponse(); + response.setId(item.get("id") != null ? item.get("id") != null ? item.get("id").toString() : null : null); + response.setName((String) item.get("name")); + response.setClassName((String) item.get("className")); + response.setCourseName((String) item.get("courseName")); + response.setTeacherName((String) item.get("teacherName")); + result.add(response); + } + return Result.success(result); + } + + @Operation(summary = "获取今日课表") + @GetMapping("/today") + public Result> getTodaySchedules() { + String tenantId = SecurityUtils.getCurrentTenantId(); + var page = scheduleService.getSchedulePlans(1, 50, tenantId, null, LocalDate.now(), LocalDate.now()); + return Result.success(page.getRecords()); + } + + @Operation(summary = "创建课表计划") + @PostMapping + public Result createSchedulePlan(@Valid @RequestBody SchedulePlanCreateRequest request) { + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); + return Result.success(scheduleService.createSchedulePlan(tenantId, userId, request)); + } + + @Operation(summary = "更新课表计划") + @PutMapping("/{id}") + public Result updateSchedulePlan( + @PathVariable String id, + @RequestBody SchedulePlanUpdateRequest request) { + SchedulePlan plan = scheduleService.getSchedulePlanById(id); + + if (request.getStartDate() != null) { + plan.setStartDate(request.getStartDate()); + } + if (request.getEndDate() != null) { + plan.setEndDate(request.getEndDate()); + } + if (request.getStartTime() != null) { + plan.setStartTime(request.getStartTime()); + } + if (request.getEndTime() != null) { + plan.setEndTime(request.getEndTime()); + } + if (request.getStatus() != null) { + plan.setStatus(request.getStatus()); + } + if (request.getNote() != null) { + plan.setNote(request.getNote()); + } + + return Result.success(scheduleService.updateSchedulePlan(id, plan)); + } + + @Operation(summary = "取消课表计划") + @DeleteMapping("/{id}") + public Result cancelSchedulePlan(@PathVariable String id) { + scheduleService.deleteSchedulePlan(id); + return Result.success(MessageResponse.of("取消成功")); + } + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherSchoolCourseController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherSchoolCourseController.java index 92a0392..5d1f90e 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherSchoolCourseController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherSchoolCourseController.java @@ -28,14 +28,14 @@ public class TeacherSchoolCourseController { @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "20") int pageSize, @RequestParam(required = false) String keyword) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = schoolCourseService.getCourses(pageNum, pageSize, tenantId, keyword); return Result.success(PageResult.of(page)); } @Operation(summary = "根据ID获取校本课程") @GetMapping("/{id}") - public Result getCourse(@PathVariable Long id) { + public Result getCourse(@PathVariable String id) { return Result.success(schoolCourseService.getCourseById(id)); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherTaskController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherTaskController.java index c260887..34c5772 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherTaskController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherTaskController.java @@ -5,6 +5,10 @@ import com.reading.platform.common.response.PageResult; import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; import com.reading.platform.dto.request.*; +import com.reading.platform.dto.response.TaskStatsResponse; +import com.reading.platform.dto.response.TaskStatsByClassResponse; +import com.reading.platform.dto.response.TaskStatsByTypeResponse; +import com.reading.platform.dto.response.MonthlyTaskStatsResponse; import com.reading.platform.entity.Task; import com.reading.platform.entity.TaskCompletion; import com.reading.platform.entity.TaskTemplate; @@ -17,6 +21,8 @@ import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Map; +import java.util.ArrayList; +import java.util.ArrayList; @Tag(name = "教师 - 任务", description = "任务接口(教师专用)") @RestController @@ -29,20 +35,20 @@ public class TeacherTaskController { @Operation(summary = "创建任务") @PostMapping public Result createTask(@Valid @RequestBody TaskCreateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Long userId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); return Result.success(taskService.createTask(tenantId, userId, "teacher", request)); } @Operation(summary = "更新任务") @PutMapping("/{id}") - public Result updateTask(@PathVariable Long id, @RequestBody TaskUpdateRequest request) { + public Result updateTask(@PathVariable String id, @RequestBody TaskUpdateRequest request) { return Result.success(taskService.updateTask(id, request)); } @Operation(summary = "根据 ID 获取任务") @GetMapping("/{id}") - public Result getTask(@PathVariable Long id) { + public Result getTask(@PathVariable String id) { return Result.success(taskService.getTaskById(id)); } @@ -54,14 +60,14 @@ public class TeacherTaskController { @RequestParam(required = false) String keyword, @RequestParam(required = false) String type, @RequestParam(required = false) String status) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = taskService.getTaskPage(tenantId, pageNum, pageSize, keyword, type, status); return Result.success(PageResult.of(page)); } @Operation(summary = "删除任务") @DeleteMapping("/{id}") - public Result deleteTask(@PathVariable Long id) { + public Result deleteTask(@PathVariable String id) { taskService.deleteTask(id); return Result.success(); } @@ -70,41 +76,90 @@ public class TeacherTaskController { @Operation(summary = "获取任务统计数据") @GetMapping("/stats") - public Result> getStats() { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(taskService.getTaskStats(tenantId)); + public Result getStats() { + String tenantId = SecurityUtils.getCurrentTenantId(); + Map stats = taskService.getTaskStats(tenantId); + + TaskStatsResponse response = new TaskStatsResponse(); + response.setTotalTasks((Integer) stats.get("totalTasks")); + response.setPublishedTasks((Integer) stats.get("publishedTasks")); + response.setCompletedTasks((Integer) stats.get("completedTasks")); + response.setInProgressTasks((Integer) stats.get("inProgressTasks")); + response.setPendingCount((Integer) stats.get("pendingCount")); + response.setTotalCompletions((Integer) stats.get("totalCompletions")); + response.setCompletionRate((Integer) stats.get("completionRate")); + + return Result.success(response); } @Operation(summary = "按任务类型统计") @GetMapping("/stats/by-type") - public Result> getStatsByType() { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(taskService.getStatsByType(tenantId)); + public Result> getStatsByType() { + String tenantId = SecurityUtils.getCurrentTenantId(); + Map stats = taskService.getStatsByType(tenantId); + + List result = new ArrayList<>(); + for (Map.Entry entry : stats.entrySet()) { + TaskStatsByTypeResponse response = new TaskStatsByTypeResponse(); + response.setType(entry.getKey()); + if (entry.getValue() instanceof Map) { + Map typeData = (Map) entry.getValue(); + response.setTotal(typeData.get("total") != null ? ((Number) typeData.get("total")).intValue() : null); + response.setCompleted(typeData.get("completed") != null ? ((Number) typeData.get("completed")).intValue() : null); + response.setRate(typeData.get("rate") != null ? ((Number) typeData.get("rate")).intValue() : null); + } + result.add(response); + } + return Result.success(result); } @Operation(summary = "按班级统计") @GetMapping("/stats/by-class") - public Result>> getStatsByClass() { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(taskService.getStatsByClass(tenantId)); + public Result> getStatsByClass() { + String tenantId = SecurityUtils.getCurrentTenantId(); + List> stats = taskService.getStatsByClass(tenantId); + + List result = new ArrayList<>(); + for (Map item : stats) { + TaskStatsByClassResponse response = new TaskStatsByClassResponse(); + response.setClassId(item.get("classId") != null ? item.get("classId").toString() : null); + response.setClassName((String) item.get("className")); + response.setGrade((String) item.get("grade")); + response.setTotal(item.get("total") != null ? ((Number) item.get("total")).intValue() : null); + response.setCompleted(item.get("completed") != null ? ((Number) item.get("completed")).intValue() : null); + response.setRate(item.get("rate") != null ? ((Number) item.get("rate")).intValue() : null); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取月度统计趋势") @GetMapping("/stats/monthly") - public Result>> getMonthlyStats( + public Result> getMonthlyStats( @RequestParam(value = "months", required = false, defaultValue = "6") Integer months) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - return Result.success(taskService.getMonthlyStats(tenantId, months)); + String tenantId = SecurityUtils.getCurrentTenantId(); + List> stats = taskService.getMonthlyStats(tenantId, months); + + List result = new ArrayList<>(); + for (Map item : stats) { + MonthlyTaskStatsResponse response = new MonthlyTaskStatsResponse(); + response.setMonth((String) item.get("month")); + response.setTasks(item.get("tasks") != null ? ((Number) item.get("tasks")).intValue() : null); + response.setCompletions(item.get("completions") != null ? ((Number) item.get("completions")).intValue() : null); + response.setCompleted(item.get("completed") != null ? ((Number) item.get("completed")).intValue() : null); + result.add(response); + } + return Result.success(result); } @Operation(summary = "获取任务完成情况分页") @GetMapping("/{id}/completions") public Result> getCompletions( - @PathVariable Long id, + @PathVariable String id, @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String status) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = taskService.getTaskCompletions(tenantId, id, pageNum, pageSize, status); return Result.success(PageResult.of(page)); } @@ -112,11 +167,11 @@ public class TeacherTaskController { @Operation(summary = "更新任务完成状态") @PutMapping("/{taskId}/completions/{studentId}") public Result updateCompletion( - @PathVariable Long taskId, - @PathVariable Long studentId, + @PathVariable String taskId, + @PathVariable String studentId, @RequestParam String status, @RequestParam(required = false) String feedback) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(taskService.updateTaskCompletion(tenantId, taskId, studentId, status, feedback)); } @@ -129,30 +184,30 @@ public class TeacherTaskController { @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String type) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); Page page = taskService.getTemplatePage(tenantId, pageNum, pageSize, keyword, type); return Result.success(PageResult.of(page)); } @Operation(summary = "根据 ID 获取任务模板") @GetMapping("/task-templates/{id}") - public Result getTemplate(@PathVariable Long id) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + public Result getTemplate(@PathVariable String id) { + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(taskService.getTemplateById(tenantId, id)); } @Operation(summary = "获取默认模板(按类型)") @GetMapping("/task-templates/default/{taskType}") public Result getDefaultTemplate(@PathVariable String taskType) { - Long tenantId = SecurityUtils.getCurrentTenantId(); + String tenantId = SecurityUtils.getCurrentTenantId(); return Result.success(taskService.getDefaultTemplate(tenantId, taskType)); } @Operation(summary = "从模板创建任务") @PostMapping("/from-template") public Result createFromTemplate(@Valid @RequestBody CreateTaskFromTemplateRequest request) { - Long tenantId = SecurityUtils.getCurrentTenantId(); - Long userId = SecurityUtils.getCurrentUserId(); + String tenantId = SecurityUtils.getCurrentTenantId(); + String userId = SecurityUtils.getCurrentUserId(); return Result.success(taskService.createTaskFromTemplate(tenantId, userId, "teacher", request)); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/AdminSettingsUpdateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/AdminSettingsUpdateRequest.java new file mode 100644 index 0000000..d015897 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/AdminSettingsUpdateRequest.java @@ -0,0 +1,81 @@ +package com.reading.platform.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 管理员设置更新请求 + */ +@Data +@Schema(description = "管理员设置更新请求") +public class AdminSettingsUpdateRequest { + + @Schema(description = "系统名称") + private String systemName; + + @Schema(description = "系统描述") + private String systemDesc; + + @Schema(description = "联系电话") + private String contactPhone; + + @Schema(description = "联系邮箱") + private String contactEmail; + + @Schema(description = "系统 Logo") + private String systemLogo; + + @Schema(description = "密码强度") + private String passwordStrength; + + @Schema(description = "最大登录尝试次数") + private Integer maxLoginAttempts; + + @Schema(description = "Token 过期时间") + private String tokenExpire; + + @Schema(description = "强制 HTTPS") + private Boolean forceHttps; + + @Schema(description = "邮箱启用") + private Boolean emailEnabled; + + @Schema(description = "SMTP 主机") + private String smtpHost; + + @Schema(description = "SMTP 端口") + private Integer smtpPort; + + @Schema(description = "SMTP 用户") + private String smtpUser; + + @Schema(description = "SMTP 密码") + private String smtpPassword; + + @Schema(description = "发件人邮箱") + private String fromEmail; + + @Schema(description = "短信启用") + private Boolean smsEnabled; + + @Schema(description = "存储类型") + private String storageType; + + @Schema(description = "最大文件大小") + private Integer maxFileSize; + + @Schema(description = "允许的文件类型") + private String allowedTypes; + + @Schema(description = "默认教师配额") + private Integer defaultTeacherQuota; + + @Schema(description = "默认学生配额") + private Integer defaultStudentQuota; + + @Schema(description = "启用自动过期") + private Boolean enableAutoExpire; + + @Schema(description = "提前通知天数") + private Integer notifyBeforeDays; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/CourseCreateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/CourseCreateRequest.java index 4f32a90..e957883 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/request/CourseCreateRequest.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/CourseCreateRequest.java @@ -83,7 +83,7 @@ public class CourseCreateRequest { // 主题与绘本 @Schema(description = "主题ID") - private Long themeId; + private String themeId; @Schema(description = "绘本名称") private String pictureBookName; diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/CourseUpdateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/CourseUpdateRequest.java index b59375e..5071fb0 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/request/CourseUpdateRequest.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/CourseUpdateRequest.java @@ -82,7 +82,7 @@ public class CourseUpdateRequest { // 主题与绘本 @Schema(description = "主题ID") - private Long themeId; + private String themeId; @Schema(description = "绘本名称") private String pictureBookName; diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/CreateTaskFromTemplateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/CreateTaskFromTemplateRequest.java index b1dd282..85c7d8b 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/request/CreateTaskFromTemplateRequest.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/CreateTaskFromTemplateRequest.java @@ -15,11 +15,11 @@ import java.util.List; public class CreateTaskFromTemplateRequest { @Schema(description = "模板 ID") - private Long templateId; + private String templateId; @Schema(description = "目标 ID 列表(班级 ID 或学生 ID)") @NotEmpty(message = "目标 ID 列表不能为空") - private List targetIds; + private List targetIds; @Schema(description = "目标类型:CLASS-班级,STUDENT-学生") private String targetType = "CLASS"; diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/GrowthRecordCreateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/GrowthRecordCreateRequest.java index 3ddae6a..a3aac61 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/request/GrowthRecordCreateRequest.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/GrowthRecordCreateRequest.java @@ -14,7 +14,7 @@ public class GrowthRecordCreateRequest { @NotNull(message = "Student ID is required") @Schema(description = "Student ID") - private Long studentId; + private String studentId; @NotBlank(message = "Type is required") @Schema(description = "Type: reading, behavior, achievement, milestone") diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/LessonCreateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/LessonCreateRequest.java index edc0f2c..d878252 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/request/LessonCreateRequest.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/LessonCreateRequest.java @@ -14,14 +14,14 @@ public class LessonCreateRequest { @NotNull(message = "课程ID不能为空") @Schema(description = "课程ID") - private Long courseId; + private String courseId; @Schema(description = "班级ID") - private Long classId; + private String classId; @NotNull(message = "教师ID不能为空") @Schema(description = "教师ID") - private Long teacherId; + private String teacherId; @NotBlank(message = "标题不能为空") @Schema(description = "课时标题") diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/SchedulePlanCreateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/SchedulePlanCreateRequest.java index 935381d..bbc02d0 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/request/SchedulePlanCreateRequest.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/SchedulePlanCreateRequest.java @@ -15,10 +15,10 @@ import java.time.LocalTime; public class SchedulePlanCreateRequest { @Schema(description = "班级 ID") - private Long classId; + private String classId; @Schema(description = "课程 ID") - private Long courseId; + private String courseId; @Schema(description = "星期几:1-7") private Integer dayOfWeek; @@ -33,7 +33,7 @@ public class SchedulePlanCreateRequest { private LocalTime endTime; @Schema(description = "授课教师 ID") - private Long teacherId; + private String teacherId; @Schema(description = "开始日期") private LocalDate startDate; diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/SchedulePlanUpdateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/SchedulePlanUpdateRequest.java new file mode 100644 index 0000000..184e5c1 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/SchedulePlanUpdateRequest.java @@ -0,0 +1,36 @@ +package com.reading.platform.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalTime; + +/** + * 课表计划更新请求 + */ +@Data +@Schema(description = "课表计划更新请求") +public class SchedulePlanUpdateRequest { + + @Schema(description = "授课教师 ID") + private String teacherId; + + @Schema(description = "开始日期") + private LocalDate startDate; + + @Schema(description = "结束日期") + private LocalDate endDate; + + @Schema(description = "开始时间") + private LocalTime startTime; + + @Schema(description = "结束时间") + private LocalTime endTime; + + @Schema(description = "状态") + private String status; + + @Schema(description = "备注") + private String note; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/ScheduleTemplateApplyRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/ScheduleTemplateApplyRequest.java index bd533f9..65d7c66 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/request/ScheduleTemplateApplyRequest.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/ScheduleTemplateApplyRequest.java @@ -15,7 +15,7 @@ public class ScheduleTemplateApplyRequest { @NotNull(message = "班级 ID 不能为空") @Schema(description = "班级 ID") - private Long classId; + private String classId; @NotNull(message = "开始日期不能为空") @Schema(description = "应用开始日期") diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/SchoolSettingsUpdateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/SchoolSettingsUpdateRequest.java new file mode 100644 index 0000000..27b3203 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/SchoolSettingsUpdateRequest.java @@ -0,0 +1,30 @@ +package com.reading.platform.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 学校设置更新请求 + */ +@Data +@Schema(description = "学校设置更新请求") +public class SchoolSettingsUpdateRequest { + + @Schema(description = "学校名称") + private String schoolName; + + @Schema(description = "学校 Logo") + private String schoolLogo; + + @Schema(description = "地址") + private String address; + + @Schema(description = "课时通知启用") + private Boolean notifyOnLesson; + + @Schema(description = "任务通知启用") + private Boolean notifyOnTask; + + @Schema(description = "成长记录通知启用") + private Boolean notifyOnGrowth; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/TaskCreateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TaskCreateRequest.java index 68aa6a1..a7644be 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/request/TaskCreateRequest.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TaskCreateRequest.java @@ -22,7 +22,7 @@ public class TaskCreateRequest { private String type; @Schema(description = "课程ID") - private Long courseId; + private String courseId; @Schema(description = "开始日期") private LocalDate startDate; @@ -37,6 +37,6 @@ public class TaskCreateRequest { private String targetType; @Schema(description = "目标ID列表") - private List targetIds; + private List targetIds; } diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/TaskFeedbackUpdateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TaskFeedbackUpdateRequest.java new file mode 100644 index 0000000..8dcc7ea --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TaskFeedbackUpdateRequest.java @@ -0,0 +1,15 @@ +package com.reading.platform.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 任务家长反馈更新请求 + */ +@Data +@Schema(description = "任务家长反馈更新请求") +public class TaskFeedbackUpdateRequest { + + @Schema(description = "家长反馈内容") + private String feedback; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantQuotaUpdateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantQuotaUpdateRequest.java new file mode 100644 index 0000000..2e1c020 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantQuotaUpdateRequest.java @@ -0,0 +1,21 @@ +package com.reading.platform.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 租户配额更新请求 + */ +@Data +@Schema(description = "租户配额更新请求") +public class TenantQuotaUpdateRequest { + + @Schema(description = "套餐类型") + private String packageType; + + @Schema(description = "教师配额") + private Integer teacherQuota; + + @Schema(description = "学生配额") + private Integer studentQuota; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantStatusUpdateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantStatusUpdateRequest.java new file mode 100644 index 0000000..79d3faf --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantStatusUpdateRequest.java @@ -0,0 +1,15 @@ +package com.reading.platform.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 租户状态更新请求 + */ +@Data +@Schema(description = "租户状态更新请求") +public class TenantStatusUpdateRequest { + + @Schema(description = "状态:active/inactive") + private String status; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/ActiveTeacherStatsResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ActiveTeacherStatsResponse.java new file mode 100644 index 0000000..860d308 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ActiveTeacherStatsResponse.java @@ -0,0 +1,21 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 活跃教师统计响应 + */ +@Data +@Schema(description = "活跃教师统计响应") +public class ActiveTeacherStatsResponse { + + @Schema(description = "教师 ID", example = "1") + private String id; + + @Schema(description = "教师姓名", example = "李老师") + private String name; + + @Schema(description = "课时数", example = "50") + private Integer lessonCount; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/AdminStatsResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/AdminStatsResponse.java new file mode 100644 index 0000000..2997b51 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/AdminStatsResponse.java @@ -0,0 +1,36 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 管理员统计数据响应 + */ +@Data +@Schema(description = "管理员统计数据响应") +public class AdminStatsResponse { + + @Schema(description = "租户总数", example = "50") + private Integer tenantCount; + + @Schema(description = "活跃租户数", example = "45") + private Integer activeTenantCount; + + @Schema(description = "教师总数", example = "500") + private Integer teacherCount; + + @Schema(description = "学生总数", example = "5000") + private Integer studentCount; + + @Schema(description = "课程总数", example = "200") + private Integer courseCount; + + @Schema(description = "已发布课程数", example = "180") + private Integer publishedCourseCount; + + @Schema(description = "课时总数", example = "10000") + private Integer lessonCount; + + @Schema(description = "本月课时数", example = "1500") + private Integer monthlyLessons; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/BatchSaveStudentRecordResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/BatchSaveStudentRecordResponse.java new file mode 100644 index 0000000..bfd2dee --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/BatchSaveStudentRecordResponse.java @@ -0,0 +1,18 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 批量保存学生记录响应 + */ +@Data +@Schema(description = "批量保存学生记录响应") +public class BatchSaveStudentRecordResponse { + + @Schema(description = "保存数量", example = "30") + private Integer count; + + @Schema(description = "学生记录列表") + private java.util.List records; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/ChildDetailResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ChildDetailResponse.java new file mode 100644 index 0000000..49fc362 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ChildDetailResponse.java @@ -0,0 +1,67 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 孩子详情响应 + */ +@Data +@Schema(description = "孩子详情响应") +public class ChildDetailResponse { + + @Schema(description = "孩子 ID", example = "1") + private String id; + + @Schema(description = "孩子姓名", example = "张三") + private String name; + + @Schema(description = "性别", example = "male") + private String gender; + + @Schema(description = "出生日期", example = "2018-01-01") + private String birthDate; + + @Schema(description = "阅读次数", example = "10") + private Integer readingCount; + + @Schema(description = "课时数", example = "20") + private Integer lessonCount; + + @Schema(description = "统计信息") + private ChildStats stats; + + @Schema(description = "班级信息") + private ClassInfo classInfo; + + @Schema(description = "关系", example = "parent") + private String relationship; + + /** + * 统计信息内部类 + */ + @Data + @Schema(description = "孩子统计信息") + public static class ChildStats { + @Schema(description = "课时记录数", example = "20") + private Integer lessonRecords; + @Schema(description = "成长记录数", example = "5") + private Integer growthRecords; + @Schema(description = "任务完成数", example = "15") + private Integer taskCompletions; + } + + /** + * 班级信息内部类 + */ + @Data + @Schema(description = "班级信息") + public static class ClassInfo { + @Schema(description = "班级 ID") + private String id; + @Schema(description = "班级名称") + private String name; + @Schema(description = "年级") + private String grade; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/ChildInfoResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ChildInfoResponse.java new file mode 100644 index 0000000..55c04bf --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ChildInfoResponse.java @@ -0,0 +1,50 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 孩子信息响应 + */ +@Data +@Schema(description = "孩子信息响应") +public class ChildInfoResponse { + + @Schema(description = "孩子 ID", example = "1") + private String id; + + @Schema(description = "孩子姓名", example = "张三") + private String name; + + @Schema(description = "性别", example = "male") + private String gender; + + @Schema(description = "出生日期", example = "2018-01-01") + private String birthDate; + + @Schema(description = "阅读次数", example = "10") + private Integer readingCount; + + @Schema(description = "课时数", example = "20") + private Integer lessonCount; + + @Schema(description = "班级信息") + private ClassInfo classInfo; + + @Schema(description = "关系", example = "parent") + private String relationship; + + /** + * 班级信息内部类 + */ + @Data + @Schema(description = "班级信息") + public static class ClassInfo { + @Schema(description = "班级 ID") + private String id; + @Schema(description = "班级名称") + private String name; + @Schema(description = "年级") + private String grade; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/ClassInfoResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ClassInfoResponse.java new file mode 100644 index 0000000..74a531a --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ClassInfoResponse.java @@ -0,0 +1,33 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 班级信息响应 + */ +@Data +@Schema(description = "班级信息响应") +public class ClassInfoResponse { + + @Schema(description = "班级 ID", example = "1") + private String id; + + @Schema(description = "班级名称", example = "大一班") + private String name; + + @Schema(description = "年级", example = "大班") + private String grade; + + @Schema(description = "学生数量", example = "30") + private Integer studentCount; + + @Schema(description = "课时数量", example = "50") + private Integer lessonCount; + + @Schema(description = "我的角色", example = "MAIN") + private String myRole; + + @Schema(description = "是否主教", example = "true") + private Boolean isPrimary; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/CommonPageResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/CommonPageResponse.java new file mode 100644 index 0000000..2e6a87e --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/CommonPageResponse.java @@ -0,0 +1,36 @@ +package com.reading.platform.dto.response; + +import com.reading.platform.entity.Lesson; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 分页响应(通用) + */ +@Data +@Schema(description = "分页响应") +public class CommonPageResponse { + + @Schema(description = "数据列表") + private List items; + + @Schema(description = "总数", example = "100") + private Long total; + + @Schema(description = "当前页码", example = "1") + private Integer page; + + @Schema(description = "每页大小", example = "10") + private Integer pageSize; + + public static CommonPageResponse of(List items, Long total, Integer page, Integer pageSize) { + CommonPageResponse response = new CommonPageResponse<>(); + response.setItems(items); + response.setTotal(total); + response.setPage(page); + response.setPageSize(pageSize); + return response; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseDistributionResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseDistributionResponse.java new file mode 100644 index 0000000..532cb09 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseDistributionResponse.java @@ -0,0 +1,18 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 课程分布响应 + */ +@Data +@Schema(description = "课程分布响应") +public class CourseDistributionResponse { + + @Schema(description = "课程名称", example = "绘本阅读入门") + private String name; + + @Schema(description = "课时数量", example = "20") + private Integer value; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseResponse.java index 5b2600f..a65076f 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseResponse.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseResponse.java @@ -14,10 +14,10 @@ import java.time.LocalDateTime; public class CourseResponse { @Schema(description = "课程ID") - private Long id; + private String id; @Schema(description = "租户ID") - private Long tenantId; + private String tenantId; @Schema(description = "课程名称") private String name; @@ -157,7 +157,7 @@ public class CourseResponse { private String version; @Schema(description = "父ID") - private Long parentId; + private String parentId; @Schema(description = "是否最新") private Integer isLatest; diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseStatsResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseStatsResponse.java new file mode 100644 index 0000000..02ebb15 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseStatsResponse.java @@ -0,0 +1,30 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 热门课程统计响应 + */ +@Data +@Schema(description = "热门课程统计响应") +public class CourseStatsResponse { + + @Schema(description = "课程 ID", example = "1") + private String id; + + @Schema(description = "课程名称", example = "绘本阅读入门") + private String name; + + @Schema(description = "分类", example = "language") + private String category; + + @Schema(description = "状态", example = "published") + private String status; + + @Schema(description = "使用次数", example = "100") + private Integer usageCount; + + @Schema(description = "教师数", example = "10") + private Integer teacherCount; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseUsageStatsResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseUsageStatsResponse.java new file mode 100644 index 0000000..c9a88b6 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/CourseUsageStatsResponse.java @@ -0,0 +1,21 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 课程使用统计响应 + */ +@Data +@Schema(description = "课程使用统计响应") +public class CourseUsageStatsResponse { + + @Schema(description = "课程 ID", example = "1") + private String courseId; + + @Schema(description = "课程名称", example = "绘本阅读入门") + private String courseName; + + @Schema(description = "使用次数", example = "100") + private Integer usageCount; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/FileUploadResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/FileUploadResponse.java new file mode 100644 index 0000000..e0e180c --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/FileUploadResponse.java @@ -0,0 +1,29 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 文件上传响应 + */ +@Data +@Schema(description = "文件上传响应") +public class FileUploadResponse { + + @Schema(description = "文件 URL", example = "https://example.com/files/abc123.jpg") + private String fileUrl; + + @Schema(description = "文件名称", example = "image.jpg") + private String fileName; + + @Schema(description = "文件大小", example = "1024") + private Long fileSize; + + public static FileUploadResponse of(String fileUrl, String fileName, Long fileSize) { + FileUploadResponse response = new FileUploadResponse(); + response.setFileUrl(fileUrl); + response.setFileName(fileName); + response.setFileSize(fileSize); + return response; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/ImportTemplateResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ImportTemplateResponse.java new file mode 100644 index 0000000..cb662f4 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ImportTemplateResponse.java @@ -0,0 +1,25 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 导入模板响应 + */ +@Data +@Schema(description = "导入模板响应") +public class ImportTemplateResponse { + + @Schema(description = "表头") + private String[] headers; + + @Schema(description = "示例数据") + private String[] example; + + public static ImportTemplateResponse studentTemplate() { + ImportTemplateResponse response = new ImportTemplateResponse(); + response.setHeaders(new String[]{"姓名", "性别", "出生日期", "家长手机号", "家长姓名", "备注"}); + response.setExample(new String[]{"张三", "男", "2018-01-01", "13800138000", "张父", "示例数据"}); + return response; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/LessonActivityResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/LessonActivityResponse.java new file mode 100644 index 0000000..c5ead09 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/LessonActivityResponse.java @@ -0,0 +1,24 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 课时活动响应 + */ +@Data +@Schema(description = "课时活动响应") +public class LessonActivityResponse { + + @Schema(description = "课时 ID", example = "1") + private String id; + + @Schema(description = "课时标题", example = "绘本阅读第一课时") + private String title; + + @Schema(description = "课时日期", example = "2024-01-15") + private String lessonDate; + + @Schema(description = "课时状态", example = "COMPLETED") + private String status; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/LessonSimpleResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/LessonSimpleResponse.java new file mode 100644 index 0000000..d804a38 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/LessonSimpleResponse.java @@ -0,0 +1,30 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 课时简单信息响应 + */ +@Data +@Schema(description = "课时简单信息响应") +public class LessonSimpleResponse { + + @Schema(description = "课时 ID", example = "1") + private String id; + + @Schema(description = "课时标题", example = "绘本阅读第一课时") + private String title; + + @Schema(description = "开始时间", example = "09:00") + private String startTime; + + @Schema(description = "结束时间", example = "10:00") + private String endTime; + + @Schema(description = "地点", example = "教室 101") + private String location; + + @Schema(description = "课时状态", example = "PLANNED") + private String status; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/LoginResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/LoginResponse.java index fdd05af..51db5b2 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/response/LoginResponse.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/LoginResponse.java @@ -17,7 +17,7 @@ public class LoginResponse { private String token; @Schema(description = "用户ID") - private Long userId; + private String userId; @Schema(description = "用户名") private String username; @@ -29,6 +29,6 @@ public class LoginResponse { private String role; @Schema(description = "租户ID") - private Long tenantId; + private String tenantId; } diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/MessageResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/MessageResponse.java new file mode 100644 index 0000000..59dad5f --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/MessageResponse.java @@ -0,0 +1,21 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 简单消息响应 + */ +@Data +@Schema(description = "简单消息响应") +public class MessageResponse { + + @Schema(description = "消息内容", example = "操作成功") + private String message; + + public static MessageResponse of(String message) { + MessageResponse response = new MessageResponse(); + response.setMessage(message); + return response; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/MonthlyTaskStatsResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/MonthlyTaskStatsResponse.java new file mode 100644 index 0000000..5ae7b46 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/MonthlyTaskStatsResponse.java @@ -0,0 +1,24 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 月度任务统计响应 + */ +@Data +@Schema(description = "月度任务统计响应") +public class MonthlyTaskStatsResponse { + + @Schema(description = "月份", example = "2024-01") + private String month; + + @Schema(description = "任务数", example = "20") + private Integer tasks; + + @Schema(description = "完成次数", example = "100") + private Integer completions; + + @Schema(description = "已完成数量", example = "80") + private Integer completed; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/RecentActivityResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/RecentActivityResponse.java new file mode 100644 index 0000000..19f416f --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/RecentActivityResponse.java @@ -0,0 +1,24 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 近期活动响应 + */ +@Data +@Schema(description = "近期活动响应") +public class RecentActivityResponse { + + @Schema(description = "活动 ID", example = "1") + private String id; + + @Schema(description = "活动类型/课时状态", example = "COMPLETED") + private String type; + + @Schema(description = "活动标题", example = "李老师完成《绘本阅读》授课") + private String title; + + @Schema(description = "活动时间") + private String time; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/ResetPasswordResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ResetPasswordResponse.java new file mode 100644 index 0000000..0ec41ab --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/ResetPasswordResponse.java @@ -0,0 +1,25 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 重置密码响应 + */ +@Data +@Schema(description = "重置密码响应") +public class ResetPasswordResponse { + + @Schema(description = "临时密码", example = "Temp123456") + private String tempPassword; + + @Schema(description = "提示信息", example = "请通知用户及时修改密码") + private String message; + + public static ResetPasswordResponse of(String tempPassword, String message) { + ResetPasswordResponse response = new ResetPasswordResponse(); + response.setTempPassword(tempPassword); + response.setMessage(message); + return response; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/SchedulePlanResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/SchedulePlanResponse.java new file mode 100644 index 0000000..44774a0 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/SchedulePlanResponse.java @@ -0,0 +1,66 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalTime; + +/** + * 课表计划响应 + */ +@Data +@Schema(description = "课表计划响应") +public class SchedulePlanResponse { + + @Schema(description = "课表 ID", example = "1") + private String id; + + @Schema(description = "课表名称", example = "周一上午课程") + private String name; + + @Schema(description = "班级 ID") + private String classId; + + @Schema(description = "班级名称") + private String className; + + @Schema(description = "课程 ID") + private String courseId; + + @Schema(description = "课程名称") + private String courseName; + + @Schema(description = "教师 ID") + private String teacherId; + + @Schema(description = "教师姓名") + private String teacherName; + + @Schema(description = "星期几 (1-7)", example = "1") + private Integer dayOfWeek; + + @Schema(description = "节次", example = "1") + private Integer period; + + @Schema(description = "开始时间", example = "08:00") + private LocalTime startTime; + + @Schema(description = "结束时间", example = "08:45") + private LocalTime endTime; + + @Schema(description = "开始日期", example = "2024-01-01") + private LocalDate startDate; + + @Schema(description = "结束日期", example = "2024-06-30") + private LocalDate endDate; + + @Schema(description = "地点", example = "教室 101") + private String location; + + @Schema(description = "备注") + private String note; + + @Schema(description = "状态", example = "active") + private String status; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/StatsResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StatsResponse.java new file mode 100644 index 0000000..5f4b439 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StatsResponse.java @@ -0,0 +1,30 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 统计数据响应 + */ +@Data +@Schema(description = "统计数据响应") +public class StatsResponse { + + @Schema(description = "学生总数", example = "500") + private Integer totalStudents; + + @Schema(description = "教师总数", example = "50") + private Integer totalTeachers; + + @Schema(description = "班级总数", example = "20") + private Integer totalClasses; + + @Schema(description = "课程总数", example = "100") + private Integer totalCourses; + + @Schema(description = "今日课时数", example = "15") + private Integer todayLessons; + + @Schema(description = "本月任务数", example = "200") + private Integer monthTasks; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentInfoResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentInfoResponse.java new file mode 100644 index 0000000..0db0c73 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentInfoResponse.java @@ -0,0 +1,59 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 学生信息响应(含班级、家长信息) + */ +@Data +@Schema(description = "学生信息响应") +public class StudentInfoResponse { + + @Schema(description = "学生 ID", example = "1") + private String id; + + @Schema(description = "学生姓名", example = "张三") + private String name; + + @Schema(description = "性别", example = "male") + private String gender; + + @Schema(description = "出生日期", example = "2018-01-01") + private String birthDate; + + @Schema(description = "班级 ID") + private String classId; + + @Schema(description = "班级信息") + private ClassSimpleInfo classInfo; + + @Schema(description = "家长姓名", example = "张父") + private String parentName; + + @Schema(description = "家长手机号", example = "13800138000") + private String parentPhone; + + @Schema(description = "课时数", example = "20") + private Integer lessonCount; + + @Schema(description = "阅读次数", example = "10") + private Integer readingCount; + + @Schema(description = "创建时间") + private String createdAt; + + /** + * 班级简单信息 + */ + @Data + @Schema(description = "班级简单信息") + public static class ClassSimpleInfo { + @Schema(description = "班级 ID") + private String id; + @Schema(description = "班级名称") + private String name; + @Schema(description = "年级") + private String grade; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentRecordListResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentRecordListResponse.java new file mode 100644 index 0000000..7890870 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentRecordListResponse.java @@ -0,0 +1,34 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 学生记录列表响应 + */ +@Data +@Schema(description = "学生记录列表响应") +public class StudentRecordListResponse { + + @Schema(description = "课程信息") + private LessonSimpleInfo lesson; + + @Schema(description = "学生记录列表") + private List students; + + /** + * 课程简单信息 + */ + @Data + @Schema(description = "课程简单信息") + public static class LessonSimpleInfo { + @Schema(description = "课程 ID") + private String id; + @Schema(description = "课程状态") + private String status; + @Schema(description = "班级名称") + private String className; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentRecordResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentRecordResponse.java new file mode 100644 index 0000000..b3215a0 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentRecordResponse.java @@ -0,0 +1,33 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 学生记录响应 + */ +@Data +@Schema(description = "学生记录响应") +public class StudentRecordResponse { + + @Schema(description = "记录 ID", example = "1") + private String id; + + @Schema(description = "学生 ID", example = "50") + private String studentId; + + @Schema(description = "专注力评分 (1-5)", example = "4") + private Integer focus; + + @Schema(description = "参与度评分 (1-5)", example = "5") + private Integer participation; + + @Schema(description = "兴趣评分 (1-5)", example = "4") + private Integer interest; + + @Schema(description = "理解度评分 (1-5)", example = "3") + private Integer understanding; + + @Schema(description = "备注") + private String notes; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentTransferHistoryResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentTransferHistoryResponse.java new file mode 100644 index 0000000..e1d85e0 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentTransferHistoryResponse.java @@ -0,0 +1,33 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 学生调班历史响应 + */ +@Data +@Schema(description = "学生调班历史响应") +public class StudentTransferHistoryResponse { + + @Schema(description = "记录 ID", example = "1") + private String id; + + @Schema(description = "班级 ID", example = "2") + private String classId; + + @Schema(description = "班级名称") + private String className; + + @Schema(description = "开始日期", example = "2024-01-01") + private String startDate; + + @Schema(description = "结束日期", example = "2024-06-30") + private String endDate; + + @Schema(description = "状态", example = "active") + private String status; + + @Schema(description = "调班原因") + private String reason; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/SystemSettingsResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/SystemSettingsResponse.java new file mode 100644 index 0000000..e0db6d9 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/SystemSettingsResponse.java @@ -0,0 +1,27 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 系统设置响应 + */ +@Data +@Schema(description = "系统设置响应") +public class SystemSettingsResponse { + + @Schema(description = "系统名称", example = "少儿智慧阅读平台") + private String systemName; + + @Schema(description = "系统 Logo URL") + private String systemLogo; + + @Schema(description = "登录页背景图 URL") + private String loginBackground; + + @Schema(description = "系统公告") + private String announcement; + + @Schema(description = "联系方式") + private String contactInfo; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskCompletionInfoResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskCompletionInfoResponse.java new file mode 100644 index 0000000..695ff9d --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskCompletionInfoResponse.java @@ -0,0 +1,50 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 任务完成信息响应 + */ +@Data +@Schema(description = "任务完成信息响应") +public class TaskCompletionInfoResponse { + + @Schema(description = "完成记录 ID", example = "1") + private String id; + + @Schema(description = "任务 ID", example = "100") + private String taskId; + + @Schema(description = "学生 ID", example = "50") + private String studentId; + + @Schema(description = "状态", example = "completed") + private String status; + + @Schema(description = "完成时间") + private String completedAt; + + @Schema(description = "反馈") + private String feedback; + + @Schema(description = "家长反馈") + private String parentFeedback; + + @Schema(description = "任务信息") + private TaskSimpleInfo task; + + /** + * 任务简单信息 + */ + @Data + @Schema(description = "任务简单信息") + public static class TaskSimpleInfo { + @Schema(description = "任务 ID") + private String id; + @Schema(description = "任务名称") + private String name; + @Schema(description = "任务类型") + private String type; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskFeedbackResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskFeedbackResponse.java new file mode 100644 index 0000000..c518ca7 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskFeedbackResponse.java @@ -0,0 +1,30 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 任务反馈响应 + */ +@Data +@Schema(description = "任务反馈响应") +public class TaskFeedbackResponse { + + @Schema(description = "完成记录 ID", example = "1") + private String id; + + @Schema(description = "任务 ID", example = "100") + private String taskId; + + @Schema(description = "学生 ID", example = "50") + private String studentId; + + @Schema(description = "状态", example = "completed") + private String status; + + @Schema(description = "家长反馈") + private String parentFeedback; + + @Schema(description = "消息(未找到记录时返回)") + private String message; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsByClassResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsByClassResponse.java new file mode 100644 index 0000000..cabe463 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsByClassResponse.java @@ -0,0 +1,30 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 按班级任务统计响应 + */ +@Data +@Schema(description = "按班级任务统计响应") +public class TaskStatsByClassResponse { + + @Schema(description = "班级 ID", example = "1") + private String classId; + + @Schema(description = "班级名称", example = "大一班") + private String className; + + @Schema(description = "年级", example = "K1") + private String grade; + + @Schema(description = "总任务数", example = "50") + private Integer total; + + @Schema(description = "已完成任务数", example = "40") + private Integer completed; + + @Schema(description = "完成率", example = "80") + private Integer rate; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsByTypeResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsByTypeResponse.java new file mode 100644 index 0000000..eb782f9 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsByTypeResponse.java @@ -0,0 +1,24 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 按类型统计的任务响应 + */ +@Data +@Schema(description = "按类型统计的任务响应") +public class TaskStatsByTypeResponse { + + @Schema(description = "任务类型", example = "homework") + private String type; + + @Schema(description = "总任务数", example = "50") + private Integer total; + + @Schema(description = "已完成任务数", example = "40") + private Integer completed; + + @Schema(description = "完成率", example = "80") + private Integer rate; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsResponse.java new file mode 100644 index 0000000..273f666 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskStatsResponse.java @@ -0,0 +1,33 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 任务统计响应 + */ +@Data +@Schema(description = "任务统计响应") +public class TaskStatsResponse { + + @Schema(description = "任务总数", example = "100") + private Integer totalTasks; + + @Schema(description = "已发布任务数", example = "80") + private Integer publishedTasks; + + @Schema(description = "已完成任务数", example = "60") + private Integer completedTasks; + + @Schema(description = "进行中任务数", example = "20") + private Integer inProgressTasks; + + @Schema(description = "待完成数量", example = "20") + private Integer pendingCount; + + @Schema(description = "总完成次数", example = "500") + private Integer totalCompletions; + + @Schema(description = "完成率", example = "80") + private Integer completionRate; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TeacherDashboardResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TeacherDashboardResponse.java new file mode 100644 index 0000000..f4c0428 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TeacherDashboardResponse.java @@ -0,0 +1,24 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 教师仪表盘概览响应 + */ +@Data +@Schema(description = "教师仪表盘概览响应") +public class TeacherDashboardResponse { + + @Schema(description = "课时数", example = "50") + private Integer lessonCount; + + @Schema(description = "任务数", example = "20") + private Integer taskCount; + + @Schema(description = "成长记录数", example = "100") + private Integer growthRecordCount; + + @Schema(description = "未读通知数", example = "5") + private Integer unreadNotifications; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TeacherInfoResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TeacherInfoResponse.java new file mode 100644 index 0000000..e8c5b86 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TeacherInfoResponse.java @@ -0,0 +1,27 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 教师信息响应 + */ +@Data +@Schema(description = "教师信息响应") +public class TeacherInfoResponse { + + @Schema(description = "教师 ID", example = "1") + private String teacherId; + + @Schema(description = "教师姓名", example = "李老师") + private String teacherName; + + @Schema(description = "教师手机号", example = "13800138000") + private String teacherPhone; + + @Schema(description = "角色", example = "MAIN") + private String role; + + @Schema(description = "是否主教", example = "true") + private Boolean isPrimary; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantInfoResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantInfoResponse.java new file mode 100644 index 0000000..4be32bb --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantInfoResponse.java @@ -0,0 +1,27 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 租户信息响应 + */ +@Data +@Schema(description = "租户信息响应") +public class TenantInfoResponse { + + @Schema(description = "租户 ID", example = "1") + private String id; + + @Schema(description = "租户名称", example = "阳光幼儿园") + private String name; + + @Schema(description = "状态", example = "active") + private String status; + + @Schema(description = "配额(最大学生数)", example = "500") + private Integer quota; + + @Schema(description = "过期时间", example = "2025-12-31") + private String expireDate; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantResponse.java index 9dd1ec9..9dd8245 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantResponse.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantResponse.java @@ -12,7 +12,7 @@ import java.time.LocalDateTime; public class TenantResponse { @Schema(description = "租户ID") - private Long id; + private String id; @Schema(description = "租户名称") private String name; diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantStatsResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantStatsResponse.java new file mode 100644 index 0000000..377d15a --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantStatsResponse.java @@ -0,0 +1,36 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 活跃租户统计响应 + */ +@Data +@Schema(description = "活跃租户统计响应") +public class TenantStatsResponse { + + @Schema(description = "租户 ID", example = "1") + private String id; + + @Schema(description = "租户名称", example = "XX 幼儿园") + private String name; + + @Schema(description = "租户编码", example = "KINDERGARTEN_001") + private String code; + + @Schema(description = "状态", example = "active") + private String status; + + @Schema(description = "过期时间") + private String expireAt; + + @Schema(description = "教师数", example = "20") + private Integer teacherCount; + + @Schema(description = "学生数", example = "200") + private Integer studentCount; + + @Schema(description = "课时数", example = "500") + private Integer lessonCount; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantStatusUpdateResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantStatusUpdateResponse.java new file mode 100644 index 0000000..44bf566 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantStatusUpdateResponse.java @@ -0,0 +1,21 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 租户状态更新响应 + */ +@Data +@Schema(description = "租户状态更新响应") +public class TenantStatusUpdateResponse { + + @Schema(description = "租户 ID", example = "1") + private String id; + + @Schema(description = "租户名称", example = "XX 幼儿园") + private String name; + + @Schema(description = "状态", example = "active") + private String status; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TrendDataPointResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TrendDataPointResponse.java new file mode 100644 index 0000000..bef6de3 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TrendDataPointResponse.java @@ -0,0 +1,24 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 趋势数据点响应 + */ +@Data +@Schema(description = "趋势数据点响应") +public class TrendDataPointResponse { + + @Schema(description = "月份", example = "2024-01") + private String month; + + @Schema(description = "租户数", example = "50") + private Integer tenantCount; + + @Schema(description = "课时数", example = "1500") + private Integer lessonCount; + + @Schema(description = "学生数", example = "5000") + private Integer studentCount; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TrendDataResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TrendDataResponse.java new file mode 100644 index 0000000..b36bfd0 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TrendDataResponse.java @@ -0,0 +1,21 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 趋势数据响应 + */ +@Data +@Schema(description = "趋势数据响应") +public class TrendDataResponse { + + @Schema(description = "月份", example = "2024-01") + private String month; + + @Schema(description = "课时数", example = "100") + private Integer lessonCount; + + @Schema(description = "学生数", example = "50") + private Integer studentCount; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/UserInfoResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/UserInfoResponse.java index 5c3b824..f500053 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/response/UserInfoResponse.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/UserInfoResponse.java @@ -14,7 +14,7 @@ import lombok.NoArgsConstructor; public class UserInfoResponse { @Schema(description = "用户ID") - private Long id; + private String id; @Schema(description = "用户名") private String username; @@ -35,6 +35,6 @@ public class UserInfoResponse { private String role; @Schema(description = "租户ID") - private Long tenantId; + private String tenantId; } diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/AdminUser.java b/reading-platform-java/src/main/java/com/reading/platform/entity/AdminUser.java index a9de840..c63cd07 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/AdminUser.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/AdminUser.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,11 +10,11 @@ import java.time.LocalDateTime; * 管理员用户实体 */ @Data -@TableName("admin_users") +@TableName("t_admin_user") public class AdminUser { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + private String id; private String username; @@ -31,9 +32,19 @@ public class AdminUser { private LocalDateTime lastLoginAt; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeacher.java b/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeacher.java index ca6da84..e490c88 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeacher.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeacher.java @@ -10,7 +10,7 @@ import java.time.LocalDateTime; * 班级 - 教师关联实体 */ @Data -@TableName("class_teachers") +@TableName("t_class_teacher") @Schema(description = "班级教师关联") public class ClassTeacher { diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeachers.java b/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeachers.java deleted file mode 100644 index 3994ee3..0000000 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/ClassTeachers.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.reading.platform.entity; - -import com.baomidou.mybatisplus.annotation.*; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 班级-教师关联实体 - */ -@Data -@TableName("class_teachers") -@Schema(description = "班级教师关联") -public class ClassTeacher { - - @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) - @TableId(type = IdType.ASSIGN_ID) - private String id; - - private String classId; - - private String teacherId; - - private String role; - - /** - * 是否主教 - */ - private Boolean isPrimary; - - /** - * 排序 - */ - private Integer sortOrder; - - @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) - @TableField(fill = FieldFill.INSERT) - private String createdBy; - - @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) - @TableField(fill = FieldFill.INSERT_UPDATE) - private String updatedBy; - - @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) - @TableField(fill = FieldFill.INSERT) - private LocalDateTime createdAt; - - @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) - @TableField(fill = FieldFill.INSERT_UPDATE) - private LocalDateTime updatedAt; - - @Schema(description = "逻辑删除标志", accessMode = Schema.AccessMode.READ_ONLY) - @TableLogic - private Integer deleted; - -} diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Clazz.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Clazz.java index 312d632..db70441 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Clazz.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Clazz.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,13 +10,16 @@ import java.time.LocalDateTime; * 班级实体 */ @Data -@TableName("classes") +@TableName("t_clazz") +@Schema(description = "班级") public class Clazz { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + @Schema(description = "租户 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String tenantId; private String name; @@ -27,12 +31,23 @@ public class Clazz { private String status; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "逻辑删除标志", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Course.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Course.java index ef78b76..04017fc 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Course.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Course.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -11,13 +12,13 @@ import java.time.LocalDateTime; * 课程包实体,包含完整的课程管理字段 */ @Data -@TableName("courses") +@TableName("t_course") public class Course { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + private String tenantId; private String name; @@ -65,7 +66,7 @@ public class Course { private String environmentConstruction; // 主题与绘本关系 - private Long themeId; + private String themeId; private String pictureBookName; // 封面图片 @@ -98,7 +99,7 @@ public class Course { // 版本与审核字段 private String version; - private Long parentId; + private String parentId; private Integer isLatest; private LocalDateTime submittedAt; private Long submittedBy; @@ -112,11 +113,20 @@ public class Course { private Integer usageCount; private Integer teacherCount; private BigDecimal avgRating; - private Long createdBy; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseActivity.java b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseActivity.java index 8b33a1f..860bb84 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseActivity.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseActivity.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,32 +10,52 @@ import java.time.LocalDateTime; * 课程活动实体 */ @Data -@TableName("course_activities") +@TableName("t_course_activity") +@Schema(description = "课程活动") public class CourseActivity { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + private String id; - private Long courseId; + @Schema(description = "课程 ID") + private String courseId; + @Schema(description = "活动标题") private String title; + @Schema(description = "活动类型") private String type; + @Schema(description = "活动内容") private String content; + @Schema(description = "所需材料") private String materials; + @Schema(description = "时长(分钟)") private Integer durationMinutes; + @Schema(description = "排序顺序") private Integer sortOrder; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "是否删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseLesson.java b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseLesson.java index 03b24e4..807407e 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseLesson.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseLesson.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,13 +10,15 @@ import java.time.LocalDateTime; * 课程课时实体(课程内的章节/部分) */ @Data -@TableName("course_lessons") +@TableName("t_course_lesson") +@Schema(description = "课程课时") public class CourseLesson { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long courseId; + private String courseId; private String title; @@ -31,6 +34,14 @@ public class CourseLesson { private String status; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/CoursePackage.java b/reading-platform-java/src/main/java/com/reading/platform/entity/CoursePackage.java index 96ef704..aff3135 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/CoursePackage.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/CoursePackage.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -10,11 +11,13 @@ import java.time.LocalDateTime; * 课程包实体 */ @Data -@TableName("course_packages") +@TableName("t_course_package") +@Schema(description = "课程包") public class CoursePackage { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; private String name; @@ -30,6 +33,14 @@ public class CoursePackage { private Integer isSystem; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseResource.java b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseResource.java index efc51e4..26fa4bc 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseResource.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseResource.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,13 +10,15 @@ import java.time.LocalDateTime; * 课程资源实体 */ @Data -@TableName("course_resources") +@TableName("t_course_resource") +@Schema(description = "课程资源") public class CourseResource { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long courseId; + private String courseId; private String title; @@ -33,6 +36,14 @@ public class CourseResource { private Integer sortOrder; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseScript.java b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseScript.java index 3ce6c9a..d70782a 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseScript.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseScript.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,13 +10,15 @@ import java.time.LocalDateTime; * 课程脚本实体 */ @Data -@TableName("course_scripts") +@TableName("t_course_script") +@Schema(description = "课程脚本") public class CourseScript { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long courseId; + private String courseId; private String title; @@ -23,6 +26,14 @@ public class CourseScript { private Integer sortOrder; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseScriptPage.java b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseScriptPage.java index 5dd378c..89d65c4 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseScriptPage.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseScriptPage.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,13 +10,15 @@ import java.time.LocalDateTime; * 课程脚本页面实体 */ @Data -@TableName("course_script_pages") +@TableName("t_course_script_page") +@Schema(description = "课程脚本页面") public class CourseScriptPage { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long scriptId; + private String scriptId; private Integer pageNumber; @@ -29,6 +32,14 @@ public class CourseScriptPage { private String notes; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseVersion.java b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseVersion.java index eeadf27..9230c56 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/CourseVersion.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/CourseVersion.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,26 +10,43 @@ import java.time.LocalDateTime; * 课程版本实体 */ @Data -@TableName("course_versions") +@TableName("t_course_version") +@Schema(description = "课程版本") public class CourseVersion { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + private String id; - private Long courseId; + @Schema(description = "课程 ID") + private String courseId; + @Schema(description = "版本号") private String version; + @Schema(description = "版本描述") private String description; + @Schema(description = "状态") private String status; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "是否删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/GrowthRecord.java b/reading-platform-java/src/main/java/com/reading/platform/entity/GrowthRecord.java index 4696602..267b97a 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/GrowthRecord.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/GrowthRecord.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDate; @@ -10,15 +11,15 @@ import java.time.LocalDateTime; * 成长档案实体 */ @Data -@TableName("growth_records") +@TableName("t_growth_record") public class GrowthRecord { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + private String tenantId; - private Long studentId; + private String studentId; private String type; @@ -28,7 +29,7 @@ public class GrowthRecord { private String images; - private Long recordedBy; + private String recordedBy; private String recorderRole; @@ -36,6 +37,14 @@ public class GrowthRecord { private String tags; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Lesson.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Lesson.java index b50a3cf..20496d4 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Lesson.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Lesson.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDate; @@ -11,40 +12,88 @@ import java.time.LocalTime; * 课时实体 */ @Data -@TableName("lessons") +@TableName("t_lesson") +@Schema(description = "课时信息") public class Lesson { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + private String id; - private Long tenantId; + @Schema(description = "租户 ID") + private String tenantId; - private Long courseId; + @Schema(description = "课程 ID") + private String courseId; - private Long classId; + @Schema(description = "班级 ID") + private String classId; - private Long teacherId; + @Schema(description = "教师 ID") + private String teacherId; + @Schema(description = "课时标题") private String title; + @Schema(description = "课时日期") private LocalDate lessonDate; + @Schema(description = "开始时间") private LocalTime startTime; + @Schema(description = "结束时间") private LocalTime endTime; + @Schema(description = "上课地点") private String location; + @Schema(description = "状态") private String status; + @Schema(description = "备注说明") private String notes; + /** + * 实际时长(分钟) + */ + @Schema(description = "实际时长(分钟)") + private Integer actualDuration; + + /** + * 整体评分 + */ + @Schema(description = "整体评分") + private String overallRating; + + /** + * 参与度评分 + */ + @Schema(description = "参与度评分") + private String participationRating; + + /** + * 完成说明 + */ + @Schema(description = "完成说明") + private String completionNote; + + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "是否删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/LessonFeedback.java b/reading-platform-java/src/main/java/com/reading/platform/entity/LessonFeedback.java index 456904b..6ff030f 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/LessonFeedback.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/LessonFeedback.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,26 +10,79 @@ import java.time.LocalDateTime; * 课时反馈实体 */ @Data -@TableName("lesson_feedbacks") +@TableName("t_lesson_feedback") +@Schema(description = "课时反馈") public class LessonFeedback { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + private String id; - private Long lessonId; + @Schema(description = "课时 ID") + private String lessonId; - private Long teacherId; + @Schema(description = "教师 ID") + private String teacherId; - private String content; + /** + * 设计质量评分 (1-5) + */ + @Schema(description = "设计质量评分 (1-5)", minimum = "1", maximum = "5") + private Integer designQuality; - private Integer rating; + /** + * 参与度评分 (1-5) + */ + @Schema(description = "参与度评分 (1-5)", minimum = "1", maximum = "5") + private Integer participation; + /** + * 目标达成度评分 (1-5) + */ + @Schema(description = "目标达成度评分 (1-5)", minimum = "1", maximum = "5") + private Integer goalAchievement; + + /** + * 环节反馈 JSON + */ + @Schema(description = "环节反馈 JSON") + private String stepFeedbacks; + + /** + * 优点 + */ + @Schema(description = "优点") + private String pros; + + /** + * 建议 + */ + @Schema(description = "建议") + private String suggestions; + + /** + * 完成的活动 JSON + */ + @Schema(description = "完成的活动 JSON") + private String activitiesDone; + + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "是否删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Notification.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Notification.java index bd72374..79f8248 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Notification.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Notification.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,35 +10,53 @@ import java.time.LocalDateTime; * 通知实体 */ @Data -@TableName("notifications") +@TableName("t_notification") +@Schema(description = "系统通知") public class Notification { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + private String id; - private Long tenantId; + @Schema(description = "租户 ID") + private String tenantId; + @Schema(description = "通知标题") private String title; + @Schema(description = "通知内容") private String content; + @Schema(description = "通知类型") private String type; - private Long senderId; + @Schema(description = "发送人 ID") + private String senderId; + @Schema(description = "发送人角色") private String senderRole; + @Schema(description = "接收者类型") private String recipientType; - private Long recipientId; + @Schema(description = "接收者 ID") + private String recipientId; + @Schema(description = "是否已读", example = "0") private Integer isRead; + @Schema(description = "阅读时间") private LocalDateTime readAt; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "是否删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/OperationLog.java b/reading-platform-java/src/main/java/com/reading/platform/entity/OperationLog.java index ccabd6c..2d6cd26 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/OperationLog.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/OperationLog.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,32 +10,49 @@ import java.time.LocalDateTime; * 操作日志实体 */ @Data -@TableName("operation_logs") +@TableName("t_operation_log") +@Schema(description = "操作日志") public class OperationLog { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "日志 ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + @Schema(description = "租户 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String tenantId; - private Long userId; + @Schema(description = "用户 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String userId; + @Schema(description = "用户角色 admin/school/teacher/parent", example = "teacher") private String userRole; + @Schema(description = "操作类型", example = "CREATE", requiredMode = Schema.RequiredMode.REQUIRED) private String action; + @Schema(description = "操作模块", example = "lesson", requiredMode = Schema.RequiredMode.REQUIRED) private String module; + @Schema(description = "目标类型", example = "student") private String targetType; - private Long targetId; + @Schema(description = "目标 ID") + private String targetId; + @Schema(description = "操作详情") private String details; + @Schema(description = "IP 地址") private String ipAddress; + @Schema(description = "用户代理") private String userAgent; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Parent.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Parent.java index df83189..f3f73df 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Parent.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Parent.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,13 +10,13 @@ import java.time.LocalDateTime; * 家长实体 */ @Data -@TableName("parents") +@TableName("t_parent") public class Parent { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + private String tenantId; private String username; @@ -35,9 +36,19 @@ public class Parent { private LocalDateTime lastLoginAt; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/ParentStudent.java b/reading-platform-java/src/main/java/com/reading/platform/entity/ParentStudent.java index 0ebb5dc..41fd2e6 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/ParentStudent.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/ParentStudent.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,23 +10,35 @@ import java.time.LocalDateTime; * 家长-学生关联实体 */ @Data -@TableName("parent_students") +@TableName("t_parent_student") +@Schema(description = "家长 - 学生关联") public class ParentStudent { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + private String id; - private Long parentId; + @Schema(description = "家长 ID") + private String parentId; - private Long studentId; + @Schema(description = "学生 ID") + private String studentId; + @Schema(description = "关系") private String relationship; + @Schema(description = "是否主要联系人", example = "1") private Integer isPrimary; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "是否删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/ResourceItem.java b/reading-platform-java/src/main/java/com/reading/platform/entity/ResourceItem.java index d7f188d..0d678b9 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/ResourceItem.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/ResourceItem.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,34 +10,55 @@ import java.time.LocalDateTime; * 资源项实体 */ @Data -@TableName("resource_items") +@TableName("t_resource_item") +@Schema(description = "资源项") public class ResourceItem { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + private String id; - private Long libraryId; + @Schema(description = "资源库 ID") + private String libraryId; + @Schema(description = "资源名称") private String name; + @Schema(description = "资源编码") private String code; + @Schema(description = "资源描述") private String description; + @Schema(description = "数量") private Integer quantity; + @Schema(description = "可用数量") private Integer availableQuantity; + @Schema(description = "存放位置") private String location; + @Schema(description = "状态") private String status; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "是否删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/ResourceLibrary.java b/reading-platform-java/src/main/java/com/reading/platform/entity/ResourceLibrary.java index 25f0040..03817e5 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/ResourceLibrary.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/ResourceLibrary.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,26 +10,43 @@ import java.time.LocalDateTime; * 资源库实体 */ @Data -@TableName("resource_libraries") +@TableName("t_resource_library") +@Schema(description = "资源库") public class ResourceLibrary { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + private String id; - private Long tenantId; + @Schema(description = "租户 ID") + private String tenantId; + @Schema(description = "资源库名称") private String name; + @Schema(description = "资源库描述") private String description; + @Schema(description = "资源库类型") private String type; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "是否删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/SchedulePlan.java b/reading-platform-java/src/main/java/com/reading/platform/entity/SchedulePlan.java index fb2d5ad..b9e6fea 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/SchedulePlan.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/SchedulePlan.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDate; @@ -11,46 +12,73 @@ import java.time.LocalTime; * 课表计划实体 */ @Data -@TableName("schedule_plans") +@TableName("t_schedule_plan") +@Schema(description = "课表计划") public class SchedulePlan { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "计划 ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + @Schema(description = "租户 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String tenantId; + @Schema(description = "计划名称", example = "周一上午课程", requiredMode = Schema.RequiredMode.REQUIRED) private String name; - private Long classId; + @Schema(description = "班级 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String classId; - private Long courseId; + @Schema(description = "课程 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String courseId; - private Long teacherId; + @Schema(description = "教师 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String teacherId; + @Schema(description = "星期几 (1-7)", example = "1", minimum = "1", maximum = "7") private Integer dayOfWeek; + @Schema(description = "第几节课", example = "1", minimum = "1") private Integer period; + @Schema(description = "开始时间", example = "08:00:00") private LocalTime startTime; + @Schema(description = "结束时间", example = "08:45:00") private LocalTime endTime; + @Schema(description = "开始日期") private LocalDate startDate; + @Schema(description = "结束日期") private LocalDate endDate; + @Schema(description = "上课地点") private String location; + @Schema(description = "备注说明") private String note; + @Schema(description = "状态 scheduled/completed/cancelled", example = "scheduled") private String status; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "是否删除 0-未删除 1-已删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/ScheduleTemplate.java b/reading-platform-java/src/main/java/com/reading/platform/entity/ScheduleTemplate.java index d253773..1054f20 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/ScheduleTemplate.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/ScheduleTemplate.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,28 +10,46 @@ import java.time.LocalDateTime; * 课表模板实体 */ @Data -@TableName("schedule_templates") +@TableName("t_schedule_template") +@Schema(description = "课表模板") public class ScheduleTemplate { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "模板 ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + @Schema(description = "租户 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String tenantId; + @Schema(description = "模板名称", example = "周一课表", requiredMode = Schema.RequiredMode.REQUIRED) private String name; + @Schema(description = "模板描述") private String description; + @Schema(description = "模板内容 JSON", requiredMode = Schema.RequiredMode.REQUIRED) private String content; + @Schema(description = "是否公开 0-私有 1-公开", example = "1") private Integer isPublic; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "是否删除 0-未删除 1-已删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/SchoolCourse.java b/reading-platform-java/src/main/java/com/reading/platform/entity/SchoolCourse.java index b9e4570..987f607 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/SchoolCourse.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/SchoolCourse.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,34 +10,50 @@ import java.time.LocalDateTime; * 校本课程实体(租户自定义课程) */ @Data -@TableName("school_courses") +@TableName("t_school_course") +@Schema(description = "校本课程") public class SchoolCourse { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "课程 ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + @Schema(description = "租户 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String tenantId; + @Schema(description = "课程名称", example = "绘本阅读入门", requiredMode = Schema.RequiredMode.REQUIRED) private String name; + @Schema(description = "课程描述") private String description; + @Schema(description = "封面图片 URL") private String coverUrl; + @Schema(description = "分类", example = "language") private String category; + @Schema(description = "适用年龄段", example = "5-6 岁") private String ageRange; + @Schema(description = "状态 published/draft", example = "published") private String status; - private Long createdBy; + @Schema(description = "创建人 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String createdBy; + @Schema(description = "更新人 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "是否删除 0-未删除 1-已删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; } diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Student.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Student.java index 1943c8f..6bfc687 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Student.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Student.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDate; @@ -10,13 +11,13 @@ import java.time.LocalDateTime; * 学生实体 */ @Data -@TableName("students") +@TableName("t_student") public class Student { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + private String tenantId; private String name; @@ -38,9 +39,44 @@ public class Student { private String status; + /** + * 班级 ID + */ + private String classId; + + /** + * 家长姓名 + */ + private String parentName; + + /** + * 家长手机号 + */ + private String parentPhone; + + /** + * 阅读次数 + */ + private Integer readingCount; + + /** + * 课时数 + */ + private Integer lessonCount; + + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/StudentClassHistory.java b/reading-platform-java/src/main/java/com/reading/platform/entity/StudentClassHistory.java index 62fbca5..a861076 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/StudentClassHistory.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/StudentClassHistory.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDate; @@ -10,25 +11,41 @@ import java.time.LocalDateTime; * 学生班级历史实体 */ @Data -@TableName("student_class_history") +@TableName("t_student_class_history") +@Schema(description = "学生班级历史") public class StudentClassHistory { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "历史记录 ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long studentId; + @Schema(description = "学生 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String studentId; - private Long classId; + @Schema(description = "班级 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String classId; + @Schema(description = "开始日期", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDate startDate; + @Schema(description = "结束日期") private LocalDate endDate; + @Schema(description = "状态 active/graduated/transferred", example = "active") private String status; + @Schema(description = "调班原因") + private String reason; + + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "是否删除 0-未删除 1-已删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/StudentRecord.java b/reading-platform-java/src/main/java/com/reading/platform/entity/StudentRecord.java index 0063490..fd538eb 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/StudentRecord.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/StudentRecord.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,28 +10,58 @@ import java.time.LocalDateTime; * 学生记录实体 */ @Data -@TableName("student_records") +@TableName("t_student_record") +@Schema(description = "学生记录") public class StudentRecord { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "记录 ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long lessonId; + @Schema(description = "课时 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String lessonId; - private Long studentId; + @Schema(description = "学生 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String studentId; + @Schema(description = "出勤状态 present/absent/late", example = "present") private String attendance; + @Schema(description = "课堂表现评价") private String performance; + @Schema(description = "备注说明") private String notes; + @Schema(description = "专注力评分 (1-5)", example = "4", minimum = "1", maximum = "5") + private Integer focus; + + @Schema(description = "参与度评分 (1-5)", example = "4", minimum = "1", maximum = "5") + private Integer participation; + + @Schema(description = "兴趣评分 (1-5)", example = "4", minimum = "1", maximum = "5") + private Integer interest; + + @Schema(description = "理解度评分 (1-5)", example = "4", minimum = "1", maximum = "5") + private Integer understanding; + + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "是否删除 0-未删除 1-已删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/SystemSetting.java b/reading-platform-java/src/main/java/com/reading/platform/entity/SystemSetting.java index ad1d0b0..276f5ff 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/SystemSetting.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/SystemSetting.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,26 +10,43 @@ import java.time.LocalDateTime; * 系统设置实体 */ @Data -@TableName("system_settings") +@TableName("t_system_setting") +@Schema(description = "系统设置") public class SystemSetting { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "设置 ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + @Schema(description = "租户 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String tenantId; + @Schema(description = "设置键", example = "school.name", requiredMode = Schema.RequiredMode.REQUIRED) private String settingKey; + @Schema(description = "设置值", example = "阳光幼儿园") private String settingValue; + @Schema(description = "设置描述") private String description; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "是否删除 0-未删除 1-已删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Tag.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Tag.java index 8590ee8..1cd9b6b 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Tag.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Tag.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,26 +10,43 @@ import java.time.LocalDateTime; * 标签实体 */ @Data -@TableName("tags") +@TableName("t_tag") +@Schema(description = "标签") public class Tag { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "标签 ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + @Schema(description = "租户 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String tenantId; + @Schema(description = "标签名称", example = "绘本阅读", requiredMode = Schema.RequiredMode.REQUIRED) private String name; + @Schema(description = "标签类型", example = "course") private String type; + @Schema(description = "标签颜色", example = "#1890ff") private String color; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "是否删除 0-未删除 1-已删除", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Task.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Task.java index 78a8172..5fd3131 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Task.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Task.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDate; @@ -10,40 +11,64 @@ import java.time.LocalDateTime; * 任务实体 */ @Data -@TableName("tasks") +@TableName("t_task") +@Schema(description = "任务信息") public class Task { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "任务 ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + @Schema(description = "租户 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String tenantId; + @Schema(description = "任务标题", example = "绘本阅读打卡", requiredMode = Schema.RequiredMode.REQUIRED) private String title; + @Schema(description = "任务描述") private String description; + @Schema(description = "任务类型", example = "reading") private String type; - private Long courseId; + @Schema(description = "课程 ID") + private String courseId; - private Long creatorId; + @Schema(description = "创建者 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String creatorId; + @Schema(description = "创建者角色", example = "teacher", accessMode = Schema.AccessMode.READ_ONLY) private String creatorRole; + @Schema(description = "开始日期", example = "2024-01-01") private LocalDate startDate; + @Schema(description = "截止日期", example = "2024-01-31") private LocalDate dueDate; + @Schema(description = "任务状态", example = "active") private String status; + @Schema(description = "附件 JSON") private String attachments; + @Schema(description = "创建者用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新者用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "逻辑删除标志", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/TaskCompletion.java b/reading-platform-java/src/main/java/com/reading/platform/entity/TaskCompletion.java index d0595ea..c96deef 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/TaskCompletion.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/TaskCompletion.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,34 +10,55 @@ import java.time.LocalDateTime; * 任务完成实体 */ @Data -@TableName("task_completions") +@TableName("t_task_completion") +@Schema(description = "任务完成信息") public class TaskCompletion { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "任务完成 ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long taskId; + @Schema(description = "任务 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String taskId; - private Long studentId; + @Schema(description = "学生 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String studentId; + @Schema(description = "完成状态", example = "completed") private String status; + @Schema(description = "完成时间") private LocalDateTime completedAt; + @Schema(description = "完成内容") private String content; + @Schema(description = "附件 JSON") private String attachments; + @Schema(description = "评分", example = "5", minimum = "1", maximum = "5") private Integer rating; + @Schema(description = "反馈内容") private String feedback; + @Schema(description = "创建者用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新者用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "逻辑删除标志", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/TaskTarget.java b/reading-platform-java/src/main/java/com/reading/platform/entity/TaskTarget.java index c41b805..3a55787 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/TaskTarget.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/TaskTarget.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,21 +10,32 @@ import java.time.LocalDateTime; * 任务目标实体 */ @Data -@TableName("task_targets") +@TableName("t_task_target") +@Schema(description = "任务目标") public class TaskTarget { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long taskId; + @Schema(description = "任务 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String taskId; + @Schema(description = "目标类型", example = "student", requiredMode = Schema.RequiredMode.REQUIRED) private String targetType; - private Long targetId; + @Schema(description = "目标 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String targetId; + @Schema(description = "创建者用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "逻辑删除标志", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/TaskTemplate.java b/reading-platform-java/src/main/java/com/reading/platform/entity/TaskTemplate.java index c9a751d..931617f 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/TaskTemplate.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/TaskTemplate.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,30 +10,49 @@ import java.time.LocalDateTime; * 任务模板实体 */ @Data -@TableName("task_templates") +@TableName("t_task_template") +@Schema(description = "任务模板信息") public class TaskTemplate { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "任务模板 ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + @Schema(description = "租户 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String tenantId; + @Schema(description = "模板名称", example = "阅读打卡模板", requiredMode = Schema.RequiredMode.REQUIRED) private String name; + @Schema(description = "模板描述") private String description; + @Schema(description = "任务类型", example = "reading") private String type; + @Schema(description = "模板内容") private String content; + @Schema(description = "是否公共模板", example = "1") private Integer isPublic; + @Schema(description = "创建者用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新者用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "逻辑删除标志", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Teacher.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Teacher.java index 13167e2..4da8f31 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Teacher.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Teacher.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,13 +10,13 @@ import java.time.LocalDateTime; * 教师实体 */ @Data -@TableName("teachers") +@TableName("t_teacher") public class Teacher { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + private String tenantId; private String username; @@ -37,9 +38,19 @@ public class Teacher { private LocalDateTime lastLoginAt; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Tenant.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Tenant.java index 7d1100a..e7fab8e 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Tenant.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Tenant.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.reading.platform.common.serializer.UpperCaseSerializer; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -12,11 +13,11 @@ import java.time.LocalDateTime; * 租户实体(幼儿园/机构) */ @Data -@TableName("tenants") +@TableName("t_tenant") public class Tenant { - @TableId(type = IdType.AUTO) - private Long id; + @TableId(type = IdType.ASSIGN_ID) + private String id; private String name; @@ -46,9 +47,19 @@ public class Tenant { @JsonProperty("teacherQuota") private Integer maxTeachers; + @Schema(description = "创建人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新人用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/TenantCourse.java b/reading-platform-java/src/main/java/com/reading/platform/entity/TenantCourse.java index 92fb2f2..d291df4 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/TenantCourse.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/TenantCourse.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,24 +10,40 @@ import java.time.LocalDateTime; * 租户-课程关联实体 */ @Data -@TableName("tenant_courses") +@TableName("t_tenant_course") +@Schema(description = "租户课程关联") public class TenantCourse { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; - private Long tenantId; + @Schema(description = "租户 ID", accessMode = Schema.AccessMode.READ_ONLY) + private String tenantId; - private Long courseId; + @Schema(description = "课程 ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String courseId; + @Schema(description = "是否启用", example = "1") private Integer enabled; + @Schema(description = "创建者用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新者用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "逻辑删除标志", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Theme.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Theme.java index b8b32f3..c7d1f49 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Theme.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Theme.java @@ -1,6 +1,7 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; @@ -9,30 +10,49 @@ import java.time.LocalDateTime; * 主题实体 */ @Data -@TableName("themes") +@TableName("t_theme") +@Schema(description = "主题") public class Theme { - @TableId(type = IdType.AUTO) - private Long id; + @Schema(description = "ID", accessMode = Schema.AccessMode.READ_ONLY) + @TableId(type = IdType.ASSIGN_ID) + private String id; + @Schema(description = "主题名称", example = "default", requiredMode = Schema.RequiredMode.REQUIRED) private String name; + @Schema(description = "主题显示名称", example = "默认主题") private String displayName; + @Schema(description = "主题颜色", example = "#1890ff") private String color; + @Schema(description = "主题图标", example = "home") private String icon; + @Schema(description = "排序顺序", example = "1") private Integer sortOrder; + @Schema(description = "是否启用", example = "1") private Integer isEnabled; + @Schema(description = "创建者用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @Schema(description = "更新者用户名", accessMode = Schema.AccessMode.READ_ONLY) + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT) private LocalDateTime createdAt; + @Schema(description = "更新时间", accessMode = Schema.AccessMode.READ_ONLY) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; + @Schema(description = "逻辑删除标志", accessMode = Schema.AccessMode.READ_ONLY) @TableLogic private Integer deleted; } diff --git a/reading-platform-java/src/main/java/com/reading/platform/mapper/ParentMapper.java b/reading-platform-java/src/main/java/com/reading/platform/mapper/ParentMapper.java index 581f63f..29ddc74 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/mapper/ParentMapper.java +++ b/reading-platform-java/src/main/java/com/reading/platform/mapper/ParentMapper.java @@ -2,8 +2,16 @@ package com.reading.platform.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.reading.platform.entity.Parent; +import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; @Mapper public interface ParentMapper extends BaseMapper { + + /** + * 物理删除家长按用户名 + */ + @Delete("DELETE FROM t_parent WHERE username = #{username}") + void deletePhysicalByUsername(@Param("username") String username); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/mapper/StudentMapper.java b/reading-platform-java/src/main/java/com/reading/platform/mapper/StudentMapper.java index 4cc3224..c554184 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/mapper/StudentMapper.java +++ b/reading-platform-java/src/main/java/com/reading/platform/mapper/StudentMapper.java @@ -2,8 +2,16 @@ package com.reading.platform.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.reading.platform.entity.Student; +import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; @Mapper public interface StudentMapper extends BaseMapper { + + /** + * 物理删除学生按学号 + */ + @Delete("DELETE FROM t_student WHERE student_no = #{studentNo}") + void deletePhysicalByStudentNo(@Param("studentNo") String studentNo); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/mapper/TeacherMapper.java b/reading-platform-java/src/main/java/com/reading/platform/mapper/TeacherMapper.java index 6b7e489..66f0ec2 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/mapper/TeacherMapper.java +++ b/reading-platform-java/src/main/java/com/reading/platform/mapper/TeacherMapper.java @@ -2,8 +2,16 @@ package com.reading.platform.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.reading.platform.entity.Teacher; +import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; @Mapper public interface TeacherMapper extends BaseMapper { + + /** + * 物理删除教师按用户名 + */ + @Delete("DELETE FROM t_teacher WHERE username = #{username}") + int deletePhysicalByUsername(@Param("username") String username); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/mapper/TenantMapper.java b/reading-platform-java/src/main/java/com/reading/platform/mapper/TenantMapper.java index fbd0c5d..7c508d4 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/mapper/TenantMapper.java +++ b/reading-platform-java/src/main/java/com/reading/platform/mapper/TenantMapper.java @@ -2,8 +2,22 @@ package com.reading.platform.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.reading.platform.entity.Tenant; +import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; @Mapper public interface TenantMapper extends BaseMapper { + + /** + * 物理删除租户(忽略逻辑删除) + */ + @Delete("DELETE FROM t_tenant WHERE id = #{id}") + int deletePhysical(@Param("id") Long id); + + /** + * 物理删除租户按 code + */ + @Delete("DELETE FROM t_tenant WHERE code = #{code}") + int deletePhysicalByCode(@Param("code") String code); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/mapper/ThemeMapper.java b/reading-platform-java/src/main/java/com/reading/platform/mapper/ThemeMapper.java index 1f12c0b..29e63be 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/mapper/ThemeMapper.java +++ b/reading-platform-java/src/main/java/com/reading/platform/mapper/ThemeMapper.java @@ -2,8 +2,15 @@ package com.reading.platform.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.reading.platform.entity.Theme; +import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Mapper; @Mapper public interface ThemeMapper extends BaseMapper { + + /** + * 物理删除所有主题数据 + */ + @Delete("DELETE FROM t_theme") + void deletePhysical(); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/ClassService.java b/reading-platform-java/src/main/java/com/reading/platform/service/ClassService.java index 990e23d..d4d55ff 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/ClassService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/ClassService.java @@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.reading.platform.dto.request.ClassCreateRequest; import com.reading.platform.dto.request.ClassUpdateRequest; import com.reading.platform.entity.Clazz; +import com.reading.platform.entity.ClassTeacher; +import com.reading.platform.entity.Student; import java.util.List; @@ -12,24 +14,56 @@ import java.util.List; */ public interface ClassService { - Clazz createClass(Long tenantId, ClassCreateRequest request); + Clazz createClass(String tenantId, ClassCreateRequest request); - Clazz updateClass(Long id, ClassUpdateRequest request); + Clazz updateClass(String id, ClassUpdateRequest request); - Clazz getClassById(Long id); + Clazz getClassById(String id); - Page getClassPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String grade, String status); + Page getClassPage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String grade, String status); - void deleteClass(Long id); + void deleteClass(String id); - void assignTeachers(Long classId, List teacherIds); + void assignTeachers(String classId, List teacherIds); - void assignStudents(Long classId, List studentIds); + void assignStudents(String classId, List studentIds); - void removeTeacher(Long classId, Long teacherId); + void removeTeacher(String classId, String teacherId); - void removeStudent(Long classId, Long studentId); + void removeStudent(String classId, String studentId); - List getTeacherIdsByClassId(Long classId); + List getTeacherIdsByClassId(String classId); + + // ==================== 新增方法 ==================== + + /** + * 获取班级列表(无分页) + */ + List getClassList(String tenantId); + + /** + * 获取班级学生分页 + */ + Page getClassStudents(String classId, Integer pageNum, Integer pageSize, String keyword); + + /** + * 获取班级教师列表 + */ + List getClassTeachers(String classId); + + /** + * 添加班级教师 + */ + ClassTeacher addClassTeacher(String tenantId, String classId, String teacherId, String role, Boolean isPrimary); + + /** + * 更新班级教师角色 + */ + ClassTeacher updateClassTeacher(String tenantId, String classId, String teacherId, String role, Boolean isPrimary); + + /** + * 移除班级教师 + */ + void removeClassTeacher(String tenantId, String classId, String teacherId); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/CourseLessonService.java b/reading-platform-java/src/main/java/com/reading/platform/service/CourseLessonService.java index f7151d6..d52bd56 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/CourseLessonService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/CourseLessonService.java @@ -12,12 +12,12 @@ public interface CourseLessonService { /** * 根据课程 ID 获取课时列表 */ - List getLessonsByCourse(Long courseId); + List getLessonsByCourse(String courseId); /** * 根据 ID 获取课时 */ - CourseLesson getLessonById(Long id); + CourseLesson getLessonById(String id); /** * 创建课时 @@ -27,10 +27,10 @@ public interface CourseLessonService { /** * 更新课时 */ - CourseLesson updateLesson(Long id, CourseLesson lesson); + CourseLesson updateLesson(String id, CourseLesson lesson); /** * 删除课时 */ - void deleteLesson(Long id); + void deleteLesson(String id); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/CoursePackageService.java b/reading-platform-java/src/main/java/com/reading/platform/service/CoursePackageService.java index 0e41ae7..73e4869 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/CoursePackageService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/CoursePackageService.java @@ -16,7 +16,7 @@ public interface CoursePackageService { /** * 根据 ID 获取课程包 */ - CoursePackage getPackageById(Long id); + CoursePackage getPackageById(String id); /** * 创建课程包 @@ -26,30 +26,30 @@ public interface CoursePackageService { /** * 更新课程包 */ - CoursePackage updatePackage(Long id, CoursePackage pkg); + CoursePackage updatePackage(String id, CoursePackage pkg); /** * 删除课程包 */ - void deletePackage(Long id); + void deletePackage(String id); /** * 提交审核 */ - void submitPackage(Long id); + void submitPackage(String id); /** * 审核课程包 */ - void reviewPackage(Long id, boolean approved, String comment); + void reviewPackage(String id, boolean approved, String comment); /** * 发布课程包 */ - void publishPackage(Long id); + void publishPackage(String id); /** * 下架课程包 */ - void offlinePackage(Long id); + void offlinePackage(String id); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/CourseService.java b/reading-platform-java/src/main/java/com/reading/platform/service/CourseService.java index 856565f..e5e0f03 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/CourseService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/CourseService.java @@ -12,32 +12,32 @@ import java.util.List; */ public interface CourseService { - Course createCourse(Long tenantId, CourseCreateRequest request); + Course createCourse(String tenantId, CourseCreateRequest request); - Course updateCourse(Long id, CourseUpdateRequest request); + Course updateCourse(String id, CourseUpdateRequest request); - Course getCourseById(Long id); + Course getCourseById(String id); - Page getCoursePage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String category, String status); + Page getCoursePage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String category, String status); Page getSystemCoursePage(Integer pageNum, Integer pageSize, String keyword, String category, String status); - void deleteCourse(Long id); + void deleteCourse(String id); - void publishCourse(Long id); + void publishCourse(String id); - void archiveCourse(Long id); + void archiveCourse(String id); - List getCoursesByTenantId(Long tenantId); + List getCoursesByTenantId(String tenantId); Page getReviewCoursePage(Integer pageNum, Integer pageSize); - void submitCourse(Long id); + void submitCourse(String id); - void withdrawCourse(Long id); + void withdrawCourse(String id); - void approveCourse(Long id, String comment); + void approveCourse(String id, String comment); - void rejectCourse(Long id, String comment); + void rejectCourse(String id, String comment); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/ExportService.java b/reading-platform-java/src/main/java/com/reading/platform/service/ExportService.java index a5d98c4..bcb9839 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/ExportService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/ExportService.java @@ -10,20 +10,20 @@ public interface ExportService { /** * 导出教师数据 */ - byte[] exportTeachers(Long tenantId) throws IOException; + byte[] exportTeachers(String tenantId) throws IOException; /** * 导出学生数据 */ - byte[] exportStudents(Long tenantId) throws IOException; + byte[] exportStudents(String tenantId) throws IOException; /** * 导出课时数据 */ - byte[] exportLessons(Long tenantId) throws IOException; + byte[] exportLessons(String tenantId) throws IOException; /** * 导出成长档案 */ - byte[] exportGrowthRecords(Long tenantId) throws IOException; + byte[] exportGrowthRecords(String tenantId) throws IOException; } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/GrowthRecordService.java b/reading-platform-java/src/main/java/com/reading/platform/service/GrowthRecordService.java index 1b9263b..2bb9de6 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/GrowthRecordService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/GrowthRecordService.java @@ -12,18 +12,18 @@ import java.util.List; */ public interface GrowthRecordService { - GrowthRecord createGrowthRecord(Long tenantId, Long recorderId, String recorderRole, GrowthRecordCreateRequest request); + GrowthRecord createGrowthRecord(String tenantId, String recorderId, String recorderRole, GrowthRecordCreateRequest request); - GrowthRecord updateGrowthRecord(Long id, GrowthRecordUpdateRequest request); + GrowthRecord updateGrowthRecord(String id, GrowthRecordUpdateRequest request); - GrowthRecord getGrowthRecordById(Long id); + GrowthRecord getGrowthRecordById(String id); - Page getGrowthRecordPage(Long tenantId, Integer pageNum, Integer pageSize, Long studentId, String type); + Page getGrowthRecordPage(String tenantId, Integer pageNum, Integer pageSize, String studentId, String type); - Page getGrowthRecordsByStudentId(Long studentId, Integer pageNum, Integer pageSize, String type); + Page getGrowthRecordsByStudentId(String studentId, Integer pageNum, Integer pageSize, String type); - void deleteGrowthRecord(Long id); + void deleteGrowthRecord(String id); - List getRecentGrowthRecords(Long studentId, Integer limit); + List getRecentGrowthRecords(String studentId, Integer limit); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/LessonService.java b/reading-platform-java/src/main/java/com/reading/platform/service/LessonService.java index afe7fd3..6813d12 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/LessonService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/LessonService.java @@ -4,33 +4,68 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.reading.platform.dto.request.LessonCreateRequest; import com.reading.platform.dto.request.LessonUpdateRequest; import com.reading.platform.entity.Lesson; +import com.reading.platform.entity.LessonFeedback; +import com.reading.platform.entity.StudentRecord; import java.time.LocalDate; import java.util.List; +import java.util.Map; /** * Lesson Service Interface */ public interface LessonService { - Lesson createLesson(Long tenantId, LessonCreateRequest request); + Lesson createLesson(String tenantId, LessonCreateRequest request); - Lesson updateLesson(Long id, LessonUpdateRequest request); + Lesson updateLesson(String id, LessonUpdateRequest request); - Lesson getLessonById(Long id); + Lesson getLessonById(String id); - Page getLessonPage(Long tenantId, Integer pageNum, Integer pageSize, Long classId, Long teacherId, String status, LocalDate startDate, LocalDate endDate); + Page getLessonPage(String tenantId, Integer pageNum, Integer pageSize, String classId, String teacherId, String status, LocalDate startDate, LocalDate endDate); - Page getTeacherLessons(Long teacherId, Integer pageNum, Integer pageSize, String status, LocalDate startDate, LocalDate endDate); + Page getTeacherLessons(String teacherId, Integer pageNum, Integer pageSize, String status, LocalDate startDate, LocalDate endDate); - void deleteLesson(Long id); + void deleteLesson(String id); - void startLesson(Long id); + void startLesson(String id); - void completeLesson(Long id); + void completeLesson(String id); - void cancelLesson(Long id); + void cancelLesson(String id); - List getTodayLessons(Long tenantId); + List getTodayLessons(String tenantId); + + // ==================== 新增方法 ==================== + + /** + * 结束上课 + */ + Lesson finishLesson(String id, Integer actualDuration, String overallRating, String participationRating, String completionNote); + + /** + * 保存学生评价记录 + */ + StudentRecord saveStudentRecord(String lessonId, String studentId, Integer focus, Integer participation, Integer interest, Integer understanding, String notes); + + /** + * 获取课程所有学生记录 + */ + List getStudentRecords(String lessonId); + + /** + * 批量保存学生评价记录 + */ + int batchSaveStudentRecords(String lessonId, List> records); + + /** + * 提交课程反馈 + */ + LessonFeedback saveLessonFeedback(String tenantId, String lessonId, String teacherId, Map feedbackData); + + /** + * 获取课程反馈 + */ + LessonFeedback getLessonFeedback(String lessonId); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/NotificationService.java b/reading-platform-java/src/main/java/com/reading/platform/service/NotificationService.java index 905ccd8..61643dd 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/NotificationService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/NotificationService.java @@ -8,21 +8,21 @@ import com.reading.platform.entity.Notification; */ public interface NotificationService { - Notification createNotification(Long tenantId, Long senderId, String senderRole, String title, String content, - String type, String recipientType, Long recipientId); + Notification createNotification(String tenantId, String senderId, String senderRole, String title, String content, + String type, String recipientType, String recipientId); - Notification getNotificationById(Long id); + Notification getNotificationById(String id); - Page getNotificationPage(Long tenantId, Integer pageNum, Integer pageSize, String type, Integer isRead); + Page getNotificationPage(String tenantId, Integer pageNum, Integer pageSize, String type, Integer isRead); - Page getMyNotifications(Long recipientId, String recipientType, Integer pageNum, Integer pageSize, Integer isRead); + Page getMyNotifications(String recipientId, String recipientType, Integer pageNum, Integer pageSize, Integer isRead); - void markAsRead(Long id); + void markAsRead(String id); - void markAllAsRead(Long recipientId, String recipientType); + void markAllAsRead(String recipientId, String recipientType); - void deleteNotification(Long id); + void deleteNotification(String id); - Long getUnreadCount(Long recipientId, String recipientType); + Long getUnreadCount(String recipientId, String recipientType); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/OperationLogService.java b/reading-platform-java/src/main/java/com/reading/platform/service/OperationLogService.java index 54bfb42..6445600 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/OperationLogService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/OperationLogService.java @@ -11,10 +11,10 @@ public interface OperationLogService { /** * 获取操作日志分页 */ - Page getLogs(int pageNum, int pageSize, Long tenantId, String module); + Page getLogs(int pageNum, int pageSize, String tenantId, String module); /** * 记录操作日志 */ - void log(String action, String module, String targetType, Long targetId, String details); + void log(String action, String module, String targetType, String targetId, String details); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/ParentService.java b/reading-platform-java/src/main/java/com/reading/platform/service/ParentService.java index 46d25f3..55dd773 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/ParentService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/ParentService.java @@ -12,20 +12,20 @@ import java.util.List; */ public interface ParentService { - Parent createParent(Long tenantId, ParentCreateRequest request); + Parent createParent(String tenantId, ParentCreateRequest request); - Parent updateParent(Long id, ParentUpdateRequest request); + Parent updateParent(String id, ParentUpdateRequest request); - Parent getParentById(Long id); + Parent getParentById(String id); - Page getParentPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String status); + Page getParentPage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String status); - void deleteParent(Long id); + void deleteParent(String id); - void resetPassword(Long id, String newPassword); + void resetPassword(String id, String newPassword); - void bindStudent(Long parentId, Long studentId, String relationship, Boolean isPrimary); + void bindStudent(String parentId, String studentId, String relationship, Boolean isPrimary); - void unbindStudent(Long parentId, Long studentId); + void unbindStudent(String parentId, String studentId); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/ResourceService.java b/reading-platform-java/src/main/java/com/reading/platform/service/ResourceService.java index efa2d19..829fb1b 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/ResourceService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/ResourceService.java @@ -14,12 +14,12 @@ public interface ResourceService { /** * 获取资源库列表 */ - List getLibraries(Long tenantId); + List getLibraries(String tenantId); /** * 根据 ID 获取资源库 */ - ResourceLibrary getLibraryById(Long id); + ResourceLibrary getLibraryById(String id); /** * 创建资源库 @@ -29,22 +29,22 @@ public interface ResourceService { /** * 更新资源库 */ - ResourceLibrary updateLibrary(Long id, ResourceLibrary library); + ResourceLibrary updateLibrary(String id, ResourceLibrary library); /** * 删除资源库 */ - void deleteLibrary(Long id); + void deleteLibrary(String id); /** * 获取资源项分页 */ - Page getItems(int pageNum, int pageSize, Long libraryId, String keyword); + Page getItems(int pageNum, int pageSize, String libraryId, String keyword); /** * 根据 ID 获取资源项 */ - ResourceItem getItemById(Long id); + ResourceItem getItemById(String id); /** * 创建资源项 @@ -54,10 +54,10 @@ public interface ResourceService { /** * 更新资源项 */ - ResourceItem updateItem(Long id, ResourceItem item); + ResourceItem updateItem(String id, ResourceItem item); /** * 删除资源项 */ - void deleteItem(Long id); + void deleteItem(String id); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/ScheduleService.java b/reading-platform-java/src/main/java/com/reading/platform/service/ScheduleService.java index 9607182..6e41230 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/ScheduleService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/ScheduleService.java @@ -18,75 +18,75 @@ public interface ScheduleService { /** * 获取课表计划分页 */ - Page getSchedulePlans(int pageNum, int pageSize, Long tenantId, Long classId); + Page getSchedulePlans(int pageNum, int pageSize, String tenantId, String classId); /** * 获取课表计划分页(按日期范围) */ - Page getSchedulePlans(int pageNum, int pageSize, Long tenantId, Long classId, LocalDate startDate, LocalDate endDate); + Page getSchedulePlans(int pageNum, int pageSize, String tenantId, String classId, LocalDate startDate, LocalDate endDate); /** * 根据 ID 获取课表计划 */ - SchedulePlan getSchedulePlanById(Long id); + SchedulePlan getSchedulePlanById(String id); /** * 创建课表计划 */ - SchedulePlan createSchedulePlan(Long tenantId, SchedulePlan plan); + SchedulePlan createSchedulePlan(String tenantId, SchedulePlan plan); /** * 创建课表计划 */ - SchedulePlan createSchedulePlan(Long tenantId, Long userId, SchedulePlanCreateRequest request); + SchedulePlan createSchedulePlan(String tenantId, String userId, SchedulePlanCreateRequest request); /** * 更新课表计划 */ - SchedulePlan updateSchedulePlan(Long id, SchedulePlan plan); + SchedulePlan updateSchedulePlan(String id, SchedulePlan plan); /** * 删除课表计划 */ - void deleteSchedulePlan(Long id); + void deleteSchedulePlan(String id); /** * 批量创建课表计划 */ - List batchCreateSchedules(Long tenantId, Long userId, List requests); + List batchCreateSchedules(String tenantId, String userId, List requests); /** * 获取课表 */ - List> getTimetable(Long tenantId, LocalDate startDate, LocalDate endDate, Long classId); + List> getTimetable(String tenantId, LocalDate startDate, LocalDate endDate, String classId); /** * 获取课表模板分页 */ - Page getScheduleTemplates(int pageNum, int pageSize, Long tenantId); + Page getScheduleTemplates(int pageNum, int pageSize, String tenantId); /** * 根据 ID 获取课表模板 */ - ScheduleTemplate getScheduleTemplateById(Long id); + ScheduleTemplate getScheduleTemplateById(String id); /** * 创建课表模板 */ - ScheduleTemplate createScheduleTemplate(Long tenantId, ScheduleTemplate template); + ScheduleTemplate createScheduleTemplate(String tenantId, ScheduleTemplate template); /** * 更新课表模板 */ - ScheduleTemplate updateScheduleTemplate(Long id, ScheduleTemplate template); + ScheduleTemplate updateScheduleTemplate(String id, ScheduleTemplate template); /** * 删除课表模板 */ - void deleteScheduleTemplate(Long id); + void deleteScheduleTemplate(String id); /** * 应用课表模板 */ - List applyScheduleTemplate(Long tenantId, Long templateId, ScheduleTemplateApplyRequest request); + List applyScheduleTemplate(String tenantId, String templateId, ScheduleTemplateApplyRequest request); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/SchoolCourseService.java b/reading-platform-java/src/main/java/com/reading/platform/service/SchoolCourseService.java index c3561ce..be73c88 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/SchoolCourseService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/SchoolCourseService.java @@ -11,25 +11,25 @@ public interface SchoolCourseService { /** * 获取校本课程分页 */ - Page getCourses(int pageNum, int pageSize, Long tenantId, String keyword); + Page getCourses(int pageNum, int pageSize, String tenantId, String keyword); /** * 根据 ID 获取校本课程 */ - SchoolCourse getCourseById(Long id); + SchoolCourse getCourseById(String id); /** * 创建校本课程 */ - SchoolCourse createCourse(Long tenantId, Long userId, SchoolCourse course); + SchoolCourse createCourse(String tenantId, String userId, SchoolCourse course); /** * 更新校本课程 */ - SchoolCourse updateCourse(Long id, SchoolCourse course); + SchoolCourse updateCourse(String id, SchoolCourse course); /** * 删除校本课程 */ - void deleteCourse(Long id); + void deleteCourse(String id); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/SchoolStatsService.java b/reading-platform-java/src/main/java/com/reading/platform/service/SchoolStatsService.java index f17df04..632d0bf 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/SchoolStatsService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/SchoolStatsService.java @@ -11,31 +11,31 @@ public interface SchoolStatsService { /** * 获取学校统计数据 */ - Map getStats(Long tenantId); + Map getStats(String tenantId); /** * 获取活跃教师统计(授课次数最多的前 N 名教师) */ - List> getActiveTeachers(Long tenantId, Integer limit); + List> getActiveTeachers(String tenantId, Integer limit); /** * 获取课程使用统计(按课时完成次数排序) */ - List> getCourseUsageStats(Long tenantId); + List> getCourseUsageStats(String tenantId); /** * 获取最近活动记录 */ - List> getRecentActivities(Long tenantId, Integer limit); + List> getRecentActivities(String tenantId, Integer limit); /** * 获取课时趋势(最近 N 个月) */ - List> getLessonTrend(Long tenantId, Integer months); + List> getLessonTrend(String tenantId, Integer months); /** * 获取课程分布统计(饼图数据) */ - List> getCourseDistribution(Long tenantId); + List> getCourseDistribution(String tenantId); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/StudentService.java b/reading-platform-java/src/main/java/com/reading/platform/service/StudentService.java index a57a999..1dc4aee 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/StudentService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/StudentService.java @@ -3,6 +3,7 @@ package com.reading.platform.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.reading.platform.dto.request.StudentCreateRequest; import com.reading.platform.dto.request.StudentUpdateRequest; +import com.reading.platform.dto.response.StudentTransferHistoryResponse; import com.reading.platform.entity.Student; import java.util.List; @@ -12,20 +13,32 @@ import java.util.List; */ public interface StudentService { - Student createStudent(Long tenantId, StudentCreateRequest request); + Student createStudent(String tenantId, StudentCreateRequest request); - Student updateStudent(Long id, StudentUpdateRequest request); + Student updateStudent(String id, StudentUpdateRequest request); - Student getStudentById(Long id); + Student getStudentById(String id); - Page getStudentPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String grade, String status); + Page getStudentPage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String grade, String status); - Page getStudentsByClassId(Long classId, Integer pageNum, Integer pageSize); + Page getStudentsByClassId(String classId, Integer pageNum, Integer pageSize); - void deleteStudent(Long id); + void deleteStudent(String id); - List getStudentsByParentId(Long parentId); + List getStudentsByParentId(String parentId); - List importStudents(Long tenantId, List requests); + List importStudents(String tenantId, List requests); + + // ==================== 新增方法 ==================== + + /** + * 学生调班 + */ + void transferStudent(String tenantId, String studentId, String toClassId, String reason); + + /** + * 获取学生调班历史 + */ + List getStudentClassHistory(String studentId); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/SystemSettingService.java b/reading-platform-java/src/main/java/com/reading/platform/service/SystemSettingService.java index fe0a39a..09f70c8 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/SystemSettingService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/SystemSettingService.java @@ -10,15 +10,15 @@ public interface SystemSettingService { /** * 获取系统设置 */ - Map getSettings(Long tenantId); + Map getSettings(String tenantId); /** * 更新系统设置 */ - void updateSettings(Long tenantId, Map settings); + void updateSettings(String tenantId, Map settings); /** * 获取单个设置项 */ - String getSetting(Long tenantId, String key); + String getSetting(String tenantId, String key); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/TaskService.java b/reading-platform-java/src/main/java/com/reading/platform/service/TaskService.java index 7c37028..12de35f 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/TaskService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/TaskService.java @@ -14,89 +14,94 @@ import java.util.Map; */ public interface TaskService { - Task createTask(Long tenantId, Long creatorId, String creatorRole, TaskCreateRequest request); + Task createTask(String tenantId, String creatorId, String creatorRole, TaskCreateRequest request); - Task updateTask(Long id, TaskUpdateRequest request); + Task updateTask(String id, TaskUpdateRequest request); - Task getTaskById(Long id); + Task getTaskById(String id); - Page getTaskPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status); + Page getTaskPage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status); - Page getTasksByStudentId(Long studentId, Integer pageNum, Integer pageSize, String status); + Page getTasksByStudentId(String studentId, Integer pageNum, Integer pageSize, String status); - void deleteTask(Long id); + void deleteTask(String id); - void completeTask(Long taskId, Long studentId, String content, String attachments); + void completeTask(String taskId, String studentId, String content, String attachments); - List getTasksByClassId(Long classId); + List getTasksByClassId(String classId); // ==================== 任务统计 ==================== /** * 获取任务统计数据 */ - Map getTaskStats(Long tenantId); + Map getTaskStats(String tenantId); /** * 按任务类型统计 */ - Map getStatsByType(Long tenantId); + Map getStatsByType(String tenantId); /** * 按班级统计 */ - List> getStatsByClass(Long tenantId); + List> getStatsByClass(String tenantId); /** * 获取月度统计趋势 */ - List> getMonthlyStats(Long tenantId, Integer months); + List> getMonthlyStats(String tenantId, Integer months); /** * 获取任务完成情况分页 */ - Page getTaskCompletions(Long tenantId, Long taskId, Integer pageNum, Integer pageSize, String status); + Page getTaskCompletions(String tenantId, String taskId, Integer pageNum, Integer pageSize, String status); /** * 更新任务完成状态 */ - TaskCompletion updateTaskCompletion(Long tenantId, Long taskId, Long studentId, String status, String feedback); + TaskCompletion updateTaskCompletion(String tenantId, String taskId, String studentId, String status, String feedback); // ==================== 任务模板 ==================== /** * 获取模板列表 */ - Page getTemplatePage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type); + Page getTemplatePage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String type); /** * 根据 ID 获取模板 */ - TaskTemplate getTemplateById(Long tenantId, Long id); + TaskTemplate getTemplateById(String tenantId, String id); /** * 获取默认模板(按类型) */ - TaskTemplate getDefaultTemplate(Long tenantId, String taskType); + TaskTemplate getDefaultTemplate(String tenantId, String taskType); /** * 创建模板 */ - TaskTemplate createTemplate(Long tenantId, Long creatorId, TaskTemplateCreateRequest request); + TaskTemplate createTemplate(String tenantId, String creatorId, TaskTemplateCreateRequest request); /** * 更新模板 */ - TaskTemplate updateTemplate(Long tenantId, Long id, TaskTemplateUpdateRequest request); + TaskTemplate updateTemplate(String tenantId, String id, TaskTemplateUpdateRequest request); /** * 删除模板 */ - void deleteTemplate(Long tenantId, Long id); + void deleteTemplate(String tenantId, String id); /** * 从模板创建任务 */ - Task createTaskFromTemplate(Long tenantId, Long creatorId, String creatorRole, CreateTaskFromTemplateRequest request); + Task createTaskFromTemplate(String tenantId, String creatorId, String creatorRole, CreateTaskFromTemplateRequest request); + + /** + * 获取任务完成记录 + */ + TaskCompletion getTaskCompletion(String taskId, String studentId); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/TeacherDashboardService.java b/reading-platform-java/src/main/java/com/reading/platform/service/TeacherDashboardService.java index 0899128..78ab6ad 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/TeacherDashboardService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/TeacherDashboardService.java @@ -11,15 +11,15 @@ public interface TeacherDashboardService { /** * 获取仪表板数据 */ - Map getDashboard(Long teacherId, Long tenantId); + Map getDashboard(String teacherId, String tenantId); /** * 获取今天的课时 */ - List> getTodayLessons(Long teacherId, Long tenantId); + List> getTodayLessons(String teacherId, String tenantId); /** * 获取本周的课时 */ - List> getWeeklyLessons(Long teacherId, Long tenantId); + List> getWeeklyLessons(String teacherId, String tenantId); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/TeacherService.java b/reading-platform-java/src/main/java/com/reading/platform/service/TeacherService.java index 88796a1..bf0a5a1 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/TeacherService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/TeacherService.java @@ -10,16 +10,16 @@ import com.reading.platform.entity.Teacher; */ public interface TeacherService { - Teacher createTeacher(Long tenantId, TeacherCreateRequest request); + Teacher createTeacher(String tenantId, TeacherCreateRequest request); - Teacher updateTeacher(Long id, TeacherUpdateRequest request); + Teacher updateTeacher(String id, TeacherUpdateRequest request); - Teacher getTeacherById(Long id); + Teacher getTeacherById(String id); - Page getTeacherPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String status); + Page getTeacherPage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String status); - void deleteTeacher(Long id); + void deleteTeacher(String id); - void resetPassword(Long id, String newPassword); + void resetPassword(String id, String newPassword); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/TenantService.java b/reading-platform-java/src/main/java/com/reading/platform/service/TenantService.java index 4b7d803..f63960b 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/TenantService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/TenantService.java @@ -15,16 +15,16 @@ public interface TenantService { Tenant createTenant(TenantCreateRequest request); - Tenant updateTenant(Long id, TenantUpdateRequest request); + Tenant updateTenant(String id, TenantUpdateRequest request); - Tenant getTenantById(Long id); + Tenant getTenantById(String id); Page getTenantPage(Integer pageNum, Integer pageSize, String keyword, String status); - void deleteTenant(Long id); + void deleteTenant(String id); List getAllActiveTenants(); - String resetSchoolAccountPassword(Long tenantId); + String resetSchoolAccountPassword(String tenantId); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/ThemeService.java b/reading-platform-java/src/main/java/com/reading/platform/service/ThemeService.java index 76ce3d9..fd4db2f 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/ThemeService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/ThemeService.java @@ -17,7 +17,7 @@ public interface ThemeService { /** * 根据 ID 获取主题 */ - Theme getThemeById(Long id); + Theme getThemeById(String id); /** * 创建主题 @@ -27,10 +27,10 @@ public interface ThemeService { /** * 更新主题 */ - Theme updateTheme(Long id, Theme theme); + Theme updateTheme(String id, Theme theme); /** * 删除主题 */ - void deleteTheme(Long id); + void deleteTheme(String id); } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/AuthServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/AuthServiceImpl.java index 0643b1d..b830c05 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/AuthServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/AuthServiceImpl.java @@ -318,7 +318,7 @@ public class AuthServiceImpl implements AuthService { public void changePassword(String oldPassword, String newPassword) { JwtPayload payload = SecurityUtils.getCurrentUser(); String role = payload.getRole(); - Long userId = payload.getUserId(); + String userId = payload.getUserId(); switch (role) { case "admin" -> { diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ClassServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ClassServiceImpl.java index 1042716..7d2d3d1 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ClassServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ClassServiceImpl.java @@ -9,10 +9,12 @@ import com.reading.platform.dto.request.ClassCreateRequest; import com.reading.platform.dto.request.ClassUpdateRequest; import com.reading.platform.entity.ClassTeacher; import com.reading.platform.entity.Clazz; +import com.reading.platform.entity.Student; import com.reading.platform.entity.StudentClassHistory; import com.reading.platform.mapper.ClassTeacherMapper; import com.reading.platform.mapper.ClazzMapper; import com.reading.platform.mapper.StudentClassHistoryMapper; +import com.reading.platform.mapper.StudentMapper; import com.reading.platform.service.ClassService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -30,10 +32,11 @@ public class ClassServiceImpl implements ClassService { private final ClazzMapper clazzMapper; private final ClassTeacherMapper classTeacherMapper; private final StudentClassHistoryMapper studentClassHistoryMapper; + private final StudentMapper studentMapper; @Override @Transactional - public Clazz createClass(Long tenantId, ClassCreateRequest request) { + public Clazz createClass(String tenantId, ClassCreateRequest request) { Clazz clazz = new Clazz(); clazz.setTenantId(tenantId); clazz.setName(request.getName()); @@ -48,7 +51,7 @@ public class ClassServiceImpl implements ClassService { @Override @Transactional - public Clazz updateClass(Long id, ClassUpdateRequest request) { + public Clazz updateClass(String id, ClassUpdateRequest request) { Clazz clazz = getClassById(id); if (StringUtils.hasText(request.getName())) { @@ -72,7 +75,7 @@ public class ClassServiceImpl implements ClassService { } @Override - public Clazz getClassById(Long id) { + public Clazz getClassById(String id) { Clazz clazz = clazzMapper.selectById(id); if (clazz == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Class not found"); @@ -81,7 +84,7 @@ public class ClassServiceImpl implements ClassService { } @Override - public Page getClassPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String grade, String status) { + public Page getClassPage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String grade, String status) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -103,14 +106,14 @@ public class ClassServiceImpl implements ClassService { @Override @Transactional - public void deleteClass(Long id) { + public void deleteClass(String id) { getClassById(id); clazzMapper.deleteById(id); } @Override @Transactional - public void assignTeachers(Long classId, List teacherIds) { + public void assignTeachers(String classId, List teacherIds) { // Verify class exists getClassById(classId); @@ -120,18 +123,18 @@ public class ClassServiceImpl implements ClassService { ); // Create new assignments - for (Long teacherId : teacherIds) { - ClassTeacher classTeacher = new ClassTeacher(); - classTeacher.setClassId(classId); - classTeacher.setTeacherId(teacherId); - classTeacher.setRole("teacher"); - classTeacherMapper.insert(classTeacher); + for (String teacherId : teacherIds) { + ClassTeacher classTeachers = new ClassTeacher(); + classTeachers.setClassId(classId); + classTeachers.setTeacherId(teacherId); + classTeachers.setRole("teacher"); + classTeacherMapper.insert(classTeachers); } } @Override @Transactional - public void assignStudents(Long classId, List studentIds) { + public void assignStudents(String classId, List studentIds) { // Verify class exists getClassById(classId); @@ -149,7 +152,7 @@ public class ClassServiceImpl implements ClassService { } // Create new assignments - for (Long studentId : studentIds) { + for (String studentId : studentIds) { StudentClassHistory history = new StudentClassHistory(); history.setStudentId(studentId); history.setClassId(classId); @@ -160,12 +163,12 @@ public class ClassServiceImpl implements ClassService { } @Override - public List getTeacherIdsByClassId(Long classId) { + public List getTeacherIdsByClassId(String classId) { List classTeachers = classTeacherMapper.selectList( new LambdaQueryWrapper().eq(ClassTeacher::getClassId, classId) ); - List teacherIds = new ArrayList<>(); + List teacherIds = new ArrayList<>(); for (ClassTeacher ct : classTeachers) { teacherIds.add(ct.getTeacherId()); } @@ -174,7 +177,7 @@ public class ClassServiceImpl implements ClassService { @Override @Transactional - public void removeTeacher(Long classId, Long teacherId) { + public void removeTeacher(String classId, String teacherId) { // Verify class exists getClassById(classId); @@ -188,7 +191,7 @@ public class ClassServiceImpl implements ClassService { @Override @Transactional - public void removeStudent(Long classId, Long studentId) { + public void removeStudent(String classId, String studentId) { // Verify class exists getClassById(classId); @@ -208,4 +211,120 @@ public class ClassServiceImpl implements ClassService { } } + @Override + public List getClassList(String tenantId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Clazz::getTenantId, tenantId) + .eq(Clazz::getStatus, "active") + .orderByDesc(Clazz::getCreatedAt); + return clazzMapper.selectList(wrapper); + } + + @Override + public Page getClassStudents(String classId, Integer pageNum, Integer pageSize, String keyword) { + Page page = PageUtils.of(pageNum, pageSize); + + // 获取班级 active 状态的学生 + List histories = studentClassHistoryMapper.selectList( + new LambdaQueryWrapper() + .eq(StudentClassHistory::getClassId, classId) + .eq(StudentClassHistory::getStatus, "active") + .isNull(StudentClassHistory::getEndDate) + ); + + if (histories.isEmpty()) { + return new Page<>(pageNum, pageSize, 0); + } + + List studentIds = new ArrayList<>(); + for (StudentClassHistory history : histories) { + studentIds.add(history.getStudentId()); + } + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.in(Student::getId, studentIds); + + if (StringUtils.hasText(keyword)) { + wrapper.like(Student::getName, keyword); + } + wrapper.orderByDesc(Student::getCreatedAt); + + return studentMapper.selectPage(page, wrapper); + } + + @Override + public List getClassTeachers(String classId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(ClassTeacher::getClassId, classId) + .orderByAsc(ClassTeacher::getSortOrder); + return classTeacherMapper.selectList(wrapper); + } + + @Override + @Transactional + public ClassTeacher addClassTeacher(String tenantId, String classId, String teacherId, String role, Boolean isPrimary) { + // 验证班级是否存在 + getClassById(classId); + + // 检查是否已存在 + ClassTeacher existing = classTeacherMapper.selectOne( + new LambdaQueryWrapper() + .eq(ClassTeacher::getClassId, classId) + .eq(ClassTeacher::getTeacherId, teacherId) + ); + + if (existing != null) { + throw new BusinessException(ErrorCode.DATA_ALREADY_EXISTS, "该教师已在班级中"); + } + + ClassTeacher classTeachers = new ClassTeacher(); + classTeachers.setClassId(classId); + classTeachers.setTeacherId(teacherId); + classTeachers.setRole(role != null ? role : "ASSIST"); + classTeachers.setIsPrimary(isPrimary != null ? isPrimary : false); + classTeacherMapper.insert(classTeachers); + + return classTeachers; + } + + @Override + @Transactional + public ClassTeacher updateClassTeacher(String tenantId, String classId, String teacherId, String role, Boolean isPrimary) { + // 验证班级是否存在 + getClassById(classId); + + ClassTeacher classTeachers = classTeacherMapper.selectOne( + new LambdaQueryWrapper() + .eq(ClassTeacher::getClassId, classId) + .eq(ClassTeacher::getTeacherId, teacherId) + ); + + if (classTeachers == null) { + throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "班级教师关系不存在"); + } + + if (StringUtils.hasText(role)) { + classTeachers.setRole(role); + } + if (isPrimary != null) { + classTeachers.setIsPrimary(isPrimary); + } + + classTeacherMapper.updateById(classTeachers); + return classTeachers; + } + + @Override + @Transactional + public void removeClassTeacher(String tenantId, String classId, String teacherId) { + // 验证班级是否存在 + getClassById(classId); + + classTeacherMapper.delete( + new LambdaQueryWrapper() + .eq(ClassTeacher::getClassId, classId) + .eq(ClassTeacher::getTeacherId, teacherId) + ); + } + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/CourseLessonServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/CourseLessonServiceImpl.java index ae1c316..e34827c 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/CourseLessonServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/CourseLessonServiceImpl.java @@ -21,7 +21,7 @@ public class CourseLessonServiceImpl implements CourseLessonService { private final CourseLessonMapper courseLessonMapper; @Override - public List getLessonsByCourse(Long courseId) { + public List getLessonsByCourse(String courseId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(CourseLesson::getCourseId, courseId) .orderByAsc(CourseLesson::getSortOrder); @@ -29,7 +29,7 @@ public class CourseLessonServiceImpl implements CourseLessonService { } @Override - public CourseLesson getLessonById(Long id) { + public CourseLesson getLessonById(String id) { CourseLesson lesson = courseLessonMapper.selectById(id); if (lesson == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Course lesson not found"); @@ -44,7 +44,7 @@ public class CourseLessonServiceImpl implements CourseLessonService { } @Override - public CourseLesson updateLesson(Long id, CourseLesson lesson) { + public CourseLesson updateLesson(String id, CourseLesson lesson) { getLessonById(id); lesson.setId(id); courseLessonMapper.updateById(lesson); @@ -52,7 +52,7 @@ public class CourseLessonServiceImpl implements CourseLessonService { } @Override - public void deleteLesson(Long id) { + public void deleteLesson(String id) { courseLessonMapper.deleteById(id); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/CoursePackageServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/CoursePackageServiceImpl.java index 7974b6b..5e15382 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/CoursePackageServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/CoursePackageServiceImpl.java @@ -34,7 +34,7 @@ public class CoursePackageServiceImpl implements CoursePackageService { } @Override - public CoursePackage getPackageById(Long id) { + public CoursePackage getPackageById(String id) { CoursePackage pkg = coursePackageMapper.selectById(id); if (pkg == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Course package not found"); @@ -49,7 +49,7 @@ public class CoursePackageServiceImpl implements CoursePackageService { } @Override - public CoursePackage updatePackage(Long id, CoursePackage pkg) { + public CoursePackage updatePackage(String id, CoursePackage pkg) { getPackageById(id); pkg.setId(id); coursePackageMapper.updateById(pkg); @@ -57,33 +57,33 @@ public class CoursePackageServiceImpl implements CoursePackageService { } @Override - public void deletePackage(Long id) { + public void deletePackage(String id) { coursePackageMapper.deleteById(id); } @Override - public void submitPackage(Long id) { + public void submitPackage(String id) { CoursePackage pkg = getPackageById(id); pkg.setStatus("pending"); coursePackageMapper.updateById(pkg); } @Override - public void reviewPackage(Long id, boolean approved, String comment) { + public void reviewPackage(String id, boolean approved, String comment) { CoursePackage pkg = getPackageById(id); pkg.setStatus(approved ? "published" : "rejected"); coursePackageMapper.updateById(pkg); } @Override - public void publishPackage(Long id) { + public void publishPackage(String id) { CoursePackage pkg = getPackageById(id); pkg.setStatus("published"); coursePackageMapper.updateById(pkg); } @Override - public void offlinePackage(Long id) { + public void offlinePackage(String id) { CoursePackage pkg = getPackageById(id); pkg.setStatus("archived"); coursePackageMapper.updateById(pkg); diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/CourseServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/CourseServiceImpl.java index 51c6af3..15a1587 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/CourseServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/CourseServiceImpl.java @@ -28,7 +28,7 @@ public class CourseServiceImpl implements CourseService { @Override @Transactional - public Course createCourse(Long tenantId, CourseCreateRequest request) { + public Course createCourse(String tenantId, CourseCreateRequest request) { Course course = new Course(); course.setTenantId(tenantId); course.setName(request.getName()); @@ -86,7 +86,7 @@ public class CourseServiceImpl implements CourseService { @Override @Transactional - public Course updateCourse(Long id, CourseUpdateRequest request) { + public Course updateCourse(String id, CourseUpdateRequest request) { Course course = getCourseById(id); // Basic fields @@ -216,7 +216,7 @@ public class CourseServiceImpl implements CourseService { } @Override - public Course getCourseById(Long id) { + public Course getCourseById(String id) { Course course = courseMapper.selectById(id); if (course == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Course not found"); @@ -225,7 +225,7 @@ public class CourseServiceImpl implements CourseService { } @Override - public Page getCoursePage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String category, String status) { + public Page getCoursePage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String category, String status) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -276,7 +276,7 @@ public class CourseServiceImpl implements CourseService { @Override @Transactional - public void deleteCourse(Long id) { + public void deleteCourse(String id) { getCourseById(id); courseMapper.deleteById(id); log.info("Course deleted: id={}", id); @@ -284,7 +284,7 @@ public class CourseServiceImpl implements CourseService { @Override @Transactional - public void publishCourse(Long id) { + public void publishCourse(String id) { Course course = getCourseById(id); course.setStatus("published"); course.setPublishedAt(LocalDateTime.now()); @@ -294,7 +294,7 @@ public class CourseServiceImpl implements CourseService { @Override @Transactional - public void archiveCourse(Long id) { + public void archiveCourse(String id) { Course course = getCourseById(id); course.setStatus("archived"); courseMapper.updateById(course); @@ -302,7 +302,7 @@ public class CourseServiceImpl implements CourseService { } @Override - public List getCoursesByTenantId(Long tenantId) { + public List getCoursesByTenantId(String tenantId) { return courseMapper.selectList( new LambdaQueryWrapper() .eq(Course::getTenantId, tenantId) @@ -323,7 +323,7 @@ public class CourseServiceImpl implements CourseService { @Override @Transactional - public void submitCourse(Long id) { + public void submitCourse(String id) { Course course = getCourseById(id); course.setStatus("pending"); course.setSubmittedAt(LocalDateTime.now()); @@ -333,7 +333,7 @@ public class CourseServiceImpl implements CourseService { @Override @Transactional - public void withdrawCourse(Long id) { + public void withdrawCourse(String id) { Course course = getCourseById(id); course.setStatus("draft"); courseMapper.updateById(course); @@ -342,7 +342,7 @@ public class CourseServiceImpl implements CourseService { @Override @Transactional - public void approveCourse(Long id, String comment) { + public void approveCourse(String id, String comment) { Course course = getCourseById(id); course.setStatus("published"); course.setReviewComment(comment); @@ -354,7 +354,7 @@ public class CourseServiceImpl implements CourseService { @Override @Transactional - public void rejectCourse(Long id, String comment) { + public void rejectCourse(String id, String comment) { Course course = getCourseById(id); course.setStatus("rejected"); course.setReviewComment(comment); diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ExportServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ExportServiceImpl.java index ecf202a..a06e2bf 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ExportServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ExportServiceImpl.java @@ -26,7 +26,7 @@ public class ExportServiceImpl implements ExportService { private final GrowthRecordMapper growthRecordMapper; @Override - public byte[] exportTeachers(Long tenantId) throws IOException { + public byte[] exportTeachers(String tenantId) throws IOException { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Teacher::getTenantId, tenantId); List teachers = teacherMapper.selectList(wrapper); @@ -52,7 +52,7 @@ public class ExportServiceImpl implements ExportService { } @Override - public byte[] exportStudents(Long tenantId) throws IOException { + public byte[] exportStudents(String tenantId) throws IOException { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Student::getTenantId, tenantId); List students = studentMapper.selectList(wrapper); @@ -78,7 +78,7 @@ public class ExportServiceImpl implements ExportService { } @Override - public byte[] exportLessons(Long tenantId) throws IOException { + public byte[] exportLessons(String tenantId) throws IOException { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Lesson::getTenantId, tenantId); List lessons = lessonMapper.selectList(wrapper); @@ -104,7 +104,7 @@ public class ExportServiceImpl implements ExportService { } @Override - public byte[] exportGrowthRecords(Long tenantId) throws IOException { + public byte[] exportGrowthRecords(String tenantId) throws IOException { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(GrowthRecord::getTenantId, tenantId); List records = growthRecordMapper.selectList(wrapper); diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/GrowthRecordServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/GrowthRecordServiceImpl.java index 6c73f7d..3e0df41 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/GrowthRecordServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/GrowthRecordServiceImpl.java @@ -30,7 +30,7 @@ public class GrowthRecordServiceImpl implements GrowthRecordService { @Override @Transactional - public GrowthRecord createGrowthRecord(Long tenantId, Long recorderId, String recorderRole, GrowthRecordCreateRequest request) { + public GrowthRecord createGrowthRecord(String tenantId, String recorderId, String recorderRole, GrowthRecordCreateRequest request) { GrowthRecord record = new GrowthRecord(); record.setTenantId(tenantId); record.setStudentId(request.getStudentId()); @@ -56,7 +56,7 @@ public class GrowthRecordServiceImpl implements GrowthRecordService { @Override @Transactional - public GrowthRecord updateGrowthRecord(Long id, GrowthRecordUpdateRequest request) { + public GrowthRecord updateGrowthRecord(String id, GrowthRecordUpdateRequest request) { GrowthRecord record = getGrowthRecordById(id); if (StringUtils.hasText(request.getType())) { @@ -87,7 +87,7 @@ public class GrowthRecordServiceImpl implements GrowthRecordService { } @Override - public GrowthRecord getGrowthRecordById(Long id) { + public GrowthRecord getGrowthRecordById(String id) { GrowthRecord record = growthRecordMapper.selectById(id); if (record == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Growth record not found"); @@ -96,7 +96,7 @@ public class GrowthRecordServiceImpl implements GrowthRecordService { } @Override - public Page getGrowthRecordPage(Long tenantId, Integer pageNum, Integer pageSize, Long studentId, String type) { + public Page getGrowthRecordPage(String tenantId, Integer pageNum, Integer pageSize, String studentId, String type) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -114,7 +114,7 @@ public class GrowthRecordServiceImpl implements GrowthRecordService { } @Override - public Page getGrowthRecordsByStudentId(Long studentId, Integer pageNum, Integer pageSize, String type) { + public Page getGrowthRecordsByStudentId(String studentId, Integer pageNum, Integer pageSize, String type) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -130,13 +130,13 @@ public class GrowthRecordServiceImpl implements GrowthRecordService { @Override @Transactional - public void deleteGrowthRecord(Long id) { + public void deleteGrowthRecord(String id) { getGrowthRecordById(id); growthRecordMapper.deleteById(id); } @Override - public List getRecentGrowthRecords(Long studentId, Integer limit) { + public List getRecentGrowthRecords(String studentId, Integer limit) { int size = limit != null && limit > 0 ? limit : 10; return growthRecordMapper.selectList( new LambdaQueryWrapper() diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/LessonServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/LessonServiceImpl.java index 4937539..1f45720 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/LessonServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/LessonServiceImpl.java @@ -8,7 +8,11 @@ import com.reading.platform.common.util.PageUtils; import com.reading.platform.dto.request.LessonCreateRequest; import com.reading.platform.dto.request.LessonUpdateRequest; import com.reading.platform.entity.Lesson; +import com.reading.platform.entity.LessonFeedback; +import com.reading.platform.entity.StudentRecord; +import com.reading.platform.mapper.LessonFeedbackMapper; import com.reading.platform.mapper.LessonMapper; +import com.reading.platform.mapper.StudentRecordMapper; import com.reading.platform.service.LessonService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -16,17 +20,19 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.time.LocalDate; -import java.util.List; +import java.util.*; @Service @RequiredArgsConstructor public class LessonServiceImpl implements LessonService { private final LessonMapper lessonMapper; + private final StudentRecordMapper studentRecordMapper; + private final LessonFeedbackMapper lessonFeedbackMapper; @Override @Transactional - public Lesson createLesson(Long tenantId, LessonCreateRequest request) { + public Lesson createLesson(String tenantId, LessonCreateRequest request) { Lesson lesson = new Lesson(); lesson.setTenantId(tenantId); lesson.setCourseId(request.getCourseId()); @@ -46,7 +52,7 @@ public class LessonServiceImpl implements LessonService { @Override @Transactional - public Lesson updateLesson(Long id, LessonUpdateRequest request) { + public Lesson updateLesson(String id, LessonUpdateRequest request) { Lesson lesson = getLessonById(id); if (StringUtils.hasText(request.getTitle())) { @@ -76,7 +82,7 @@ public class LessonServiceImpl implements LessonService { } @Override - public Lesson getLessonById(Long id) { + public Lesson getLessonById(String id) { Lesson lesson = lessonMapper.selectById(id); if (lesson == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Lesson not found"); @@ -85,7 +91,7 @@ public class LessonServiceImpl implements LessonService { } @Override - public Page getLessonPage(Long tenantId, Integer pageNum, Integer pageSize, Long classId, Long teacherId, String status, LocalDate startDate, LocalDate endDate) { + public Page getLessonPage(String tenantId, Integer pageNum, Integer pageSize, String classId, String teacherId, String status, LocalDate startDate, LocalDate endDate) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -112,7 +118,7 @@ public class LessonServiceImpl implements LessonService { } @Override - public Page getTeacherLessons(Long teacherId, Integer pageNum, Integer pageSize, String status, LocalDate startDate, LocalDate endDate) { + public Page getTeacherLessons(String teacherId, Integer pageNum, Integer pageSize, String status, LocalDate startDate, LocalDate endDate) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -134,14 +140,14 @@ public class LessonServiceImpl implements LessonService { @Override @Transactional - public void deleteLesson(Long id) { + public void deleteLesson(String id) { getLessonById(id); lessonMapper.deleteById(id); } @Override @Transactional - public void startLesson(Long id) { + public void startLesson(String id) { Lesson lesson = getLessonById(id); lesson.setStatus("in_progress"); lessonMapper.updateById(lesson); @@ -149,7 +155,7 @@ public class LessonServiceImpl implements LessonService { @Override @Transactional - public void completeLesson(Long id) { + public void completeLesson(String id) { Lesson lesson = getLessonById(id); lesson.setStatus("completed"); lessonMapper.updateById(lesson); @@ -157,14 +163,14 @@ public class LessonServiceImpl implements LessonService { @Override @Transactional - public void cancelLesson(Long id) { + public void cancelLesson(String id) { Lesson lesson = getLessonById(id); lesson.setStatus("cancelled"); lessonMapper.updateById(lesson); } @Override - public List getTodayLessons(Long tenantId) { + public List getTodayLessons(String tenantId) { return lessonMapper.selectList( new LambdaQueryWrapper() .eq(Lesson::getTenantId, tenantId) @@ -174,4 +180,146 @@ public class LessonServiceImpl implements LessonService { ); } + @Override + @Transactional + public Lesson finishLesson(String id, Integer actualDuration, String overallRating, String participationRating, String completionNote) { + Lesson lesson = getLessonById(id); + lesson.setStatus("completed"); + lesson.setActualDuration(actualDuration); + lesson.setOverallRating(overallRating); + lesson.setParticipationRating(participationRating); + lesson.setCompletionNote(completionNote); + lessonMapper.updateById(lesson); + return lesson; + } + + @Override + @Transactional + public StudentRecord saveStudentRecord(String lessonId, String studentId, Integer focus, Integer participation, Integer interest, Integer understanding, String notes) { + // 验证课程是否存在 + getLessonById(lessonId); + + // 检查是否已存在记录 + StudentRecord existing = studentRecordMapper.selectOne( + new LambdaQueryWrapper() + .eq(StudentRecord::getLessonId, lessonId) + .eq(StudentRecord::getStudentId, studentId) + ); + + StudentRecord record; + if (existing != null) { + record = existing; + } else { + record = new StudentRecord(); + record.setLessonId(lessonId); + record.setStudentId(studentId); + } + + record.setFocus(focus); + record.setParticipation(participation); + record.setInterest(interest); + record.setUnderstanding(understanding); + record.setNotes(notes); + + if (existing != null) { + studentRecordMapper.updateById(record); + } else { + studentRecordMapper.insert(record); + } + + return record; + } + + @Override + public List getStudentRecords(String lessonId) { + // 验证课程是否存在 + getLessonById(lessonId); + + // 获取该课程的所有学生记录 + return studentRecordMapper.selectList( + new LambdaQueryWrapper() + .eq(StudentRecord::getLessonId, lessonId) + ); + } + + @Override + @Transactional + public int batchSaveStudentRecords(String lessonId, List> records) { + int count = 0; + for (Map recordData : records) { + String studentId = recordData.get("studentId") != null ? recordData.get("studentId").toString() : null; + Integer focus = recordData.get("focus") != null ? ((Number) recordData.get("focus")).intValue() : null; + Integer participation = recordData.get("participation") != null ? ((Number) recordData.get("participation")).intValue() : null; + Integer interest = recordData.get("interest") != null ? ((Number) recordData.get("interest")).intValue() : null; + Integer understanding = recordData.get("understanding") != null ? ((Number) recordData.get("understanding")).intValue() : null; + String notes = (String) recordData.get("notes"); + + saveStudentRecord(lessonId, studentId, focus, participation, interest, understanding, notes); + count++; + } + return count; + } + + @Override + @Transactional + public LessonFeedback saveLessonFeedback(String tenantId, String lessonId, String teacherId, Map feedbackData) { + // 验证课程是否存在 + Lesson lesson = getLessonById(lessonId); + + // 检查是否已存在反馈 + LessonFeedback existing = lessonFeedbackMapper.selectOne( + new LambdaQueryWrapper() + .eq(LessonFeedback::getLessonId, lessonId) + .eq(LessonFeedback::getTeacherId, teacherId) + ); + + LessonFeedback feedback; + if (existing != null) { + feedback = existing; + } else { + feedback = new LessonFeedback(); + feedback.setLessonId(lessonId); + feedback.setTeacherId(teacherId); + } + + // 设置反馈数据 + if (feedbackData.get("designQuality") != null) { + feedback.setDesignQuality(((Number) feedbackData.get("designQuality")).intValue()); + } + if (feedbackData.get("participation") != null) { + feedback.setParticipation(((Number) feedbackData.get("participation")).intValue()); + } + if (feedbackData.get("goalAchievement") != null) { + feedback.setGoalAchievement(((Number) feedbackData.get("goalAchievement")).intValue()); + } + if (feedbackData.get("stepFeedbacks") != null) { + feedback.setStepFeedbacks((String) feedbackData.get("stepFeedbacks")); + } + if (feedbackData.get("pros") != null) { + feedback.setPros((String) feedbackData.get("pros")); + } + if (feedbackData.get("suggestions") != null) { + feedback.setSuggestions((String) feedbackData.get("suggestions")); + } + if (feedbackData.get("activitiesDone") != null) { + feedback.setActivitiesDone((String) feedbackData.get("activitiesDone")); + } + + if (existing != null) { + lessonFeedbackMapper.updateById(feedback); + } else { + lessonFeedbackMapper.insert(feedback); + } + + return feedback; + } + + @Override + public LessonFeedback getLessonFeedback(String lessonId) { + return lessonFeedbackMapper.selectOne( + new LambdaQueryWrapper() + .eq(LessonFeedback::getLessonId, lessonId) + ); + } + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/NotificationServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/NotificationServiceImpl.java index 9fb6f87..7dd9616 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/NotificationServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/NotificationServiceImpl.java @@ -23,8 +23,8 @@ public class NotificationServiceImpl implements NotificationService { @Override @Transactional - public Notification createNotification(Long tenantId, Long senderId, String senderRole, String title, - String content, String type, String recipientType, Long recipientId) { + public Notification createNotification(String tenantId, String senderId, String senderRole, String title, + String content, String type, String recipientType, String recipientId) { Notification notification = new Notification(); notification.setTenantId(tenantId); notification.setTitle(title); @@ -41,7 +41,7 @@ public class NotificationServiceImpl implements NotificationService { } @Override - public Notification getNotificationById(Long id) { + public Notification getNotificationById(String id) { Notification notification = notificationMapper.selectById(id); if (notification == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Notification not found"); @@ -50,7 +50,7 @@ public class NotificationServiceImpl implements NotificationService { } @Override - public Page getNotificationPage(Long tenantId, Integer pageNum, Integer pageSize, String type, Integer isRead) { + public Page getNotificationPage(String tenantId, Integer pageNum, Integer pageSize, String type, Integer isRead) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -68,7 +68,7 @@ public class NotificationServiceImpl implements NotificationService { } @Override - public Page getMyNotifications(Long recipientId, String recipientType, Integer pageNum, Integer pageSize, Integer isRead) { + public Page getMyNotifications(String recipientId, String recipientType, Integer pageNum, Integer pageSize, Integer isRead) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -88,7 +88,7 @@ public class NotificationServiceImpl implements NotificationService { @Override @Transactional - public void markAsRead(Long id) { + public void markAsRead(String id) { Notification notification = getNotificationById(id); notification.setIsRead(1); notification.setReadAt(LocalDateTime.now()); @@ -97,7 +97,7 @@ public class NotificationServiceImpl implements NotificationService { @Override @Transactional - public void markAllAsRead(Long recipientId, String recipientType) { + public void markAllAsRead(String recipientId, String recipientType) { notificationMapper.update(null, new LambdaUpdateWrapper() .set(Notification::getIsRead, 1) @@ -113,13 +113,13 @@ public class NotificationServiceImpl implements NotificationService { @Override @Transactional - public void deleteNotification(Long id) { + public void deleteNotification(String id) { getNotificationById(id); notificationMapper.deleteById(id); } @Override - public Long getUnreadCount(Long recipientId, String recipientType) { + public Long getUnreadCount(String recipientId, String recipientType) { return notificationMapper.selectCount( new LambdaQueryWrapper() .eq(Notification::getIsRead, 0) diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/OperationLogServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/OperationLogServiceImpl.java index 50dab8f..63b5a4a 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/OperationLogServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/OperationLogServiceImpl.java @@ -19,7 +19,7 @@ public class OperationLogServiceImpl implements OperationLogService { private final OperationLogMapper operationLogMapper; @Override - public Page getLogs(int pageNum, int pageSize, Long tenantId, String module) { + public Page getLogs(int pageNum, int pageSize, String tenantId, String module) { Page page = new Page<>(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); if (tenantId != null) { @@ -33,7 +33,7 @@ public class OperationLogServiceImpl implements OperationLogService { } @Override - public void log(String action, String module, String targetType, Long targetId, String details) { + public void log(String action, String module, String targetType, String targetId, String details) { try { OperationLog log = new OperationLog(); log.setAction(action); diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ParentServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ParentServiceImpl.java index aaec81a..7008f2a 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ParentServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ParentServiceImpl.java @@ -28,7 +28,7 @@ public class ParentServiceImpl implements ParentService { @Override @Transactional - public Parent createParent(Long tenantId, ParentCreateRequest request) { + public Parent createParent(String tenantId, ParentCreateRequest request) { // Check if username already exists Parent existing = parentMapper.selectOne( new LambdaQueryWrapper().eq(Parent::getUsername, request.getUsername()) @@ -53,7 +53,7 @@ public class ParentServiceImpl implements ParentService { @Override @Transactional - public Parent updateParent(Long id, ParentUpdateRequest request) { + public Parent updateParent(String id, ParentUpdateRequest request) { Parent parent = getParentById(id); if (StringUtils.hasText(request.getName())) { @@ -80,7 +80,7 @@ public class ParentServiceImpl implements ParentService { } @Override - public Parent getParentById(Long id) { + public Parent getParentById(String id) { Parent parent = parentMapper.selectById(id); if (parent == null) { throw new BusinessException(ErrorCode.USER_NOT_FOUND, "Parent not found"); @@ -89,7 +89,7 @@ public class ParentServiceImpl implements ParentService { } @Override - public Page getParentPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String status) { + public Page getParentPage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String status) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -114,14 +114,14 @@ public class ParentServiceImpl implements ParentService { @Override @Transactional - public void deleteParent(Long id) { + public void deleteParent(String id) { getParentById(id); parentMapper.deleteById(id); } @Override @Transactional - public void resetPassword(Long id, String newPassword) { + public void resetPassword(String id, String newPassword) { Parent parent = getParentById(id); parent.setPassword(passwordEncoder.encode(newPassword)); parentMapper.updateById(parent); @@ -129,7 +129,7 @@ public class ParentServiceImpl implements ParentService { @Override @Transactional - public void bindStudent(Long parentId, Long studentId, String relationship, Boolean isPrimary) { + public void bindStudent(String parentId, String studentId, String relationship, Boolean isPrimary) { // Check if already bound ParentStudent existing = parentStudentMapper.selectOne( new LambdaQueryWrapper() @@ -151,7 +151,7 @@ public class ParentServiceImpl implements ParentService { @Override @Transactional - public void unbindStudent(Long parentId, Long studentId) { + public void unbindStudent(String parentId, String studentId) { parentStudentMapper.delete( new LambdaQueryWrapper() .eq(ParentStudent::getParentId, parentId) diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ResourceServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ResourceServiceImpl.java index 998d756..84a5fb8 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ResourceServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ResourceServiceImpl.java @@ -25,7 +25,7 @@ public class ResourceServiceImpl implements ResourceService { private final ResourceItemMapper resourceItemMapper; @Override - public List getLibraries(Long tenantId) { + public List getLibraries(String tenantId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); if (tenantId != null) { wrapper.eq(ResourceLibrary::getTenantId, tenantId); @@ -35,7 +35,7 @@ public class ResourceServiceImpl implements ResourceService { } @Override - public ResourceLibrary getLibraryById(Long id) { + public ResourceLibrary getLibraryById(String id) { ResourceLibrary lib = resourceLibraryMapper.selectById(id); if (lib == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Resource library not found"); @@ -50,7 +50,7 @@ public class ResourceServiceImpl implements ResourceService { } @Override - public ResourceLibrary updateLibrary(Long id, ResourceLibrary library) { + public ResourceLibrary updateLibrary(String id, ResourceLibrary library) { getLibraryById(id); library.setId(id); resourceLibraryMapper.updateById(library); @@ -58,12 +58,12 @@ public class ResourceServiceImpl implements ResourceService { } @Override - public void deleteLibrary(Long id) { + public void deleteLibrary(String id) { resourceLibraryMapper.deleteById(id); } @Override - public Page getItems(int pageNum, int pageSize, Long libraryId, String keyword) { + public Page getItems(int pageNum, int pageSize, String libraryId, String keyword) { Page page = new Page<>(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); if (libraryId != null) { @@ -77,7 +77,7 @@ public class ResourceServiceImpl implements ResourceService { } @Override - public ResourceItem getItemById(Long id) { + public ResourceItem getItemById(String id) { ResourceItem item = resourceItemMapper.selectById(id); if (item == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Resource item not found"); @@ -92,7 +92,7 @@ public class ResourceServiceImpl implements ResourceService { } @Override - public ResourceItem updateItem(Long id, ResourceItem item) { + public ResourceItem updateItem(String id, ResourceItem item) { getItemById(id); item.setId(id); resourceItemMapper.updateById(item); @@ -100,7 +100,7 @@ public class ResourceServiceImpl implements ResourceService { } @Override - public void deleteItem(Long id) { + public void deleteItem(String id) { resourceItemMapper.deleteById(id); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ScheduleServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ScheduleServiceImpl.java index 26134a5..16f7bd5 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ScheduleServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ScheduleServiceImpl.java @@ -31,7 +31,7 @@ public class ScheduleServiceImpl implements ScheduleService { private final ScheduleTemplateMapper scheduleTemplateMapper; @Override - public Page getSchedulePlans(int pageNum, int pageSize, Long tenantId, Long classId) { + public Page getSchedulePlans(int pageNum, int pageSize, String tenantId, String classId) { Page page = new Page<>(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(SchedulePlan::getTenantId, tenantId); @@ -43,7 +43,7 @@ public class ScheduleServiceImpl implements ScheduleService { } @Override - public Page getSchedulePlans(int pageNum, int pageSize, Long tenantId, Long classId, LocalDate startDate, LocalDate endDate) { + public Page getSchedulePlans(int pageNum, int pageSize, String tenantId, String classId, LocalDate startDate, LocalDate endDate) { Page page = new Page<>(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(SchedulePlan::getTenantId, tenantId); @@ -61,7 +61,7 @@ public class ScheduleServiceImpl implements ScheduleService { } @Override - public SchedulePlan getSchedulePlanById(Long id) { + public SchedulePlan getSchedulePlanById(String id) { SchedulePlan plan = schedulePlanMapper.selectById(id); if (plan == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Schedule plan not found"); @@ -70,14 +70,14 @@ public class ScheduleServiceImpl implements ScheduleService { } @Override - public SchedulePlan createSchedulePlan(Long tenantId, SchedulePlan plan) { + public SchedulePlan createSchedulePlan(String tenantId, SchedulePlan plan) { plan.setTenantId(tenantId); schedulePlanMapper.insert(plan); return plan; } @Override - public SchedulePlan createSchedulePlan(Long tenantId, Long userId, SchedulePlanCreateRequest request) { + public SchedulePlan createSchedulePlan(String tenantId, String userId, SchedulePlanCreateRequest request) { SchedulePlan plan = new SchedulePlan(); plan.setTenantId(tenantId); plan.setClassId(request.getClassId()); @@ -98,7 +98,7 @@ public class ScheduleServiceImpl implements ScheduleService { } @Override - public SchedulePlan updateSchedulePlan(Long id, SchedulePlan plan) { + public SchedulePlan updateSchedulePlan(String id, SchedulePlan plan) { SchedulePlan existing = getSchedulePlanById(id); plan.setId(id); plan.setTenantId(existing.getTenantId()); @@ -107,13 +107,13 @@ public class ScheduleServiceImpl implements ScheduleService { } @Override - public void deleteSchedulePlan(Long id) { + public void deleteSchedulePlan(String id) { schedulePlanMapper.deleteById(id); } @Override @Transactional - public List batchCreateSchedules(Long tenantId, Long userId, List requests) { + public List batchCreateSchedules(String tenantId, String userId, List requests) { List plans = new ArrayList<>(); for (SchedulePlanCreateRequest request : requests) { SchedulePlan plan = createSchedulePlan(tenantId, userId, request); @@ -123,7 +123,7 @@ public class ScheduleServiceImpl implements ScheduleService { } @Override - public List> getTimetable(Long tenantId, LocalDate startDate, LocalDate endDate, Long classId) { + public List> getTimetable(String tenantId, LocalDate startDate, LocalDate endDate, String classId) { if (startDate == null) { startDate = LocalDate.now(); } @@ -184,7 +184,7 @@ public class ScheduleServiceImpl implements ScheduleService { } @Override - public Page getScheduleTemplates(int pageNum, int pageSize, Long tenantId) { + public Page getScheduleTemplates(int pageNum, int pageSize, String tenantId) { Page page = new Page<>(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(ScheduleTemplate::getTenantId, tenantId) @@ -193,7 +193,7 @@ public class ScheduleServiceImpl implements ScheduleService { } @Override - public ScheduleTemplate getScheduleTemplateById(Long id) { + public ScheduleTemplate getScheduleTemplateById(String id) { ScheduleTemplate template = scheduleTemplateMapper.selectById(id); if (template == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Schedule template not found"); @@ -202,14 +202,14 @@ public class ScheduleServiceImpl implements ScheduleService { } @Override - public ScheduleTemplate createScheduleTemplate(Long tenantId, ScheduleTemplate template) { + public ScheduleTemplate createScheduleTemplate(String tenantId, ScheduleTemplate template) { template.setTenantId(tenantId); scheduleTemplateMapper.insert(template); return template; } @Override - public ScheduleTemplate updateScheduleTemplate(Long id, ScheduleTemplate template) { + public ScheduleTemplate updateScheduleTemplate(String id, ScheduleTemplate template) { ScheduleTemplate existing = getScheduleTemplateById(id); template.setId(id); template.setTenantId(existing.getTenantId()); @@ -218,13 +218,13 @@ public class ScheduleServiceImpl implements ScheduleService { } @Override - public void deleteScheduleTemplate(Long id) { + public void deleteScheduleTemplate(String id) { scheduleTemplateMapper.deleteById(id); } @Override @Transactional - public List applyScheduleTemplate(Long tenantId, Long templateId, ScheduleTemplateApplyRequest request) { + public List applyScheduleTemplate(String tenantId, String templateId, ScheduleTemplateApplyRequest request) { ScheduleTemplate template = getScheduleTemplateById(templateId); // 解析模板内容(JSON 格式) diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/SchoolCourseServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/SchoolCourseServiceImpl.java index 5852872..9e18156 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/SchoolCourseServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/SchoolCourseServiceImpl.java @@ -20,7 +20,7 @@ public class SchoolCourseServiceImpl implements SchoolCourseService { private final SchoolCourseMapper schoolCourseMapper; @Override - public Page getCourses(int pageNum, int pageSize, Long tenantId, String keyword) { + public Page getCourses(int pageNum, int pageSize, String tenantId, String keyword) { Page page = new Page<>(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(SchoolCourse::getTenantId, tenantId); @@ -32,7 +32,7 @@ public class SchoolCourseServiceImpl implements SchoolCourseService { } @Override - public SchoolCourse getCourseById(Long id) { + public SchoolCourse getCourseById(String id) { SchoolCourse course = schoolCourseMapper.selectById(id); if (course == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "School course not found"); @@ -41,7 +41,7 @@ public class SchoolCourseServiceImpl implements SchoolCourseService { } @Override - public SchoolCourse createCourse(Long tenantId, Long userId, SchoolCourse course) { + public SchoolCourse createCourse(String tenantId, String userId, SchoolCourse course) { course.setTenantId(tenantId); course.setCreatedBy(userId); schoolCourseMapper.insert(course); @@ -49,7 +49,7 @@ public class SchoolCourseServiceImpl implements SchoolCourseService { } @Override - public SchoolCourse updateCourse(Long id, SchoolCourse course) { + public SchoolCourse updateCourse(String id, SchoolCourse course) { SchoolCourse existing = getCourseById(id); course.setId(id); course.setTenantId(existing.getTenantId()); @@ -58,7 +58,7 @@ public class SchoolCourseServiceImpl implements SchoolCourseService { } @Override - public void deleteCourse(Long id) { + public void deleteCourse(String id) { schoolCourseMapper.deleteById(id); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/SchoolStatsServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/SchoolStatsServiceImpl.java index 5eb7bfe..0d0dcc7 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/SchoolStatsServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/SchoolStatsServiceImpl.java @@ -25,7 +25,7 @@ public class SchoolStatsServiceImpl implements SchoolStatsService { private final CourseMapper courseMapper; @Override - public Map getStats(Long tenantId) { + public Map getStats(String tenantId) { Map stats = new HashMap<>(); stats.put("teacherCount", teacherMapper.selectCount( new LambdaQueryWrapper().eq(Teacher::getTenantId, tenantId))); @@ -39,7 +39,7 @@ public class SchoolStatsServiceImpl implements SchoolStatsService { } @Override - public List> getActiveTeachers(Long tenantId, Integer limit) { + public List> getActiveTeachers(String tenantId, Integer limit) { if (limit == null) { limit = 5; } @@ -83,7 +83,7 @@ public class SchoolStatsServiceImpl implements SchoolStatsService { } @Override - public List> getCourseUsageStats(Long tenantId) { + public List> getCourseUsageStats(String tenantId) { // 获取所有已完成的课时 List lessons = lessonMapper.selectList( new LambdaQueryWrapper() @@ -92,10 +92,10 @@ public class SchoolStatsServiceImpl implements SchoolStatsService { ); // 统计每个课程的使用次数 - Map> courseUsageMap = new LinkedHashMap<>(); + Map> courseUsageMap = new LinkedHashMap<>(); for (Lesson lesson : lessons) { - Long courseId = lesson.getCourseId(); + String courseId = lesson.getCourseId(); if (courseId == null) continue; if (!courseUsageMap.containsKey(courseId)) { @@ -124,7 +124,7 @@ public class SchoolStatsServiceImpl implements SchoolStatsService { } @Override - public List> getRecentActivities(Long tenantId, Integer limit) { + public List> getRecentActivities(String tenantId, Integer limit) { if (limit == null) { limit = 10; } @@ -151,7 +151,7 @@ public class SchoolStatsServiceImpl implements SchoolStatsService { } @Override - public List> getLessonTrend(Long tenantId, Integer months) { + public List> getLessonTrend(String tenantId, Integer months) { if (months == null) { months = 6; } @@ -191,7 +191,7 @@ public class SchoolStatsServiceImpl implements SchoolStatsService { } @Override - public List> getCourseDistribution(Long tenantId) { + public List> getCourseDistribution(String tenantId) { // 获取所有已完成的课时 List lessons = lessonMapper.selectList( new LambdaQueryWrapper() @@ -203,7 +203,7 @@ public class SchoolStatsServiceImpl implements SchoolStatsService { Map courseMap = new LinkedHashMap<>(); for (Lesson lesson : lessons) { - Long courseId = lesson.getCourseId(); + String courseId = lesson.getCourseId(); if (courseId == null) continue; Course course = courseMapper.selectById(courseId); diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/StudentServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/StudentServiceImpl.java index 01ddede..012dbaf 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/StudentServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/StudentServiceImpl.java @@ -7,12 +7,15 @@ import com.reading.platform.common.exception.BusinessException; import com.reading.platform.common.util.PageUtils; import com.reading.platform.dto.request.StudentCreateRequest; import com.reading.platform.dto.request.StudentUpdateRequest; +import com.reading.platform.dto.response.StudentTransferHistoryResponse; import com.reading.platform.entity.ParentStudent; import com.reading.platform.entity.Student; import com.reading.platform.entity.StudentClassHistory; +import com.reading.platform.entity.Clazz; import com.reading.platform.mapper.ParentStudentMapper; import com.reading.platform.mapper.StudentClassHistoryMapper; import com.reading.platform.mapper.StudentMapper; +import com.reading.platform.mapper.ClazzMapper; import com.reading.platform.service.StudentService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -30,10 +33,11 @@ public class StudentServiceImpl implements StudentService { private final StudentMapper studentMapper; private final ParentStudentMapper parentStudentMapper; private final StudentClassHistoryMapper studentClassHistoryMapper; + private final ClazzMapper classMapper; @Override @Transactional - public Student createStudent(Long tenantId, StudentCreateRequest request) { + public Student createStudent(String tenantId, StudentCreateRequest request) { Student student = new Student(); student.setTenantId(tenantId); student.setName(request.getName()); @@ -52,7 +56,7 @@ public class StudentServiceImpl implements StudentService { @Override @Transactional - public Student updateStudent(Long id, StudentUpdateRequest request) { + public Student updateStudent(String id, StudentUpdateRequest request) { Student student = getStudentById(id); if (StringUtils.hasText(request.getName())) { @@ -91,7 +95,7 @@ public class StudentServiceImpl implements StudentService { } @Override - public Student getStudentById(Long id) { + public Student getStudentById(String id) { Student student = studentMapper.selectById(id); if (student == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Student not found"); @@ -100,7 +104,7 @@ public class StudentServiceImpl implements StudentService { } @Override - public Page getStudentPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String grade, String status) { + public Page getStudentPage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String grade, String status) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -125,7 +129,7 @@ public class StudentServiceImpl implements StudentService { } @Override - public Page getStudentsByClassId(Long classId, Integer pageNum, Integer pageSize) { + public Page getStudentsByClassId(String classId, Integer pageNum, Integer pageSize) { Page page = PageUtils.of(pageNum, pageSize); // Get active student IDs from class history @@ -142,7 +146,7 @@ public class StudentServiceImpl implements StudentService { return page; } - List studentIds = histories.stream() + List studentIds = histories.stream() .map(StudentClassHistory::getStudentId) .toList(); @@ -160,13 +164,13 @@ public class StudentServiceImpl implements StudentService { @Override @Transactional - public void deleteStudent(Long id) { + public void deleteStudent(String id) { getStudentById(id); studentMapper.deleteById(id); } @Override - public List getStudentsByParentId(Long parentId) { + public List getStudentsByParentId(String parentId) { List parentStudents = parentStudentMapper.selectList( new LambdaQueryWrapper() .eq(ParentStudent::getParentId, parentId) @@ -176,7 +180,7 @@ public class StudentServiceImpl implements StudentService { return new ArrayList<>(); } - List studentIds = parentStudents.stream() + List studentIds = parentStudents.stream() .map(ParentStudent::getStudentId) .toList(); @@ -189,7 +193,7 @@ public class StudentServiceImpl implements StudentService { @Override @Transactional - public List importStudents(Long tenantId, List requests) { + public List importStudents(String tenantId, List requests) { List students = new ArrayList<>(); for (StudentCreateRequest request : requests) { Student student = createStudent(tenantId, request); @@ -198,4 +202,69 @@ public class StudentServiceImpl implements StudentService { return students; } + @Override + @Transactional + public void transferStudent(String tenantId, String studentId, String toClassId, String reason) { + // 验证学生存在 + Student student = getStudentById(studentId); + if (!student.getTenantId().equals(tenantId)) { + throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "学生不存在或无权限访问"); + } + + // 结束当前班级关系 + List currentHistories = studentClassHistoryMapper.selectList( + new LambdaQueryWrapper() + .eq(StudentClassHistory::getStudentId, studentId) + .eq(StudentClassHistory::getStatus, "active") + .isNull(StudentClassHistory::getEndDate) + ); + + for (StudentClassHistory history : currentHistories) { + history.setEndDate(LocalDate.now()); + history.setStatus("left"); + studentClassHistoryMapper.updateById(history); + } + + // 创建新的班级关系 + StudentClassHistory newHistory = new StudentClassHistory(); + newHistory.setStudentId(studentId); + newHistory.setClassId(toClassId); + newHistory.setStartDate(LocalDate.now()); + newHistory.setStatus("active"); + newHistory.setReason(reason); + studentClassHistoryMapper.insert(newHistory); + } + + @Override + public List getStudentClassHistory(String studentId) { + List histories = studentClassHistoryMapper.selectList( + new LambdaQueryWrapper() + .eq(StudentClassHistory::getStudentId, studentId) + .orderByDesc(StudentClassHistory::getStartDate) + ); + + List result = new ArrayList<>(); + for (StudentClassHistory history : histories) { + StudentTransferHistoryResponse response = new StudentTransferHistoryResponse(); + response.setId(history.getId()); + response.setClassId(history.getClassId()); + response.setStartDate(history.getStartDate() != null ? history.getStartDate().toString() : null); + response.setEndDate(history.getEndDate() != null ? history.getEndDate().toString() : null); + response.setStatus(history.getStatus()); + response.setReason(history.getReason()); + + // 获取班级名称 + if (history.getClassId() != null) { + var clazz = classMapper.selectById(history.getClassId()); + if (clazz != null) { + response.setClassName(clazz.getName()); + } + } + + result.add(response); + } + + return result; + } + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/SystemSettingServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/SystemSettingServiceImpl.java index 9ef2421..179e5de 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/SystemSettingServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/SystemSettingServiceImpl.java @@ -22,7 +22,7 @@ public class SystemSettingServiceImpl implements SystemSettingService { private final SystemSettingMapper systemSettingMapper; @Override - public Map getSettings(Long tenantId) { + public Map getSettings(String tenantId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(SystemSetting::getTenantId, tenantId); List settings = systemSettingMapper.selectList(wrapper); @@ -34,7 +34,7 @@ public class SystemSettingServiceImpl implements SystemSettingService { } @Override - public void updateSettings(Long tenantId, Map settings) { + public void updateSettings(String tenantId, Map settings) { for (Map.Entry entry : settings.entrySet()) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(SystemSetting::getTenantId, tenantId) @@ -58,7 +58,7 @@ public class SystemSettingServiceImpl implements SystemSettingService { } @Override - public String getSetting(Long tenantId, String key) { + public String getSetting(String tenantId, String key) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(SystemSetting::getTenantId, tenantId) .eq(SystemSetting::getSettingKey, key); diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TaskServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TaskServiceImpl.java index 69d88d3..c701c19 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TaskServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TaskServiceImpl.java @@ -31,7 +31,7 @@ public class TaskServiceImpl implements TaskService { @Override @Transactional - public Task createTask(Long tenantId, Long creatorId, String creatorRole, TaskCreateRequest request) { + public Task createTask(String tenantId, String creatorId, String creatorRole, TaskCreateRequest request) { Task task = new Task(); task.setTenantId(tenantId); task.setTitle(request.getTitle()); @@ -49,7 +49,7 @@ public class TaskServiceImpl implements TaskService { // Create task targets if (request.getTargetIds() != null && !request.getTargetIds().isEmpty()) { - for (Long targetId : request.getTargetIds()) { + for (String targetId : request.getTargetIds()) { TaskTarget target = new TaskTarget(); target.setTaskId(task.getId()); target.setTargetType(request.getTargetType() != null ? request.getTargetType() : "class"); @@ -63,7 +63,7 @@ public class TaskServiceImpl implements TaskService { @Override @Transactional - public Task updateTask(Long id, TaskUpdateRequest request) { + public Task updateTask(String id, TaskUpdateRequest request) { Task task = getTaskById(id); if (StringUtils.hasText(request.getTitle())) { @@ -93,7 +93,7 @@ public class TaskServiceImpl implements TaskService { } @Override - public Task getTaskById(Long id) { + public Task getTaskById(String id) { Task task = taskMapper.selectById(id); if (task == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Task not found"); @@ -102,7 +102,7 @@ public class TaskServiceImpl implements TaskService { } @Override - public Page getTaskPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status) { + public Page getTaskPage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -123,7 +123,7 @@ public class TaskServiceImpl implements TaskService { } @Override - public Page getTasksByStudentId(Long studentId, Integer pageNum, Integer pageSize, String status) { + public Page getTasksByStudentId(String studentId, Integer pageNum, Integer pageSize, String status) { Page page = PageUtils.of(pageNum, pageSize); // Get task IDs from task_completions for this student @@ -135,7 +135,7 @@ public class TaskServiceImpl implements TaskService { return page; } - List taskIds = completions.stream() + List taskIds = completions.stream() .map(TaskCompletion::getTaskId) .toList(); @@ -152,14 +152,14 @@ public class TaskServiceImpl implements TaskService { @Override @Transactional - public void deleteTask(Long id) { + public void deleteTask(String id) { getTaskById(id); taskMapper.deleteById(id); } @Override @Transactional - public void completeTask(Long taskId, Long studentId, String content, String attachments) { + public void completeTask(String taskId, String studentId, String content, String attachments) { TaskCompletion completion = taskCompletionMapper.selectOne( new LambdaQueryWrapper() .eq(TaskCompletion::getTaskId, taskId) @@ -185,7 +185,7 @@ public class TaskServiceImpl implements TaskService { } @Override - public List getTasksByClassId(Long classId) { + public List getTasksByClassId(String classId) { List targets = taskTargetMapper.selectList( new LambdaQueryWrapper() .eq(TaskTarget::getTargetType, "class") @@ -196,7 +196,7 @@ public class TaskServiceImpl implements TaskService { return new ArrayList<>(); } - List taskIds = targets.stream() + List taskIds = targets.stream() .map(TaskTarget::getTaskId) .toList(); @@ -210,7 +210,7 @@ public class TaskServiceImpl implements TaskService { // ==================== 任务统计 ==================== @Override - public Map getTaskStats(Long tenantId) { + public Map getTaskStats(String tenantId) { // 统计任务总数 long totalTasks = taskMapper.selectCount(new LambdaQueryWrapper().eq(Task::getTenantId, tenantId)); @@ -245,7 +245,7 @@ public class TaskServiceImpl implements TaskService { } @Override - public Map getStatsByType(Long tenantId) { + public Map getStatsByType(String tenantId) { List tasks = taskMapper.selectList(new LambdaQueryWrapper().eq(Task::getTenantId, tenantId)); Map> typeStats = new HashMap<>(); @@ -281,7 +281,7 @@ public class TaskServiceImpl implements TaskService { } @Override - public List> getStatsByClass(Long tenantId) { + public List> getStatsByClass(String tenantId) { List classes = classMapper.selectList(new LambdaQueryWrapper().eq(Clazz::getTenantId, tenantId)); List> classStats = new ArrayList<>(); @@ -298,7 +298,7 @@ public class TaskServiceImpl implements TaskService { continue; } - List studentIds = histories.stream() + List studentIds = histories.stream() .map(StudentClassHistory::getStudentId) .toList(); @@ -330,7 +330,7 @@ public class TaskServiceImpl implements TaskService { } @Override - public List> getMonthlyStats(Long tenantId, Integer months) { + public List> getMonthlyStats(String tenantId, Integer months) { months = months != null ? months : 6; LocalDate now = LocalDate.now(); LocalDate startDate = now.minusMonths(months - 1).withDayOfMonth(1); @@ -391,7 +391,7 @@ public class TaskServiceImpl implements TaskService { } @Override - public Page getTaskCompletions(Long tenantId, Long taskId, Integer pageNum, Integer pageSize, String status) { + public Page getTaskCompletions(String tenantId, String taskId, Integer pageNum, Integer pageSize, String status) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -412,7 +412,7 @@ public class TaskServiceImpl implements TaskService { @Override @Transactional - public TaskCompletion updateTaskCompletion(Long tenantId, Long taskId, Long studentId, String status, String feedback) { + public TaskCompletion updateTaskCompletion(String tenantId, String taskId, String studentId, String status, String feedback) { // 验证任务属于该租户 Task task = taskMapper.selectById(taskId); if (task == null || !task.getTenantId().equals(tenantId)) { @@ -444,7 +444,7 @@ public class TaskServiceImpl implements TaskService { // ==================== 任务模板 ==================== @Override - public Page getTemplatePage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type) { + public Page getTemplatePage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String type) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -465,7 +465,7 @@ public class TaskServiceImpl implements TaskService { } @Override - public TaskTemplate getTemplateById(Long tenantId, Long id) { + public TaskTemplate getTemplateById(String tenantId, String id) { TaskTemplate template = taskTemplateMapper.selectById(id); if (template == null || !template.getTenantId().equals(tenantId)) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "模板不存在或无权限访问"); @@ -474,7 +474,7 @@ public class TaskServiceImpl implements TaskService { } @Override - public TaskTemplate getDefaultTemplate(Long tenantId, String taskType) { + public TaskTemplate getDefaultTemplate(String tenantId, String taskType) { // 优先查找公共模板,再查找租户的默认模板 TaskTemplate template = taskTemplateMapper.selectOne(new LambdaQueryWrapper() .eq(TaskTemplate::getType, taskType) @@ -493,7 +493,7 @@ public class TaskServiceImpl implements TaskService { @Override @Transactional - public TaskTemplate createTemplate(Long tenantId, Long creatorId, TaskTemplateCreateRequest request) { + public TaskTemplate createTemplate(String tenantId, String creatorId, TaskTemplateCreateRequest request) { TaskTemplate template = new TaskTemplate(); template.setTenantId(tenantId); template.setName(request.getName()); @@ -508,7 +508,7 @@ public class TaskServiceImpl implements TaskService { @Override @Transactional - public TaskTemplate updateTemplate(Long tenantId, Long id, TaskTemplateUpdateRequest request) { + public TaskTemplate updateTemplate(String tenantId, String id, TaskTemplateUpdateRequest request) { TaskTemplate template = getTemplateById(tenantId, id); if (StringUtils.hasText(request.getName())) { @@ -533,14 +533,14 @@ public class TaskServiceImpl implements TaskService { @Override @Transactional - public void deleteTemplate(Long tenantId, Long id) { + public void deleteTemplate(String tenantId, String id) { getTemplateById(tenantId, id); taskTemplateMapper.deleteById(id); } @Override @Transactional - public Task createTaskFromTemplate(Long tenantId, Long creatorId, String creatorRole, CreateTaskFromTemplateRequest request) { + public Task createTaskFromTemplate(String tenantId, String creatorId, String creatorRole, CreateTaskFromTemplateRequest request) { // 获取模板 TaskTemplate template = getTemplateById(tenantId, request.getTemplateId()); @@ -559,7 +559,7 @@ public class TaskServiceImpl implements TaskService { taskMapper.insert(task); // 创建任务目标和完成记录 - for (Long targetId : request.getTargetIds()) { + for (String targetId : request.getTargetIds()) { TaskTarget target = new TaskTarget(); target.setTaskId(task.getId()); target.setTargetType(request.getTargetType() != null ? request.getTargetType() : "class"); @@ -575,11 +575,11 @@ public class TaskServiceImpl implements TaskService { .eq(StudentClassHistory::getStatus, "active") ); - List studentIds = histories.stream() + List studentIds = histories.stream() .map(StudentClassHistory::getStudentId) .toList(); - for (Long studentId : studentIds) { + for (String studentId : studentIds) { TaskCompletion completion = new TaskCompletion(); completion.setTaskId(task.getId()); completion.setStudentId(studentId); @@ -599,4 +599,13 @@ public class TaskServiceImpl implements TaskService { return task; } + @Override + public TaskCompletion getTaskCompletion(String taskId, String studentId) { + return taskCompletionMapper.selectOne( + new LambdaQueryWrapper() + .eq(TaskCompletion::getTaskId, taskId) + .eq(TaskCompletion::getStudentId, studentId) + ); + } + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TeacherDashboardServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TeacherDashboardServiceImpl.java index 2167604..64d31bc 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TeacherDashboardServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TeacherDashboardServiceImpl.java @@ -26,7 +26,7 @@ public class TeacherDashboardServiceImpl implements TeacherDashboardService { private final NotificationMapper notificationMapper; @Override - public Map getDashboard(Long teacherId, Long tenantId) { + public Map getDashboard(String teacherId, String tenantId) { Map dashboard = new HashMap<>(); dashboard.put("lessonCount", lessonMapper.selectCount( new LambdaQueryWrapper() @@ -48,7 +48,7 @@ public class TeacherDashboardServiceImpl implements TeacherDashboardService { } @Override - public List> getTodayLessons(Long teacherId, Long tenantId) { + public List> getTodayLessons(String teacherId, String tenantId) { LocalDate today = LocalDate.now(); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Lesson::getTeacherId, teacherId) @@ -69,7 +69,7 @@ public class TeacherDashboardServiceImpl implements TeacherDashboardService { } @Override - public List> getWeeklyLessons(Long teacherId, Long tenantId) { + public List> getWeeklyLessons(String teacherId, String tenantId) { LocalDate today = LocalDate.now(); LocalDate weekStart = today.minusDays(today.getDayOfWeek().getValue() - 1); LocalDate weekEnd = weekStart.plusDays(6); diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TeacherServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TeacherServiceImpl.java index 279d3ae..96369f4 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TeacherServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TeacherServiceImpl.java @@ -25,7 +25,7 @@ public class TeacherServiceImpl implements TeacherService { @Override @Transactional - public Teacher createTeacher(Long tenantId, TeacherCreateRequest request) { + public Teacher createTeacher(String tenantId, TeacherCreateRequest request) { // Check if username already exists Teacher existing = teacherMapper.selectOne( new LambdaQueryWrapper().eq(Teacher::getUsername, request.getUsername()) @@ -51,7 +51,7 @@ public class TeacherServiceImpl implements TeacherService { @Override @Transactional - public Teacher updateTeacher(Long id, TeacherUpdateRequest request) { + public Teacher updateTeacher(String id, TeacherUpdateRequest request) { Teacher teacher = getTeacherById(id); if (StringUtils.hasText(request.getName())) { @@ -81,7 +81,7 @@ public class TeacherServiceImpl implements TeacherService { } @Override - public Teacher getTeacherById(Long id) { + public Teacher getTeacherById(String id) { Teacher teacher = teacherMapper.selectById(id); if (teacher == null) { throw new BusinessException(ErrorCode.USER_NOT_FOUND, "Teacher not found"); @@ -90,7 +90,7 @@ public class TeacherServiceImpl implements TeacherService { } @Override - public Page getTeacherPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String status) { + public Page getTeacherPage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String status) { Page page = PageUtils.of(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -115,14 +115,14 @@ public class TeacherServiceImpl implements TeacherService { @Override @Transactional - public void deleteTeacher(Long id) { + public void deleteTeacher(String id) { getTeacherById(id); teacherMapper.deleteById(id); } @Override @Transactional - public void resetPassword(Long id, String newPassword) { + public void resetPassword(String id, String newPassword) { Teacher teacher = getTeacherById(id); teacher.setPassword(passwordEncoder.encode(newPassword)); teacherMapper.updateById(teacher); diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TenantServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TenantServiceImpl.java index 8690ca2..9d03d6c 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TenantServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TenantServiceImpl.java @@ -73,7 +73,7 @@ public class TenantServiceImpl implements TenantService { @Override @Transactional - public Tenant updateTenant(Long id, TenantUpdateRequest request) { + public Tenant updateTenant(String id, TenantUpdateRequest request) { Tenant tenant = getTenantById(id); if (StringUtils.hasText(request.getName())) { @@ -112,7 +112,7 @@ public class TenantServiceImpl implements TenantService { } @Override - public Tenant getTenantById(Long id) { + public Tenant getTenantById(String id) { Tenant tenant = tenantMapper.selectById(id); if (tenant == null) { throw new BusinessException(ErrorCode.TENANT_NOT_FOUND); @@ -145,14 +145,14 @@ public class TenantServiceImpl implements TenantService { @Override @Transactional - public void deleteTenant(Long id) { + public void deleteTenant(String id) { Tenant tenant = getTenantById(id); tenantMapper.deleteById(id); } @Override @Transactional - public String resetSchoolAccountPassword(Long tenantId) { + public String resetSchoolAccountPassword(String tenantId) { Tenant tenant = getTenantById(tenantId); // Find the school account (username = tenant code) Teacher schoolAccount = teacherMapper.selectOne( diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ThemeServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ThemeServiceImpl.java index 0cadefd..da06c0c 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ThemeServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ThemeServiceImpl.java @@ -31,7 +31,7 @@ public class ThemeServiceImpl implements ThemeService { } @Override - public Theme getThemeById(Long id) { + public Theme getThemeById(String id) { Theme theme = themeMapper.selectById(id); if (theme == null) { throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Theme not found"); @@ -46,7 +46,7 @@ public class ThemeServiceImpl implements ThemeService { } @Override - public Theme updateTheme(Long id, Theme theme) { + public Theme updateTheme(String id, Theme theme) { getThemeById(id); theme.setId(id); themeMapper.updateById(theme); @@ -54,7 +54,7 @@ public class ThemeServiceImpl implements ThemeService { } @Override - public void deleteTheme(Long id) { + public void deleteTheme(String id) { themeMapper.deleteById(id); } } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TokenServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TokenServiceImpl.java index 5930320..7cff875 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TokenServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TokenServiceImpl.java @@ -60,11 +60,11 @@ public class TokenServiceImpl implements TokenService { * 将 JwtPayload 转换为字符串存储 */ private String payloadToString(JwtPayload payload) { - return String.format("%d|%s|%s|%s|%s", + return String.format("%s|%s|%s|%s|%s", payload.getUserId(), payload.getUsername(), payload.getRole(), - payload.getTenantId() != null ? payload.getTenantId().toString() : "", + payload.getTenantId() != null ? payload.getTenantId() : "", payload.getName() != null ? payload.getName() : ""); } @@ -77,10 +77,10 @@ public class TokenServiceImpl implements TokenService { return null; } return JwtPayload.builder() - .userId(Long.parseLong(parts[0])) + .userId(parts[0]) .username(parts[1]) .role(parts[2]) - .tenantId(parts[3].isEmpty() ? null : Long.parseLong(parts[3])) + .tenantId(parts[3].isEmpty() ? null : parts[3]) .name(parts[4].isEmpty() ? null : parts[4]) .build(); } diff --git a/reading-platform-java/src/main/resources/application-dev.yml b/reading-platform-java/src/main/resources/application-dev.yml index cdefdf2..b52762d 100644 --- a/reading-platform-java/src/main/resources/application-dev.yml +++ b/reading-platform-java/src/main/resources/application-dev.yml @@ -17,6 +17,7 @@ spring: enabled: true locations: classpath:db/migration baseline-on-migrate: true + validate-on-migrate: false data: redis: host: 8.148.151.56 diff --git a/reading-platform-java/src/main/resources/application.yml b/reading-platform-java/src/main/resources/application.yml index 5c50480..1be36f8 100644 --- a/reading-platform-java/src/main/resources/application.yml +++ b/reading-platform-java/src/main/resources/application.yml @@ -49,3 +49,34 @@ knife4j: enable: true setting: language: zh_cn + +# Rate Limit Configuration +rate-limit: + enabled: true + default-time-window: 60 + default-max-requests: 1000 + # 限流规则 + rules: + # 登录接口限流 - 防止暴力破解 + - pattern: "/api/v1/auth/login" + time-window: 60 + max-requests: 10 + # 验证码接口限流 - 防止刷验证码 + - pattern: "/api/v1/auth/captcha" + time-window: 60 + max-requests: 5 + # 短信接口限流 - 防止短信轰炸 + - pattern: "/api/v1/sms/**" + time-window: 60 + max-requests: 3 + # 文件上传接口限流 + - pattern: "/api/v1/**/upload/**" + time-window: 60 + max-requests: 30 + # 排除限流的接口 + exclude-patterns: + - "/doc.html" + - "/swagger-resources/**" + - "/v3/api-docs/**" + - "/webjars/**" + - "/uploads/**" diff --git a/reading-platform-java/src/main/resources/db/migration/V1__init_schema.sql b/reading-platform-java/src/main/resources/db/migration/V1__init_schema.sql deleted file mode 100644 index 2e53ee9..0000000 --- a/reading-platform-java/src/main/resources/db/migration/V1__init_schema.sql +++ /dev/null @@ -1,522 +0,0 @@ --- Reading Platform Database Schema --- MySQL 8.0+ - -CREATE DATABASE IF NOT EXISTS reading_platform DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - -USE reading_platform; - --- ============================================ --- Tenant Tables --- ============================================ - -CREATE TABLE tenants ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - name VARCHAR(100) NOT NULL COMMENT 'Tenant name', - code VARCHAR(50) NOT NULL UNIQUE COMMENT 'Tenant code', - contact_name VARCHAR(50) COMMENT 'Contact person', - contact_phone VARCHAR(20) COMMENT 'Contact phone', - contact_email VARCHAR(100) COMMENT 'Contact email', - address VARCHAR(255) COMMENT 'Address', - logo_url VARCHAR(500) COMMENT 'Logo URL', - status VARCHAR(20) DEFAULT 'active' COMMENT 'Status: active, expired, disabled', - expire_at DATETIME COMMENT 'Expiration date', - max_students INT DEFAULT 0 COMMENT 'Max students allowed', - max_teachers INT DEFAULT 0 COMMENT 'Max teachers allowed', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Tenants'; - -CREATE TABLE tenant_courses ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - course_id BIGINT NOT NULL, - enabled TINYINT DEFAULT 1, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0, - UNIQUE KEY uk_tenant_course (tenant_id, course_id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Tenant-Course Relations'; - --- ============================================ --- User Tables --- ============================================ - -CREATE TABLE teachers ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - username VARCHAR(50) NOT NULL, - password VARCHAR(255) NOT NULL, - name VARCHAR(50) NOT NULL, - phone VARCHAR(20), - email VARCHAR(100), - avatar_url VARCHAR(500), - gender VARCHAR(10), - bio TEXT, - status VARCHAR(20) DEFAULT 'active', - last_login_at DATETIME, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0, - UNIQUE KEY uk_username (username) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Teachers'; - -CREATE TABLE students ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - name VARCHAR(50) NOT NULL, - gender VARCHAR(10), - birth_date DATE, - avatar_url VARCHAR(500), - grade VARCHAR(20), - student_no VARCHAR(50), - reading_level VARCHAR(20), - interests TEXT, - notes TEXT, - status VARCHAR(20) DEFAULT 'active', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Students'; - -CREATE TABLE parents ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - username VARCHAR(50) NOT NULL, - password VARCHAR(255) NOT NULL, - name VARCHAR(50) NOT NULL, - phone VARCHAR(20), - email VARCHAR(100), - avatar_url VARCHAR(500), - gender VARCHAR(10), - status VARCHAR(20) DEFAULT 'active', - last_login_at DATETIME, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0, - UNIQUE KEY uk_username (username) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Parents'; - -CREATE TABLE parent_students ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - parent_id BIGINT NOT NULL, - student_id BIGINT NOT NULL, - relationship VARCHAR(20) DEFAULT 'parent' COMMENT 'parent, guardian, etc.', - is_primary TINYINT DEFAULT 0, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0, - UNIQUE KEY uk_parent_student (parent_id, student_id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Parent-Student Relations'; - --- ============================================ --- Class Tables --- ============================================ - -CREATE TABLE classes ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - name VARCHAR(100) NOT NULL, - grade VARCHAR(20), - description TEXT, - capacity INT DEFAULT 30, - status VARCHAR(20) DEFAULT 'active', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Classes'; - -CREATE TABLE class_teachers ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - class_id BIGINT NOT NULL, - teacher_id BIGINT NOT NULL, - role VARCHAR(20) DEFAULT 'teacher' COMMENT 'head_teacher, teacher, assistant', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0, - UNIQUE KEY uk_class_teacher (class_id, teacher_id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Class-Teacher Relations'; - -CREATE TABLE student_class_history ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - student_id BIGINT NOT NULL, - class_id BIGINT NOT NULL, - start_date DATE NOT NULL, - end_date DATE, - status VARCHAR(20) DEFAULT 'active', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Student Class History'; - --- ============================================ --- Course Tables --- ============================================ - -CREATE TABLE courses ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT COMMENT 'NULL for system courses', - name VARCHAR(200) NOT NULL, - code VARCHAR(50), - description TEXT, - cover_url VARCHAR(500), - category VARCHAR(50), - age_range VARCHAR(50), - difficulty_level VARCHAR(20), - duration_minutes INT, - objectives TEXT, - status VARCHAR(20) DEFAULT 'draft', - is_system TINYINT DEFAULT 0, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Courses'; - -CREATE TABLE course_versions ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - course_id BIGINT NOT NULL, - version VARCHAR(20) NOT NULL, - description TEXT, - status VARCHAR(20) DEFAULT 'draft', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Course Versions'; - -CREATE TABLE course_resources ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - course_id BIGINT NOT NULL, - title VARCHAR(200) NOT NULL, - type VARCHAR(50) COMMENT 'video, audio, document, image, link', - url VARCHAR(1000), - file_path VARCHAR(500), - file_size BIGINT, - duration INT COMMENT 'Duration in seconds', - description TEXT, - sort_order INT DEFAULT 0, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Course Resources'; - -CREATE TABLE course_scripts ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - course_id BIGINT NOT NULL, - title VARCHAR(200) NOT NULL, - description TEXT, - sort_order INT DEFAULT 0, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Course Scripts'; - -CREATE TABLE course_script_pages ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - script_id BIGINT NOT NULL, - page_number INT NOT NULL, - content TEXT, - image_url VARCHAR(500), - audio_url VARCHAR(500), - duration INT COMMENT 'Duration in seconds', - notes TEXT, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Course Script Pages'; - -CREATE TABLE course_activities ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - course_id BIGINT NOT NULL, - title VARCHAR(200) NOT NULL, - type VARCHAR(50) COMMENT 'quiz, discussion, practice, game', - content TEXT, - materials TEXT, - duration_minutes INT, - sort_order INT DEFAULT 0, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Course Activities'; - --- ============================================ --- Lesson Tables --- ============================================ - -CREATE TABLE lessons ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - course_id BIGINT NOT NULL, - class_id BIGINT, - teacher_id BIGINT NOT NULL, - title VARCHAR(200) NOT NULL, - lesson_date DATE NOT NULL, - start_time TIME, - end_time TIME, - location VARCHAR(100), - status VARCHAR(20) DEFAULT 'scheduled', - notes TEXT, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Lessons'; - -CREATE TABLE lesson_feedbacks ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - lesson_id BIGINT NOT NULL, - teacher_id BIGINT NOT NULL, - content TEXT NOT NULL, - rating INT, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Lesson Feedbacks'; - -CREATE TABLE student_records ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - lesson_id BIGINT NOT NULL, - student_id BIGINT NOT NULL, - attendance VARCHAR(20) DEFAULT 'present' COMMENT 'present, absent, late', - performance TEXT, - notes TEXT, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0, - UNIQUE KEY uk_lesson_student (lesson_id, student_id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Student Records'; - --- ============================================ --- Task Tables --- ============================================ - -CREATE TABLE tasks ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - title VARCHAR(200) NOT NULL, - description TEXT, - type VARCHAR(50) DEFAULT 'homework' COMMENT 'reading, homework, activity', - course_id BIGINT, - creator_id BIGINT NOT NULL, - creator_role VARCHAR(20) NOT NULL, - start_date DATE, - due_date DATE, - status VARCHAR(20) DEFAULT 'pending', - attachments TEXT COMMENT 'JSON array of attachment URLs', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Tasks'; - -CREATE TABLE task_targets ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - task_id BIGINT NOT NULL, - target_type VARCHAR(20) NOT NULL COMMENT 'class, student', - target_id BIGINT NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Task Targets'; - -CREATE TABLE task_completions ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - task_id BIGINT NOT NULL, - student_id BIGINT NOT NULL, - status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending, in_progress, completed', - completed_at DATETIME, - content TEXT, - attachments TEXT COMMENT 'JSON array of attachment URLs', - rating INT, - feedback TEXT, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0, - UNIQUE KEY uk_task_student (task_id, student_id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Task Completions'; - -CREATE TABLE task_templates ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - name VARCHAR(100) NOT NULL, - description TEXT, - type VARCHAR(50), - content TEXT, - is_public TINYINT DEFAULT 0, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Task Templates'; - --- ============================================ --- Growth Record Tables --- ============================================ - -CREATE TABLE growth_records ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - student_id BIGINT NOT NULL, - type VARCHAR(50) NOT NULL COMMENT 'reading, behavior, achievement, milestone', - title VARCHAR(200) NOT NULL, - content TEXT, - images TEXT COMMENT 'JSON array of image URLs', - recorded_by BIGINT NOT NULL, - recorder_role VARCHAR(20) NOT NULL, - record_date DATE NOT NULL, - tags TEXT COMMENT 'JSON array of tags', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Growth Records'; - --- ============================================ --- Resource Tables --- ============================================ - -CREATE TABLE resource_libraries ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - name VARCHAR(100) NOT NULL, - description TEXT, - type VARCHAR(50) COMMENT 'book, material, equipment', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Resource Libraries'; - -CREATE TABLE resource_items ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - library_id BIGINT NOT NULL, - name VARCHAR(200) NOT NULL, - code VARCHAR(50), - description TEXT, - quantity INT DEFAULT 1, - available_quantity INT DEFAULT 1, - location VARCHAR(100), - status VARCHAR(20) DEFAULT 'available', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Resource Items'; - --- ============================================ --- Schedule Tables --- ============================================ - -CREATE TABLE schedule_plans ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - name VARCHAR(100) NOT NULL, - class_id BIGINT, - start_date DATE NOT NULL, - end_date DATE NOT NULL, - status VARCHAR(20) DEFAULT 'draft', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Schedule Plans'; - -CREATE TABLE schedule_templates ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - name VARCHAR(100) NOT NULL, - description TEXT, - content TEXT COMMENT 'JSON schedule data', - is_public TINYINT DEFAULT 0, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Schedule Templates'; - --- ============================================ --- System Tables --- ============================================ - -CREATE TABLE system_settings ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT COMMENT 'NULL for global settings', - setting_key VARCHAR(100) NOT NULL, - setting_value TEXT, - description VARCHAR(255), - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0, - UNIQUE KEY uk_tenant_key (tenant_id, setting_key) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='System Settings'; - -CREATE TABLE notifications ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - title VARCHAR(200) NOT NULL, - content TEXT NOT NULL, - type VARCHAR(50) COMMENT 'system, course, task, growth', - sender_id BIGINT, - sender_role VARCHAR(20), - recipient_type VARCHAR(20) NOT NULL COMMENT 'all, class, teacher, parent, student', - recipient_id BIGINT, - is_read TINYINT DEFAULT 0, - read_at DATETIME, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Notifications'; - -CREATE TABLE operation_logs ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT, - user_id BIGINT NOT NULL, - user_role VARCHAR(20), - action VARCHAR(100) NOT NULL, - module VARCHAR(50), - target_type VARCHAR(50), - target_id BIGINT, - details TEXT, - ip_address VARCHAR(50), - user_agent VARCHAR(500), - created_at DATETIME DEFAULT CURRENT_TIMESTAMP -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Operation Logs'; - -CREATE TABLE tags ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - name VARCHAR(50) NOT NULL, - type VARCHAR(50) COMMENT 'student, course, resource', - color VARCHAR(20), - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0, - UNIQUE KEY uk_tenant_name_type (tenant_id, name, type) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Tags'; - --- ============================================ --- Admin User (for super admin) --- ============================================ - -CREATE TABLE admin_users ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - username VARCHAR(50) NOT NULL UNIQUE, - password VARCHAR(255) NOT NULL, - name VARCHAR(50) NOT NULL, - email VARCHAR(100), - phone VARCHAR(20), - avatar_url VARCHAR(500), - status VARCHAR(20) DEFAULT 'active', - last_login_at DATETIME, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Admin Users'; - --- ============================================ --- Indexes --- ============================================ - -CREATE INDEX idx_teachers_tenant ON teachers(tenant_id); -CREATE INDEX idx_students_tenant ON students(tenant_id); -CREATE INDEX idx_parents_tenant ON parents(tenant_id); -CREATE INDEX idx_classes_tenant ON classes(tenant_id); -CREATE INDEX idx_courses_tenant ON courses(tenant_id); -CREATE INDEX idx_lessons_tenant ON lessons(tenant_id); -CREATE INDEX idx_tasks_tenant ON tasks(tenant_id); -CREATE INDEX idx_growth_records_tenant ON growth_records(tenant_id); -CREATE INDEX idx_notifications_tenant ON notifications(tenant_id); - --- ============================================ --- Initial Data --- ============================================ - --- Insert default admin user (password: admin123) -INSERT INTO admin_users (username, password, name, status) VALUES -('admin', '$2b$10$VSes.57X35WZov4LdyJ.eu1pll7qnt7tGuq/u3iXOrYawHTebe.Eu', 'Super Admin', 'active'); diff --git a/reading-platform-java/src/main/resources/db/migration/V2__add_course_package_fields.sql b/reading-platform-java/src/main/resources/db/migration/V2__add_course_package_fields.sql deleted file mode 100644 index 6b9537a..0000000 --- a/reading-platform-java/src/main/resources/db/migration/V2__add_course_package_fields.sql +++ /dev/null @@ -1,78 +0,0 @@ --- Course Package Refactoring - Add new fields --- Date: 2026-02-28 - --- Add new fields to courses table for course package refactoring - --- Core content -ALTER TABLE courses ADD COLUMN core_content TEXT COMMENT 'Core content summary'; - --- Course introduction fields (8 fields) -ALTER TABLE courses ADD COLUMN intro_summary TEXT COMMENT 'Course summary'; -ALTER TABLE courses ADD COLUMN intro_highlights TEXT COMMENT 'Course highlights'; -ALTER TABLE courses ADD COLUMN intro_goals TEXT COMMENT 'Course goals'; -ALTER TABLE courses ADD COLUMN intro_schedule TEXT COMMENT 'Content schedule'; -ALTER TABLE courses ADD COLUMN intro_key_points TEXT COMMENT 'Key points and difficulties'; -ALTER TABLE courses ADD COLUMN intro_methods TEXT COMMENT 'Teaching methods'; -ALTER TABLE courses ADD COLUMN intro_evaluation TEXT COMMENT 'Evaluation methods'; -ALTER TABLE courses ADD COLUMN intro_notes TEXT COMMENT 'Notes and precautions'; - --- Schedule reference data -ALTER TABLE courses ADD COLUMN schedule_ref_data TEXT COMMENT 'Schedule reference data (JSON)'; - --- Environment construction (Step 7) -ALTER TABLE courses ADD COLUMN environment_construction TEXT COMMENT 'Environment construction content'; - --- Theme and picture book relation -ALTER TABLE courses ADD COLUMN theme_id BIGINT COMMENT 'Theme ID'; -ALTER TABLE courses ADD COLUMN picture_book_name VARCHAR(200) COMMENT 'Picture book name'; - --- Cover image path -ALTER TABLE courses ADD COLUMN cover_image_path VARCHAR(500) COMMENT 'Cover image file path'; - --- Digital resources (JSON arrays) -ALTER TABLE courses ADD COLUMN ebook_paths TEXT COMMENT 'Ebook paths (JSON array)'; -ALTER TABLE courses ADD COLUMN audio_paths TEXT COMMENT 'Audio paths (JSON array)'; -ALTER TABLE courses ADD COLUMN video_paths TEXT COMMENT 'Video paths (JSON array)'; -ALTER TABLE courses ADD COLUMN other_resources TEXT COMMENT 'Other resources (JSON array)'; - --- Teaching materials -ALTER TABLE courses ADD COLUMN ppt_path VARCHAR(500) COMMENT 'PPT file path'; -ALTER TABLE courses ADD COLUMN ppt_name VARCHAR(200) COMMENT 'PPT file name'; -ALTER TABLE courses ADD COLUMN poster_paths TEXT COMMENT 'Poster paths (JSON array)'; -ALTER TABLE courses ADD COLUMN tools TEXT COMMENT 'Teaching tools (JSON array)'; -ALTER TABLE courses ADD COLUMN student_materials TEXT COMMENT 'Student materials'; - --- Lesson plan and activities -ALTER TABLE courses ADD COLUMN lesson_plan_data TEXT COMMENT 'Lesson plan data (JSON)'; -ALTER TABLE courses ADD COLUMN activities_data TEXT COMMENT 'Activities data (JSON)'; -ALTER TABLE courses ADD COLUMN assessment_data TEXT COMMENT 'Assessment data (JSON)'; - --- Grade and domain tags -ALTER TABLE courses ADD COLUMN grade_tags TEXT COMMENT 'Grade tags (JSON array)'; -ALTER TABLE courses ADD COLUMN domain_tags TEXT COMMENT 'Domain tags (JSON array)'; - --- Collective lesson flag -ALTER TABLE courses ADD COLUMN has_collective_lesson TINYINT DEFAULT 0 COMMENT 'Has collective lesson'; - --- Version and review fields -ALTER TABLE courses ADD COLUMN version VARCHAR(20) DEFAULT '1.0' COMMENT 'Version number'; -ALTER TABLE courses ADD COLUMN parent_id BIGINT COMMENT 'Parent course ID for versions'; -ALTER TABLE courses ADD COLUMN is_latest TINYINT DEFAULT 1 COMMENT 'Is latest version'; -ALTER TABLE courses ADD COLUMN submitted_at DATETIME COMMENT 'Submitted for review at'; -ALTER TABLE courses ADD COLUMN submitted_by BIGINT COMMENT 'Submitted by user ID'; -ALTER TABLE courses ADD COLUMN reviewed_at DATETIME COMMENT 'Reviewed at'; -ALTER TABLE courses ADD COLUMN reviewed_by BIGINT COMMENT 'Reviewed by user ID'; -ALTER TABLE courses ADD COLUMN review_comment TEXT COMMENT 'Review comment'; -ALTER TABLE courses ADD COLUMN review_checklist TEXT COMMENT 'Review checklist (JSON)'; -ALTER TABLE courses ADD COLUMN published_at DATETIME COMMENT 'Published at'; - --- Usage statistics -ALTER TABLE courses ADD COLUMN usage_count INT DEFAULT 0 COMMENT 'Usage count'; -ALTER TABLE courses ADD COLUMN teacher_count INT DEFAULT 0 COMMENT 'Teacher count'; -ALTER TABLE courses ADD COLUMN avg_rating DECIMAL(3,2) DEFAULT 0 COMMENT 'Average rating'; -ALTER TABLE courses ADD COLUMN created_by BIGINT COMMENT 'Created by user ID'; - --- Create indexes for better query performance -CREATE INDEX idx_courses_theme ON courses(theme_id); -CREATE INDEX idx_courses_status ON courses(status); -CREATE INDEX idx_courses_parent ON courses(parent_id); diff --git a/reading-platform-java/src/main/resources/db/migration/V3__add_themes.sql b/reading-platform-java/src/main/resources/db/migration/V3__add_themes.sql deleted file mode 100644 index eec1a23..0000000 --- a/reading-platform-java/src/main/resources/db/migration/V3__add_themes.sql +++ /dev/null @@ -1,21 +0,0 @@ --- Add themes table -CREATE TABLE IF NOT EXISTS themes ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - name VARCHAR(50) NOT NULL UNIQUE COMMENT 'Theme technical name', - display_name VARCHAR(100) NOT NULL COMMENT 'Display name', - color VARCHAR(20) COMMENT 'Theme color (hex)', - icon VARCHAR(100) COMMENT 'Theme icon', - sort_order INT DEFAULT 0 COMMENT 'Sort order', - is_enabled TINYINT DEFAULT 1 COMMENT 'Is enabled', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Themes'; - --- Insert default themes -INSERT INTO themes (name, display_name, color, sort_order, is_enabled) VALUES -('nature', '自然探索', '#4CAF50', 1, 1), -('ocean', '海洋世界', '#2196F3', 2, 1), -('space', '太空冒险', '#9C27B0', 3, 1), -('animals', '动物王国', '#FF9800', 4, 1), -('fairytale', '童话故事', '#E91E63', 5, 1); diff --git a/reading-platform-java/src/main/resources/db/migration/V4__add_course_packages.sql b/reading-platform-java/src/main/resources/db/migration/V4__add_course_packages.sql deleted file mode 100644 index a73d133..0000000 --- a/reading-platform-java/src/main/resources/db/migration/V4__add_course_packages.sql +++ /dev/null @@ -1,14 +0,0 @@ --- Add course packages table -CREATE TABLE IF NOT EXISTS course_packages ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - name VARCHAR(200) NOT NULL COMMENT 'Package name', - description TEXT COMMENT 'Package description', - cover_url VARCHAR(500) COMMENT 'Cover image URL', - course_count INT DEFAULT 0 COMMENT 'Number of courses', - price DECIMAL(10, 2) DEFAULT 0 COMMENT 'Price', - status VARCHAR(20) DEFAULT 'draft' COMMENT 'Status: draft, published, archived', - is_system TINYINT DEFAULT 1 COMMENT 'Is system package', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Course Packages'; diff --git a/reading-platform-java/src/main/resources/db/migration/V5__add_school_courses.sql b/reading-platform-java/src/main/resources/db/migration/V5__add_school_courses.sql deleted file mode 100644 index e4514a8..0000000 --- a/reading-platform-java/src/main/resources/db/migration/V5__add_school_courses.sql +++ /dev/null @@ -1,17 +0,0 @@ --- Add school courses table (tenant-customized courses) -CREATE TABLE IF NOT EXISTS school_courses ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - tenant_id BIGINT NOT NULL COMMENT 'Tenant ID', - name VARCHAR(200) NOT NULL COMMENT 'Course name', - description TEXT COMMENT 'Course description', - cover_url VARCHAR(500) COMMENT 'Cover URL', - category VARCHAR(50) COMMENT 'Course category', - age_range VARCHAR(50) COMMENT 'Age range', - status VARCHAR(20) DEFAULT 'draft' COMMENT 'Status: draft, published, archived', - created_by BIGINT COMMENT 'Created by user ID', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0, - INDEX idx_tenant (tenant_id), - INDEX idx_status (status) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='School Custom Courses'; diff --git a/reading-platform-java/src/main/resources/db/migration/V6__add_course_lessons.sql b/reading-platform-java/src/main/resources/db/migration/V6__add_course_lessons.sql deleted file mode 100644 index c479b1c..0000000 --- a/reading-platform-java/src/main/resources/db/migration/V6__add_course_lessons.sql +++ /dev/null @@ -1,17 +0,0 @@ --- Add course lessons table (chapters/sections within a course) -CREATE TABLE IF NOT EXISTS course_lessons ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - course_id BIGINT NOT NULL COMMENT 'Course ID', - title VARCHAR(200) NOT NULL COMMENT 'Lesson title', - description TEXT COMMENT 'Lesson description', - content TEXT COMMENT 'Lesson content', - sort_order INT DEFAULT 0 COMMENT 'Sort order', - duration_minutes INT COMMENT 'Duration in minutes', - video_url VARCHAR(1000) COMMENT 'Video URL', - status VARCHAR(20) DEFAULT 'draft' COMMENT 'Status: draft, published', - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted TINYINT DEFAULT 0, - INDEX idx_course (course_id), - INDEX idx_sort (sort_order) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Course Lessons (chapters/sections)'; diff --git a/reading-platform-java/src/main/resources/db/migration/V7__fix_schedule_plans.sql b/reading-platform-java/src/main/resources/db/migration/V7__fix_schedule_plans.sql deleted file mode 100644 index bf29f3f..0000000 --- a/reading-platform-java/src/main/resources/db/migration/V7__fix_schedule_plans.sql +++ /dev/null @@ -1,15 +0,0 @@ --- ============================================ --- 修复 schedule_plans 表,添加缺失字段 --- ============================================ - -ALTER TABLE schedule_plans -ADD COLUMN course_id BIGINT COMMENT '课程 ID' AFTER class_id, -ADD COLUMN teacher_id BIGINT COMMENT '教师 ID' AFTER course_id, -ADD COLUMN day_of_week TINYINT COMMENT '星期几 (1-7)' AFTER teacher_id, -ADD COLUMN period TINYINT COMMENT '节次' AFTER day_of_week, -ADD COLUMN start_time TIME COMMENT '开始时间' AFTER period, -ADD COLUMN end_time TIME COMMENT '结束时间' AFTER start_time, -ADD COLUMN location VARCHAR(100) COMMENT '教室/地点' AFTER end_time, -ADD COLUMN note VARCHAR(500) COMMENT '备注' AFTER location; - -ALTER TABLE schedule_plans COMMENT='课表计划(增强版)'; diff --git a/reading-platform-java/src/main/resources/db/schema/database_schema.sql b/reading-platform-java/src/main/resources/db/schema/database_schema.sql new file mode 100644 index 0000000..0af35ef --- /dev/null +++ b/reading-platform-java/src/main/resources/db/schema/database_schema.sql @@ -0,0 +1,738 @@ +-- ============================================ +-- Reading Platform Database Schema +-- ============================================ +-- 版本:1.0.0 +-- 数据库:MySQL 8.0+ +-- 字符集:utf8mb4 +-- 表名规范:t_前缀 + 单数形式 +-- ID 类型:VARCHAR(32) +-- 包含审计字段:created_by, updated_by +-- +-- 表列表:共 36 张表 +-- - 用户表:6 张 +-- - 班级表:3 张 +-- - 课程表:10 张 +-- - 课时表:3 张 +-- - 任务表:4 张 +-- - 成长表:1 张 +-- - 资源表:2 张 +-- - 日程表:2 张 +-- - 系统表:5 张 +-- ============================================ + +CREATE DATABASE IF NOT EXISTS reading_platform DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +USE reading_platform; + +-- ============================================ +-- Admin User (for super admin) +-- ============================================ + +CREATE TABLE IF NOT EXISTS t_admin_user ( + id VARCHAR(32) PRIMARY KEY COMMENT '管理员 ID', + username VARCHAR(50) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + name VARCHAR(50) NOT NULL, + email VARCHAR(100), + phone VARCHAR(20), + avatar_url VARCHAR(500), + status VARCHAR(20) DEFAULT 'active', + last_login_at DATETIME, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管理员用户'; + +-- ============================================ +-- Tenant Tables +-- ============================================ + +CREATE TABLE IF NOT EXISTS t_tenant ( + id VARCHAR(32) PRIMARY KEY COMMENT '租户 ID', + name VARCHAR(100) NOT NULL COMMENT 'Tenant name', + code VARCHAR(50) NOT NULL UNIQUE COMMENT 'Tenant code', + contact_name VARCHAR(50) COMMENT 'Contact person', + contact_phone VARCHAR(20) COMMENT 'Contact phone', + contact_email VARCHAR(100) COMMENT 'Contact email', + address VARCHAR(255) COMMENT 'Address', + logo_url VARCHAR(500) COMMENT 'Logo URL', + status VARCHAR(20) DEFAULT 'active' COMMENT 'Status: active, expired, disabled', + expire_at DATETIME COMMENT 'Expiration date', + max_students INT DEFAULT 0 COMMENT 'Max students allowed', + max_teachers INT DEFAULT 0 COMMENT 'Max teachers allowed', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户(幼儿园/机构)'; + +-- ============================================ +-- User Tables +-- ============================================ + +CREATE TABLE IF NOT EXISTS t_teacher ( + id VARCHAR(32) PRIMARY KEY COMMENT '教师 ID', + tenant_id VARCHAR(32) NOT NULL COMMENT '租户 ID', + username VARCHAR(50) NOT NULL, + password VARCHAR(255) NOT NULL, + name VARCHAR(50) NOT NULL, + phone VARCHAR(20), + email VARCHAR(100), + avatar_url VARCHAR(500), + gender VARCHAR(10), + bio TEXT, + status VARCHAR(20) DEFAULT 'active', + last_login_at DATETIME, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名', + UNIQUE KEY uk_username (username) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='教师'; + +CREATE TABLE IF NOT EXISTS t_student ( + id VARCHAR(32) PRIMARY KEY COMMENT '学生 ID', + tenant_id VARCHAR(32) NOT NULL COMMENT '租户 ID', + name VARCHAR(50) NOT NULL, + gender VARCHAR(10), + birth_date DATE, + avatar_url VARCHAR(500), + grade VARCHAR(20), + student_no VARCHAR(50), + reading_level VARCHAR(20), + interests TEXT, + notes TEXT, + status VARCHAR(20) DEFAULT 'active', + class_id VARCHAR(32) COMMENT '班级 ID', + parent_name VARCHAR(100) COMMENT '家长姓名', + parent_phone VARCHAR(20) COMMENT '家长手机号', + reading_count INT DEFAULT 0 COMMENT '阅读次数', + lesson_count INT DEFAULT 0 COMMENT '课时数', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生'; + +CREATE TABLE IF NOT EXISTS t_parent ( + id VARCHAR(32) PRIMARY KEY COMMENT '家长 ID', + tenant_id VARCHAR(32) NOT NULL COMMENT '租户 ID', + username VARCHAR(50) NOT NULL, + password VARCHAR(255) NOT NULL, + name VARCHAR(50) NOT NULL, + phone VARCHAR(20), + email VARCHAR(100), + avatar_url VARCHAR(500), + gender VARCHAR(10), + status VARCHAR(20) DEFAULT 'active', + last_login_at DATETIME, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名', + UNIQUE KEY uk_username (username) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家长'; + +CREATE TABLE IF NOT EXISTS t_parent_student ( + id VARCHAR(32) PRIMARY KEY COMMENT '主键 ID', + parent_id VARCHAR(32) NOT NULL COMMENT '家长 ID', + student_id VARCHAR(32) NOT NULL COMMENT '学生 ID', + relationship VARCHAR(20) DEFAULT 'parent' COMMENT 'parent, guardian, etc.', + is_primary TINYINT DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名', + UNIQUE KEY uk_parent_student (parent_id, student_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家长 - 学生关联'; + +-- ============================================ +-- Class Tables +-- ============================================ + +CREATE TABLE IF NOT EXISTS t_clazz ( + id VARCHAR(32) PRIMARY KEY COMMENT '班级 ID', + tenant_id VARCHAR(32) NOT NULL COMMENT '租户 ID', + name VARCHAR(100) NOT NULL, + grade VARCHAR(20), + description TEXT, + capacity INT DEFAULT 30, + status VARCHAR(20) DEFAULT 'active', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='班级'; + +CREATE TABLE IF NOT EXISTS t_class_teacher ( + id VARCHAR(32) PRIMARY KEY COMMENT '主键 ID', + class_id VARCHAR(32) NOT NULL COMMENT '班级 ID', + teacher_id VARCHAR(32) NOT NULL COMMENT '教师 ID', + role VARCHAR(20) DEFAULT 'teacher' COMMENT 'head_teacher, teacher, assistant', + is_primary BOOLEAN DEFAULT FALSE COMMENT '是否主教', + sort_order INT DEFAULT 0 COMMENT '排序', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名', + UNIQUE KEY uk_class_teacher (class_id, teacher_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='班级 - 教师关联'; + +CREATE TABLE IF NOT EXISTS t_student_class_history ( + id VARCHAR(32) PRIMARY KEY COMMENT '主键 ID', + student_id VARCHAR(32) NOT NULL COMMENT '学生 ID', + class_id VARCHAR(32) NOT NULL COMMENT '班级 ID', + start_date DATE NOT NULL, + end_date DATE, + status VARCHAR(20) DEFAULT 'active', + reason VARCHAR(255) COMMENT '调班原因', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生班级历史'; + +-- ============================================ +-- Course Tables +-- ============================================ + +CREATE TABLE IF NOT EXISTS t_course ( + id VARCHAR(32) PRIMARY KEY COMMENT '课程 ID', + tenant_id VARCHAR(32) COMMENT 'NULL for system courses', + name VARCHAR(200) NOT NULL, + code VARCHAR(50), + description TEXT, + cover_url VARCHAR(500), + category VARCHAR(50), + age_range VARCHAR(50), + difficulty_level VARCHAR(20), + duration_minutes INT, + objectives TEXT, + status VARCHAR(20) DEFAULT 'draft', + is_system TINYINT DEFAULT 0, + -- 课程包重构字段 + core_content TEXT, + intro_summary TEXT, + intro_highlights TEXT, + intro_goals TEXT, + intro_schedule TEXT, + intro_key_points TEXT, + intro_methods TEXT, + intro_evaluation TEXT, + intro_notes TEXT, + schedule_ref_data TEXT, + environment_construction TEXT, + theme_id VARCHAR(32) COMMENT '主题 ID', + picture_book_name VARCHAR(100), + cover_image_path VARCHAR(500), + ebook_paths TEXT, + audio_paths TEXT, + video_paths TEXT, + other_resources TEXT, + ppt_path VARCHAR(500), + ppt_name VARCHAR(100), + poster_paths TEXT, + tools TEXT, + student_materials TEXT, + lesson_plan_data TEXT, + activities_data TEXT, + assessment_data TEXT, + grade_tags TEXT, + domain_tags TEXT, + has_collective_lesson TINYINT DEFAULT 0, + -- 版本与审核字段 + version VARCHAR(20), + parent_id VARCHAR(32) COMMENT '父课程 ID', + is_latest TINYINT DEFAULT 0, + submitted_at DATETIME, + submitted_by VARCHAR(64), + reviewed_at DATETIME, + reviewed_by VARCHAR(64), + review_comment TEXT, + review_checklist TEXT, + published_at DATETIME, + -- 使用统计 + usage_count INT DEFAULT 0, + teacher_count INT DEFAULT 0, + avg_rating DECIMAL(10,2), + -- 审计字段 + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程'; + +CREATE TABLE IF NOT EXISTS t_course_version ( + id VARCHAR(32) PRIMARY KEY COMMENT '课程版本 ID', + course_id VARCHAR(32) NOT NULL COMMENT '课程 ID', + version VARCHAR(20) NOT NULL, + description TEXT, + status VARCHAR(20) DEFAULT 'draft', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程版本'; + +CREATE TABLE IF NOT EXISTS t_course_package ( + id VARCHAR(32) PRIMARY KEY COMMENT '课程包 ID', + name VARCHAR(100) NOT NULL, + description TEXT, + cover_url VARCHAR(500), + course_count INT DEFAULT 0, + price DECIMAL(10,2), + status VARCHAR(20) DEFAULT 'draft', + is_system TINYINT DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程包'; + +CREATE TABLE IF NOT EXISTS t_school_course ( + id VARCHAR(32) PRIMARY KEY COMMENT '校本课程 ID', + tenant_id VARCHAR(32) NOT NULL COMMENT '租户 ID', + name VARCHAR(200) NOT NULL, + description TEXT, + cover_url VARCHAR(500), + category VARCHAR(50), + age_range VARCHAR(50), + status VARCHAR(20) DEFAULT 'draft', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='校本课程'; + +CREATE TABLE IF NOT EXISTS t_tenant_course ( + id VARCHAR(32) PRIMARY KEY COMMENT '租户课程 ID', + tenant_id VARCHAR(32) NOT NULL COMMENT '租户 ID', + course_id VARCHAR(32) NOT NULL COMMENT '课程 ID', + enabled TINYINT DEFAULT 1, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名', + UNIQUE KEY uk_tenant_course (tenant_id, course_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户 - 课程关联'; + +CREATE TABLE IF NOT EXISTS t_course_resource ( + id VARCHAR(32) PRIMARY KEY COMMENT '课程资源 ID', + course_id VARCHAR(32) NOT NULL, + title VARCHAR(200) NOT NULL, + type VARCHAR(50) COMMENT 'video, audio, document, image, link', + url VARCHAR(1000), + file_path VARCHAR(500), + file_size BIGINT, + duration INT COMMENT 'Duration in seconds', + description TEXT, + sort_order INT DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程资源'; + +CREATE TABLE IF NOT EXISTS t_course_script ( + id VARCHAR(32) PRIMARY KEY COMMENT '课程脚本 ID', + course_id VARCHAR(32) NOT NULL, + title VARCHAR(200) NOT NULL, + description TEXT, + sort_order INT DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程脚本'; + +CREATE TABLE IF NOT EXISTS t_course_script_page ( + id VARCHAR(32) PRIMARY KEY COMMENT '课程脚本页面 ID', + script_id VARCHAR(32) NOT NULL, + page_number INT NOT NULL, + content TEXT, + image_url VARCHAR(500), + audio_url VARCHAR(500), + duration INT COMMENT 'Duration in seconds', + notes TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程脚本页面'; + +CREATE TABLE IF NOT EXISTS t_course_activity ( + id VARCHAR(32) PRIMARY KEY COMMENT '课程活动 ID', + course_id VARCHAR(32) NOT NULL, + title VARCHAR(200) NOT NULL, + type VARCHAR(50) COMMENT 'quiz, discussion, practice, game', + content TEXT, + materials TEXT, + duration_minutes INT, + sort_order INT DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程活动'; + +CREATE TABLE IF NOT EXISTS t_course_lesson ( + id VARCHAR(32) PRIMARY KEY COMMENT '课程课时 ID', + course_id VARCHAR(32) NOT NULL, + title VARCHAR(200) NOT NULL, + description TEXT, + content TEXT, + sort_order INT DEFAULT 0, + duration_minutes INT, + video_url VARCHAR(500), + status VARCHAR(20) DEFAULT 'draft', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程课时'; + +-- ============================================ +-- Lesson Tables +-- ============================================ + +CREATE TABLE IF NOT EXISTS t_lesson ( + id VARCHAR(32) PRIMARY KEY COMMENT '课时 ID', + tenant_id VARCHAR(32) NOT NULL COMMENT '租户 ID', + course_id VARCHAR(32) NOT NULL COMMENT '课程 ID', + class_id VARCHAR(32) COMMENT '班级 ID', + teacher_id VARCHAR(32) NOT NULL COMMENT '教师 ID', + title VARCHAR(200) NOT NULL, + lesson_date DATE NOT NULL, + start_time TIME, + end_time TIME, + location VARCHAR(100), + status VARCHAR(20) DEFAULT 'scheduled', + notes TEXT, + -- 新增字段 + actual_duration INT COMMENT '实际时长(分钟)', + overall_rating VARCHAR(10) COMMENT '整体评分', + participation_rating VARCHAR(10) COMMENT '参与度评分', + completion_note TEXT COMMENT '完成说明', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课时'; + +CREATE TABLE IF NOT EXISTS t_lesson_feedback ( + id VARCHAR(32) PRIMARY KEY COMMENT '课时反馈 ID', + lesson_id VARCHAR(32) NOT NULL COMMENT '课时 ID', + teacher_id VARCHAR(32) NOT NULL COMMENT '教师 ID', + design_quality INT COMMENT '设计质量评分 (1-5)', + participation INT COMMENT '参与度评分 (1-5)', + goal_achievement INT COMMENT '目标达成度评分 (1-5)', + step_feedbacks TEXT COMMENT '环节反馈 JSON', + pros TEXT COMMENT '优点', + suggestions TEXT COMMENT '建议', + activities_done TEXT COMMENT '完成的活动 JSON', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课时反馈'; + +CREATE TABLE IF NOT EXISTS t_student_record ( + id VARCHAR(32) PRIMARY KEY COMMENT '学生记录 ID', + lesson_id VARCHAR(32) NOT NULL COMMENT '课时 ID', + student_id VARCHAR(32) NOT NULL COMMENT '学生 ID', + attendance VARCHAR(20) DEFAULT 'present' COMMENT 'present, absent, late', + performance TEXT, + notes TEXT, + focus INT COMMENT '专注力评分 (1-5)', + participation INT COMMENT '参与度评分 (1-5)', + interest INT COMMENT '兴趣评分 (1-5)', + understanding INT COMMENT '理解度评分 (1-5)', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名', + UNIQUE KEY uk_lesson_student (lesson_id, student_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生记录'; + +-- ============================================ +-- Task Tables +-- ============================================ + +CREATE TABLE IF NOT EXISTS t_task ( + id VARCHAR(32) PRIMARY KEY COMMENT '任务 ID', + tenant_id VARCHAR(32) NOT NULL COMMENT '租户 ID', + title VARCHAR(200) NOT NULL, + description TEXT, + type VARCHAR(50) DEFAULT 'homework' COMMENT 'reading, homework, activity', + course_id VARCHAR(32) COMMENT '课程 ID', + creator_id VARCHAR(32) NOT NULL, + creator_role VARCHAR(20) NOT NULL, + start_date DATE, + due_date DATE, + status VARCHAR(20) DEFAULT 'pending', + attachments TEXT COMMENT 'JSON array of attachment URLs', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务'; + +CREATE TABLE IF NOT EXISTS t_task_template ( + id VARCHAR(32) PRIMARY KEY COMMENT '任务模板 ID', + tenant_id VARCHAR(32) NOT NULL, + name VARCHAR(100) NOT NULL, + description TEXT, + type VARCHAR(50), + content TEXT, + is_public TINYINT DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务模板'; + +CREATE TABLE IF NOT EXISTS t_task_target ( + id VARCHAR(32) PRIMARY KEY COMMENT '任务目标 ID', + task_id VARCHAR(32) NOT NULL, + target_type VARCHAR(20) NOT NULL COMMENT 'class, student', + target_id VARCHAR(32) NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务目标'; + +CREATE TABLE IF NOT EXISTS t_task_completion ( + id VARCHAR(32) PRIMARY KEY COMMENT '任务完成 ID', + task_id VARCHAR(32) NOT NULL, + student_id VARCHAR(32) NOT NULL, + status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending, in_progress, completed', + completed_at DATETIME, + content TEXT, + attachments TEXT COMMENT 'JSON array of attachment URLs', + rating INT, + feedback TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名', + UNIQUE KEY uk_task_student (task_id, student_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务完成'; + +-- ============================================ +-- Growth Record Tables +-- ============================================ + +CREATE TABLE IF NOT EXISTS t_growth_record ( + id VARCHAR(32) PRIMARY KEY COMMENT '成长档案 ID', + tenant_id VARCHAR(32) NOT NULL, + student_id VARCHAR(32) NOT NULL, + type VARCHAR(50) NOT NULL COMMENT 'reading, behavior, achievement, milestone', + title VARCHAR(200) NOT NULL, + content TEXT, + images TEXT COMMENT 'JSON array of image URLs', + recorded_by VARCHAR(32) NOT NULL, + recorder_role VARCHAR(20) NOT NULL, + record_date DATE NOT NULL, + tags TEXT COMMENT 'JSON array of tags', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长档案'; + +-- ============================================ +-- Resource Tables +-- ============================================ + +CREATE TABLE IF NOT EXISTS t_resource_library ( + id VARCHAR(32) PRIMARY KEY COMMENT '资源库 ID', + tenant_id VARCHAR(32) NOT NULL, + name VARCHAR(100) NOT NULL, + description TEXT, + type VARCHAR(50) COMMENT 'book, material, equipment', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资源库'; + +CREATE TABLE IF NOT EXISTS t_resource_item ( + id VARCHAR(32) PRIMARY KEY COMMENT '资源项 ID', + library_id VARCHAR(32) NOT NULL, + name VARCHAR(200) NOT NULL, + code VARCHAR(50), + description TEXT, + quantity INT DEFAULT 1, + available_quantity INT DEFAULT 1, + location VARCHAR(100), + status VARCHAR(20) DEFAULT 'available', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资源项'; + +-- ============================================ +-- Schedule Tables +-- ============================================ + +CREATE TABLE IF NOT EXISTS t_schedule_plan ( + id VARCHAR(32) PRIMARY KEY COMMENT '日程计划 ID', + tenant_id VARCHAR(32) NOT NULL, + name VARCHAR(100) NOT NULL, + class_id VARCHAR(32) COMMENT '班级 ID', + course_id VARCHAR(32) COMMENT '课程 ID', + teacher_id VARCHAR(32) COMMENT '教师 ID', + day_of_week INT COMMENT '星期几 (1-7)', + period INT COMMENT '第几节课', + start_time TIME, + end_time TIME, + start_date DATE, + end_date DATE, + location VARCHAR(100), + note TEXT, + status VARCHAR(20) DEFAULT 'scheduled', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日程计划'; + +CREATE TABLE IF NOT EXISTS t_schedule_template ( + id VARCHAR(32) PRIMARY KEY COMMENT '日程模板 ID', + tenant_id VARCHAR(32) NOT NULL, + name VARCHAR(100) NOT NULL, + description TEXT, + content TEXT COMMENT 'JSON schedule data', + is_public TINYINT DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日程模板'; + +-- ============================================ +-- System Tables +-- ============================================ + +CREATE TABLE IF NOT EXISTS t_system_setting ( + id VARCHAR(32) PRIMARY KEY COMMENT '系统设置 ID', + tenant_id VARCHAR(32) COMMENT 'NULL for global settings', + setting_key VARCHAR(100) NOT NULL, + setting_value TEXT, + description VARCHAR(255), + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名', + UNIQUE KEY uk_tenant_key (tenant_id, setting_key) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统设置'; + +CREATE TABLE IF NOT EXISTS t_notification ( + id VARCHAR(32) PRIMARY KEY COMMENT '通知 ID', + tenant_id VARCHAR(32) NOT NULL, + title VARCHAR(200) NOT NULL, + content TEXT NOT NULL, + type VARCHAR(50) COMMENT 'system, course, task, growth', + sender_id VARCHAR(32), + sender_role VARCHAR(20), + recipient_type VARCHAR(20) NOT NULL COMMENT 'all, class, teacher, parent, student', + recipient_id VARCHAR(32), + is_read TINYINT DEFAULT 0, + read_at DATETIME, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通知'; + +CREATE TABLE IF NOT EXISTS t_operation_log ( + id VARCHAR(32) PRIMARY KEY COMMENT '操作日志 ID', + tenant_id VARCHAR(32), + user_id VARCHAR(32) NOT NULL, + user_role VARCHAR(20), + action VARCHAR(100) NOT NULL, + module VARCHAR(50), + target_type VARCHAR(50), + target_id VARCHAR(32), + details TEXT, + ip_address VARCHAR(50), + user_agent VARCHAR(500), + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + created_by VARCHAR(64) COMMENT '创建人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志'; + +CREATE TABLE IF NOT EXISTS t_tag ( + id VARCHAR(32) PRIMARY KEY COMMENT '标签 ID', + tenant_id VARCHAR(32) NOT NULL, + name VARCHAR(50) NOT NULL, + type VARCHAR(50) COMMENT 'student, course, resource', + color VARCHAR(20), + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名', + UNIQUE KEY uk_tenant_name_type (tenant_id, name, type) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='标签'; + +CREATE TABLE IF NOT EXISTS t_theme ( + id VARCHAR(32) PRIMARY KEY COMMENT '主题 ID', + name VARCHAR(50) NOT NULL, + display_name VARCHAR(100), + color VARCHAR(20), + icon VARCHAR(50), + sort_order INT DEFAULT 0, + is_enabled TINYINT DEFAULT 1, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted TINYINT DEFAULT 0, + created_by VARCHAR(64) COMMENT '创建人用户名', + updated_by VARCHAR(64) COMMENT '更新人用户名' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='主题'; + +-- ============================================ +-- Indexes +-- ============================================ + +CREATE INDEX idx_teacher_tenant ON t_teacher(tenant_id); +CREATE INDEX idx_student_tenant ON t_student(tenant_id); +CREATE INDEX idx_parent_tenant ON t_parent(tenant_id); +CREATE INDEX idx_clazz_tenant ON t_clazz(tenant_id); +CREATE INDEX idx_course_tenant ON t_course(tenant_id); +CREATE INDEX idx_lesson_tenant ON t_lesson(tenant_id); +CREATE INDEX idx_task_tenant ON t_task(tenant_id); +CREATE INDEX idx_growth_record_tenant ON t_growth_record(tenant_id); +CREATE INDEX idx_notification_tenant ON t_notification(tenant_id); diff --git a/reading-platform-java/src/test/java/com/reading/platform/DatabaseInspectTool.java b/reading-platform-java/src/test/java/com/reading/platform/DatabaseInspectTool.java new file mode 100644 index 0000000..94d2fc5 --- /dev/null +++ b/reading-platform-java/src/test/java/com/reading/platform/DatabaseInspectTool.java @@ -0,0 +1,57 @@ +package com.reading.platform; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.junit.jupiter.api.Test; +import org.springframework.test.context.ActiveProfiles; + +import java.util.List; +import java.util.Map; + +/** + * 数据库表结构检查工具 + */ +@SpringBootTest +@ActiveProfiles("dev") +public class DatabaseInspectTool { + + @Autowired + private JdbcTemplate jdbcTemplate; + + /** + * 检查 V20 迁移涉及的表和列 + */ + @Test + public void checkV20Tables() { + System.out.println("=== 检查 V20 迁移涉及的表和列 ===\n"); + + String[] tables = {"student_records", "lesson_feedbacks", "lessons", "student_class_history", "class_teacher", "students"}; + + for (String table : tables) { + System.out.println("表:" + table); + try { + List> columns = jdbcTemplate.queryForList( + "SHOW COLUMNS FROM " + table + ); + System.out.println(" 列名:"); + for (Map col : columns) { + System.out.println(" - " + col.get("Field") + " (" + col.get("Type") + ")"); + } + } catch (Exception e) { + System.out.println(" 表不存在:" + e.getMessage()); + } + System.out.println(); + } + } + + /** + * 清理 flyway_schema_history 表中的 V20 记录 + */ + @Test + public void cleanFlywayHistory() { + System.out.println("=== 清理 Flyway V20 记录 ==="); + int deleted = jdbcTemplate.update("DELETE FROM flyway_schema_history WHERE version = '20'"); + System.out.println("已删除 " + deleted + " 条记录"); + } +} diff --git a/reading-platform-java/src/test/java/com/reading/platform/FlywayHistoryTool.java b/reading-platform-java/src/test/java/com/reading/platform/FlywayHistoryTool.java new file mode 100644 index 0000000..f5faefd --- /dev/null +++ b/reading-platform-java/src/test/java/com/reading/platform/FlywayHistoryTool.java @@ -0,0 +1,73 @@ +package com.reading.platform; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.junit.jupiter.api.Test; +import org.springframework.test.context.ActiveProfiles; + +import java.util.List; +import java.util.Map; + +/** + * Flyway 迁移历史查看和清理工具 + */ +@SpringBootTest +@ActiveProfiles("dev") +public class FlywayHistoryTool { + + @Autowired + private JdbcTemplate jdbcTemplate; + + /** + * 查看迁移历史 + */ + @Test + public void showHistory() { + System.out.println("=== Flyway 迁移历史 ==="); + List> history = jdbcTemplate.queryForList( + "SELECT version, description, type, script, checksum, installed_by, installed_on, execution_time, success " + + "FROM flyway_schema_history " + + "ORDER BY installed_rank DESC" + ); + + for (Map row : history) { + System.out.printf("Version: %-10s | Type: %-15s | Script: %-50s | Success: %s | Installed: %s%n", + row.get("version"), + row.get("type"), + row.get("script"), + row.get("success"), + row.get("installed_on") + ); + } + } + + /** + * 清理版本 20 的迁移记录 + */ + @Test + public void cleanV20() { + System.out.println("=== 清理版本 20 的迁移记录 ==="); + + // 查看版本 20 的记录 + List> v20Records = jdbcTemplate.queryForList( + "SELECT * FROM flyway_schema_history WHERE version = '20'" + ); + + if (v20Records.isEmpty()) { + System.out.println("没有找到版本 20 的记录"); + return; + } + + System.out.println("找到 " + v20Records.size() + " 条版本 20 的记录:"); + for (Map row : v20Records) { + System.out.printf(" - ID: %s, Script: %s, Success: %s%n", + row.get("installed_rank"), row.get("script"), row.get("success")); + } + + // 删除版本 20 的所有记录 + int deleted = jdbcTemplate.update("DELETE FROM flyway_schema_history WHERE version = '20'"); + System.out.println("已删除 " + deleted + " 条记录"); + System.out.println("请重启应用,Flyway 会重新执行 V20 迁移"); + } +} diff --git a/reading-platform-java/src/test/java/com/reading/platform/FlywayRepairTool.java b/reading-platform-java/src/test/java/com/reading/platform/FlywayRepairTool.java new file mode 100644 index 0000000..67d6a8c --- /dev/null +++ b/reading-platform-java/src/test/java/com/reading/platform/FlywayRepairTool.java @@ -0,0 +1,55 @@ +package com.reading.platform; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.junit.jupiter.api.Test; +import org.springframework.test.context.ActiveProfiles; + +/** + * Flyway 修复工具 + * 用于修复失败的数据库迁移 + * + * 使用方法: + * 1. 在 application-dev.yml 中添加:spring.flyway.enabled=false + * 2. 运行此测试类:mvn test -Dtest=FlywayRepairTool#repairV20 + * 3. 恢复 Flyway 配置 + * 4. 重启应用 + */ +@SpringBootTest +@ActiveProfiles("dev") +public class FlywayRepairTool { + + @Autowired + private JdbcTemplate jdbcTemplate; + + /** + * 修复 V20 失败的迁移 + */ + @Test + public void repairV20() { + System.out.println("开始修复 Flyway V20 迁移..."); + + // 删除 V20 的失败记录 + int rows = jdbcTemplate.update( + "DELETE FROM flyway_schema_history WHERE version = '20'" + ); + + System.out.println("已删除 " + rows + " 条失败记录"); + System.out.println("修复完成!请重启应用。"); + } + + /** + * 查看当前的迁移历史 + */ + @Test + public void showMigrationHistory() { + System.out.println("当前迁移历史:"); + jdbcTemplate.queryForList("SELECT * FROM flyway_schema_history ORDER BY installed_on DESC") + .forEach(record -> { + System.out.println(" Version: " + record.get("version") + + ", Status: " + record.get("success") + + ", Installed: " + record.get("installed_on")); + }); + } +} diff --git a/reading-platform-java/src/test/java/com/reading/platform/TestDataGenerator.java b/reading-platform-java/src/test/java/com/reading/platform/TestDataGenerator.java new file mode 100644 index 0000000..ae8a962 --- /dev/null +++ b/reading-platform-java/src/test/java/com/reading/platform/TestDataGenerator.java @@ -0,0 +1,898 @@ +package com.reading.platform; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.reading.platform.entity.*; +import com.reading.platform.mapper.*; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.annotation.Propagation; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +/** + * 测试数据生成器 + * 用于生成一批测试数据并插入到数据库 + */ +@SpringBootTest +@ActiveProfiles("dev") +public class TestDataGenerator { + + @Autowired + private TenantMapper tenantMapper; + + @Autowired + private TeacherMapper teacherMapper; + + @Autowired + private StudentMapper studentMapper; + + @Autowired + private ParentMapper parentMapper; + + @Autowired + private ClazzMapper clazzMapper; + + @Autowired + private ClassTeacherMapper classTeacherMapper; + + @Autowired + private ParentStudentMapper parentStudentMapper; + + @Autowired + private CourseMapper courseMapper; + + @Autowired + private CourseLessonMapper courseLessonMapper; + + @Autowired + private LessonMapper lessonMapper; + + @Autowired + private TaskMapper taskMapper; + + @Autowired + private TaskTemplateMapper taskTemplateMapper; + + @Autowired + private NotificationMapper notificationMapper; + + @Autowired + private ThemeMapper themeMapper; + + @Autowired + private SchedulePlanMapper schedulePlanMapper; + + @Autowired + private GrowthRecordMapper growthRecordMapper; + + private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + + /** + * 清理测试数据(按顺序删除,避免外键约束问题) + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + private void cleanupTestData() { + System.out.println("【清理】开始清理旧的测试数据..."); + + // 测试租户的 code + String testTenantCode1 = "sunshine_kinder"; + String testTenantCode2 = "hope_kinder"; + + // 测试教师的 username + String[] testTeacherUsernames = {"teacher_wang", "teacher_li", "teacher_zhang"}; + + // 测试家长的 username + String[] testParentUsernames = {"parent_zhang", "parent_liu"}; + + System.out.println(" 开始清理教师数据..."); + // 物理删除测试教师 + for (String username : testTeacherUsernames) { + teacherMapper.deletePhysicalByUsername(username); + } + System.out.println(" ✓ 物理删除测试教师"); + + System.out.println(" 开始删除学校账号..."); + // 物理删除教师表中的学校账号(这些账号的用户名 = 租户 code) + teacherMapper.deletePhysicalByUsername(testTenantCode1); + teacherMapper.deletePhysicalByUsername(testTenantCode2); + System.out.println(" ✓ 物理删除学校账号"); + + System.out.println(" 开始清理家长数据..."); + // 物理删除测试家长 + for (String username : testParentUsernames) { + parentMapper.deletePhysicalByUsername(username); + } + System.out.println(" ✓ 物理删除测试家长"); + + System.out.println(" 开始清理学生数据..."); + // 物理删除测试学生(按学号) + studentMapper.deletePhysicalByStudentNo("S2024001"); + studentMapper.deletePhysicalByStudentNo("S2024002"); + studentMapper.deletePhysicalByStudentNo("S2024003"); + System.out.println(" ✓ 物理删除测试学生"); + + System.out.println(" 开始物理删除租户..."); + // 使用物理删除清理租户 + int deleted1 = tenantMapper.deletePhysicalByCode(testTenantCode1); + System.out.println(" ✓ 物理删除租户:" + testTenantCode1 + " (" + deleted1 + " 条)"); + + int deleted2 = tenantMapper.deletePhysicalByCode(testTenantCode2); + System.out.println(" ✓ 物理删除租户:" + testTenantCode2 + " (" + deleted2 + " 条)"); + + // 清理主题数据(使用物理删除) + System.out.println(" 开始清理主题数据..."); + themeMapper.deletePhysical(); + System.out.println(" ✓ 删除所有主题数据"); + + System.out.println("【清理】清理完成"); + } + + /** + * 清理指定租户的所有数据 + */ + private void cleanupTenantData(Long tenantId) { + // 按依赖顺序删除 + growthRecordMapper.delete(new LambdaQueryWrapper().eq(GrowthRecord::getTenantId, tenantId)); + schedulePlanMapper.delete(new LambdaQueryWrapper().eq(SchedulePlan::getTenantId, tenantId)); + notificationMapper.delete(new LambdaQueryWrapper().eq(Notification::getTenantId, tenantId)); + taskTemplateMapper.delete(new LambdaQueryWrapper().eq(TaskTemplate::getTenantId, tenantId)); + taskMapper.delete(new LambdaQueryWrapper().eq(Task::getTenantId, tenantId)); + lessonMapper.delete(new LambdaQueryWrapper().eq(Lesson::getTenantId, tenantId)); + courseMapper.delete(new LambdaQueryWrapper().eq(Course::getTenantId, tenantId)); + + // 删除家长学生关联 + ParentStudentMapper psMapper = parentStudentMapper; + // 先获取该租户的家长和学生 + var parents = parentMapper.selectList(new LambdaQueryWrapper().eq(Parent::getTenantId, tenantId)); + for (Parent parent : parents) { + psMapper.delete(new LambdaQueryWrapper().eq(ParentStudent::getParentId, parent.getId())); + } + + // 删除学生 + studentMapper.delete(new LambdaQueryWrapper().eq(Student::getTenantId, tenantId)); + + // 删除家长 + parentMapper.delete(new LambdaQueryWrapper().eq(Parent::getTenantId, tenantId)); + + // 删除班级教师关联 + var classes = clazzMapper.selectList(new LambdaQueryWrapper().eq(Clazz::getTenantId, tenantId)); + for (Clazz clazz : classes) { + classTeacherMapper.delete(new LambdaQueryWrapper().eq(ClassTeachers::getClassId, clazz.getId())); + } + + // 删除班级 + clazzMapper.delete(new LambdaQueryWrapper().eq(Clazz::getTenantId, tenantId)); + + // 删除教师(包括学校账号) + teacherMapper.delete(new LambdaQueryWrapper().eq(Teacher::getTenantId, tenantId)); + } + + /** + * 生成完整的测试数据 + * 包括:租户、教师、学生、家长、班级、课程、课时、任务、通知等 + */ + @Test + public void generateAllTestData() { + System.out.println("========== 开始生成测试数据 =========="); + + // 先清理测试租户的旧数据(如果存在) + cleanupTestData(); + + // 1. 创建租户(幼儿园) + Long tenantId = createTenants(); + + // 2. 创建主题 + createThemes(); + + // 3. 创建教师 + Long teacherId1 = createTeachers(tenantId); + Long teacherId2 = createTeachers2(tenantId); + + // 4. 创建学生 + Long studentId1 = createStudents(tenantId); + Long studentId2 = createStudents2(tenantId); + Long studentId3 = createStudents3(tenantId); + + // 5. 创建家长 + Long parentId1 = createParents(tenantId); + Long parentId2 = createParents2(tenantId); + + // 6. 创建班级 + Long classId1 = createClasses(tenantId); + Long classId2 = createClasses2(tenantId); + + // 7. 关联班级和教师 + createClassTeachers(classId1, teacherId1); + createClassTeachers2(classId2, teacherId2); + + // 8. 关联家长和学生 + createParentStudents(parentId1, studentId1); + createParentStudents2(parentId2, studentId2, studentId3); + + // 9. 创建课程 + Long courseId1 = createCourses(tenantId); + Long courseId2 = createCourses2(tenantId); + + // 10. 创建课程课时 + createCourseLessons(courseId1); + createCourseLessons2(courseId2); + + // 11. 创建课时(教学活动) + createLessons(tenantId, courseId1, classId1, teacherId1); + + // 12. 创建任务 + createTasks(tenantId, courseId1, teacherId1); + + // 13. 创建任务模板 + createTaskTemplates(tenantId); + + // 14. 创建通知 + createNotifications(tenantId, teacherId1, parentId1); + + // 15. 创建课表计划 + createSchedulePlans(tenantId, classId1, courseId1, teacherId1); + + // 16. 创建成长记录 + createGrowthRecords(tenantId, studentId1); + + System.out.println("========== 测试数据生成完成 =========="); + } + + /** + * 创建租户(幼儿园) + */ + private Long createTenants() { + System.out.println("【1】创建租户..."); + + Tenant tenant = new Tenant(); + tenant.setName("阳光幼儿园"); + tenant.setCode("sunshine_kinder"); + tenant.setContactName("张园长"); + tenant.setContactPhone("13800138001"); + tenant.setContactEmail("sunshine@kinder.com"); + tenant.setAddress("北京市朝阳区阳光路 100 号"); + tenant.setLogoUrl("/uploads/logos/sunshine.png"); + tenant.setStatus("active"); + tenant.setExpireAt(LocalDateTime.now().plusYears(1)); + tenant.setMaxStudents(500); + tenant.setMaxTeachers(50); + + tenantMapper.insert(tenant); + System.out.println(" ✓ 创建租户:阳光幼儿园 (ID=" + tenant.getId() + ")"); + + // 创建第二个租户 + Tenant tenant2 = new Tenant(); + tenant2.setName("希望幼儿园"); + tenant2.setCode("hope_kinder"); + tenant2.setContactName("李园长"); + tenant2.setContactPhone("13800138002"); + tenant2.setContactEmail("hope@kinder.com"); + tenant2.setAddress("北京市海淀区希望路 200 号"); + tenant2.setLogoUrl("/uploads/logos/hope.png"); + tenant2.setStatus("active"); + tenant2.setExpireAt(LocalDateTime.now().plusYears(1)); + tenant2.setMaxStudents(300); + tenant2.setMaxTeachers(30); + + tenantMapper.insert(tenant2); + System.out.println(" ✓ 创建租户:希望幼儿园 (ID=" + tenant2.getId() + ")"); + + // 创建学校登录账号(教师表中) + Teacher schoolAccount = new Teacher(); + schoolAccount.setTenantId(tenant.getId()); + schoolAccount.setUsername(tenant.getCode()); + schoolAccount.setPassword(passwordEncoder.encode("123456")); + schoolAccount.setName("阳光幼儿园 - 学校账号"); + schoolAccount.setStatus("active"); + teacherMapper.insert(schoolAccount); + System.out.println(" ✓ 创建学校登录账号 (username=" + tenant.getCode() + ", password=123456)"); + + return tenant.getId(); + } + + /** + * 创建主题 + */ + private void createThemes() { + System.out.println("【2】创建主题..."); + + String[][] themes = { + {"language", "语言与文字", "#FF6B6B"}, + {"math", "数学与逻辑", "#4ECDC4"}, + {"science", "科学探索", "#45B7D1"}, + {"art", "艺术与创造", "#FFA07A"}, + {"social", "社会情感", "#98D8C8"}, + {"health", "健康运动", "#F7DC6F"}, + {"nature", "自然认知", "#82E0AA"} + }; + + int sortOrder = 1; + for (String[] theme : themes) { + Theme entity = new Theme(); + entity.setName(theme[0]); + entity.setDisplayName(theme[1]); + entity.setColor(theme[2]); + entity.setIcon("icon-" + theme[0]); + entity.setSortOrder(sortOrder++); + entity.setIsEnabled(1); + + themeMapper.insert(entity); + System.out.println(" ✓ 创建主题:" + theme[1] + " (" + theme[0] + ")"); + } + } + + /** + * 创建教师 + */ + private Long createTeachers(Long tenantId) { + System.out.println("【3】创建教师..."); + + Teacher teacher = new Teacher(); + teacher.setTenantId(tenantId); + teacher.setUsername("teacher_wang"); + teacher.setPassword(passwordEncoder.encode("123456")); + teacher.setName("王老师"); + teacher.setPhone("13900139001"); + teacher.setEmail("wang@kinder.com"); + teacher.setGender("female"); + teacher.setBio("资深幼儿教师,擅长语言教学"); + teacher.setStatus("active"); + + teacherMapper.insert(teacher); + System.out.println(" ✓ 创建教师:王老师 (ID=" + teacher.getId() + ", username=teacher_wang)"); + + return teacher.getId(); + } + + private Long createTeachers2(Long tenantId) { + Teacher teacher = new Teacher(); + teacher.setTenantId(tenantId); + teacher.setUsername("teacher_li"); + teacher.setPassword(passwordEncoder.encode("123456")); + teacher.setName("李老师"); + teacher.setPhone("13900139002"); + teacher.setEmail("li@kinder.com"); + teacher.setGender("male"); + teacher.setBio("体育教师,擅长运动游戏"); + teacher.setStatus("active"); + + teacherMapper.insert(teacher); + System.out.println(" ✓ 创建教师:李老师 (ID=" + teacher.getId() + ", username=teacher_li)"); + + return teacher.getId(); + } + + /** + * 创建学生 + */ + private Long createStudents(Long tenantId) { + System.out.println("【4】创建学生..."); + + Student student = new Student(); + student.setTenantId(tenantId); + student.setName("小明"); + student.setGender("male"); + student.setBirthDate(LocalDate.of(2019, 5, 15)); + student.setAvatarUrl("/uploads/avatars/student1.png"); + student.setGrade("大班"); + student.setStudentNo("S2024001"); + student.setReadingLevel("中级"); + student.setInterests("阅读、画画、积木"); + student.setNotes("活泼好动,喜欢提问"); + student.setStatus("active"); + + studentMapper.insert(student); + System.out.println(" ✓ 创建学生:小明 (ID=" + student.getId() + ")"); + + return student.getId(); + } + + private Long createStudents2(Long tenantId) { + Student student = new Student(); + student.setTenantId(tenantId); + student.setName("小红"); + student.setGender("female"); + student.setBirthDate(LocalDate.of(2019, 8, 20)); + student.setAvatarUrl("/uploads/avatars/student2.png"); + student.setGrade("大班"); + student.setStudentNo("S2024002"); + student.setReadingLevel("高级"); + student.setInterests("阅读、唱歌、跳舞"); + student.setNotes("文静乖巧,记忆力好"); + student.setStatus("active"); + + studentMapper.insert(student); + System.out.println(" ✓ 创建学生:小红 (ID=" + student.getId() + ")"); + + return student.getId(); + } + + private Long createStudents3(Long tenantId) { + Student student = new Student(); + student.setTenantId(tenantId); + student.setName("小强"); + student.setGender("male"); + student.setBirthDate(LocalDate.of(2020, 2, 10)); + student.setAvatarUrl("/uploads/avatars/student3.png"); + student.setGrade("中班"); + student.setStudentNo("S2024003"); + student.setReadingLevel("初级"); + student.setInterests("运动、游戏"); + student.setNotes("性格开朗,喜欢集体活动"); + student.setStatus("active"); + + studentMapper.insert(student); + System.out.println(" ✓ 创建学生:小强 (ID=" + student.getId() + ")"); + + return student.getId(); + } + + /** + * 创建家长 + */ + private Long createParents(Long tenantId) { + System.out.println("【5】创建家长..."); + + Parent parent = new Parent(); + parent.setTenantId(tenantId); + parent.setUsername("parent_zhang"); + parent.setPassword(passwordEncoder.encode("123456")); + parent.setName("张先生"); + parent.setPhone("13700137001"); + parent.setEmail("zhang@qq.com"); + parent.setGender("male"); + parent.setStatus("active"); + + parentMapper.insert(parent); + System.out.println(" ✓ 创建家长:张先生 (ID=" + parent.getId() + ", username=parent_zhang)"); + + return parent.getId(); + } + + private Long createParents2(Long tenantId) { + Parent parent = new Parent(); + parent.setTenantId(tenantId); + parent.setUsername("parent_liu"); + parent.setPassword(passwordEncoder.encode("123456")); + parent.setName("刘女士"); + parent.setPhone("13700137002"); + parent.setEmail("liu@qq.com"); + parent.setGender("female"); + parent.setStatus("active"); + + parentMapper.insert(parent); + System.out.println(" ✓ 创建家长:刘女士 (ID=" + parent.getId() + ", username=parent_liu)"); + + return parent.getId(); + } + + /** + * 创建班级 + */ + private Long createClasses(Long tenantId) { + System.out.println("【6】创建班级..."); + + Clazz clazz = new Clazz(); + clazz.setTenantId(tenantId); + clazz.setName("大(一)班"); + clazz.setGrade("大班"); + clazz.setDescription("2019 年出生的小朋友"); + clazz.setCapacity(35); + clazz.setStatus("active"); + + clazzMapper.insert(clazz); + System.out.println(" ✓ 创建班级:大(一)班 (ID=" + clazz.getId() + ")"); + + return clazz.getId(); + } + + private Long createClasses2(Long tenantId) { + Clazz clazz = new Clazz(); + clazz.setTenantId(tenantId); + clazz.setName("中(一)班"); + clazz.setGrade("中班"); + clazz.setDescription("2020 年出生的小朋友"); + clazz.setCapacity(30); + clazz.setStatus("active"); + + clazzMapper.insert(clazz); + System.out.println(" ✓ 创建班级:中(一)班 (ID=" + clazz.getId() + ")"); + + return clazz.getId(); + } + + /** + * 创建班级 - 教师关联 + */ + private void createClassTeachers(Long classId, Long teacherId) { + System.out.println("【7】创建班级 - 教师关联..."); + + ClassTeachers ct = new ClassTeachers(); + ct.setClassId(classId); + ct.setTeacherId(teacherId); + ct.setRole("head_teacher"); + + classTeacherMapper.insert(ct); + System.out.println(" ✓ 关联班级 - 教师:大(一)班 - 王老师(班主任)"); + } + + private void createClassTeachers2(Long classId, Long teacherId) { + ClassTeachers ct = new ClassTeachers(); + ct.setClassId(classId); + ct.setTeacherId(teacherId); + ct.setRole("head_teacher"); + + classTeacherMapper.insert(ct); + System.out.println(" ✓ 关联班级 - 教师:中(一)班 - 李老师(班主任)"); + } + + /** + * 创建家长 - 学生关联 + */ + private void createParentStudents(Long parentId, Long studentId) { + System.out.println("【8】创建家长 - 学生关联..."); + + ParentStudent ps = new ParentStudent(); + ps.setParentId(parentId); + ps.setStudentId(studentId); + ps.setRelationship("father"); + ps.setIsPrimary(1); + + parentStudentMapper.insert(ps); + System.out.println(" ✓ 关联家长 - 学生:张先生 - 小明(父子)"); + } + + private void createParentStudents2(Long parentId, Long studentId1, Long studentId2) { + ParentStudent ps1 = new ParentStudent(); + ps1.setParentId(parentId); + ps1.setStudentId(studentId1); + ps1.setRelationship("mother"); + ps1.setIsPrimary(1); + + parentStudentMapper.insert(ps1); + + ParentStudent ps2 = new ParentStudent(); + ps2.setParentId(parentId); + ps2.setStudentId(studentId2); + ps2.setRelationship("mother"); + ps2.setIsPrimary(1); + + parentStudentMapper.insert(ps2); + System.out.println(" ✓ 关联家长 - 学生:刘女士 - 小红、小强(母子)"); + } + + /** + * 创建课程 + */ + private Long createCourses(Long tenantId) { + System.out.println("【9】创建课程..."); + + Course course = new Course(); + course.setTenantId(tenantId); + course.setName("绘本阅读入门"); + course.setCode("READ001"); + course.setDescription("适合大班幼儿的绘本阅读课程,培养孩子的阅读兴趣和基础阅读能力"); + course.setCoverUrl("/uploads/courses/reading101.png"); + course.setCategory("language"); + course.setAgeRange("5-6 岁"); + course.setDifficultyLevel("beginner"); + course.setDurationMinutes(30); + course.setObjectives("培养阅读兴趣、提升语言表达能力、增强想象力"); + course.setStatus("published"); + course.setIsSystem(0); + course.setThemeId(1L); + course.setPictureBookName("《猜猜我有多爱你》"); + course.setVersion("1.0"); + course.setIsLatest(1); + + courseMapper.insert(course); + System.out.println(" ✓ 创建课程:绘本阅读入门 (ID=" + course.getId() + ")"); + + return course.getId(); + } + + private Long createCourses2(Long tenantId) { + Course course = new Course(); + course.setTenantId(tenantId); + course.setName("趣味数学游戏"); + course.setCode("MATH001"); + course.setDescription("通过游戏的方式学习基础数学概念"); + course.setCoverUrl("/uploads/courses/math101.png"); + course.setCategory("math"); + course.setAgeRange("4-5 岁"); + course.setDifficultyLevel("beginner"); + course.setDurationMinutes(25); + course.setObjectives("认识数字、学习简单加减法、培养逻辑思维"); + course.setStatus("published"); + course.setIsSystem(0); + course.setThemeId(2L); + course.setVersion("1.0"); + course.setIsLatest(1); + + courseMapper.insert(course); + System.out.println(" ✓ 创建课程:趣味数学游戏 (ID=" + course.getId() + ")"); + + return course.getId(); + } + + /** + * 创建课程课时 + */ + private void createCourseLessons(Long courseId) { + System.out.println("【10】创建课程课时..."); + + String[][] lessons = { + {"第一讲:认识绘本", "了解绘本的结构和特点"}, + {"第二讲:封面故事", "从封面猜测故事内容"}, + {"第三讲:角色认知", "认识故事中的主要角色"}, + {"第四讲:情节理解", "理解故事的发展脉络"}, + {"第五讲:情感体验", "感受故事中的情感表达"}, + {"第六讲:创意延伸", "发挥想象,创编故事结局"} + }; + + for (int i = 0; i < lessons.length; i++) { + CourseLesson lesson = new CourseLesson(); + lesson.setCourseId(courseId); + lesson.setTitle(lessons[i][0]); + lesson.setDescription(lessons[i][1]); + lesson.setContent("这里是课时内容详情..."); + lesson.setSortOrder(i + 1); + lesson.setDurationMinutes(15); + lesson.setStatus("published"); + + courseLessonMapper.insert(lesson); + } + System.out.println(" ✓ 创建课程课时:" + lessons.length + " 个课时"); + } + + private void createCourseLessons2(Long courseId) { + String[][] lessons = { + {"第一讲:数字歌", "学习数字 1-10"}, + {"第二讲:比大小", "认识大小概念"}, + {"第三讲:数一数", "练习点数"}, + {"第四讲:简单加法", "学习 5 以内加法"}, + {"第五讲:简单减法", "学习 5 以内减法"} + }; + + for (int i = 0; i < lessons.length; i++) { + CourseLesson lesson = new CourseLesson(); + lesson.setCourseId(courseId); + lesson.setTitle(lessons[i][0]); + lesson.setDescription(lessons[i][1]); + lesson.setContent("这里是课时内容详情..."); + lesson.setSortOrder(i + 1); + lesson.setDurationMinutes(12); + lesson.setStatus("published"); + + courseLessonMapper.insert(lesson); + } + System.out.println(" ✓ 创建课程课时:" + lessons.length + " 个课时"); + } + + /** + * 创建课时(教学活动) + */ + private void createLessons(Long tenantId, Long courseId, Long classId, Long teacherId) { + System.out.println("【11】创建课时(教学活动)..."); + + LocalDate baseDate = LocalDate.now(); + + for (int i = 0; i < 4; i++) { + Lesson lesson = new Lesson(); + lesson.setTenantId(tenantId); + lesson.setCourseId(courseId); + lesson.setClassId(classId); + lesson.setTeacherId(teacherId); + lesson.setTitle("绘本阅读 - 第" + (i + 1) + "课"); + lesson.setLessonDate(baseDate.plusWeeks(i)); + lesson.setStartTime(LocalTime.of(9, 0)); + lesson.setEndTime(LocalTime.of(9, 30)); + lesson.setLocation("大一班教室"); + lesson.setStatus("scheduled"); + lesson.setNotes("请小朋友们提前准备好绘本"); + + lessonMapper.insert(lesson); + } + System.out.println(" ✓ 创建课时:4 个教学活动"); + } + + /** + * 创建任务 + */ + private void createTasks(Long tenantId, Long courseId, Long teacherId) { + System.out.println("【12】创建任务..."); + + LocalDate baseDate = LocalDate.now(); + + // 任务 1 + Task task1 = new Task(); + task1.setTenantId(tenantId); + task1.setTitle("阅读打卡第 1 周"); + task1.setDescription("请家长陪同孩子每天阅读 15 分钟,并记录阅读内容"); + task1.setType("reading"); + task1.setCourseId(courseId); + task1.setCreatorId(teacherId); + task1.setCreatorRole("teacher"); + task1.setStartDate(baseDate); + task1.setDueDate(baseDate.plusDays(7)); + task1.setStatus("published"); + + taskMapper.insert(task1); + + // 任务 2 + Task task2 = new Task(); + task2.setTenantId(tenantId); + task2.setTitle("绘画作业:我喜欢的故事角色"); + task2.setDescription("画出你最喜欢的故事角色,并说明理由"); + task2.setType("homework"); + task2.setCourseId(courseId); + task2.setCreatorId(teacherId); + task2.setCreatorRole("teacher"); + task2.setStartDate(baseDate); + task2.setDueDate(baseDate.plusDays(5)); + task2.setStatus("published"); + + taskMapper.insert(task2); + + // 任务 3 + Task task3 = new Task(); + task3.setTenantId(tenantId); + task3.setTitle("周末亲子活动"); + task3.setDescription("周末和孩子一起去图书馆或书店"); + task3.setType("activity"); + task3.setCourseId(courseId); + task3.setCreatorId(teacherId); + task3.setCreatorRole("teacher"); + task3.setStartDate(baseDate.plusDays(5)); + task3.setDueDate(baseDate.plusDays(7)); + task3.setStatus("published"); + + taskMapper.insert(task3); + + System.out.println(" ✓ 创建任务:3 个任务"); + } + + /** + * 创建任务模板 + */ + private void createTaskTemplates(Long tenantId) { + System.out.println("【13】创建任务模板..."); + + String[][] templates = { + {"阅读打卡模板", "用于日常阅读打卡记录", "reading", "请记录今天的阅读内容..."}, + {"绘画作业模板", "用于美术类作业", "homework", "请上传孩子的绘画作品..."}, + {"亲子活动模板", "用于记录亲子活动", "activity", "请分享活动过程和感受..."}, + {"观察记录模板", "用于观察类作业", "homework", "请记录观察到的现象..."} + }; + + for (String[] template : templates) { + TaskTemplate tt = new TaskTemplate(); + tt.setTenantId(tenantId); + tt.setName(template[0]); + tt.setDescription(template[1]); + tt.setType(template[2]); + tt.setContent(template[3]); + tt.setIsPublic(1); + + taskTemplateMapper.insert(tt); + } + System.out.println(" ✓ 创建任务模板:" + templates.length + " 个模板"); + } + + /** + * 创建通知 + */ + private void createNotifications(Long tenantId, Long teacherId, Long parentId) { + System.out.println("【14】创建通知..."); + + // 通知 1 - 系统通知 + Notification n1 = new Notification(); + n1.setTenantId(tenantId); + n1.setTitle("新学期开始通知"); + n1.setContent("亲爱的家长们,新学期即将开始,请做好入园准备。"); + n1.setType("system"); + n1.setRecipientType("all"); + n1.setIsRead(0); + + notificationMapper.insert(n1); + + // 通知 2 - 课程通知 + Notification n2 = new Notification(); + n2.setTenantId(tenantId); + n2.setTitle("绘本阅读课程更新"); + n2.setContent("《猜猜我有多爱你》课程已更新,请查看。"); + n2.setType("course"); + n2.setSenderId(teacherId); + n2.setSenderRole("teacher"); + n2.setRecipientType("all"); + n2.setIsRead(0); + + notificationMapper.insert(n2); + + // 通知 3 - 任务通知 + Notification n3 = new Notification(); + n3.setTenantId(tenantId); + n3.setTitle("新任务发布"); + n3.setContent("本周的阅读打卡任务已发布,请家长陪同完成。"); + n3.setType("task"); + n3.setSenderId(teacherId); + n3.setSenderRole("teacher"); + n3.setRecipientId(parentId); + n3.setRecipientType("parent"); + n3.setIsRead(0); + + notificationMapper.insert(n3); + + System.out.println(" ✓ 创建通知:3 条通知"); + } + + /** + * 创建课表计划 + */ + private void createSchedulePlans(Long tenantId, Long classId, Long courseId, Long teacherId) { + System.out.println("【15】创建课表计划..."); + + int[][] schedules = { + {1, 1}, // 周一第 1 节 + {1, 3}, // 周一第 3 节 + {3, 2}, // 周三第 2 节 + {5, 1} // 周五第 1 节 + }; + + for (int[] schedule : schedules) { + SchedulePlan plan = new SchedulePlan(); + plan.setTenantId(tenantId); + plan.setName("绘本阅读课"); + plan.setClassId(classId); + plan.setCourseId(courseId); + plan.setTeacherId(teacherId); + plan.setDayOfWeek(schedule[0]); + plan.setPeriod(schedule[1]); + plan.setStartTime(LocalTime.of(9, 0)); + plan.setEndTime(LocalTime.of(9, 30)); + plan.setStartDate(LocalDate.now()); + plan.setEndDate(LocalDate.now().plusMonths(4)); + plan.setLocation("大一班教室"); + plan.setStatus("active"); + + schedulePlanMapper.insert(plan); + } + System.out.println(" ✓ 创建课表计划:" + schedules.length + " 个课程安排"); + } + + /** + * 创建成长记录 + */ + private void createGrowthRecords(Long tenantId, Long studentId) { + System.out.println("【16】创建成长记录..."); + + String[][] records = { + {"reading", "第一次独立阅读", "今天小明第一次独立读完了一本绘本,非常棒!", "阅读进步"}, + {"behavior", "帮助同学", "小明主动帮助摔倒的同学,很有爱心", "品德表现"}, + {"achievement", "绘画比赛获奖", "在幼儿园绘画比赛中获得一等奖", "荣誉奖项"} + }; + + for (String[] record : records) { + GrowthRecord gr = new GrowthRecord(); + gr.setTenantId(tenantId); + gr.setStudentId(studentId); + gr.setType(record[0]); + gr.setTitle(record[1]); + gr.setContent(record[2]); + gr.setRecordedBy(1L); // 设置记录人 ID + gr.setRecorderRole("teacher"); // 设置记录人角色 + gr.setRecordDate(LocalDate.now()); + gr.setTags("[\"" + record[3] + "\"]"); + + growthRecordMapper.insert(gr); + } + System.out.println(" ✓ 创建成长记录:" + records.length + " 条记录"); + } +}