# 学生操行分管理 - API 接口设计 ## 📋 文档说明 **版本**: v1.0 **制定时间**: 2025-01-13 **适用范围**: 学生操行分管理模块 API 接口设计 **重要性**: ⚠️ **强制性规范** - API 设计必须遵循项目统一接口规范 --- ## 🎯 设计原则 ### 1. RESTful 设计 - 使用标准的 HTTP 方法(GET、POST、PUT、DELETE) - 资源路径清晰,层次分明 - 状态码规范,返回信息明确 ### 2. 统一响应格式 - 所有接口返回统一的 JSON 格式 - 包含状态码、消息、数据三个部分 - 分页查询使用统一的 TableDataInfo 格式 ### 3. 权限控制 - 每个接口必须有 @SaCheckPermission 注解 - 班主任只能操作自己班级的学生 - 学生处管理员可查看全校数据 --- ## 🔌 接口概览 ### 接口分类 #### 基础 CRUD 接口 | 接口名称 | 请求方式 | 路径 | 权限字符 | 功能描述 | | -------------- | -------- | --------------------------- | ---------------------- | ---------------------- | | 查询操行分列表 | GET | /api/conduct-score/list | conduct:score:list | 分页查询操行分记录 | | 查询操行分详情 | GET | /api/conduct-score/{id} | conduct:score:query | 根据 ID 查询操行分详情 | | 新增操行分 | POST | /api/conduct-score | conduct:score:add | 创建新的操行分记录 | | 更新操行分 | PUT | /api/conduct-score/{id} | conduct:score:edit | 更新指定操行分记录 | | 删除操行分 | DELETE | /api/conduct-score/{id} | conduct:score:remove | 删除指定操行分记录 | #### 业务逻辑接口 | 接口名称 | 请求方式 | 路径 | 权限字符 | 功能描述 | | ---------------- | -------- | ----------------------------- | ---------------------- | ------------------------ | | 批量录入操行分 | POST | /api/conduct-score/batch | conduct:score:batchAdd | 批量保存操行分 | | 班主任班级学生 | GET | /api/conduct-score/class-students | conduct:score:classStudents | 获取班主任班级学生列表 | | 学期平均分统计 | GET | /api/statistics/semester-average | conduct:statistics:semester | 查询学期平均分 | | 导出学期统计 | GET | /api/statistics/export | conduct:statistics:export | 导出学期统计数据 | | 验证录入权限 | GET | /api/conduct-score/check-permission | conduct:score:checkPermission | 检查班主任录入权限 | --- ## 📝 接口详细设计 ### 1. 查询操行分列表 #### 接口信息 - **请求方式**: GET - **接口路径**: `/api/conduct-score/list` - **权限字符**: `conduct:score:list` - **接口描述**: 分页查询操行分记录列表 #### 请求参数 | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------- | ---- | ---------------------- | | academicYear| Integer | 否 | 学年(如:2024) | | semester | Integer | 否 | 学期(1-第一学期,2-第二学期) | | month | Integer | 否 | 月份(1-12) | | studentName | String | 否 | 学生姓名 | | className | String | 否 | 班级名称 | | scoreMin | BigDecimal | 否 | 最低分数 | | scoreMax | BigDecimal | 否 | 最高分数 | | pageNum | Integer | 否 | 当前页码(默认1) | | pageSize | Integer | 否 | 每页显示数量(默认10) | #### 响应格式 ```json { "code": 200, "msg": "查询成功", "data": { "total": 100, "rows": [ { "id": 1234567890123456789, "academicYear": 2024, "semester": 1, "month": 9, "studentId": 987654321098765432, "studentName": "张三", "studentNo": "2024001", "classId": 876543210987654321, "className": "计算机应用1班", "classTeacherId": 765432109876543210, "classTeacherName": "李老师", "score": 95.50, "remark": "表现优秀,积极参加班级活动", "createTime": "2024-09-01 10:00:00", "createBy": "李老师" } ], "code": 200, "msg": "查询成功" } } ``` ### 2. 批量录入操行分 #### 接口信息 - **请求方式**: POST - **接口路径**: `/api/conduct-score/batch` - **权限字符**: `conduct:score:batchAdd` - **接口描述**: 批量保存操行分记录 #### 请求参数 ```json { "academicYear": 2024, "semester": 1, "month": 9, "classId": 876543210987654321, "scores": [ { "studentId": 987654321098765432, "score": 95.50, "remark": "表现优秀,积极参加班级活动" }, { "studentId": 987654321098765433, "score": 88.00, "remark": "表现良好,需要继续努力" } ] } ``` #### 参数说明 | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------- | ---- | ---------------------- | | academicYear| Integer | 是 | 学年(如:2024) | | semester | Integer | 是 | 学期(1-第一学期,2-第二学期) | | month | Integer | 是 | 月份(1-12) | | classId | Long | 是 | 班级ID | | scores | Array | 是 | 操行分记录数组 | | └─studentId | Long | 是 | 学生ID | | └─score | BigDecimal | 是 | 操行分数(0.00-100.00) | | └─remark | String | 否 | 备注信息 | #### 响应格式 ```json { "code": 200, "msg": "批量录入成功", "data": { "successCount": 45, "failCount": 0, "failList": [] } } ``` ### 3. 班主任班级学生列表 #### 接口信息 - **请求方式**: GET - **接口路径**: `/api/conduct-score/class-students` - **权限字符**: `conduct:score:classStudents` - **接口描述**: 获取班主任负责的所有班级及学生列表,用于多Tab页展示 #### 请求参数 | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------- | ---- | ---------------------- | | academicYear| Integer | 否 | 学年(如:2024) | | semester | Integer | 否 | 学期(1-第一学期,2-第二学期) | | month | Integer | 否 | 月份(1-12) | #### 响应格式 ```json { "code": 200, "msg": "查询成功", "data": { "classes": [ { "classId": 876543210987654321, "className": "计算机1班", "classCode": "JSJ202401", "studentCount": 45, "enrollmentYear": 2024, "majorName": "计算机应用技术", "students": [ { "studentId": 987654321098765432, "studentNo": "2024001", "studentName": "张三", "gender": "0", "existingScore": null, "lastScore": 95.50, "lastMonth": 8 }, { "studentId": 987654321098765433, "studentNo": "2024002", "studentName": "李四", "gender": "1", "existingScore": { "id": 1234567890123456789, "score": 88.00, "remark": "表现良好", "createTime": "2024-09-01 09:00:00" }, "lastScore": 90.00, "lastMonth": 8 } ] }, { "classId": 876543210987654322, "className": "计算机2班", "classCode": "JSJ202402", "studentCount": 42, "enrollmentYear": 2024, "majorName": "计算机应用技术", "students": [ { "studentId": 987654321098765434, "studentNo": "2024046", "studentName": "王五", "gender": "0", "existingScore": { "id": 1234567890123456790, "score": 92.00, "remark": "学习认真", "createTime": "2024-09-01 09:15:00" }, "lastScore": 90.00, "lastMonth": 8 } ] }, { "classId": 876543210987654323, "className": "电子1班", "classCode": "DZ202401", "studentCount": 38, "enrollmentYear": 2024, "majorName": "电子信息工程", "students": [ { "studentId": 987654321098765435, "studentNo": "2024088", "studentName": "赵六", "gender": "0", "existingScore": null, "lastScore": 87.50, "lastMonth": 8 } ] } ], "summary": { "totalClasses": 3, "totalStudents": 125, "recordedStudents": 87, "pendingStudents": 38, "completionRate": 69.6 } } } ``` ### 4. 学期平均分统计 #### 接口信息 - **请求方式**: GET - **接口路径**: `/api/statistics/semester-average` - **权限字符**: `conduct:statistics:semester` - **接口描述**: 查询学生的学期操行平均分 #### 请求参数 | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------- | ---- | ---------------------- | | academicYear| Integer | 是 | 学年(如:2024) | | semester | Integer | 是 | 学期(1-第一学期,2-第二学期) | | className | String | 否 | 班级名称筛选 | | studentName | String | 否 | 学生姓名筛选 | | pageNum | Integer | 否 | 当前页码(默认1) | | pageSize | Integer | 否 | 每页显示数量(默认10) | #### 响应格式 ```json { "code": 200, "msg": "查询成功", "data": { "total": 500, "rows": [ { "studentId": 987654321098765432, "studentNo": "2024001", "studentName": "张三", "gender": "0", "classId": 876543210987654321, "className": "计算机应用1班", "academicYear": 2024, "semester": 1, "avgScore": 92.83, "recordCount": 6, "maxScore": 98.00, "minScore": 88.00, "scoreRange": "88.00-98.00", "lastUpdateTime": "2024-09-30 16:00:00" } ], "summary": { "totalStudents": 500, "avgScore": 85.67, "excellentCount": 120, "goodCount": 280, "averageCount": 85, "needImprovementCount": 15 }, "code": 200, "msg": "查询成功" } } ``` ### 5. 导出学期统计 #### 接口信息 - **请求方式**: GET - **接口路径**: `/api/statistics/export` - **权限字符**: `conduct:statistics:export` - **接口描述**: 导出学期操行分统计数据 #### 请求参数 | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------- | ---- | ---------------------- | | academicYear| Integer | 是 | 学年(如:2024) | | semester | Integer | 是 | 学期(1-第一学期,2-第二学期) | | className | String | 否 | 班级名称筛选 | | exportType | String | 否 | 导出类型(excel/pdf,默认excel) | #### 响应格式 返回 Excel 或 PDF 文件流 --- ## 🔒 权限控制设计 ### 权限字符定义 ```java // 操行分管理权限 conduct:score:list // 查看操行分列表 conduct:score:query // 查看操行分详情 conduct:score:add // 新增操行分 conduct:score:edit // 编辑操行分 conduct:score:remove // 删除操行分 conduct:score:batchAdd // 批量录入操行分 conduct:score:classStudents // 查看班主任班级学生 // 统计分析权限 conduct:statistics:semester // 学期统计查看 conduct:statistics:export // 数据导出 ``` ### 权限控制逻辑 #### 班主任权限控制 ```java @SaCheckPermission("conduct:score:classStudents") @GetMapping("/class-students") public AjaxResult getClassStudents(@RequestParam Integer academicYear, @RequestParam Integer semester, @RequestParam Integer month) { // 获取当前登录用户ID Long userId = SecurityUtils.getUserId(); // 从 xg_class_msg 表查询该用户作为班主任的所有班级 // WHERE class_teacher_id = #{userId} AND deleted = 0 List classIds = conductScoreService.getTeacherClassIds(userId); // 返回按班级分组的学生信息,用于前端生成Tab页 return AjaxResult.success(conductScoreService.getClassStudentsGrouped(classIds, academicYear, semester, month)); } ``` #### 管理员权限控制 ```java @SaCheckPermission("conduct:statistics:semester") @GetMapping("/semester-average") public TableDataInfo getSemesterAverage(@RequestParam Integer academicYear, @RequestParam Integer semester, ConductScoreQueryBo queryBo) { // 管理员可以查看全校数据,无班级限制 startPage(); List list = statisticsService.getSemesterAverage(academicYear, semester, queryBo); return getDataTable(list); } ``` --- ## 📊 数据验证规则 ### 请求参数验证 ```java public class ConductScoreBatchBo { @NotNull(message = "学年不能为空") @Min(value = 2020, message = "学年不能小于2020") @Max(value = 2030, message = "学年不能大于2030") private Integer academicYear; @NotNull(message = "学期不能为空") @Min(value = 1, message = "学期只能是1或2") @Max(value = 2, message = "学期只能是1或2") private Integer semester; @NotNull(message = "月份不能为空") @Min(value = 1, message = "月份范围为1-12") @Max(value = 12, message = "月份范围为1-12") private Integer month; @NotNull(message = "班级ID不能为空") private Long classId; @NotEmpty(message = "操行分记录不能为空") @Size(min = 1, max = 100, message = "一次最多录入100条记录") private List scores; } public class ConductScoreItemBo { @NotNull(message = "学生ID不能为空") private Long studentId; @NotNull(message = "分数不能为空") @DecimalMin(value = "0.00", message = "分数不能小于0") @DecimalMax(value = "100.00", message = "分数不能大于100") private BigDecimal score; @Size(max = 500, message = "备注不能超过500字符") private String remark; } ``` ### 业务逻辑验证 #### 班主任权限验证 ```java private void validateTeacherPermission(Long classId, Long teacherId) { // 验证班主任是否负责该班级 boolean isResponsible = conductScoreService.checkTeacherClass(teacherId, classId); if (!isResponsible) { throw new ServiceException("您不是该班级的班主任,无权录入操行分"); } } ``` #### 重复录入验证 ```java private void validateNoDuplicate(Long studentId, Integer academicYear, Integer semester, Integer month) { // 检查是否已存在该学生的当月记录 boolean exists = conductScoreService.existsByStudentAndMonth( studentId, academicYear, semester, month); if (exists) { throw new ServiceException("该学生当月操行分已录入,不可重复录入"); } } ``` --- ## 🔄 错误码设计 ### 系统级错误码 | 错误码 | 说明 | | ------ | ------------ | | 200 | 成功 | | 400 | 请求参数错误 | | 401 | 未授权 | | 403 | 权限不足 | | 500 | 系统错误 | ### 业务级错误码 | 错误码 | 说明 | | ------ | ------------------------ | | 1001 | 班主任权限不足 | | 1002 | 学生不存在 | | 1003 | 班级不存在 | | 1004 | 操行分已存在,不可重复录入 | | 1005 | 分数范围错误 | | 1006 | 时间参数错误 | ### 错误响应格式 ```json { "code": 1001, "msg": "您不是该班级的班主任,无权录入操行分", "data": null } ``` --- ## 📈 性能优化 ### 接口性能指标 - **响应时间**: 平均 < 200ms,95% < 500ms - **并发处理**: 支持 100+ 并发请求 - **数据量**: 支持万人规模数据查询 ### 缓存策略 #### Redis 缓存配置 ```java // 学期统计缓存 @Cacheable(value = "conductScoreStats", key = "#academicYear + '_' + #semester") public List getSemesterAverage(Integer academicYear, Integer semester) { // 查询逻辑 } // 班主任班级缓存 @Cacheable(value = "teacherClasses", key = "#teacherId") public List getTeacherClassIds(Long teacherId) { // 查询逻辑 } ``` ### 分页查询优化 ```java // 大数据量分页查询 PageHelper.startPage(pageNum, pageSize); List list = conductScoreMapper.selectConductScoreList(queryBo); // 自动添加 LIMIT 和 OFFSET ``` --- ## 🧪 接口测试 ### 测试用例设计 #### 正常流程测试 ```bash # 批量录入操行分 curl -X POST "http://localhost:8080/api/conduct-score/batch" \ -H "Authorization: Bearer {token}" \ -H "Content-Type: application/json" \ -d '{ "academicYear": 2024, "semester": 1, "month": 9, "classId": 876543210987654321, "scores": [ {"studentId": 987654321098765432, "score": 95.5, "remark": "优秀"} ] }' ``` #### 异常流程测试 ```bash # 权限不足测试 curl -X GET "http://localhost:8080/api/conduct-score/class-students" \ -H "Authorization: Bearer {invalid_token}" # 响应: {"code": 403, "msg": "权限不足", "data": null} ``` #### 性能测试 ```bash # 并发测试脚本 ab -n 1000 -c 50 "http://localhost:8080/api/statistics/semester-average?academicYear=2024&semester=1" ``` --- ## 📚 接口文档 ### Swagger 文档 ```java @Api(tags = "操行分管理") @RestController @RequestMapping("/api/conduct-score") public class ConductScoreController { @ApiOperation("批量录入操行分") @ApiImplicitParams({ @ApiImplicitParam(name = "academicYear", value = "学年", required = true), @ApiImplicitParam(name = "semester", value = "学期", required = true), @ApiImplicitParam(name = "month", value = "月份", required = true) }) @PostMapping("/batch") public AjaxResult batchAddConductScore(@RequestBody ConductScoreBatchBo bo) { // 接口实现 } } ``` ### 接口变更记录 | 版本 | 变更时间 | 变更内容 | 变更人 | | ---- | -------- | -------- | ------ | | v1.0 | 2025-01-13 | 初始版本 | 开发团队 | --- ## 📞 技术支持 如有疑问或需要技术支持,请联系: - **接口负责人**: 后端开发负责人 - **测试负责人**: 测试团队 - **业务负责人**: 学生处管理员 --- **最后更新**: 2025-01-13 **接口版本**: v1.0 **兼容性**: 向后兼容