diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/controller/AssessmentApprovalController.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/controller/AssessmentApprovalController.java index c0212d60..47fca4ab 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/controller/AssessmentApprovalController.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/controller/AssessmentApprovalController.java @@ -14,6 +14,7 @@ import org.dromara.common.core.domain.R; import org.dromara.common.log.enums.BusinessType; import org.dromara.bzrkh.domain.vo.AssessmentApprovalVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalDetailVo; +import org.dromara.bzrkh.domain.vo.EvaluationLevelStatsVo; import org.dromara.bzrkh.domain.vo.SchemeOptionVo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalQueryBo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalSubmitBo; @@ -87,13 +88,24 @@ public class AssessmentApprovalController extends BaseController { /** * 批量审核拒绝 */ - @SaCheckPermission("bzrkh:assessmentApproval:approve") + @SaCheckPermission("bzrkh:assessmentApproval:reject") @Log(title = "班主任考核审核", businessType = BusinessType.UPDATE) @PostMapping("/batchReject") - public R batchReject(@RequestBody BatchRejectBo bo) { - Long approverUserId = LoginHelper.getUserId(); - boolean result = assessmentApprovalService.batchReject(bo.getIds(), bo.getRejectReason(), approverUserId); - return toAjax(result); + public R batchReject(@Validated @RequestBody BatchApprovalBo bo) { + boolean result = assessmentApprovalService.batchReject(bo.getIds(), bo.getRejectReason(), LoginHelper.getUserId()); + return result ? R.ok() : R.fail("批量审核拒绝失败"); + } + + /** + * 删除异常的审批记录(管理员专用) + * 用于清理审批列表中显示但实际已被删除的异常数据 + */ + @SaCheckPermission("bzrkh:assessmentApproval:delete") + @Log(title = "班主任考核审核", businessType = BusinessType.DELETE) + @DeleteMapping("/deleteAbnormalRecord") + public R deleteAbnormalRecord(@RequestParam Long planId, @RequestParam Long evaluatedUserId) { + boolean result = assessmentApprovalService.deleteAbnormalRecord(planId, evaluatedUserId); + return result ? R.ok() : R.fail("删除异常记录失败"); } /** @@ -117,6 +129,16 @@ public class AssessmentApprovalController extends BaseController { ExcelUtil.exportExcel(list, "班主任考核审核数据", AssessmentApprovalVo.class, response); } + /** + * 获取评价等级统计数据 + */ + @SaCheckPermission("bzrkh:assessmentApproval:query") + @GetMapping("/evaluationStats") + public R getEvaluationLevelStats(@RequestParam @NotNull(message = "计划ID不能为空") Long planId) { + EvaluationLevelStatsVo stats = assessmentApprovalService.getEvaluationLevelStats(planId); + return R.ok(stats); + } + /** * 批量拒绝请求对象 */ diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/controller/TeacherAssessmentController.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/controller/TeacherAssessmentController.java index 7dd7ebbb..253d0f22 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/controller/TeacherAssessmentController.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/controller/TeacherAssessmentController.java @@ -4,6 +4,7 @@ import java.math.BigDecimal; import java.util.List; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; import org.springframework.web.bind.annotation.*; @@ -16,6 +17,7 @@ import org.dromara.common.log.enums.BusinessType; import org.dromara.bzrkh.domain.vo.TeacherClassVo; import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo; import org.dromara.bzrkh.domain.vo.AssessmentDetailVo; +import org.dromara.bzrkh.domain.vo.ClassStudentRecordsVo; import org.dromara.bzrkh.domain.bo.TeacherAssessmentQueryBo; import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo; import org.dromara.bzrkh.service.ITeacherAssessmentService; @@ -28,6 +30,7 @@ import org.dromara.common.satoken.utils.LoginHelper; * @author ruoyi * @date 2025-01-27 */ +@Slf4j @Validated @RequiredArgsConstructor @RestController @@ -68,9 +71,18 @@ public class TeacherAssessmentController extends BaseController { @Log(title = "班主任考核管理", businessType = BusinessType.UPDATE) @PostMapping("/submit") public R submitAssessment(@RequestBody TeacherAssessmentSubmitRequest request) { - Long teacherId = LoginHelper.getUserId(); - boolean result = teacherAssessmentService.submitAssessment(request.getPlanId(), request.getClassId(), teacherId); - return toAjax(result); + try { + Long teacherId = LoginHelper.getUserId(); + boolean result = teacherAssessmentService.submitAssessment(request.getPlanId(), request.getClassId(), teacherId); + return toAjax(result); + } catch (RuntimeException e) { + // 返回具体的错误信息 + return R.fail(e.getMessage()); + } catch (Exception e) { + // 记录详细的异常信息 + log.error("提交考核异常", e); + return R.fail("系统异常,请联系管理员"); + } } /** @@ -114,9 +126,18 @@ public class TeacherAssessmentController extends BaseController { @Log(title = "班主任考核管理", businessType = BusinessType.INSERT) @PostMapping("/submitScore") public R submitAssessmentScore(@RequestBody AssessmentSubmitBo bo) { - Long teacherId = LoginHelper.getUserId(); - boolean result = teacherAssessmentService.submitAssessmentScore(bo, teacherId); - return toAjax(result); + try { + Long teacherId = LoginHelper.getUserId(); + boolean result = teacherAssessmentService.submitAssessmentScore(bo, teacherId); + return toAjax(result); + } catch (RuntimeException e) { + // 返回具体的错误信息 + return R.fail(e.getMessage()); + } catch (Exception e) { + // 记录详细的异常信息 + log.error("提交考核评分数据异常", e); + return R.fail("系统异常,请联系管理员"); + } } /** @@ -129,6 +150,16 @@ public class TeacherAssessmentController extends BaseController { return R.ok("学生人数: " + studentCount + ", 计算系数: " + coefficient); } + /** + * 查询班级学生违纪记录和奖励记录 + */ + @SaCheckPermission("bzrkh:teacherAssessment:detail") + @GetMapping("/classStudentRecords") + public R getClassStudentRecords(@RequestParam Long classId) { + ClassStudentRecordsVo records = teacherAssessmentService.queryClassStudentRecords(classId); + return R.ok(records); + } + /** * 提交考核请求对象 */ diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/BmzrAssessmentScore.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/BmzrAssessmentScore.java index 69946dee..4bf8110e 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/BmzrAssessmentScore.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/BmzrAssessmentScore.java @@ -6,7 +6,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; import java.util.Date; import com.fasterxml.jackson.annotation.JsonFormat; -import java.math.BigDecimal; import java.io.Serial; @@ -63,7 +62,7 @@ public class BmzrAssessmentScore extends TenantEntity { /** * 自评分数 */ - private BigDecimal selfScore; + private Double selfScore; /** * 自评意见 @@ -79,7 +78,7 @@ public class BmzrAssessmentScore extends TenantEntity { /** * 上级评分数 */ - private BigDecimal superiorScore; + private Double superiorScore; /** * 上级评意见 @@ -103,14 +102,14 @@ public class BmzrAssessmentScore extends TenantEntity { private String evaluationLevel; /** - * 审核状态(0=待审核 1=审核通过 2=审核不通过) + * 审核状态(9=草稿 0=待审核 1=审核通过 2=审核不通过) */ private String auditStatus; /** * 最终得分 */ - private BigDecimal finalScore; + private Double finalScore; /** * 提交时间 @@ -133,4 +132,10 @@ public class BmzrAssessmentScore extends TenantEntity { */ private String superiorOverallComment; + /** + * 逻辑删除标志(0代表存在 1代表删除) + */ + @TableLogic + private Integer deleted; + } \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/bo/AssessmentSubmitBo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/bo/AssessmentSubmitBo.java index bfefe10d..49725d6f 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/bo/AssessmentSubmitBo.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/bo/AssessmentSubmitBo.java @@ -9,7 +9,6 @@ import org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo; import org.dromara.bzrkh.domain.vo.SpecialWorkIndicatorVo; import jakarta.validation.constraints.NotNull; -import java.math.BigDecimal; import java.util.List; /** @@ -42,7 +41,7 @@ public class AssessmentSubmitBo extends BaseEntity { /** * 班级扣分 */ - private BigDecimal classDeduction; + private Double classDeduction; /** * 班级扣分意见 diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/bo/BatchApprovalBo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/bo/BatchApprovalBo.java index 56a450ff..0444104a 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/bo/BatchApprovalBo.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/bo/BatchApprovalBo.java @@ -2,6 +2,7 @@ package org.dromara.bzrkh.domain.bo; import lombok.Data; import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotBlank; import java.util.List; @@ -19,4 +20,9 @@ public class BatchApprovalBo { */ @NotEmpty(message = "审核ID列表不能为空") private List ids; + + /** + * 拒绝原因(批量拒绝时必填) + */ + private String rejectReason; } \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentApprovalSpecialWorkVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentApprovalSpecialWorkVo.java index 5fd3dfac..17976551 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentApprovalSpecialWorkVo.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentApprovalSpecialWorkVo.java @@ -35,10 +35,15 @@ public class AssessmentApprovalSpecialWorkVo implements Serializable { // 自评相关 /** - * 自评分数 + * 自评分数(兼容字段) */ private BigDecimal score; + /** + * 自评分数 + */ + private BigDecimal selfScore; + /** * 自评意见 */ diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentIndicatorScoreVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentIndicatorScoreVo.java index f3604c19..96790aa0 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentIndicatorScoreVo.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentIndicatorScoreVo.java @@ -5,7 +5,6 @@ import com.fasterxml.jackson.annotation.JsonFormat; import java.io.Serial; import java.io.Serializable; -import java.math.BigDecimal; import java.util.Date; /** @@ -43,12 +42,12 @@ public class AssessmentIndicatorScoreVo implements Serializable { /** * 指标分值 */ - private BigDecimal score; + private Double score; /** * 自评分数 */ - private BigDecimal selfScore; + private Double selfScore; /** * 自评意见 diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentScoreDetailVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentScoreDetailVo.java new file mode 100644 index 00000000..b29d6c23 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentScoreDetailVo.java @@ -0,0 +1,80 @@ +package org.dromara.bzrkh.domain.vo; + +import lombok.Data; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 班主任考核自评数据详情视图对象 + * + * 包含从bmzr_assessment_score表查询的完整自评数据 + * + * @author ruoyi + * @date 2025-01-28 + */ +@Data +public class AssessmentScoreDetailVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 考核计划ID + */ + private Long planId; + + /** + * 班级ID + */ + private Long classId; + + /** + * 被评价用户ID + */ + private Long evaluatedUserId; + + /** + * 被评价用户姓名 + */ + private String evaluatedUserName; + + /** + * 班主任常规工作自评数据列表 + */ + private List routineWorkScores; + + /** + * 班级管理实效自评数据 + */ + private AssessmentScoreIndicatorVo classDeductionScore; + + /** + * 特色工作自评数据列表 + */ + private List specialWorkScores; + + /** + * 自我总体评价 + */ + private String selfOverallComment; + + /** + * 自评提交时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date selfSubmitTime; + + /** + * 审核状态 + */ + private String auditStatus; + + /** + * 是否有自评数据 + */ + private Boolean hasAssessmentData; +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentScoreIndicatorVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentScoreIndicatorVo.java new file mode 100644 index 00000000..45044d61 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentScoreIndicatorVo.java @@ -0,0 +1,77 @@ +package org.dromara.bzrkh.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 班主任考核自评指标视图对象 + * + * 用于班主任常规工作和班级管理实效的自评数据 + * + * @author ruoyi + * @date 2025-01-28 + */ +@Data +public class AssessmentScoreIndicatorVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 评分记录ID + */ + private Long id; + + /** + * 指标ID + */ + private Long indicatorId; + + /** + * 指标名称 + */ + private String indicatorName; + + /** + * 指标编码 + */ + private String indicatorCode; + + /** + * 指标描述 + */ + private String description; + + /** + * 指标分值 + */ + private BigDecimal score; + + /** + * 最高分值 + */ + private BigDecimal maxScore; + + /** + * 自评分数 + */ + private Double selfScore; + + /** + * 自评意见 + */ + private String selfComment; + + /** + * 上级评分 + */ + private Double superiorScore; + + /** + * 上级评意见 + */ + private String superiorComment; +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentScoreSpecialWorkVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentScoreSpecialWorkVo.java new file mode 100644 index 00000000..36a33da7 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentScoreSpecialWorkVo.java @@ -0,0 +1,66 @@ +package org.dromara.bzrkh.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 班主任考核特色工作自评视图对象 + * + * 用于特色工作的自评数据 + * + * @author ruoyi + * @date 2025-01-28 + */ +@Data +public class AssessmentScoreSpecialWorkVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 评分记录ID + */ + private Long id; + + /** + * 指标ID + */ + private Long indicatorId; + + /** + * 指标编码 + */ + private String indicatorCode; + + /** + * 指标名称 + */ + private String indicatorName; + + /** + * 自评分数 + */ + private Double score; + + /** + * 自评分数(兼容字段) + */ + private Double selfScore; + + /** + * 自评意见 + */ + private String selfComment; + + /** + * 上级评分 + */ + private Double superiorScore; + + /** + * 上级评意见 + */ + private String superiorComment; +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/ClassStudentRecordsVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/ClassStudentRecordsVo.java new file mode 100644 index 00000000..59d659b1 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/ClassStudentRecordsVo.java @@ -0,0 +1,51 @@ +package org.dromara.bzrkh.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 班级学生记录综合视图对象 + * + * @author ruoyi + * @date 2025-01-03 + */ +@Data +public class ClassStudentRecordsVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 班级ID + */ + private Long classId; + + /** + * 班级名称 + */ + private String className; + + /** + * 学生违纪记录列表 + */ + private List disciplineRecords; + + /** + * 学生奖励记录列表 + */ + private List rewardRecords; + + /** + * 违纪记录总数 + */ + private Integer disciplineCount; + + /** + * 奖励记录总数 + */ + private Integer rewardCount; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/EvaluationLevelStatsVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/EvaluationLevelStatsVo.java new file mode 100644 index 00000000..ee60df76 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/EvaluationLevelStatsVo.java @@ -0,0 +1,48 @@ +package org.dromara.bzrkh.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 评价等级统计数据视图对象 + * + * @author ruoyi + * @date 2025-01-30 + */ +@Data +public class EvaluationLevelStatsVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 总班主任数量 + */ + private Integer totalTeachers; + + /** + * 分数排名列表 + */ + private List scoreRankings; + + /** + * 评价等级规则 + */ + private EvaluationLevelRules evaluationLevelRules; + + @Data + public static class EvaluationLevelRules { + /** + * A等最大占比(如20%) + */ + private Double aLevelMaxPercentage; + + /** + * 及格分数(如60分) + */ + private Double passScore; + } +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/ScoreRankingVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/ScoreRankingVo.java new file mode 100644 index 00000000..37cd29b4 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/ScoreRankingVo.java @@ -0,0 +1,39 @@ +package org.dromara.bzrkh.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 分数排名视图对象 + * + * @author ruoyi + * @date 2025-01-30 + */ +@Data +public class ScoreRankingVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 考核得分 + */ + private Double score; + + /** + * 排名(从1开始) + */ + private Integer ranking; + + /** + * 百分比排名(前X%) + */ + private Double percentage; + + /** + * 被评价用户ID(可选,用于标识当前用户) + */ + private Long evaluatedUserId; +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/SpecialWorkIndicatorVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/SpecialWorkIndicatorVo.java index 92a3ec8e..07a6bff9 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/SpecialWorkIndicatorVo.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/SpecialWorkIndicatorVo.java @@ -5,7 +5,6 @@ import com.fasterxml.jackson.annotation.JsonFormat; import java.io.Serial; import java.io.Serializable; -import java.math.BigDecimal; import java.util.Date; /** @@ -33,7 +32,7 @@ public class SpecialWorkIndicatorVo implements Serializable { /** * 分值 */ - private BigDecimal score; + private Double score; /** * 自评意见 diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/StudentDisciplineRecordVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/StudentDisciplineRecordVo.java new file mode 100644 index 00000000..82ac5de1 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/StudentDisciplineRecordVo.java @@ -0,0 +1,157 @@ +package org.dromara.bzrkh.domain.vo; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 学生违纪记录视图对象 xskh_discipline_record + * + * @author ruoyi + * @date 2025-01-03 + */ +@Data +@ExcelIgnoreUnannotated +public class StudentDisciplineRecordVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private Long id; + + /** + * 学生ID + */ + @ExcelProperty(value = "学生ID") + private Long studentId; + + /** + * 学号 + */ + @ExcelProperty(value = "学号") + private String studentNo; + + /** + * 学生姓名 + */ + @ExcelProperty(value = "学生姓名") + private String studentName; + + /** + * 学院ID + */ + @ExcelProperty(value = "学院ID") + private Long collegeId; + + /** + * 学院名称 + */ + @ExcelProperty(value = "学院名称") + private String collegeName; + + /** + * 专业ID + */ + @ExcelProperty(value = "专业ID") + private Long majorId; + + /** + * 专业名称 + */ + @ExcelProperty(value = "专业名称") + private String majorName; + + /** + * 班级ID + */ + @ExcelProperty(value = "班级ID") + private Long classId; + + /** + * 班级名称 + */ + @ExcelProperty(value = "班级名称") + private String className; + + /** + * 违纪处分类型ID + */ + @ExcelProperty(value = "违纪处分类型ID") + private Long disciplineTypeId; + + /** + * 违纪处分类型名称 + */ + @ExcelProperty(value = "违纪处分类型名称") + private String disciplineTypeName; + + /** + * 违纪处分日期 + */ + @ExcelProperty(value = "违纪处分日期") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date disciplineDate; + + /** + * 违纪处分原因 + */ + @ExcelProperty(value = "违纪处分原因") + private String disciplineReason; + + /** + * 违纪处分内容 + */ + @ExcelProperty(value = "违纪处分内容") + private String disciplineContent; + + /** + * 扣分分值 + */ + @ExcelProperty(value = "扣分分值") + private BigDecimal scoreDeduction; + + /** + * 状态(1-生效 2-已撤销) + */ + @ExcelProperty(value = "状态") + private String status; + + /** + * 附件OSS文件ID,多个用逗号分隔 + */ + @ExcelProperty(value = "附件OSS文件ID") + private String attachmentOssIds; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** + * 更新者 + */ + private Long updateBy; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/StudentRewardRecordVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/StudentRewardRecordVo.java new file mode 100644 index 00000000..4d2ef465 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/StudentRewardRecordVo.java @@ -0,0 +1,151 @@ +package org.dromara.bzrkh.domain.vo; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 学生奖励记录视图对象 xskh_reward_record + * + * @author ruoyi + * @date 2025-01-03 + */ +@Data +@ExcelIgnoreUnannotated +public class StudentRewardRecordVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private Long id; + + /** + * 学生ID + */ + @ExcelProperty(value = "学生ID") + private Long studentId; + + /** + * 学号 + */ + @ExcelProperty(value = "学号") + private String studentNo; + + /** + * 学生姓名 + */ + @ExcelProperty(value = "学生姓名") + private String studentName; + + /** + * 学院ID + */ + @ExcelProperty(value = "学院ID") + private Long collegeId; + + /** + * 学院名称 + */ + @ExcelProperty(value = "学院名称") + private String collegeName; + + /** + * 专业ID + */ + @ExcelProperty(value = "专业ID") + private Long majorId; + + /** + * 专业名称 + */ + @ExcelProperty(value = "专业名称") + private String majorName; + + /** + * 班级ID + */ + @ExcelProperty(value = "班级ID") + private Long classId; + + /** + * 班级名称 + */ + @ExcelProperty(value = "班级名称") + private String className; + + /** + * 奖励类型ID + */ + @ExcelProperty(value = "奖励类型ID") + private Long rewardTypeId; + + /** + * 奖励类型名称 + */ + @ExcelProperty(value = "奖励类型名称") + private String rewardTypeName; + + /** + * 奖励日期 + */ + @ExcelProperty(value = "奖励日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date rewardDate; + + /** + * 奖励内容 + */ + @ExcelProperty(value = "奖励内容") + private String rewardContent; + + /** + * 加分分值 + */ + @ExcelProperty(value = "加分分值") + private BigDecimal scoreAddition; + + /** + * 附件OSS文件ID,多个用逗号分隔 + */ + @ExcelProperty(value = "附件OSS文件ID") + private String attachmentOssIds; + + /** + * 状态(1-生效 2-撤销) + */ + @ExcelProperty(value = "状态") + private String status; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** + * 更新者 + */ + private Long updateBy; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/AssessmentApprovalMapper.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/AssessmentApprovalMapper.java index 756edc94..28a04c5d 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/AssessmentApprovalMapper.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/AssessmentApprovalMapper.java @@ -5,6 +5,8 @@ import org.dromara.bzrkh.domain.vo.AssessmentApprovalDetailVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalIndicatorVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalSpecialWorkVo; import org.dromara.bzrkh.domain.vo.SchemeOptionVo; +import org.dromara.bzrkh.domain.vo.ClassDetailVo; +import org.dromara.bzrkh.domain.vo.CoefficientVo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalQueryBo; import org.dromara.bzrkh.domain.BmzrAssessmentScore; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; @@ -130,4 +132,22 @@ public interface AssessmentApprovalMapper extends BaseMapperPlus getSchemeOptions(); + + /** + * 删除异常的审批记录(管理员专用) + * 逻辑删除指定计划下指定用户的所有评分记录 + * + * @param planId 计划ID + * @param evaluatedUserId 被评价用户ID + * @return 删除记录数 + */ + int deleteAbnormalAssessmentRecord(@Param("planId") Long planId, @Param("evaluatedUserId") Long evaluatedUserId); + + /** + * 根据计划ID查询所有审批数据 + * + * @param planId 计划ID + * @return 审批数据列表 + */ + List selectApprovalListByPlan(@Param("planId") Long planId); } \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/AssessmentScoreMapper.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/AssessmentScoreMapper.java new file mode 100644 index 00000000..b52e6510 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/AssessmentScoreMapper.java @@ -0,0 +1,81 @@ +package org.dromara.bzrkh.mapper; + +import org.dromara.bzrkh.domain.vo.AssessmentScoreDetailVo; +import org.dromara.bzrkh.domain.vo.AssessmentScoreIndicatorVo; +import org.dromara.bzrkh.domain.vo.AssessmentScoreSpecialWorkVo; +import org.dromara.bzrkh.domain.BmzrAssessmentScore; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 班主任考核评分数据Mapper接口 + * + * 提供统一的自评数据查询,确保数据一致性 + * + * @author ruoyi + * @date 2025-01-28 + */ +public interface AssessmentScoreMapper extends BaseMapperPlus { + + /** + * 获取自评数据基本信息 + * + * @param planId 考核计划ID + * @param classId 班级ID + * @param evaluatedUserId 被评价用户ID + * @return 自评数据基本信息 + */ + AssessmentScoreDetailVo getAssessmentScoreBasicInfo(@Param("planId") Long planId, + @Param("classId") Long classId, + @Param("evaluatedUserId") Long evaluatedUserId); + + /** + * 获取班主任常规工作自评数据 + * + * @param planId 考核计划ID + * @param classId 班级ID + * @param evaluatedUserId 被评价用户ID + * @return 常规工作自评数据列表 + */ + List getRoutineWorkScores(@Param("planId") Long planId, + @Param("classId") Long classId, + @Param("evaluatedUserId") Long evaluatedUserId); + + /** + * 获取班级管理实效自评数据 + * + * @param planId 考核计划ID + * @param classId 班级ID + * @param evaluatedUserId 被评价用户ID + * @return 班级管理实效自评数据 + */ + AssessmentScoreIndicatorVo getClassDeductionScore(@Param("planId") Long planId, + @Param("classId") Long classId, + @Param("evaluatedUserId") Long evaluatedUserId); + + /** + * 获取特色工作自评数据 + * + * @param planId 考核计划ID + * @param classId 班级ID + * @param evaluatedUserId 被评价用户ID + * @return 特色工作自评数据列表 + */ + List getSpecialWorkScores(@Param("planId") Long planId, + @Param("classId") Long classId, + @Param("evaluatedUserId") Long evaluatedUserId); + + /** + * 检查是否存在自评数据 + * + * @param planId 考核计划ID + * @param classId 班级ID + * @param evaluatedUserId 被评价用户ID + * @return 记录数量 + */ + int countAssessmentScore(@Param("planId") Long planId, + @Param("classId") Long classId, + @Param("evaluatedUserId") Long evaluatedUserId); +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/BmzrAssessmentPlanMapper.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/BmzrAssessmentPlanMapper.java index 50be25e3..7a017d7d 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/BmzrAssessmentPlanMapper.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/BmzrAssessmentPlanMapper.java @@ -7,7 +7,9 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.common.mybatis.core.page.PageQuery; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; import java.util.List; +import java.util.Collection; /** * 班主任考核计划Mapper接口 @@ -27,4 +29,11 @@ public interface BmzrAssessmentPlanMapper extends BaseMapperPlus selectAssessmentPlanPageWithScheme(Page page, BmzrAssessmentPlanBo bo); + /** + * 根据考核计划ID批量逻辑删除关联的考核得分数据 + * @param planIds 考核计划ID集合 + * @return 影响行数 + */ + int deleteAssessmentScoresByPlanIds(@Param("planIds") Collection planIds); + } \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/TeacherAssessmentMapper.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/TeacherAssessmentMapper.java index 89735ac4..740c28d4 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/TeacherAssessmentMapper.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/TeacherAssessmentMapper.java @@ -5,6 +5,8 @@ import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo; import org.dromara.bzrkh.domain.vo.ClassDetailVo; import org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo; import org.dromara.bzrkh.domain.vo.SpecialWorkIndicatorVo; +import org.dromara.bzrkh.domain.vo.StudentDisciplineRecordVo; +import org.dromara.bzrkh.domain.vo.StudentRewardRecordVo; import org.dromara.bzrkh.domain.bo.TeacherAssessmentQueryBo; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.apache.ibatis.annotations.Param; @@ -67,13 +69,24 @@ public interface TeacherAssessmentMapper extends BaseMapperPlus List selectSpecialWorkIndicators(); /** - * 查询已保存的评分数据 + * 查询已保存的评分数据(草稿状态) * * @param planId 计划ID * @param teacherId 班主任ID + * @param classId 班级ID * @return 评分数据列表 */ - List selectSavedAssessmentScores(@Param("planId") Long planId, @Param("teacherId") Long teacherId); + List selectSavedAssessmentScores(@Param("planId") Long planId, @Param("teacherId") Long teacherId, @Param("classId") Long classId); + + /** + * 查询已提交的评分数据(待审核状态,用于撤销功能) + * + * @param planId 计划ID + * @param teacherId 班主任ID + * @param classId 班级ID + * @return 评分数据列表 + */ + List selectSubmittedAssessmentScores(@Param("planId") Long planId, @Param("teacherId") Long teacherId, @Param("classId") Long classId); /** * 根据计划ID查询方案ID @@ -92,12 +105,13 @@ public interface TeacherAssessmentMapper extends BaseMapperPlus Long selectIndicatorIdByCode(@Param("indicatorCode") String indicatorCode); /** - * 逻辑删除指定计划和教师的评分数据 + * 逻辑删除指定计划、班级和教师的评分数据 * * @param planId 计划ID * @param teacherId 教师ID + * @param classId 班级ID */ - void deleteAssessmentScoresByPlanAndTeacher(@Param("planId") Long planId, @Param("teacherId") Long teacherId); + void deleteAssessmentScoresByPlanAndTeacher(@Param("planId") Long planId, @Param("teacherId") Long teacherId, @Param("classId") Long classId); @@ -113,4 +127,28 @@ public interface TeacherAssessmentMapper extends BaseMapperPlus @Param("indicatorId") Long indicatorId, @Param("teacherId") Long teacherId, @Param("remark") String remark); + + /** + * 根据班级ID查询班级名称 + * + * @param classId 班级ID + * @return 班级名称 + */ + String selectClassNameById(@Param("classId") Long classId); + + /** + * 根据班级ID查询学生违纪记录 + * + * @param classId 班级ID + * @return 学生违纪记录列表 + */ + List selectStudentDisciplineRecordsByClassId(@Param("classId") Long classId); + + /** + * 根据班级ID查询学生奖励记录 + * + * @param classId 班级ID + * @return 学生奖励记录列表 + */ + List selectStudentRewardRecordsByClassId(@Param("classId") Long classId); } \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/IAssessmentApprovalService.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/IAssessmentApprovalService.java index e698b468..f6cdccf1 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/IAssessmentApprovalService.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/IAssessmentApprovalService.java @@ -2,6 +2,7 @@ package org.dromara.bzrkh.service; import org.dromara.bzrkh.domain.vo.AssessmentApprovalVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalDetailVo; +import org.dromara.bzrkh.domain.vo.EvaluationLevelStatsVo; import org.dromara.bzrkh.domain.vo.SchemeOptionVo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalQueryBo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalSubmitBo; @@ -73,10 +74,28 @@ public interface IAssessmentApprovalService { */ boolean batchReject(List ids, String rejectReason, Long approverUserId); + /** + * 删除异常的审批记录(管理员专用) + * 用于清理审批列表中显示但实际已被删除的异常数据 + * + * @param planId 计划ID + * @param evaluatedUserId 被评价用户ID + * @return 是否成功 + */ + boolean deleteAbnormalRecord(Long planId, Long evaluatedUserId); + /** * 获取考核方案下拉选项 * * @return 方案选项列表 */ List getSchemeOptions(); + + /** + * 获取评价等级统计数据 + * + * @param planId 计划ID + * @return 评价等级统计数据 + */ + EvaluationLevelStatsVo getEvaluationLevelStats(Long planId); } \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/IAssessmentScoreService.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/IAssessmentScoreService.java new file mode 100644 index 00000000..706b4298 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/IAssessmentScoreService.java @@ -0,0 +1,38 @@ +package org.dromara.bzrkh.service; + +import org.dromara.bzrkh.domain.vo.AssessmentScoreDetailVo; + +/** + * 班主任考核评分数据Service接口 + * + * 提供统一的自评数据查询服务,确保提交API和审批API使用相同的数据源 + * + * @author ruoyi + * @date 2025-01-28 + */ +public interface IAssessmentScoreService { + + /** + * 获取班主任考核的完整自评数据 + * + * 从bmzr_assessment_score表中查询指定计划、班级的所有自评数据, + * 包括常规工作、班级管理实效、特色工作的自评分数和自评意见, + * 以及自我总体评价 + * + * @param planId 考核计划ID + * @param classId 班级ID + * @param evaluatedUserId 被评价用户ID(班主任用户ID) + * @return 完整的自评数据详情 + */ + AssessmentScoreDetailVo getAssessmentScoreDetail(Long planId, Long classId, Long evaluatedUserId); + + /** + * 检查指定计划和班级是否已有自评数据 + * + * @param planId 考核计划ID + * @param classId 班级ID + * @param evaluatedUserId 被评价用户ID + * @return 是否存在自评数据 + */ + boolean hasAssessmentScore(Long planId, Long classId, Long evaluatedUserId); +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/ITeacherAssessmentService.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/ITeacherAssessmentService.java index ad505a43..251a7f76 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/ITeacherAssessmentService.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/ITeacherAssessmentService.java @@ -3,6 +3,7 @@ package org.dromara.bzrkh.service; import org.dromara.bzrkh.domain.vo.TeacherClassVo; import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo; import org.dromara.bzrkh.domain.vo.AssessmentDetailVo; +import org.dromara.bzrkh.domain.vo.ClassStudentRecordsVo; import org.dromara.bzrkh.domain.bo.TeacherAssessmentQueryBo; import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo; import org.dromara.common.mybatis.core.page.TableDataInfo; @@ -93,4 +94,12 @@ public interface ITeacherAssessmentService { * @return 计算出的系数 */ BigDecimal testStudentCountCoefficient(int studentCount); + + /** + * 查询班级学生违纪记录和奖励记录 + * + * @param classId 班级ID + * @return 班级学生记录 + */ + ClassStudentRecordsVo queryClassStudentRecords(Long classId); } \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/AssessmentApprovalServiceImpl.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/AssessmentApprovalServiceImpl.java index 1be403e8..2d485fcf 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/AssessmentApprovalServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/AssessmentApprovalServiceImpl.java @@ -10,10 +10,16 @@ import org.dromara.common.core.utils.MapstructUtils; import org.dromara.bzrkh.domain.vo.AssessmentApprovalVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalDetailVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalIndicatorVo; +import org.dromara.bzrkh.domain.vo.AssessmentDetailVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalSpecialWorkVo; +import org.dromara.bzrkh.domain.vo.EvaluationLevelStatsVo; +import org.dromara.bzrkh.domain.vo.ScoreRankingVo; import org.dromara.bzrkh.domain.vo.SchemeOptionVo; import org.dromara.bzrkh.domain.vo.ClassDetailVo; import org.dromara.bzrkh.domain.vo.CoefficientVo; +import org.dromara.bzrkh.domain.vo.AssessmentScoreDetailVo; +import org.dromara.bzrkh.domain.vo.AssessmentScoreIndicatorVo; +import org.dromara.bzrkh.domain.vo.AssessmentScoreSpecialWorkVo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalQueryBo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalSubmitBo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalIndicatorSubmitBo; @@ -21,9 +27,16 @@ import org.dromara.bzrkh.domain.bo.AssessmentApprovalSpecialWorkSubmitBo; import org.dromara.bzrkh.mapper.AssessmentApprovalMapper; import org.dromara.bzrkh.service.IAssessmentApprovalService; import org.dromara.bzrkh.service.ITeacherAssessmentService; +import org.dromara.bzrkh.service.IAssessmentScoreService; +import lombok.extern.slf4j.Slf4j; import java.util.List; import java.util.Date; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.math.BigDecimal; +import java.math.RoundingMode; /** * 班主任考核审核Service业务层处理 @@ -31,12 +44,14 @@ import java.util.Date; * @author ruoyi * @date 2025-01-28 */ +@Slf4j @RequiredArgsConstructor @Service public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService { private final AssessmentApprovalMapper assessmentApprovalMapper; private final ITeacherAssessmentService teacherAssessmentService; + private final IAssessmentScoreService assessmentScoreService; @Override public TableDataInfo queryPageList(AssessmentApprovalQueryBo bo, PageQuery pageQuery) { @@ -63,6 +78,8 @@ public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService @Override public AssessmentApprovalDetailVo getApprovalDetail(Long planId, Long classId, Long evaluatedUserId) { + log.info("获取审批详情 - planId: {}, classId: {}, evaluatedUserId: {}", planId, classId, evaluatedUserId); + // 1. 获取基本信息 AssessmentApprovalDetailVo detail = assessmentApprovalMapper.getApprovalBasicInfo(planId, classId, evaluatedUserId); if (detail == null) { @@ -91,29 +108,170 @@ public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService coefficient.setBoardingCoefficient(assessmentDetail.getCoefficient().getBoardingCoefficient()); detail.setCoefficient(coefficient); } catch (Exception e) { + log.warn("获取班级信息和系数信息失败: {}", e.getMessage()); // 如果获取失败,使用默认值 detail.setClassDetail(new ClassDetailVo()); detail.setCoefficient(new CoefficientVo()); } - // 3. 获取班主任常规工作指标列表 - List routineWorkIndicators = - assessmentApprovalMapper.getRoutineWorkIndicators(planId, classId, evaluatedUserId); - detail.setRoutineWorkIndicators(routineWorkIndicators); + // 3. 使用统一的自评数据服务获取完整的自评数据 + AssessmentScoreDetailVo scoreDetail = assessmentScoreService.getAssessmentScoreDetail(planId, classId, evaluatedUserId); + + if (scoreDetail != null && scoreDetail.getHasAssessmentData()) { + log.info("通过统一服务获取到自评数据 - 自我总体评价: {}", scoreDetail.getSelfOverallComment()); + + // 3.1 设置自我总体评价 + detail.setSelfOverallComment(scoreDetail.getSelfOverallComment()); - // 4. 获取班级扣分指标(班级管理实效) - AssessmentApprovalIndicatorVo classDeductionIndicator = - assessmentApprovalMapper.getClassDeductionIndicator(planId, classId, evaluatedUserId); - detail.setClassDeductionIndicator(classDeductionIndicator); + // 3.2 转换班主任常规工作自评数据 + List routineWorkIndicators = convertRoutineWorkScores(scoreDetail.getRoutineWorkScores()); + detail.setRoutineWorkIndicators(routineWorkIndicators); + log.info("转换常规工作自评数据 - 数量: {}", routineWorkIndicators.size()); - // 5. 获取特色工作指标列表 - List specialWorkIndicators = - assessmentApprovalMapper.getSpecialWorkIndicators(planId, classId, evaluatedUserId); - detail.setSpecialWorkIndicators(specialWorkIndicators); + // 3.3 转换班级管理实效自评数据 + AssessmentApprovalIndicatorVo classDeductionIndicator = convertClassDeductionScore(scoreDetail.getClassDeductionScore()); + detail.setClassDeductionIndicator(classDeductionIndicator); + if (classDeductionIndicator != null) { + log.info("转换班级管理实效自评数据 - 自评分数: {}", classDeductionIndicator.getSelfScore()); + } + + // 3.4 转换特色工作自评数据 + List specialWorkIndicators = convertSpecialWorkScores(scoreDetail.getSpecialWorkScores()); + detail.setSpecialWorkIndicators(specialWorkIndicators); + log.info("转换特色工作自评数据 - 数量: {}", specialWorkIndicators.size()); + } else { + log.warn("未获取到自评数据,使用原有查询方式作为备用"); + + // 备用方案:使用原有的查询方式 + List routineWorkIndicators = + assessmentApprovalMapper.getRoutineWorkIndicators(planId, classId, evaluatedUserId); + detail.setRoutineWorkIndicators(routineWorkIndicators); + + AssessmentApprovalIndicatorVo classDeductionIndicator = + assessmentApprovalMapper.getClassDeductionIndicator(planId, classId, evaluatedUserId); + detail.setClassDeductionIndicator(classDeductionIndicator); + + List specialWorkIndicators = + assessmentApprovalMapper.getSpecialWorkIndicators(planId, classId, evaluatedUserId); + detail.setSpecialWorkIndicators(specialWorkIndicators); + } + + // 4. 验证自评数据完整性 + validateSelfAssessmentData(detail); return detail; } + /** + * 转换班主任常规工作自评数据 + */ + private List convertRoutineWorkScores(List routineWorkScores) { + if (routineWorkScores == null) { + return new ArrayList<>(); + } + + List result = new ArrayList<>(); + for (AssessmentScoreIndicatorVo score : routineWorkScores) { + AssessmentApprovalIndicatorVo indicator = new AssessmentApprovalIndicatorVo(); + indicator.setId(score.getId()); + indicator.setIndicatorId(score.getIndicatorId()); + indicator.setIndicatorName(score.getIndicatorName()); + indicator.setIndicatorCode(score.getIndicatorCode()); + indicator.setDescription(score.getDescription()); + indicator.setScore(score.getScore()); + indicator.setMaxScore(score.getMaxScore()); + // 类型转换:Double -> BigDecimal + indicator.setSelfScore(score.getSelfScore() != null ? BigDecimal.valueOf(score.getSelfScore()) : null); + indicator.setSelfComment(score.getSelfComment()); + indicator.setSuperiorScore(score.getSuperiorScore() != null ? BigDecimal.valueOf(score.getSuperiorScore()) : null); + indicator.setSuperiorComment(score.getSuperiorComment()); + result.add(indicator); + } + return result; + } + + /** + * 转换班级管理实效自评数据 + */ + private AssessmentApprovalIndicatorVo convertClassDeductionScore(AssessmentScoreIndicatorVo classDeductionScore) { + if (classDeductionScore == null) { + return null; + } + + AssessmentApprovalIndicatorVo indicator = new AssessmentApprovalIndicatorVo(); + indicator.setId(classDeductionScore.getId()); + indicator.setIndicatorId(classDeductionScore.getIndicatorId()); + indicator.setIndicatorName(classDeductionScore.getIndicatorName()); + indicator.setIndicatorCode(classDeductionScore.getIndicatorCode()); + indicator.setDescription(classDeductionScore.getDescription()); + indicator.setScore(classDeductionScore.getScore()); + indicator.setMaxScore(classDeductionScore.getMaxScore()); + // 类型转换:Double -> BigDecimal + indicator.setSelfScore(classDeductionScore.getSelfScore() != null ? BigDecimal.valueOf(classDeductionScore.getSelfScore()) : null); + indicator.setSelfComment(classDeductionScore.getSelfComment()); + indicator.setSuperiorScore(classDeductionScore.getSuperiorScore() != null ? BigDecimal.valueOf(classDeductionScore.getSuperiorScore()) : null); + indicator.setSuperiorComment(classDeductionScore.getSuperiorComment()); + return indicator; + } + + /** + * 转换特色工作自评数据 + */ + private List convertSpecialWorkScores(List specialWorkScores) { + if (specialWorkScores == null) { + return new ArrayList<>(); + } + + List result = new ArrayList<>(); + for (AssessmentScoreSpecialWorkVo score : specialWorkScores) { + AssessmentApprovalSpecialWorkVo specialWork = new AssessmentApprovalSpecialWorkVo(); + specialWork.setId(score.getId()); + specialWork.setIndicatorCode(score.getIndicatorCode()); + specialWork.setIndicatorName(score.getIndicatorName()); + // 类型转换:Double -> BigDecimal + specialWork.setScore(score.getScore() != null ? BigDecimal.valueOf(score.getScore()) : null); + specialWork.setSelfScore(score.getSelfScore() != null ? BigDecimal.valueOf(score.getSelfScore()) : null); + specialWork.setSelfComment(score.getSelfComment()); + specialWork.setSuperiorScore(score.getSuperiorScore() != null ? BigDecimal.valueOf(score.getSuperiorScore()) : null); + specialWork.setSuperiorComment(score.getSuperiorComment()); + result.add(specialWork); + } + return result; + } + + /** + * 验证自评数据完整性 + */ + private void validateSelfAssessmentData(AssessmentApprovalDetailVo detail) { + // 检查常规工作指标的自评数据 + if (detail.getRoutineWorkIndicators() != null) { + for (AssessmentApprovalIndicatorVo indicator : detail.getRoutineWorkIndicators()) { + if (indicator.getSelfScore() == null || indicator.getSelfComment() == null) { + log.warn("常规工作指标缺少自评数据 - ID: {}, 指标名称: {}", + indicator.getId(), indicator.getIndicatorName()); + } + } + } + + // 检查班级管理实效的自评数据 + if (detail.getClassDeductionIndicator() != null) { + AssessmentApprovalIndicatorVo indicator = detail.getClassDeductionIndicator(); + if (indicator.getSelfScore() == null || indicator.getSelfComment() == null) { + log.warn("班级管理实效缺少自评数据 - ID: {}", indicator.getId()); + } + } + + // 检查特色工作的自评数据 + if (detail.getSpecialWorkIndicators() != null) { + for (AssessmentApprovalSpecialWorkVo indicator : detail.getSpecialWorkIndicators()) { + if (indicator.getScore() == null || indicator.getSelfComment() == null) { + log.warn("特色工作指标缺少自评数据 - ID: {}, 指标名称: {}", + indicator.getId(), indicator.getIndicatorName()); + } + } + } + } + @Override @Transactional(rollbackFor = Exception.class) public boolean submitApproval(AssessmentApprovalSubmitBo bo, Long approverUserId) { @@ -210,4 +368,176 @@ public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService public List getSchemeOptions() { return assessmentApprovalMapper.getSchemeOptions(); } + + /** + * 删除异常的审批记录(管理员专用) + * 用于清理审批列表中显示但实际已被删除的异常数据 + * + * @param planId 计划ID + * @param evaluatedUserId 被评价用户ID + * @return 是否成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteAbnormalRecord(Long planId, Long evaluatedUserId) { + try { + // 参数验证 + if (planId == null || evaluatedUserId == null) { + throw new RuntimeException("计划ID和用户ID不能为空"); + } + + // 逻辑删除该计划下该用户的所有评分记录 + int result = assessmentApprovalMapper.deleteAbnormalAssessmentRecord(planId, evaluatedUserId); + + return result > 0; + } catch (Exception e) { + throw new RuntimeException("删除异常记录失败: " + e.getMessage(), e); + } + } + + @Override + public EvaluationLevelStatsVo getEvaluationLevelStats(Long planId) { + log.info("获取评价等级统计数据 - planId: {}", planId); + + try { + // 获取指定计划下所有班主任的考核得分 + List approvalList = assessmentApprovalMapper.selectApprovalListByPlan(planId); + log.info("查询到的审批数据数量: {}", approvalList.size()); + + if (approvalList.isEmpty()) { + log.warn("⚠️ 计划ID: {} 下没有找到任何已提交的班主任考核数据,将使用简化评级", planId); + } + + EvaluationLevelStatsVo statsVo = new EvaluationLevelStatsVo(); + statsVo.setTotalTeachers(approvalList.size()); + + if (approvalList.isEmpty()) { + statsVo.setScoreRankings(new ArrayList<>()); + statsVo.setEvaluationLevelRules(getDefaultEvaluationLevelRules()); + log.warn("返回空统计数据,前端将使用简化评级规则"); + return statsVo; + } + + // 计算每个班主任的得分并排序 + List scoreRankings = new ArrayList<>(); + for (AssessmentApprovalVo approval : approvalList) { + try { + // 获取详细信息用于计算得分 + AssessmentDetailVo detailVo = teacherAssessmentService.getAssessmentSubmitDetail( + approval.getPlanId(), approval.getClassId(), approval.getEvaluatedUserId()); + + // 计算月考核得分 + Double monthlyScore = calculateMonthlyScore(detailVo, approval); + + ScoreRankingVo ranking = new ScoreRankingVo(); + ranking.setScore(monthlyScore); + ranking.setEvaluatedUserId(approval.getEvaluatedUserId()); + + scoreRankings.add(ranking); + } catch (Exception e) { + log.warn("计算用户{}得分失败: {}", approval.getEvaluatedUserId(), e.getMessage()); + // 对于计算失败的用户,设置默认得分0 + ScoreRankingVo ranking = new ScoreRankingVo(); + ranking.setScore(0.0); + ranking.setEvaluatedUserId(approval.getEvaluatedUserId()); + scoreRankings.add(ranking); + } + } + + // 按得分降序排序 + Collections.sort(scoreRankings, Comparator.comparing(ScoreRankingVo::getScore, Comparator.reverseOrder())); + + // 计算排名和百分比 + for (int i = 0; i < scoreRankings.size(); i++) { + ScoreRankingVo ranking = scoreRankings.get(i); + ranking.setRanking(i + 1); + // 计算前百分之几(保留2位小数) + double percentage = ((double)(i + 1) / scoreRankings.size()) * 100; + ranking.setPercentage(BigDecimal.valueOf(percentage).setScale(2, RoundingMode.HALF_UP).doubleValue()); + } + + statsVo.setScoreRankings(scoreRankings); + statsVo.setEvaluationLevelRules(getDefaultEvaluationLevelRules()); + + log.info("统计数据计算完成 - 总人数: {}, 有效得分人数: {}", statsVo.getTotalTeachers(), scoreRankings.size()); + return statsVo; + + } catch (Exception e) { + log.error("获取评价等级统计数据失败", e); + throw new RuntimeException("获取评价等级统计数据失败: " + e.getMessage(), e); + } + } + + /** + * 计算月考核得分 + */ + private Double calculateMonthlyScore(AssessmentDetailVo detailVo, AssessmentApprovalVo approval) { + // 总系数(K) + BigDecimal totalCoefficient = detailVo.getCoefficient().getTotalCoefficient(); + + // 获取已审批的评分数据 + AssessmentScoreDetailVo scoreDetail = assessmentScoreService.getAssessmentScoreDetail( + approval.getPlanId(), approval.getClassId(), approval.getEvaluatedUserId()); + + if (scoreDetail == null) { + return 0.0; + } + + // 班主任常规工作上级评分之和(使用上级评分,如果没有则使用自评分) + double routineWorkTotal = 0.0; + if (scoreDetail.getRoutineWorkScores() != null) { + for (AssessmentScoreIndicatorVo score : scoreDetail.getRoutineWorkScores()) { + Double superiorScore = score.getSuperiorScore(); + if (superiorScore != null) { + routineWorkTotal += superiorScore; + } else if (score.getSelfScore() != null) { + routineWorkTotal += score.getSelfScore(); + } + } + } + + // 班级管理实效评分(班级扣分,使用上级评分,如果没有则使用自评分) + double classDeductionScore = 0.0; + if (scoreDetail.getClassDeductionScore() != null) { + Double superiorScore = scoreDetail.getClassDeductionScore().getSuperiorScore(); + if (superiorScore != null) { + classDeductionScore = superiorScore; + } else if (scoreDetail.getClassDeductionScore().getSelfScore() != null) { + classDeductionScore = scoreDetail.getClassDeductionScore().getSelfScore(); + } + } + + // 计算按班级扣分50%计的分值 + double deductionHalf = classDeductionScore * 0.5; + + // 特色工作上级评分之和(使用上级评分,如果没有则使用自评分) + double specialWorkTotal = 0.0; + if (scoreDetail.getSpecialWorkScores() != null) { + for (AssessmentScoreSpecialWorkVo score : scoreDetail.getSpecialWorkScores()) { + Double superiorScore = score.getSuperiorScore(); + if (superiorScore != null) { + specialWorkTotal += superiorScore; + } else if (score.getSelfScore() != null) { + specialWorkTotal += score.getSelfScore(); + } + } + } + + // 月考核得分 = 总系数(K)* (班主任常规工作评分 - 按班级扣分50%计的分值 + 特色工作评分) + // 注意:班级扣分是减法,因为它是扣分项 + BigDecimal monthlyScore = totalCoefficient.multiply( + BigDecimal.valueOf(routineWorkTotal - deductionHalf + specialWorkTotal)); + + return monthlyScore.setScale(2, RoundingMode.HALF_UP).doubleValue(); + } + + /** + * 获取默认评价等级规则 + */ + private EvaluationLevelStatsVo.EvaluationLevelRules getDefaultEvaluationLevelRules() { + EvaluationLevelStatsVo.EvaluationLevelRules rules = new EvaluationLevelStatsVo.EvaluationLevelRules(); + rules.setALevelMaxPercentage(20.0); // A等最大占比20% + rules.setPassScore(60.0); // 及格分数60分 + return rules; + } } \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/AssessmentScoreServiceImpl.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/AssessmentScoreServiceImpl.java new file mode 100644 index 00000000..780007b8 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/AssessmentScoreServiceImpl.java @@ -0,0 +1,100 @@ +package org.dromara.bzrkh.service.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.dromara.bzrkh.service.IAssessmentScoreService; +import org.dromara.bzrkh.mapper.AssessmentScoreMapper; +import org.dromara.bzrkh.domain.vo.AssessmentScoreDetailVo; +import org.dromara.bzrkh.domain.vo.AssessmentScoreIndicatorVo; +import org.dromara.bzrkh.domain.vo.AssessmentScoreSpecialWorkVo; + +import java.util.List; + +/** + * 班主任考核评分数据Service业务层处理 + * + * 提供统一的自评数据查询服务,确保提交API和审批API使用相同的数据源 + * + * @author ruoyi + * @date 2025-01-28 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class AssessmentScoreServiceImpl implements IAssessmentScoreService { + + private final AssessmentScoreMapper assessmentScoreMapper; + + @Override + public AssessmentScoreDetailVo getAssessmentScoreDetail(Long planId, Long classId, Long evaluatedUserId) { + log.info("获取自评数据详情 - planId: {}, classId: {}, evaluatedUserId: {}", planId, classId, evaluatedUserId); + + // 1. 获取自评数据基本信息 + AssessmentScoreDetailVo detail = assessmentScoreMapper.getAssessmentScoreBasicInfo(planId, classId, evaluatedUserId); + if (detail == null) { + log.warn("未找到自评数据 - planId: {}, classId: {}, evaluatedUserId: {}", planId, classId, evaluatedUserId); + // 返回空的详情对象,表示没有自评数据 + detail = new AssessmentScoreDetailVo(); + detail.setPlanId(planId); + detail.setClassId(classId); + detail.setEvaluatedUserId(evaluatedUserId); + detail.setHasAssessmentData(false); + return detail; + } + + log.info("找到自评数据基本信息 - 自我总体评价: {}, 提交时间: {}", + detail.getSelfOverallComment(), detail.getSelfSubmitTime()); + + // 2. 获取班主任常规工作自评数据 + List routineWorkScores = + assessmentScoreMapper.getRoutineWorkScores(planId, classId, evaluatedUserId); + detail.setRoutineWorkScores(routineWorkScores); + log.info("获取常规工作自评数据 - 数量: {}", routineWorkScores.size()); + for (AssessmentScoreIndicatorVo score : routineWorkScores) { + log.debug("常规工作自评 - 指标: {}, 自评分数: {}, 自评意见: {}", + score.getIndicatorName(), score.getSelfScore(), score.getSelfComment()); + } + + // 3. 获取班级管理实效自评数据 + AssessmentScoreIndicatorVo classDeductionScore = + assessmentScoreMapper.getClassDeductionScore(planId, classId, evaluatedUserId); + detail.setClassDeductionScore(classDeductionScore); + if (classDeductionScore != null) { + log.info("获取班级管理实效自评数据 - 自评分数: {}, 自评意见: {}", + classDeductionScore.getSelfScore(), classDeductionScore.getSelfComment()); + } else { + log.warn("未找到班级管理实效自评数据"); + } + + // 4. 获取特色工作自评数据 + List specialWorkScores = + assessmentScoreMapper.getSpecialWorkScores(planId, classId, evaluatedUserId); + detail.setSpecialWorkScores(specialWorkScores); + log.info("获取特色工作自评数据 - 数量: {}", specialWorkScores.size()); + for (AssessmentScoreSpecialWorkVo score : specialWorkScores) { + log.debug("特色工作自评 - 指标: {}, 自评分数: {}, 自评意见: {}", + score.getIndicatorName(), score.getScore(), score.getSelfComment()); + } + + // 5. 标记有自评数据 + detail.setHasAssessmentData(true); + + log.info("自评数据详情获取完成 - 总体评价: {}, 常规工作: {}项, 班级管理: {}, 特色工作: {}项", + detail.getSelfOverallComment(), + routineWorkScores.size(), + classDeductionScore != null ? "有" : "无", + specialWorkScores.size()); + + return detail; + } + + @Override + public boolean hasAssessmentScore(Long planId, Long classId, Long evaluatedUserId) { + int count = assessmentScoreMapper.countAssessmentScore(planId, classId, evaluatedUserId); + boolean hasData = count > 0; + log.info("检查自评数据存在性 - planId: {}, classId: {}, evaluatedUserId: {}, 结果: {}", + planId, classId, evaluatedUserId, hasData ? "存在" : "不存在"); + return hasData; + } +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/BmzrAssessmentPlanServiceImpl.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/BmzrAssessmentPlanServiceImpl.java index 296a9266..b99803a7 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/BmzrAssessmentPlanServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/BmzrAssessmentPlanServiceImpl.java @@ -121,8 +121,27 @@ public class BmzrAssessmentPlanServiceImpl implements IBmzrAssessmentPlanService // 删除前校验 // 这里可以添加删除前的业务校验逻辑 } + + // 1. 先删除关联的考核得分数据 + deleteRelatedAssessmentScores(ids); + + // 2. 再删除考核计划主表数据 return baseMapper.deleteBatchIds(ids) > 0; } + + /** + * 删除关联的考核得分数据 + * @param planIds 考核计划ID集合 + */ + private void deleteRelatedAssessmentScores(Collection planIds) { + if (planIds == null || planIds.isEmpty()) { + return; + } + + // 通过SQL更新关联表的deleted字段,实现逻辑删除 + // 这里需要直接执行SQL,因为可能没有对应的Service + baseMapper.deleteAssessmentScoresByPlanIds(planIds); + } /** * 修改考核计划状态 diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/TeacherAssessmentServiceImpl.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/TeacherAssessmentServiceImpl.java index d01befbc..d42f5e34 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/TeacherAssessmentServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/TeacherAssessmentServiceImpl.java @@ -13,6 +13,9 @@ import org.dromara.bzrkh.domain.vo.ClassDetailVo; import org.dromara.bzrkh.domain.vo.CoefficientVo; import org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo; import org.dromara.bzrkh.domain.vo.SpecialWorkIndicatorVo; +import org.dromara.bzrkh.domain.vo.ClassStudentRecordsVo; +import org.dromara.bzrkh.domain.vo.StudentDisciplineRecordVo; +import org.dromara.bzrkh.domain.vo.StudentRewardRecordVo; import org.dromara.bzrkh.domain.bo.TeacherAssessmentQueryBo; import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo; import org.dromara.bzrkh.mapper.TeacherAssessmentMapper; @@ -20,6 +23,7 @@ import org.dromara.bzrkh.mapper.BmzrAssessmentScoreMapper; import org.dromara.bzrkh.service.ITeacherAssessmentService; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.bzrkh.domain.BmzrAssessmentScore; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import java.math.BigDecimal; import java.math.RoundingMode; @@ -61,9 +65,16 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService { */ @Override public TableDataInfo queryTeacherAssessmentPlanPageList(TeacherAssessmentQueryBo bo, PageQuery pageQuery) { + log.info("🔍 查询班主任考核计划列表 - 参数: teacherId={}, classId={}, planName={}, planStatus={}", + bo.getTeacherId(), bo.getClassId(), bo.getPlanName(), bo.getPlanStatus()); + Page page = pageQuery.build(); List list = teacherAssessmentMapper.selectTeacherAssessmentPlanList(bo); + log.info("📊 查询结果: 总数={}, 第一条数据状态={}", + list.size(), + list.isEmpty() ? "无数据" : "auditStatus=" + list.get(0).getAuditStatus() + ",submitted=" + list.get(0).getSubmitted()); + // 手动分页处理 int total = list.size(); int start = (int) ((page.getCurrent() - 1) * page.getSize()); @@ -87,12 +98,69 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService { */ @Override public boolean submitAssessment(Long planId, Long classId, Long teacherId) { - // TODO: 实现提交考核逻辑 - // 1. 验证班主任是否有权限提交该班级的考核 - // 2. 验证考核计划是否有效 - // 3. 创建或更新考核记录 - // 4. 更新考核状态 - return true; + log.info("开始提交考核到审批流程 - planId: {}, classId: {}, teacherId: {}", planId, classId, teacherId); + + try { + // 参数验证 + if (planId == null || classId == null || teacherId == null) { + log.error("参数验证失败 - planId: {}, classId: {}, teacherId: {}", planId, classId, teacherId); + throw new RuntimeException("必要参数不能为空"); + } + + // 1. 验证是否存在草稿状态的评分数据 + log.info("1. 验证是否存在草稿状态的评分数据..."); + List draftScores = teacherAssessmentMapper.selectSavedAssessmentScores(planId, teacherId, classId); + if (draftScores == null || draftScores.isEmpty()) { + log.error("未找到任何评分数据 - planId: {}, teacherId: {}, classId: {}", planId, teacherId, classId); + throw new RuntimeException("请先保存考核评分数据后再提交"); + } + log.info("找到评分数据记录数: {}", draftScores.size()); + + // 2. 验证所有草稿数据的审核状态 + log.info("2. 验证草稿数据的审核状态..."); + long draftCount = draftScores.stream().filter(score -> "9".equals(score.getAuditStatus())).count(); + long otherStatusCount = draftScores.size() - draftCount; + + log.info("草稿状态记录数: {}, 其他状态记录数: {}", draftCount, otherStatusCount); + + if (draftCount == 0) { + log.error("未找到可提交的草稿数据 - planId: {}, teacherId: {}", planId, teacherId); + throw new RuntimeException("未找到可提交的草稿数据,可能已经提交过了"); + } + + // 3. 将所有草稿状态的评分记录更新为待审核状态 + log.info("3. 更新评分记录状态为待审核..."); + try { + Date now = new Date(); + int updateCount = assessmentScoreMapper.update(null, + new LambdaUpdateWrapper() + .set(BmzrAssessmentScore::getAuditStatus, "0") // 设置为待审核状态 + .set(BmzrAssessmentScore::getSubmitTime, now) // 更新提交时间 + .set(BmzrAssessmentScore::getSelfSubmitTime, now) // 设置自评提交时间,使数据出现在审批列表中 + .eq(BmzrAssessmentScore::getPlanId, planId) + .eq(BmzrAssessmentScore::getEvaluatedUserId, teacherId) + .eq(BmzrAssessmentScore::getClassId, classId) // 添加班级ID过滤条件,确保班级隔离 + .eq(BmzrAssessmentScore::getAuditStatus, "9") // 只更新草稿状态的记录 + .eq(BmzrAssessmentScore::getDeleted, 0) + ); + + if (updateCount <= 0) { + log.error("更新评分记录状态失败 - planId: {}, teacherId: {}", planId, teacherId); + throw new RuntimeException("更新评分记录状态失败"); + } + + log.info("成功更新评分记录状态,更新记录数: {}", updateCount); + } catch (Exception e) { + log.error("更新评分记录状态异常 - planId: {}, teacherId: {}, error: {}", planId, teacherId, e.getMessage(), e); + throw new RuntimeException("更新评分记录状态失败: " + e.getMessage()); + } + + log.info("考核提交到审批流程成功 - planId: {}, classId: {}, teacherId: {}", planId, classId, teacherId); + return true; + } catch (Exception e) { + log.error("提交考核失败:planId={}, classId={}, teacherId={}, error={}", planId, classId, teacherId, e.getMessage(), e); + throw new RuntimeException("提交考核失败:" + e.getMessage()); + } } /** @@ -146,7 +214,7 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService { detailVo.setSpecialWorkIndicators(specialWorkIndicators); // 6. 获取已保存的评分数据(如果有) - List savedScores = teacherAssessmentMapper.selectSavedAssessmentScores(planId, teacherId); + List savedScores = teacherAssessmentMapper.selectSavedAssessmentScores(planId, teacherId, classId); if (savedScores != null && !savedScores.isEmpty()) { // 将已保存的评分数据合并到指标中 mergeAssessmentScores(detailVo, savedScores); @@ -169,41 +237,86 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService { */ @Override public boolean submitAssessmentScore(AssessmentSubmitBo bo, Long teacherId) { + log.info("开始提交考核评分数据 - planId: {}, classId: {}, teacherId: {}", bo.getPlanId(), bo.getClassId(), teacherId); + try { - // 1. 先逻辑删除该计划下该教师的历史评分数据 - teacherAssessmentMapper.deleteAssessmentScoresByPlanAndTeacher(bo.getPlanId(), teacherId); + // 参数验证 + if (bo.getPlanId() == null || bo.getClassId() == null || teacherId == null) { + log.error("参数验证失败 - planId: {}, classId: {}, teacherId: {}", bo.getPlanId(), bo.getClassId(), teacherId); + throw new RuntimeException("必要参数不能为空"); + } + log.info("1. 开始逻辑删除历史评分数据..."); + // 1. 先逻辑删除该计划下该教师该班级的历史评分数据 + teacherAssessmentMapper.deleteAssessmentScoresByPlanAndTeacher(bo.getPlanId(), teacherId, bo.getClassId()); + log.info("逻辑删除历史评分数据完成"); + + log.info("2. 查询方案ID..."); Long schemeId = teacherAssessmentMapper.selectSchemeIdByPlanId(bo.getPlanId()); + if (schemeId == null) { + log.error("根据计划ID查询方案ID失败 - planId: {}", bo.getPlanId()); + throw new RuntimeException("找不到对应的考核方案,请检查考核计划配置"); + } + log.info("查询方案ID成功: {}", schemeId); + String currentUserName = LoginHelper.getUsername(); Long currentDeptId = LoginHelper.getDeptId(); Date now = new Date(); + log.info("当前用户信息 - username: {}, deptId: {}", currentUserName, currentDeptId); + // 2. 插入班主任常规工作指标评分 if (bo.getRoutineWorkScores() != null && !bo.getRoutineWorkScores().isEmpty()) { - for (AssessmentIndicatorScoreVo score : bo.getRoutineWorkScores()) { - BmzrAssessmentScore assessmentScore = new BmzrAssessmentScore(); - assessmentScore.setPlanId(bo.getPlanId()); - assessmentScore.setSchemeId(schemeId); - assessmentScore.setIndicatorId(score.getId()); - assessmentScore.setEvaluatedUserId(teacherId); - assessmentScore.setEvaluatedUserName(currentUserName); - assessmentScore.setEvaluatedDeptId(currentDeptId); - assessmentScore.setSelfScore(score.getSelfScore()); - assessmentScore.setSelfComment(score.getSelfComment()); - assessmentScore.setSelfSubmitTime(now); - assessmentScore.setSubmitTime(now); - assessmentScore.setAuditStatus("0"); - // 设置班级ID和自我总体评价 - assessmentScore.setClassId(bo.getClassId()); - assessmentScore.setSelfOverallComment(bo.getOverallComment()); + log.info("3. 开始插入班主任常规工作指标评分,共{}条", bo.getRoutineWorkScores().size()); + for (int i = 0; i < bo.getRoutineWorkScores().size(); i++) { + AssessmentIndicatorScoreVo score = bo.getRoutineWorkScores().get(i); + log.info("插入常规工作指标 {}/{} - indicatorId: {}, selfScore: {}", + i + 1, bo.getRoutineWorkScores().size(), score.getId(), score.getSelfScore()); - assessmentScoreMapper.insert(assessmentScore); + try { + BmzrAssessmentScore assessmentScore = new BmzrAssessmentScore(); + assessmentScore.setPlanId(bo.getPlanId()); + assessmentScore.setSchemeId(schemeId); + assessmentScore.setIndicatorId(score.getId()); + assessmentScore.setEvaluatedUserId(teacherId); + assessmentScore.setEvaluatedUserName(currentUserName); + assessmentScore.setEvaluatedDeptId(currentDeptId); + assessmentScore.setSelfScore(score.getSelfScore()); + assessmentScore.setSelfComment(score.getSelfComment()); + // 保存操作不设置 self_submit_time,只有提交到审批流程时才设置 + // assessmentScore.setSelfSubmitTime(now); + assessmentScore.setSubmitTime(now); + assessmentScore.setAuditStatus("9"); // 设置为草稿状态 + // 设置班级ID和自我总体评价 + assessmentScore.setClassId(bo.getClassId()); + assessmentScore.setSelfOverallComment(bo.getOverallComment()); + + int insertResult = assessmentScoreMapper.insert(assessmentScore); + if (insertResult <= 0) { + log.error("插入常规工作指标评分失败 - indicatorId: {}", score.getId()); + throw new RuntimeException("插入常规工作指标评分失败"); + } + log.info("插入常规工作指标评分成功 - indicatorId: {}, 新记录ID: {}", score.getId(), assessmentScore.getId()); + } catch (Exception e) { + log.error("插入常规工作指标评分异常 - indicatorId: {}, error: {}", score.getId(), e.getMessage(), e); + throw new RuntimeException("插入常规工作指标评分失败: " + e.getMessage()); + } } + log.info("班主任常规工作指标评分插入完成"); + } else { + log.warn("班主任常规工作指标评分数据为空"); } // 3. 插入班级扣分指标评分 + log.info("4. 开始插入班级扣分指标评分..."); Long classDeductionIndicatorId = teacherAssessmentMapper.selectIndicatorIdByCode("bzrwjkf001"); - if (classDeductionIndicatorId != null) { + if (classDeductionIndicatorId == null) { + log.error("找不到班级扣分指标 - indicatorCode: bzrwjkf001"); + throw new RuntimeException("找不到班级扣分指标,请检查指标配置"); + } + log.info("班级扣分指标ID: {}", classDeductionIndicatorId); + + try { BmzrAssessmentScore assessmentScore = new BmzrAssessmentScore(); assessmentScore.setPlanId(bo.getPlanId()); assessmentScore.setSchemeId(schemeId); @@ -213,21 +326,41 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService { assessmentScore.setEvaluatedDeptId(currentDeptId); assessmentScore.setSelfScore(bo.getClassDeduction()); assessmentScore.setSelfComment(bo.getClassDeductionComment()); - assessmentScore.setSelfSubmitTime(now); + // 保存操作不设置 self_submit_time,只有提交到审批流程时才设置 + // assessmentScore.setSelfSubmitTime(now); assessmentScore.setSubmitTime(now); - assessmentScore.setAuditStatus("0"); + assessmentScore.setAuditStatus("9"); // 设置为草稿状态 // 设置班级ID和自我总体评价 assessmentScore.setClassId(bo.getClassId()); assessmentScore.setSelfOverallComment(bo.getOverallComment()); - assessmentScoreMapper.insert(assessmentScore); + int insertResult = assessmentScoreMapper.insert(assessmentScore); + if (insertResult <= 0) { + log.error("插入班级扣分指标评分失败"); + throw new RuntimeException("插入班级扣分指标评分失败"); + } + log.info("插入班级扣分指标评分成功 - 新记录ID: {}", assessmentScore.getId()); + } catch (Exception e) { + log.error("插入班级扣分指标评分异常: {}", e.getMessage(), e); + throw new RuntimeException("插入班级扣分指标评分失败: " + e.getMessage()); } // 4. 插入特色工作指标评分 if (bo.getSpecialWorkScores() != null && !bo.getSpecialWorkScores().isEmpty()) { - for (SpecialWorkIndicatorVo score : bo.getSpecialWorkScores()) { + log.info("5. 开始插入特色工作指标评分,共{}条", bo.getSpecialWorkScores().size()); + for (int i = 0; i < bo.getSpecialWorkScores().size(); i++) { + SpecialWorkIndicatorVo score = bo.getSpecialWorkScores().get(i); + log.info("插入特色工作指标 {}/{} - indicatorCode: {}, score: {}", + i + 1, bo.getSpecialWorkScores().size(), score.getIndicatorCode(), score.getScore()); + Long indicatorId = teacherAssessmentMapper.selectIndicatorIdByCode(score.getIndicatorCode()); - if (indicatorId != null) { + if (indicatorId == null) { + log.error("找不到特色工作指标 - indicatorCode: {}", score.getIndicatorCode()); + throw new RuntimeException("找不到特色工作指标: " + score.getIndicatorCode()); + } + log.info("特色工作指标ID: {} - {}", score.getIndicatorCode(), indicatorId); + + try { BmzrAssessmentScore assessmentScore = new BmzrAssessmentScore(); assessmentScore.setPlanId(bo.getPlanId()); assessmentScore.setSchemeId(schemeId); @@ -237,24 +370,39 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService { assessmentScore.setEvaluatedDeptId(currentDeptId); assessmentScore.setSelfScore(score.getScore()); assessmentScore.setSelfComment(score.getSelfComment()); - assessmentScore.setSelfSubmitTime(now); + // 保存操作不设置 self_submit_time,只有提交到审批流程时才设置 + // assessmentScore.setSelfSubmitTime(now); assessmentScore.setSubmitTime(now); - assessmentScore.setAuditStatus("0"); + assessmentScore.setAuditStatus("9"); // 设置为草稿状态 // 设置班级ID和自我总体评价 assessmentScore.setClassId(bo.getClassId()); assessmentScore.setSelfOverallComment(bo.getOverallComment()); - assessmentScoreMapper.insert(assessmentScore); + int insertResult = assessmentScoreMapper.insert(assessmentScore); + if (insertResult <= 0) { + log.error("插入特色工作指标评分失败 - indicatorCode: {}", score.getIndicatorCode()); + throw new RuntimeException("插入特色工作指标评分失败"); + } + log.info("插入特色工作指标评分成功 - indicatorCode: {}, 新记录ID: {}", + score.getIndicatorCode(), assessmentScore.getId()); + } catch (Exception e) { + log.error("插入特色工作指标评分异常 - indicatorCode: {}, error: {}", + score.getIndicatorCode(), e.getMessage(), e); + throw new RuntimeException("插入特色工作指标评分失败: " + e.getMessage()); } } + log.info("特色工作指标评分插入完成"); + } else { + log.warn("特色工作指标评分数据为空"); } - // 5. 总体评价已经通过上述步骤存储到每条记录的 self_overall_comment 字段中 - + log.info("考核评分数据提交成功 - planId: {}, classId: {}, teacherId: {}", bo.getPlanId(), bo.getClassId(), teacherId); return true; } catch (Exception e) { - e.printStackTrace(); - return false; + log.error("提交考核评分数据失败 - planId: {}, classId: {}, teacherId: {}, error: {}", + bo.getPlanId(), bo.getClassId(), teacherId, e.getMessage(), e); + // 重新抛出异常,让Controller能够捕获并返回错误信息 + throw new RuntimeException("提交考核评分数据失败: " + e.getMessage()); } } @@ -391,23 +539,33 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService { public boolean withdrawAssessment(Long planId, Long classId, Long teacherId) { try { // 验证是否有权限撤销(只能撤销自己提交的且状态为待审核的考核) - List savedScores = teacherAssessmentMapper.selectSavedAssessmentScores(planId, teacherId); - if (savedScores == null || savedScores.isEmpty()) { - log.warn("未找到可撤销的考核提交记录,计划ID: {}, 教师ID: {}", planId, teacherId); + List submittedScores = teacherAssessmentMapper.selectSubmittedAssessmentScores(planId, teacherId, classId); + if (submittedScores == null || submittedScores.isEmpty()) { + log.warn("未找到可撤销的考核提交记录,计划ID: {}, 教师ID: {}, 班级ID: {}", planId, teacherId, classId); return false; } // 检查审核状态,只有待审核状态("0")的才能撤销 - boolean canWithdraw = savedScores.stream().anyMatch(score -> "0".equals(score.getAuditStatus())); + boolean canWithdraw = submittedScores.stream().anyMatch(score -> "0".equals(score.getAuditStatus())); if (!canWithdraw) { log.warn("考核已审核,无法撤销,计划ID: {}, 教师ID: {}", planId, teacherId); return false; } - // 逻辑删除该计划下该教师的所有评分数据 - teacherAssessmentMapper.deleteAssessmentScoresByPlanAndTeacher(planId, teacherId); + // 将待审核状态的评分记录恢复为草稿状态 + assessmentScoreMapper.update(null, + new LambdaUpdateWrapper() + .set(BmzrAssessmentScore::getAuditStatus, "9") // 设置为草稿状态 + .set(BmzrAssessmentScore::getSubmitTime, null) // 清空提交时间 + .set(BmzrAssessmentScore::getSelfSubmitTime, null) // 清空自评提交时间 + .eq(BmzrAssessmentScore::getPlanId, planId) + .eq(BmzrAssessmentScore::getEvaluatedUserId, teacherId) + .eq(BmzrAssessmentScore::getClassId, classId) // 添加班级ID过滤条件,确保班级隔离 + .eq(BmzrAssessmentScore::getAuditStatus, "0") // 只更新待审核状态的记录 + .eq(BmzrAssessmentScore::getDeleted, 0) + ); - log.info("成功撤销考核提交,计划ID: {}, 教师ID: {}", planId, teacherId); + log.info("成功撤销考核提交,数据已恢复为草稿状态,计划ID: {}, 教师ID: {}", planId, teacherId); return true; } catch (Exception e) { log.error("撤销考核提交失败,计划ID: {}, 教师ID: {}", planId, teacherId, e); @@ -502,4 +660,33 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService { } } } + + /** + * 查询班级学生违纪记录和奖励记录 + * + * @param classId 班级ID + * @return 班级学生记录 + */ + @Override + public ClassStudentRecordsVo queryClassStudentRecords(Long classId) { + // 查询班级信息 + String className = teacherAssessmentMapper.selectClassNameById(classId); + + // 查询班级学生违纪记录 + List disciplineRecords = teacherAssessmentMapper.selectStudentDisciplineRecordsByClassId(classId); + + // 查询班级学生奖励记录 + List rewardRecords = teacherAssessmentMapper.selectStudentRewardRecordsByClassId(classId); + + // 构建返回对象 + ClassStudentRecordsVo result = new ClassStudentRecordsVo(); + result.setClassId(classId); + result.setClassName(className); + result.setDisciplineRecords(disciplineRecords); + result.setRewardRecords(rewardRecords); + result.setDisciplineCount(disciplineRecords != null ? disciplineRecords.size() : 0); + result.setRewardCount(rewardRecords != null ? rewardRecords.size() : 0); + + return result; + } } \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/AssessmentApprovalMapper.xml b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/AssessmentApprovalMapper.xml index 6f5e5c6a..69660560 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/AssessmentApprovalMapper.xml +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/AssessmentApprovalMapper.xml @@ -67,7 +67,8 @@ - + + @@ -148,22 +149,28 @@ @@ -223,7 +230,7 @@ s.id, i.indicator_code, i.indicator_name, - s.self_score as score, + s.self_score, s.self_comment, s.superior_score, s.superior_comment, @@ -278,16 +285,52 @@ AND deleted = 0 - - SELECT - id, - scheme_code, - scheme_name + id as value, + scheme_name as label FROM bmzr_assessment_scheme - WHERE status = '0' - AND deleted = 0 + WHERE deleted = 0 + AND status = '0' ORDER BY create_time DESC + + + UPDATE bmzr_assessment_score + SET deleted = 1, + update_time = NOW() + WHERE plan_id = #{planId} + AND evaluated_user_id = #{evaluatedUserId} + AND deleted = 0 + + + + + \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/AssessmentScoreMapper.xml b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/AssessmentScoreMapper.xml new file mode 100644 index 00000000..3f0d96a6 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/AssessmentScoreMapper.xml @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/BmzrAssessmentPlanMapper.xml b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/BmzrAssessmentPlanMapper.xml index 880ac6ca..4002c25e 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/BmzrAssessmentPlanMapper.xml +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/BmzrAssessmentPlanMapper.xml @@ -143,4 +143,16 @@ ORDER BY p.create_time DESC + + + UPDATE bmzr_assessment_score + SET deleted = 1, + update_time = NOW() + WHERE deleted = 0 + AND plan_id IN + + #{planId} + + + \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/TeacherAssessmentMapper.xml b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/TeacherAssessmentMapper.xml index 47c9c923..f6ca8ec7 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/TeacherAssessmentMapper.xml +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/TeacherAssessmentMapper.xml @@ -139,15 +139,37 @@ p.update_by, p.update_time, p.deleted, - score.audit_status as audit_status, + COALESCE(score.audit_status, '') as audit_status, score.self_submit_time as submit_time, CASE WHEN score.plan_id IS NOT NULL THEN 1 ELSE 0 END as submitted FROM bmzr_assessment_plan p LEFT JOIN bmzr_assessment_scheme s ON p.scheme_id = s.id AND s.deleted = 0 LEFT JOIN ( - SELECT DISTINCT plan_id, audit_status, self_submit_time - FROM bmzr_assessment_score - WHERE evaluated_user_id = #{teacherId} AND deleted = 0 + SELECT DISTINCT s1.plan_id, s1.audit_status, s1.self_submit_time + FROM bmzr_assessment_score s1 + WHERE s1.evaluated_user_id = #{teacherId} + AND s1.deleted = 0 + + AND s1.class_id = #{classId} + + AND s1.id = ( + SELECT s2.id + FROM bmzr_assessment_score s2 + WHERE s2.plan_id = s1.plan_id + AND s2.evaluated_user_id = #{teacherId} + AND s2.deleted = 0 + + AND s2.class_id = #{classId} + + ORDER BY CASE + WHEN s2.audit_status = '9' THEN 1 -- 草稿状态优先级最高 + WHEN s2.audit_status = '0' THEN 2 -- 待审核状态 + WHEN s2.audit_status = '1' THEN 3 -- 审核通过状态 + WHEN s2.audit_status = '2' THEN 4 -- 审核不通过状态 + ELSE 5 + END ASC, s2.id DESC + LIMIT 1 + ) ) score ON p.id = score.plan_id WHERE p.deleted = 0 @@ -256,7 +278,7 @@ ORDER BY i.indicator_code ASC - + + + + @@ -298,13 +349,14 @@ LIMIT 1 - + UPDATE bmzr_assessment_score SET deleted = 1, update_time = NOW() WHERE plan_id = #{planId} AND evaluated_user_id = #{teacherId} + AND class_id = #{classId} AND deleted = 0 @@ -321,4 +373,75 @@ AND deleted = 0 + + + + + + + + + \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/班主任考核审核权限配置.sql b/backend/ruoyi-modules/ruoyi-bzrkh/班主任考核审核权限配置.sql index ed3e0ca2..b801fe9d 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/班主任考核审核权限配置.sql +++ b/backend/ruoyi-modules/ruoyi-bzrkh/班主任考核审核权限配置.sql @@ -33,6 +33,7 @@ SET @dict_type_id = LAST_INSERT_ID(); -- 审核状态字典数据 INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_dept, create_by, create_time, update_by, update_time, remark) VALUES +(0, '草稿', '9', 'bmzr_audit_status', '', 'info', 'N', '0', 103, 1, now(), 1, now(), '草稿状态'), (1, '待审核', '0', 'bmzr_audit_status', '', 'warning', 'Y', '0', 103, 1, now(), 1, now(), '待审核状态'), (2, '审核通过', '1', 'bmzr_audit_status', '', 'success', 'N', '0', 103, 1, now(), 1, now(), '审核通过状态'), (3, '审核不通过', '2', 'bmzr_audit_status', '', 'danger', 'N', '0', 103, 1, now(), 1, now(), '审核不通过状态'); diff --git a/docs/设计文档/database/班主任考核管理/bmzr_assessment_tables.sql b/docs/设计文档/database/班主任考核管理/bmzr_assessment_tables.sql index 9e05bd97..6f9e11ff 100644 --- a/docs/设计文档/database/班主任考核管理/bmzr_assessment_tables.sql +++ b/docs/设计文档/database/班主任考核管理/bmzr_assessment_tables.sql @@ -166,7 +166,7 @@ CREATE TABLE `bmzr_assessment_score` ( `superior_evaluator_id` bigint(20) COMMENT '上级评价人ID', `superior_submit_time` datetime COMMENT '上级评提交时间', `evaluation_level` varchar(20) COMMENT '评价等级 dict_type = bmzr_evaluation_level', - `audit_status` char(1) NOT NULL DEFAULT '0' COMMENT '审核状态(0=待审核 1=审核通过 2=审核不通过)', + `audit_status` char(1) NOT NULL DEFAULT '0' COMMENT '审核状态(0=待审核 1=审核通过 2=审核不通过 9=草稿)', `final_score` decimal(5,2) COMMENT '最终得分', `submit_time` datetime COMMENT '提交时间', `remark` varchar(500) COMMENT '备注', diff --git a/docs/设计文档/database/班主任考核管理/bmzr_dict_data_mysql.sql b/docs/设计文档/database/班主任考核管理/bmzr_dict_data_mysql.sql index 49b0bc9e..038709ff 100644 --- a/docs/设计文档/database/班主任考核管理/bmzr_dict_data_mysql.sql +++ b/docs/设计文档/database/班主任考核管理/bmzr_dict_data_mysql.sql @@ -38,17 +38,15 @@ INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_ty DELETE FROM sys_dict_type WHERE dict_type = 'bmzr_evaluation_level'; -- 插入字典类型 INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, status, create_dept, create_by, create_time, remark) -VALUES ('000000', '评价等级', 'bmzr_evaluation_level', '0', 103, 1, NOW(), '班主任考核-评价等级'); +VALUES ('000000', '评价等级', 'bmzr_evaluation_level', '0', 103, 1, NOW(), '班主任考核-评价等级(三等级制度)'); -- 删除已存在的字典数据 DELETE FROM sys_dict_data WHERE dict_type = 'bmzr_evaluation_level'; -- 插入字典数据 INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_dept, create_by, create_time, remark) VALUES -('000000', 1, '优秀', 'excellent', 'bmzr_evaluation_level', '', 'success', 'Y', '0', 103, 1, NOW(), '优秀等级(90-100分)'), -('000000', 2, '良好', 'good', 'bmzr_evaluation_level', '', 'primary', 'N', '0', 103, 1, NOW(), '良好等级(80-89分)'), -('000000', 3, '合格', 'qualified', 'bmzr_evaluation_level', '', 'info', 'N', '0', 103, 1, NOW(), '合格等级(70-79分)'), -('000000', 4, '基本合格', 'basic', 'bmzr_evaluation_level', '', 'warning', 'N', '0', 103, 1, NOW(), '基本合格等级(60-69分)'), -('000000', 5, '不合格', 'unqualified', 'bmzr_evaluation_level', '', 'danger', 'N', '0', 103, 1, NOW(), '不合格等级(60分以下)'); +('000000', 1, 'A等(优秀)', 'A', 'bmzr_evaluation_level', '', 'success', 'Y', '0', 103, 1, NOW(), 'A等优秀(占比≤20%班主任人数)'), +('000000', 2, 'B等(合格)', 'B', 'bmzr_evaluation_level', '', 'primary', 'N', '0', 103, 1, NOW(), 'B等合格(60分及以上,与C等合计≥80%)'), +('000000', 3, 'C等(不合格)', 'C', 'bmzr_evaluation_level', '', 'danger', 'N', '0', 103, 1, NOW(), 'C等不合格(60分以下)'); -- ========================================== \ No newline at end of file diff --git a/web/src/api/bzrkh/assessmentApproval/index.ts b/web/src/api/bzrkh/assessmentApproval/index.ts index 4b39ebb0..133d9224 100644 --- a/web/src/api/bzrkh/assessmentApproval/index.ts +++ b/web/src/api/bzrkh/assessmentApproval/index.ts @@ -1,11 +1,6 @@ import request from '@/utils/request'; import { AxiosPromise } from 'axios'; -import { - AssessmentApprovalQuery, - AssessmentApprovalVO, - AssessmentApprovalDetailVO, - AssessmentApprovalSubmitBO -} from './types'; +import { AssessmentApprovalQuery, AssessmentApprovalVO, AssessmentApprovalDetailVO, AssessmentApprovalSubmitBO, EvaluationLevelStatsVO } from './types'; /** * 查询班主任考核审核列表 @@ -27,7 +22,11 @@ export const listAssessmentApproval = (query?: AssessmentApprovalQuery): AxiosPr * @param evaluatedUserId 被评价用户ID * @returns {*} */ -export const getAssessmentApprovalDetail = (planId: string | number, classId: string | number, evaluatedUserId: string | number): AxiosPromise => { +export const getAssessmentApprovalDetail = ( + planId: string | number, + classId: string | number, + evaluatedUserId: string | number +): AxiosPromise => { return request({ url: '/bzrkh/assessmentApproval/detail', method: 'get', @@ -75,7 +74,7 @@ export const batchRejectAssessment = (ids: (string | number)[], rejectReason: st return request({ url: '/bzrkh/assessmentApproval/batchReject', method: 'post', - data: { + data: { ids, rejectReason } @@ -105,4 +104,17 @@ export const exportAssessmentApproval = (query?: AssessmentApprovalQuery): Axios data: query, responseType: 'blob' }); -}; \ No newline at end of file +}; + +/** + * 获取评价等级统计数据 + * @param planId 计划ID + * @returns {*} + */ +export const getEvaluationLevelStats = (planId: string | number): AxiosPromise => { + return request({ + url: '/bzrkh/assessmentApproval/evaluationStats', + method: 'get', + params: { planId } + }); +}; diff --git a/web/src/api/bzrkh/assessmentApproval/types.ts b/web/src/api/bzrkh/assessmentApproval/types.ts index 261ce075..ce8c6dbe 100644 --- a/web/src/api/bzrkh/assessmentApproval/types.ts +++ b/web/src/api/bzrkh/assessmentApproval/types.ts @@ -51,7 +51,7 @@ export interface AssessmentApprovalDetailVO { id?: string | number; planId?: string | number; classId?: string | number; - + /** * 班级详细信息 */ @@ -64,7 +64,7 @@ export interface AssessmentApprovalDetailVO { totalStudentCount?: number; boardingStudentCount?: number; }; - + /** * 系数信息 */ @@ -74,42 +74,42 @@ export interface AssessmentApprovalDetailVO { studentCountCoefficient?: number; boardingCoefficient?: number; }; - + /** * 班主任常规工作指标列表 - 包含自评和上级评分 */ routineWorkIndicators?: AssessmentApprovalIndicatorVO[]; - + /** * 班级扣分指标 - 班级管理实效 */ classDeductionIndicator?: AssessmentApprovalIndicatorVO; - + /** * 特色工作指标列表 */ specialWorkIndicators?: AssessmentApprovalSpecialWorkVO[]; - + /** * 自我总体评价 */ selfOverallComment?: string; - + /** * 上级总体评价 */ superiorOverallComment?: string; - + /** * 月考核得分 */ monthlyScore?: number; - + /** * 审核状态 */ auditStatus?: string; - + /** * 提交时间 */ @@ -125,17 +125,17 @@ export interface AssessmentApprovalIndicatorVO { indicatorName?: string; indicatorCode?: string; description?: string; - score?: number; // 指标分值 + score?: number; // 指标分值 maxScore?: number; - + // 自评相关 selfScore?: number; selfComment?: string; - + // 上级评相关 superiorScore?: number; superiorComment?: string; - + // 审核状态 auditStatus?: string; } @@ -147,15 +147,16 @@ export interface AssessmentApprovalSpecialWorkVO { id?: string | number; indicatorCode?: string; indicatorName?: string; - + // 自评相关 - score?: number; // 自评分数 + score?: number; // 自评分数 (兼容原有字段) + selfScore?: number; // 自评分数 (标准字段名) selfComment?: string; - + // 上级评相关 superiorScore?: number; superiorComment?: string; - + // 审核状态 auditStatus?: string; } @@ -167,32 +168,32 @@ export interface AssessmentApprovalSubmitBO { planId?: string | number; classId?: string | number; evaluatedUserId?: string | number; - + /** * 班主任常规工作审核数据 */ routineWorkApproval?: AssessmentApprovalIndicatorSubmitVO[]; - + /** * 班级管理实效审核数据 */ classDeductionApproval?: AssessmentApprovalIndicatorSubmitVO; - + /** * 特色工作审核数据 */ specialWorkApproval?: AssessmentApprovalSpecialWorkSubmitVO[]; - + /** * 上级总体评价 */ superiorOverallComment?: string; - + /** * 审核状态 0=待审核 1=审核通过 2=审核不通过 */ auditStatus?: string; - + /** * 审核意见 */ @@ -217,4 +218,26 @@ export interface AssessmentApprovalSpecialWorkSubmitVO { indicatorCode?: string; superiorScore?: number; superiorComment?: string; -} \ No newline at end of file +} + +/** + * 评价等级统计数据 + */ +export interface EvaluationLevelStatsVO { + totalTeachers: number; // 总班主任数量 + scoreRankings: ScoreRankingVO[]; // 分数排名列表 + evaluationLevelRules: { // 评价等级规则 + aLevelMaxPercentage: number; // A等最大占比(如20%) + passScore: number; // 及格分数(如60分) + }; +} + +/** + * 分数排名VO + */ +export interface ScoreRankingVO { + score: number; // 考核得分 + ranking: number; // 排名(从1开始) + percentage: number; // 百分比排名(前X%) + evaluatedUserId?: string | number; // 被评价用户ID(可选,用于标识当前用户) +} diff --git a/web/src/api/bzrkh/teacherAssessment/index.ts b/web/src/api/bzrkh/teacherAssessment/index.ts index 6412ce1c..56ccad15 100644 --- a/web/src/api/bzrkh/teacherAssessment/index.ts +++ b/web/src/api/bzrkh/teacherAssessment/index.ts @@ -1,9 +1,9 @@ import request from '@/utils/request'; import { AxiosPromise } from 'axios'; -import { - TeacherClassVO, - TeacherAssessmentPlanVO, - TeacherAssessmentPlanQuery, +import { + TeacherClassVO, + TeacherAssessmentPlanVO, + TeacherAssessmentPlanQuery, TeacherClassQuery, AssessmentDetailVO, AssessmentSubmitVO @@ -95,6 +95,18 @@ export const submitAssessmentScore = (data: AssessmentSubmitVO): AxiosPromise => { + return request({ + url: '/bzrkh/teacherAssessment/classStudentRecords', + method: 'get', + params: { classId } + }); +}; + /** * 撤销考核提交 * @param planId 计划ID @@ -109,4 +121,4 @@ export const withdrawAssessment = (planId: string | number, classId: string | nu classId } }); -}; \ No newline at end of file +}; diff --git a/web/src/api/bzrkh/teacherAssessment/types.ts b/web/src/api/bzrkh/teacherAssessment/types.ts index bb1771bf..9531bad5 100644 --- a/web/src/api/bzrkh/teacherAssessment/types.ts +++ b/web/src/api/bzrkh/teacherAssessment/types.ts @@ -231,32 +231,32 @@ export interface ClassDetailVO { * 班级ID */ id?: string | number; - + /** * 学院名称 */ collegeName?: string; - + /** * 专业名称 */ majorName?: string; - + /** * 班级名称 */ className?: string; - + /** * 班级层次:1-中级工 2-高级工 3-预备技师 4-技师 5-中高职一体 */ classType?: string; - + /** * 班级总人数 */ totalStudentCount?: number; - + /** * 住校生人数 */ @@ -271,17 +271,17 @@ export interface CoefficientVO { * 人数系数(K2) */ studentCountCoefficient?: number; - + /** * 住校生系数(K3) */ boardingCoefficient?: number; - + /** * 层次系数(K1) */ levelCoefficient?: number; - + /** * 总系数(K = K1 * (K2 + K3)) */ @@ -296,37 +296,37 @@ export interface AssessmentIndicatorVO { * 指标ID */ id?: string | number; - + /** * 指标名称 */ indicatorName?: string; - + /** * 指标编码 */ indicatorCode?: string; - + /** * 指标描述 */ description?: string; - + /** * 指标分值 */ score?: number; - + /** * 自评分数 */ selfScore?: number; - + /** * 自评意见 */ selfComment?: string; - + /** * 排序 */ @@ -341,17 +341,17 @@ export interface SpecialWorkIndicatorVO { * 指标编码 */ indicatorCode?: string; - + /** * 指标名称 */ indicatorName?: string; - + /** * 分值 */ score?: number; - + /** * 自评意见 */ @@ -366,32 +366,32 @@ export interface AssessmentSubmitVO { * 考核计划ID */ planId?: string | number; - + /** * 班级ID */ classId?: string | number; - + /** * 班主任常规工作指标评分 */ routineWorkScores?: AssessmentIndicatorVO[]; - + /** * 班级扣分 */ classDeduction?: number; - + /** * 班级扣分意见 */ classDeductionComment?: string; - + /** * 特色工作指标评分 */ specialWorkScores?: SpecialWorkIndicatorVO[]; - + /** * 总体评价 */ @@ -406,34 +406,179 @@ export interface AssessmentDetailVO { * 班级详细信息 */ classDetail?: ClassDetailVO; - + /** * 系数信息 */ coefficient?: CoefficientVO; - + /** * 班主任常规工作指标列表 */ routineWorkIndicators?: AssessmentIndicatorVO[]; - + /** * 班级扣分指标 */ classDeductionIndicator?: AssessmentIndicatorVO; - + /** * 特色工作指标列表 */ specialWorkIndicators?: SpecialWorkIndicatorVO[]; - + /** * 月考核得分 */ monthlyScore?: number; - + /** * 总体评价 */ overallComment?: string; -} \ No newline at end of file +} + +/** + * 班级学生违纪奖励记录 + */ +export interface ClassStudentRecordsVO { + /** + * 班级名称 + */ + className?: string; + + /** + * 违纪记录数量 + */ + disciplineCount?: number; + + /** + * 奖励记录数量 + */ + rewardCount?: number; + + /** + * 违纪记录列表 + */ + disciplineRecords?: StudentDisciplineRecordVO[]; + + /** + * 奖励记录列表 + */ + rewardRecords?: StudentRewardRecordVO[]; +} + +/** + * 学生违纪记录 + */ +export interface StudentDisciplineRecordVO { + /** + * 记录ID + */ + id?: string | number; + + /** + * 学生ID + */ + studentId?: string | number; + + /** + * 学号 + */ + studentNo?: string; + + /** + * 学生姓名 + */ + studentName?: string; + + /** + * 违纪类型ID + */ + disciplineTypeId?: string | number; + + /** + * 违纪类型名称 + */ + disciplineTypeName?: string; + + /** + * 违纪日期 + */ + disciplineDate?: string; + + /** + * 违纪原因 + */ + disciplineReason?: string; + + /** + * 处分内容 + */ + disciplineContent?: string; + + /** + * 扣分分值 + */ + scoreDeduction?: number; + + /** + * 状态(1=生效 0=已撤销) + */ + status?: string; +} + +/** + * 学生奖励记录 + */ +export interface StudentRewardRecordVO { + /** + * 记录ID + */ + id?: string | number; + + /** + * 学生ID + */ + studentId?: string | number; + + /** + * 学号 + */ + studentNo?: string; + + /** + * 学生姓名 + */ + studentName?: string; + + /** + * 奖励类型ID + */ + rewardTypeId?: string | number; + + /** + * 奖励类型名称 + */ + rewardTypeName?: string; + + /** + * 奖励日期 + */ + rewardDate?: string; + + /** + * 奖励内容 + */ + rewardContent?: string; + + /** + * 加分分值 + */ + scoreAddition?: number; + + /** + * 状态(1=生效 0=撤销) + */ + status?: string; +} diff --git a/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue b/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue index 021c3309..4e1cfe06 100644 --- a/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue +++ b/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue @@ -1,12 +1,5 @@ {{ approvalDetail?.classDetail?.totalStudentCount || 0 }}人 - {{ formatNumber(approvalDetail?.coefficient?.studentCountCoefficient, 3) }} + {{ + formatNumber(approvalDetail?.coefficient?.studentCountCoefficient, 3) + }} @@ -153,7 +148,7 @@ @@ -162,7 +157,7 @@ @@ -183,12 +178,7 @@ - + @@ -219,7 +209,7 @@ @@ -270,22 +260,19 @@ - + - @@ -313,16 +300,6 @@ - - - - - 通过 - 拒绝 - - - - @@ -343,7 +320,8 @@ @@ -351,10 +329,7 @@ @@ -637,21 +697,21 @@ defineExpose({ max-height: 350px; overflow-y: auto; } - + .el-table__row { height: auto; } - + .el-table__cell { padding: 8px 0; vertical-align: middle; } - + /* 优化输入框在表格中的显示 */ .el-input-number { width: 100% !important; } - + .el-textarea__inner { resize: none; min-height: 60px !important; @@ -663,16 +723,16 @@ defineExpose({ .el-table__row { height: auto; } - + .el-table__cell { padding: 8px 0; vertical-align: middle; } - + .el-input-number { width: 100% !important; } - + .el-textarea__inner { resize: none; min-height: 60px !important; @@ -700,7 +760,7 @@ defineExpose({ text-align: center; font-weight: 500; } - + .el-descriptions__content { text-align: center; } @@ -717,4 +777,4 @@ defineExpose({ margin-right: 30px; } } - \ No newline at end of file + diff --git a/web/src/views/bzrkh/assessmentApproval/index.vue b/web/src/views/bzrkh/assessmentApproval/index.vue index 95f88b65..14988a9b 100644 --- a/web/src/views/bzrkh/assessmentApproval/index.vue +++ b/web/src/views/bzrkh/assessmentApproval/index.vue @@ -14,12 +14,7 @@ - + @@ -89,22 +84,16 @@ @@ -117,27 +106,16 @@ - + - + + + \ No newline at end of file