This commit is contained in:
zlwu committed 2025-08-22 15:06:08 +08:00
commit 5e23af2076
44 files changed
+4390 -427

No files matched your search

@@ -14,6 +14,7 @@ import org.dromara.common.core.domain.R;
import org.dromara.common.log.enums.BusinessType; import org.dromara.common.log.enums.BusinessType;
import org.dromara.bzrkh.domain.vo.AssessmentApprovalVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalVo;
import org.dromara.bzrkh.domain.vo.AssessmentApprovalDetailVo; 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.vo.SchemeOptionVo;
import org.dromara.bzrkh.domain.bo.AssessmentApprovalQueryBo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalQueryBo;
import org.dromara.bzrkh.domain.bo.AssessmentApprovalSubmitBo; 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) @Log(title = "班主任考核审核", businessType = BusinessType.UPDATE)
@PostMapping("/batchReject") @PostMapping("/batchReject")
public R<Void> batchReject(@RequestBody BatchRejectBo bo) { public R<Void> batchReject(@Validated @RequestBody BatchApprovalBo bo) {
Long approverUserId = LoginHelper.getUserId(); boolean result = assessmentApprovalService.batchReject(bo.getIds(), bo.getRejectReason(), LoginHelper.getUserId());
boolean result = assessmentApprovalService.batchReject(bo.getIds(), bo.getRejectReason(), approverUserId); return result ? R.ok() : R.fail("批量审核拒绝失败");
return toAjax(result); }
/**
* 删除异常的审批记录(管理员专用)
* 用于清理审批列表中显示但实际已被删除的异常数据
*/
@SaCheckPermission("bzrkh:assessmentApproval:delete")
@Log(title = "班主任考核审核", businessType = BusinessType.DELETE)
@DeleteMapping("/deleteAbnormalRecord")
public R<Void> 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); ExcelUtil.exportExcel(list, "班主任考核审核数据", AssessmentApprovalVo.class, response);
} }
/**
* 获取评价等级统计数据
*/
@SaCheckPermission("bzrkh:assessmentApproval:query")
@GetMapping("/evaluationStats")
public R<EvaluationLevelStatsVo> getEvaluationLevelStats(@RequestParam @NotNull(message = "计划ID不能为空") Long planId) {
EvaluationLevelStatsVo stats = assessmentApprovalService.getEvaluationLevelStats(planId);
return R.ok(stats);
}
/** /**
* 批量拒绝请求对象 * 批量拒绝请求对象
*/ */
@@ -4,6 +4,7 @@ import java.math.BigDecimal;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*; 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.TeacherClassVo;
import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo; import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo;
import org.dromara.bzrkh.domain.vo.AssessmentDetailVo; 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.TeacherAssessmentQueryBo;
import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo; import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo;
import org.dromara.bzrkh.service.ITeacherAssessmentService; import org.dromara.bzrkh.service.ITeacherAssessmentService;
@@ -28,6 +30,7 @@ import org.dromara.common.satoken.utils.LoginHelper;
* @author ruoyi * @author ruoyi
* @date 2025-01-27 * @date 2025-01-27
*/ */
@Slf4j
@Validated @Validated
@RequiredArgsConstructor @RequiredArgsConstructor
@RestController @RestController
@@ -68,9 +71,18 @@ public class TeacherAssessmentController extends BaseController {
@Log(title = "班主任考核管理", businessType = BusinessType.UPDATE) @Log(title = "班主任考核管理", businessType = BusinessType.UPDATE)
@PostMapping("/submit") @PostMapping("/submit")
public R<Void> submitAssessment(@RequestBody TeacherAssessmentSubmitRequest request) { public R<Void> submitAssessment(@RequestBody TeacherAssessmentSubmitRequest request) {
try {
Long teacherId = LoginHelper.getUserId(); Long teacherId = LoginHelper.getUserId();
boolean result = teacherAssessmentService.submitAssessment(request.getPlanId(), request.getClassId(), teacherId); boolean result = teacherAssessmentService.submitAssessment(request.getPlanId(), request.getClassId(), teacherId);
return toAjax(result); 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) @Log(title = "班主任考核管理", businessType = BusinessType.INSERT)
@PostMapping("/submitScore") @PostMapping("/submitScore")
public R<Void> submitAssessmentScore(@RequestBody AssessmentSubmitBo bo) { public R<Void> submitAssessmentScore(@RequestBody AssessmentSubmitBo bo) {
try {
Long teacherId = LoginHelper.getUserId(); Long teacherId = LoginHelper.getUserId();
boolean result = teacherAssessmentService.submitAssessmentScore(bo, teacherId); boolean result = teacherAssessmentService.submitAssessmentScore(bo, teacherId);
return toAjax(result); 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); return R.ok("学生人数: " + studentCount + ", 计算系数: " + coefficient);
} }
/**
* 查询班级学生违纪记录和奖励记录
*/
@SaCheckPermission("bzrkh:teacherAssessment:detail")
@GetMapping("/classStudentRecords")
public R<ClassStudentRecordsVo> getClassStudentRecords(@RequestParam Long classId) {
ClassStudentRecordsVo records = teacherAssessmentService.queryClassStudentRecords(classId);
return R.ok(records);
}
/** /**
* 提交考核请求对象 * 提交考核请求对象
*/ */
@@ -6,7 +6,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.util.Date; import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import java.math.BigDecimal;
import java.io.Serial; 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; private String evaluationLevel;
/** /**
* 审核状态(0=待审核 1=审核通过 2=审核不通过) * 审核状态(9=草稿 0=待审核 1=审核通过 2=审核不通过)
*/ */
private String auditStatus; private String auditStatus;
/** /**
* 最终得分 * 最终得分
*/ */
private BigDecimal finalScore; private Double finalScore;
/** /**
* 提交时间 * 提交时间
@@ -133,4 +132,10 @@ public class BmzrAssessmentScore extends TenantEntity {
*/ */
private String superiorOverallComment; private String superiorOverallComment;
/**
* 逻辑删除标志(0代表存在 1代表删除)
*/
@TableLogic
private Integer deleted;
} }
@@ -9,7 +9,6 @@ import org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo;
import org.dromara.bzrkh.domain.vo.SpecialWorkIndicatorVo; import org.dromara.bzrkh.domain.vo.SpecialWorkIndicatorVo;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
/** /**
@@ -42,7 +41,7 @@ public class AssessmentSubmitBo extends BaseEntity {
/** /**
* 班级扣分 * 班级扣分
*/ */
private BigDecimal classDeduction; private Double classDeduction;
/** /**
* 班级扣分意见 * 班级扣分意见
@@ -2,6 +2,7 @@ package org.dromara.bzrkh.domain.bo;
import lombok.Data; import lombok.Data;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotBlank;
import java.util.List; import java.util.List;
@@ -19,4 +20,9 @@ public class BatchApprovalBo {
*/ */
@NotEmpty(message = "审核ID列表不能为空") @NotEmpty(message = "审核ID列表不能为空")
private List<Long> ids; private List<Long> ids;
/**
* 拒绝原因(批量拒绝时必填)
*/
private String rejectReason;
} }
@@ -35,10 +35,15 @@ public class AssessmentApprovalSpecialWorkVo implements Serializable {
// 自评相关 // 自评相关
/** /**
* 自评分数 * 自评分数(兼容字段)
*/ */
private BigDecimal score; private BigDecimal score;
/**
* 自评分数
*/
private BigDecimal selfScore;
/** /**
* 自评意见 * 自评意见
*/ */
@@ -5,7 +5,6 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date; 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;
/** /**
* 自评意见 * 自评意见
@@ -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<AssessmentScoreIndicatorVo> routineWorkScores;
/**
* 班级管理实效自评数据
*/
private AssessmentScoreIndicatorVo classDeductionScore;
/**
* 特色工作自评数据列表
*/
private List<AssessmentScoreSpecialWorkVo> specialWorkScores;
/**
* 自我总体评价
*/
private String selfOverallComment;
/**
* 自评提交时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date selfSubmitTime;
/**
* 审核状态
*/
private String auditStatus;
/**
* 是否有自评数据
*/
private Boolean hasAssessmentData;
}
@@ -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;
}
@@ -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;
}
@@ -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<StudentDisciplineRecordVo> disciplineRecords;
/**
* 学生奖励记录列表
*/
private List<StudentRewardRecordVo> rewardRecords;
/**
* 违纪记录总数
*/
private Integer disciplineCount;
/**
* 奖励记录总数
*/
private Integer rewardCount;
}
@@ -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<ScoreRankingVo> scoreRankings;
/**
* 评价等级规则
*/
private EvaluationLevelRules evaluationLevelRules;
@Data
public static class EvaluationLevelRules {
/**
* A等最大占比(如20%)
*/
private Double aLevelMaxPercentage;
/**
* 及格分数(如60分)
*/
private Double passScore;
}
}
@@ -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;
}
@@ -5,7 +5,6 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
/** /**
@@ -33,7 +32,7 @@ public class SpecialWorkIndicatorVo implements Serializable {
/** /**
* 分值 * 分值
*/ */
private BigDecimal score; private Double score;
/** /**
* 自评意见 * 自评意见
@@ -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;
}
@@ -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;
}
@@ -5,6 +5,8 @@ import org.dromara.bzrkh.domain.vo.AssessmentApprovalDetailVo;
import org.dromara.bzrkh.domain.vo.AssessmentApprovalIndicatorVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalIndicatorVo;
import org.dromara.bzrkh.domain.vo.AssessmentApprovalSpecialWorkVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalSpecialWorkVo;
import org.dromara.bzrkh.domain.vo.SchemeOptionVo; 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.bo.AssessmentApprovalQueryBo;
import org.dromara.bzrkh.domain.BmzrAssessmentScore; import org.dromara.bzrkh.domain.BmzrAssessmentScore;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
@@ -130,4 +132,22 @@ public interface AssessmentApprovalMapper extends BaseMapperPlus<BmzrAssessmentS
* @return 方案选项列表 * @return 方案选项列表
*/ */
List<SchemeOptionVo> getSchemeOptions(); List<SchemeOptionVo> getSchemeOptions();
/**
* 删除异常的审批记录(管理员专用)
* 逻辑删除指定计划下指定用户的所有评分记录
*
* @param planId 计划ID
* @param evaluatedUserId 被评价用户ID
* @return 删除记录数
*/
int deleteAbnormalAssessmentRecord(@Param("planId") Long planId, @Param("evaluatedUserId") Long evaluatedUserId);
/**
* 根据计划ID查询所有审批数据
*
* @param planId 计划ID
* @return 审批数据列表
*/
List<AssessmentApprovalVo> selectApprovalListByPlan(@Param("planId") Long planId);
} }
@@ -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<BmzrAssessmentScore, BmzrAssessmentScore> {
/**
* 获取自评数据基本信息
*
* @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<AssessmentScoreIndicatorVo> 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<AssessmentScoreSpecialWorkVo> 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);
}
@@ -7,7 +7,9 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
import java.util.Collection;
/** /**
* 班主任考核计划Mapper接口 * 班主任考核计划Mapper接口
@@ -27,4 +29,11 @@ public interface BmzrAssessmentPlanMapper extends BaseMapperPlus<BmzrAssessmentP
*/ */
IPage<BmzrAssessmentPlanVo> selectAssessmentPlanPageWithScheme(Page<BmzrAssessmentPlanVo> page, BmzrAssessmentPlanBo bo); IPage<BmzrAssessmentPlanVo> selectAssessmentPlanPageWithScheme(Page<BmzrAssessmentPlanVo> page, BmzrAssessmentPlanBo bo);
/**
* 根据考核计划ID批量逻辑删除关联的考核得分数据
* @param planIds 考核计划ID集合
* @return 影响行数
*/
int deleteAssessmentScoresByPlanIds(@Param("planIds") Collection<Long> planIds);
} }
@@ -5,6 +5,8 @@ import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo;
import org.dromara.bzrkh.domain.vo.ClassDetailVo; import org.dromara.bzrkh.domain.vo.ClassDetailVo;
import org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo; import org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo;
import org.dromara.bzrkh.domain.vo.SpecialWorkIndicatorVo; 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.bzrkh.domain.bo.TeacherAssessmentQueryBo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
@@ -67,13 +69,24 @@ public interface TeacherAssessmentMapper extends BaseMapperPlus<Object, Object>
List<SpecialWorkIndicatorVo> selectSpecialWorkIndicators(); List<SpecialWorkIndicatorVo> selectSpecialWorkIndicators();
/** /**
* 查询已保存的评分数据 * 查询已保存的评分数据(草稿状态)
* *
* @param planId 计划ID * @param planId 计划ID
* @param teacherId 班主任ID * @param teacherId 班主任ID
* @param classId 班级ID
* @return 评分数据列表 * @return 评分数据列表
*/ */
List<AssessmentIndicatorScoreVo> selectSavedAssessmentScores(@Param("planId") Long planId, @Param("teacherId") Long teacherId); List<AssessmentIndicatorScoreVo> selectSavedAssessmentScores(@Param("planId") Long planId, @Param("teacherId") Long teacherId, @Param("classId") Long classId);
/**
* 查询已提交的评分数据(待审核状态,用于撤销功能)
*
* @param planId 计划ID
* @param teacherId 班主任ID
* @param classId 班级ID
* @return 评分数据列表
*/
List<AssessmentIndicatorScoreVo> selectSubmittedAssessmentScores(@Param("planId") Long planId, @Param("teacherId") Long teacherId, @Param("classId") Long classId);
/** /**
* 根据计划ID查询方案ID * 根据计划ID查询方案ID
@@ -92,12 +105,13 @@ public interface TeacherAssessmentMapper extends BaseMapperPlus<Object, Object>
Long selectIndicatorIdByCode(@Param("indicatorCode") String indicatorCode); Long selectIndicatorIdByCode(@Param("indicatorCode") String indicatorCode);
/** /**
* 逻辑删除指定计划和教师的评分数据 * 逻辑删除指定计划、班级和教师的评分数据
* *
* @param planId 计划ID * @param planId 计划ID
* @param teacherId 教师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<Object, Object>
@Param("indicatorId") Long indicatorId, @Param("indicatorId") Long indicatorId,
@Param("teacherId") Long teacherId, @Param("teacherId") Long teacherId,
@Param("remark") String remark); @Param("remark") String remark);
/**
* 根据班级ID查询班级名称
*
* @param classId 班级ID
* @return 班级名称
*/
String selectClassNameById(@Param("classId") Long classId);
/**
* 根据班级ID查询学生违纪记录
*
* @param classId 班级ID
* @return 学生违纪记录列表
*/
List<StudentDisciplineRecordVo> selectStudentDisciplineRecordsByClassId(@Param("classId") Long classId);
/**
* 根据班级ID查询学生奖励记录
*
* @param classId 班级ID
* @return 学生奖励记录列表
*/
List<StudentRewardRecordVo> selectStudentRewardRecordsByClassId(@Param("classId") Long classId);
} }
@@ -2,6 +2,7 @@ package org.dromara.bzrkh.service;
import org.dromara.bzrkh.domain.vo.AssessmentApprovalVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalVo;
import org.dromara.bzrkh.domain.vo.AssessmentApprovalDetailVo; 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.vo.SchemeOptionVo;
import org.dromara.bzrkh.domain.bo.AssessmentApprovalQueryBo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalQueryBo;
import org.dromara.bzrkh.domain.bo.AssessmentApprovalSubmitBo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalSubmitBo;
@@ -73,10 +74,28 @@ public interface IAssessmentApprovalService {
*/ */
boolean batchReject(List<Long> ids, String rejectReason, Long approverUserId); boolean batchReject(List<Long> ids, String rejectReason, Long approverUserId);
/**
* 删除异常的审批记录(管理员专用)
* 用于清理审批列表中显示但实际已被删除的异常数据
*
* @param planId 计划ID
* @param evaluatedUserId 被评价用户ID
* @return 是否成功
*/
boolean deleteAbnormalRecord(Long planId, Long evaluatedUserId);
/** /**
* 获取考核方案下拉选项 * 获取考核方案下拉选项
* *
* @return 方案选项列表 * @return 方案选项列表
*/ */
List<SchemeOptionVo> getSchemeOptions(); List<SchemeOptionVo> getSchemeOptions();
/**
* 获取评价等级统计数据
*
* @param planId 计划ID
* @return 评价等级统计数据
*/
EvaluationLevelStatsVo getEvaluationLevelStats(Long planId);
} }
@@ -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);
}
@@ -3,6 +3,7 @@ package org.dromara.bzrkh.service;
import org.dromara.bzrkh.domain.vo.TeacherClassVo; import org.dromara.bzrkh.domain.vo.TeacherClassVo;
import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo; import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo;
import org.dromara.bzrkh.domain.vo.AssessmentDetailVo; 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.TeacherAssessmentQueryBo;
import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo; import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -93,4 +94,12 @@ public interface ITeacherAssessmentService {
* @return 计算出的系数 * @return 计算出的系数
*/ */
BigDecimal testStudentCountCoefficient(int studentCount); BigDecimal testStudentCountCoefficient(int studentCount);
/**
* 查询班级学生违纪记录和奖励记录
*
* @param classId 班级ID
* @return 班级学生记录
*/
ClassStudentRecordsVo queryClassStudentRecords(Long classId);
} }
@@ -10,10 +10,16 @@ import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.bzrkh.domain.vo.AssessmentApprovalVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalVo;
import org.dromara.bzrkh.domain.vo.AssessmentApprovalDetailVo; import org.dromara.bzrkh.domain.vo.AssessmentApprovalDetailVo;
import org.dromara.bzrkh.domain.vo.AssessmentApprovalIndicatorVo; 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.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.SchemeOptionVo;
import org.dromara.bzrkh.domain.vo.ClassDetailVo; import org.dromara.bzrkh.domain.vo.ClassDetailVo;
import org.dromara.bzrkh.domain.vo.CoefficientVo; 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.AssessmentApprovalQueryBo;
import org.dromara.bzrkh.domain.bo.AssessmentApprovalSubmitBo; import org.dromara.bzrkh.domain.bo.AssessmentApprovalSubmitBo;
import org.dromara.bzrkh.domain.bo.AssessmentApprovalIndicatorSubmitBo; 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.mapper.AssessmentApprovalMapper;
import org.dromara.bzrkh.service.IAssessmentApprovalService; import org.dromara.bzrkh.service.IAssessmentApprovalService;
import org.dromara.bzrkh.service.ITeacherAssessmentService; import org.dromara.bzrkh.service.ITeacherAssessmentService;
import org.dromara.bzrkh.service.IAssessmentScoreService;
import lombok.extern.slf4j.Slf4j;
import java.util.List; import java.util.List;
import java.util.Date; 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业务层处理 * 班主任考核审核Service业务层处理
@@ -31,12 +44,14 @@ import java.util.Date;
* @author ruoyi * @author ruoyi
* @date 2025-01-28 * @date 2025-01-28
*/ */
@Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
@Service @Service
public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService { public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService {
private final AssessmentApprovalMapper assessmentApprovalMapper; private final AssessmentApprovalMapper assessmentApprovalMapper;
private final ITeacherAssessmentService teacherAssessmentService; private final ITeacherAssessmentService teacherAssessmentService;
private final IAssessmentScoreService assessmentScoreService;
@Override @Override
public TableDataInfo<AssessmentApprovalVo> queryPageList(AssessmentApprovalQueryBo bo, PageQuery pageQuery) { public TableDataInfo<AssessmentApprovalVo> queryPageList(AssessmentApprovalQueryBo bo, PageQuery pageQuery) {
@@ -63,6 +78,8 @@ public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService
@Override @Override
public AssessmentApprovalDetailVo getApprovalDetail(Long planId, Long classId, Long evaluatedUserId) { public AssessmentApprovalDetailVo getApprovalDetail(Long planId, Long classId, Long evaluatedUserId) {
log.info("获取审批详情 - planId: {}, classId: {}, evaluatedUserId: {}", planId, classId, evaluatedUserId);
// 1. 获取基本信息 // 1. 获取基本信息
AssessmentApprovalDetailVo detail = assessmentApprovalMapper.getApprovalBasicInfo(planId, classId, evaluatedUserId); AssessmentApprovalDetailVo detail = assessmentApprovalMapper.getApprovalBasicInfo(planId, classId, evaluatedUserId);
if (detail == null) { if (detail == null) {
@@ -91,29 +108,170 @@ public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService
coefficient.setBoardingCoefficient(assessmentDetail.getCoefficient().getBoardingCoefficient()); coefficient.setBoardingCoefficient(assessmentDetail.getCoefficient().getBoardingCoefficient());
detail.setCoefficient(coefficient); detail.setCoefficient(coefficient);
} catch (Exception e) { } catch (Exception e) {
log.warn("获取班级信息和系数信息失败: {}", e.getMessage());
// 如果获取失败,使用默认值 // 如果获取失败,使用默认值
detail.setClassDetail(new ClassDetailVo()); detail.setClassDetail(new ClassDetailVo());
detail.setCoefficient(new CoefficientVo()); detail.setCoefficient(new CoefficientVo());
} }
// 3. 获取班主任常规工作指标列表 // 3. 使用统一的自评数据服务获取完整的自评数据
AssessmentScoreDetailVo scoreDetail = assessmentScoreService.getAssessmentScoreDetail(planId, classId, evaluatedUserId);
if (scoreDetail != null && scoreDetail.getHasAssessmentData()) {
log.info("通过统一服务获取到自评数据 - 自我总体评价: {}", scoreDetail.getSelfOverallComment());
// 3.1 设置自我总体评价
detail.setSelfOverallComment(scoreDetail.getSelfOverallComment());
// 3.2 转换班主任常规工作自评数据
List<AssessmentApprovalIndicatorVo> routineWorkIndicators = convertRoutineWorkScores(scoreDetail.getRoutineWorkScores());
detail.setRoutineWorkIndicators(routineWorkIndicators);
log.info("转换常规工作自评数据 - 数量: {}", routineWorkIndicators.size());
// 3.3 转换班级管理实效自评数据
AssessmentApprovalIndicatorVo classDeductionIndicator = convertClassDeductionScore(scoreDetail.getClassDeductionScore());
detail.setClassDeductionIndicator(classDeductionIndicator);
if (classDeductionIndicator != null) {
log.info("转换班级管理实效自评数据 - 自评分数: {}", classDeductionIndicator.getSelfScore());
}
// 3.4 转换特色工作自评数据
List<AssessmentApprovalSpecialWorkVo> specialWorkIndicators = convertSpecialWorkScores(scoreDetail.getSpecialWorkScores());
detail.setSpecialWorkIndicators(specialWorkIndicators);
log.info("转换特色工作自评数据 - 数量: {}", specialWorkIndicators.size());
} else {
log.warn("未获取到自评数据,使用原有查询方式作为备用");
// 备用方案:使用原有的查询方式
List<AssessmentApprovalIndicatorVo> routineWorkIndicators = List<AssessmentApprovalIndicatorVo> routineWorkIndicators =
assessmentApprovalMapper.getRoutineWorkIndicators(planId, classId, evaluatedUserId); assessmentApprovalMapper.getRoutineWorkIndicators(planId, classId, evaluatedUserId);
detail.setRoutineWorkIndicators(routineWorkIndicators); detail.setRoutineWorkIndicators(routineWorkIndicators);
// 4. 获取班级扣分指标(班级管理实效)
AssessmentApprovalIndicatorVo classDeductionIndicator = AssessmentApprovalIndicatorVo classDeductionIndicator =
assessmentApprovalMapper.getClassDeductionIndicator(planId, classId, evaluatedUserId); assessmentApprovalMapper.getClassDeductionIndicator(planId, classId, evaluatedUserId);
detail.setClassDeductionIndicator(classDeductionIndicator); detail.setClassDeductionIndicator(classDeductionIndicator);
// 5. 获取特色工作指标列表
List<AssessmentApprovalSpecialWorkVo> specialWorkIndicators = List<AssessmentApprovalSpecialWorkVo> specialWorkIndicators =
assessmentApprovalMapper.getSpecialWorkIndicators(planId, classId, evaluatedUserId); assessmentApprovalMapper.getSpecialWorkIndicators(planId, classId, evaluatedUserId);
detail.setSpecialWorkIndicators(specialWorkIndicators); detail.setSpecialWorkIndicators(specialWorkIndicators);
}
// 4. 验证自评数据完整性
validateSelfAssessmentData(detail);
return detail; return detail;
} }
/**
* 转换班主任常规工作自评数据
*/
private List<AssessmentApprovalIndicatorVo> convertRoutineWorkScores(List<AssessmentScoreIndicatorVo> routineWorkScores) {
if (routineWorkScores == null) {
return new ArrayList<>();
}
List<AssessmentApprovalIndicatorVo> 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<AssessmentApprovalSpecialWorkVo> convertSpecialWorkScores(List<AssessmentScoreSpecialWorkVo> specialWorkScores) {
if (specialWorkScores == null) {
return new ArrayList<>();
}
List<AssessmentApprovalSpecialWorkVo> 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 @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public boolean submitApproval(AssessmentApprovalSubmitBo bo, Long approverUserId) { public boolean submitApproval(AssessmentApprovalSubmitBo bo, Long approverUserId) {
@@ -210,4 +368,176 @@ public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService
public List<SchemeOptionVo> getSchemeOptions() { public List<SchemeOptionVo> getSchemeOptions() {
return assessmentApprovalMapper.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<AssessmentApprovalVo> 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<ScoreRankingVo> 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;
}
} }
@@ -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<AssessmentScoreIndicatorVo> 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<AssessmentScoreSpecialWorkVo> 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;
}
}
@@ -121,9 +121,28 @@ public class BmzrAssessmentPlanServiceImpl implements IBmzrAssessmentPlanService
// 删除前校验 // 删除前校验
// 这里可以添加删除前的业务校验逻辑 // 这里可以添加删除前的业务校验逻辑
} }
// 1. 先删除关联的考核得分数据
deleteRelatedAssessmentScores(ids);
// 2. 再删除考核计划主表数据
return baseMapper.deleteBatchIds(ids) > 0; return baseMapper.deleteBatchIds(ids) > 0;
} }
/**
* 删除关联的考核得分数据
* @param planIds 考核计划ID集合
*/
private void deleteRelatedAssessmentScores(Collection<Long> planIds) {
if (planIds == null || planIds.isEmpty()) {
return;
}
// 通过SQL更新关联表的deleted字段,实现逻辑删除
// 这里需要直接执行SQL,因为可能没有对应的Service
baseMapper.deleteAssessmentScoresByPlanIds(planIds);
}
/** /**
* 修改考核计划状态 * 修改考核计划状态
*/ */
@@ -13,6 +13,9 @@ import org.dromara.bzrkh.domain.vo.ClassDetailVo;
import org.dromara.bzrkh.domain.vo.CoefficientVo; import org.dromara.bzrkh.domain.vo.CoefficientVo;
import org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo; import org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo;
import org.dromara.bzrkh.domain.vo.SpecialWorkIndicatorVo; 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.TeacherAssessmentQueryBo;
import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo; import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo;
import org.dromara.bzrkh.mapper.TeacherAssessmentMapper; 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.bzrkh.service.ITeacherAssessmentService;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.bzrkh.domain.BmzrAssessmentScore; import org.dromara.bzrkh.domain.BmzrAssessmentScore;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
@@ -61,9 +65,16 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService {
*/ */
@Override @Override
public TableDataInfo<BmzrAssessmentPlanVo> queryTeacherAssessmentPlanPageList(TeacherAssessmentQueryBo bo, PageQuery pageQuery) { public TableDataInfo<BmzrAssessmentPlanVo> queryTeacherAssessmentPlanPageList(TeacherAssessmentQueryBo bo, PageQuery pageQuery) {
log.info("🔍 查询班主任考核计划列表 - 参数: teacherId={}, classId={}, planName={}, planStatus={}",
bo.getTeacherId(), bo.getClassId(), bo.getPlanName(), bo.getPlanStatus());
Page<BmzrAssessmentPlanVo> page = pageQuery.build(); Page<BmzrAssessmentPlanVo> page = pageQuery.build();
List<BmzrAssessmentPlanVo> list = teacherAssessmentMapper.selectTeacherAssessmentPlanList(bo); List<BmzrAssessmentPlanVo> 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 total = list.size();
int start = (int) ((page.getCurrent() - 1) * page.getSize()); int start = (int) ((page.getCurrent() - 1) * page.getSize());
@@ -87,12 +98,69 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService {
*/ */
@Override @Override
public boolean submitAssessment(Long planId, Long classId, Long teacherId) { public boolean submitAssessment(Long planId, Long classId, Long teacherId) {
// TODO: 实现提交考核逻辑 log.info("开始提交考核到审批流程 - planId: {}, classId: {}, teacherId: {}", planId, classId, teacherId);
// 1. 验证班主任是否有权限提交该班级的考核
// 2. 验证考核计划是否有效 try {
// 3. 创建或更新考核记录 // 参数验证
// 4. 更新考核状态 if (planId == null || classId == null || teacherId == null) {
log.error("参数验证失败 - planId: {}, classId: {}, teacherId: {}", planId, classId, teacherId);
throw new RuntimeException("必要参数不能为空");
}
// 1. 验证是否存在草稿状态的评分数据
log.info("1. 验证是否存在草稿状态的评分数据...");
List<AssessmentIndicatorScoreVo> 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<BmzrAssessmentScore>()
.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; 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); detailVo.setSpecialWorkIndicators(specialWorkIndicators);
// 6. 获取已保存的评分数据(如果有) // 6. 获取已保存的评分数据(如果有)
List<AssessmentIndicatorScoreVo> savedScores = teacherAssessmentMapper.selectSavedAssessmentScores(planId, teacherId); List<AssessmentIndicatorScoreVo> savedScores = teacherAssessmentMapper.selectSavedAssessmentScores(planId, teacherId, classId);
if (savedScores != null && !savedScores.isEmpty()) { if (savedScores != null && !savedScores.isEmpty()) {
// 将已保存的评分数据合并到指标中 // 将已保存的评分数据合并到指标中
mergeAssessmentScores(detailVo, savedScores); mergeAssessmentScores(detailVo, savedScores);
@@ -169,18 +237,43 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService {
*/ */
@Override @Override
public boolean submitAssessmentScore(AssessmentSubmitBo bo, Long teacherId) { public boolean submitAssessmentScore(AssessmentSubmitBo bo, Long teacherId) {
try { log.info("开始提交考核评分数据 - planId: {}, classId: {}, teacherId: {}", bo.getPlanId(), bo.getClassId(), teacherId);
// 1. 先逻辑删除该计划下该教师的历史评分数据
teacherAssessmentMapper.deleteAssessmentScoresByPlanAndTeacher(bo.getPlanId(), teacherId);
try {
// 参数验证
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()); 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(); String currentUserName = LoginHelper.getUsername();
Long currentDeptId = LoginHelper.getDeptId(); Long currentDeptId = LoginHelper.getDeptId();
Date now = new Date(); Date now = new Date();
log.info("当前用户信息 - username: {}, deptId: {}", currentUserName, currentDeptId);
// 2. 插入班主任常规工作指标评分 // 2. 插入班主任常规工作指标评分
if (bo.getRoutineWorkScores() != null && !bo.getRoutineWorkScores().isEmpty()) { if (bo.getRoutineWorkScores() != null && !bo.getRoutineWorkScores().isEmpty()) {
for (AssessmentIndicatorScoreVo score : bo.getRoutineWorkScores()) { 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());
try {
BmzrAssessmentScore assessmentScore = new BmzrAssessmentScore(); BmzrAssessmentScore assessmentScore = new BmzrAssessmentScore();
assessmentScore.setPlanId(bo.getPlanId()); assessmentScore.setPlanId(bo.getPlanId());
assessmentScore.setSchemeId(schemeId); assessmentScore.setSchemeId(schemeId);
@@ -190,20 +283,40 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService {
assessmentScore.setEvaluatedDeptId(currentDeptId); assessmentScore.setEvaluatedDeptId(currentDeptId);
assessmentScore.setSelfScore(score.getSelfScore()); assessmentScore.setSelfScore(score.getSelfScore());
assessmentScore.setSelfComment(score.getSelfComment()); assessmentScore.setSelfComment(score.getSelfComment());
assessmentScore.setSelfSubmitTime(now); // 保存操作不设置 self_submit_time,只有提交到审批流程时才设置
// assessmentScore.setSelfSubmitTime(now);
assessmentScore.setSubmitTime(now); assessmentScore.setSubmitTime(now);
assessmentScore.setAuditStatus("0"); assessmentScore.setAuditStatus("9"); // 设置为草稿状态
// 设置班级ID和自我总体评价 // 设置班级ID和自我总体评价
assessmentScore.setClassId(bo.getClassId()); assessmentScore.setClassId(bo.getClassId());
assessmentScore.setSelfOverallComment(bo.getOverallComment()); assessmentScore.setSelfOverallComment(bo.getOverallComment());
assessmentScoreMapper.insert(assessmentScore); 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. 插入班级扣分指标评分 // 3. 插入班级扣分指标评分
log.info("4. 开始插入班级扣分指标评分...");
Long classDeductionIndicatorId = teacherAssessmentMapper.selectIndicatorIdByCode("bzrwjkf001"); 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(); BmzrAssessmentScore assessmentScore = new BmzrAssessmentScore();
assessmentScore.setPlanId(bo.getPlanId()); assessmentScore.setPlanId(bo.getPlanId());
assessmentScore.setSchemeId(schemeId); assessmentScore.setSchemeId(schemeId);
@@ -213,21 +326,41 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService {
assessmentScore.setEvaluatedDeptId(currentDeptId); assessmentScore.setEvaluatedDeptId(currentDeptId);
assessmentScore.setSelfScore(bo.getClassDeduction()); assessmentScore.setSelfScore(bo.getClassDeduction());
assessmentScore.setSelfComment(bo.getClassDeductionComment()); assessmentScore.setSelfComment(bo.getClassDeductionComment());
assessmentScore.setSelfSubmitTime(now); // 保存操作不设置 self_submit_time,只有提交到审批流程时才设置
// assessmentScore.setSelfSubmitTime(now);
assessmentScore.setSubmitTime(now); assessmentScore.setSubmitTime(now);
assessmentScore.setAuditStatus("0"); assessmentScore.setAuditStatus("9"); // 设置为草稿状态
// 设置班级ID和自我总体评价 // 设置班级ID和自我总体评价
assessmentScore.setClassId(bo.getClassId()); assessmentScore.setClassId(bo.getClassId());
assessmentScore.setSelfOverallComment(bo.getOverallComment()); 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. 插入特色工作指标评分 // 4. 插入特色工作指标评分
if (bo.getSpecialWorkScores() != null && !bo.getSpecialWorkScores().isEmpty()) { 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()); 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(); BmzrAssessmentScore assessmentScore = new BmzrAssessmentScore();
assessmentScore.setPlanId(bo.getPlanId()); assessmentScore.setPlanId(bo.getPlanId());
assessmentScore.setSchemeId(schemeId); assessmentScore.setSchemeId(schemeId);
@@ -237,24 +370,39 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService {
assessmentScore.setEvaluatedDeptId(currentDeptId); assessmentScore.setEvaluatedDeptId(currentDeptId);
assessmentScore.setSelfScore(score.getScore()); assessmentScore.setSelfScore(score.getScore());
assessmentScore.setSelfComment(score.getSelfComment()); assessmentScore.setSelfComment(score.getSelfComment());
assessmentScore.setSelfSubmitTime(now); // 保存操作不设置 self_submit_time,只有提交到审批流程时才设置
// assessmentScore.setSelfSubmitTime(now);
assessmentScore.setSubmitTime(now); assessmentScore.setSubmitTime(now);
assessmentScore.setAuditStatus("0"); assessmentScore.setAuditStatus("9"); // 设置为草稿状态
// 设置班级ID和自我总体评价 // 设置班级ID和自我总体评价
assessmentScore.setClassId(bo.getClassId()); assessmentScore.setClassId(bo.getClassId());
assessmentScore.setSelfOverallComment(bo.getOverallComment()); 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; return true;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); log.error("提交考核评分数据失败 - planId: {}, classId: {}, teacherId: {}, error: {}",
return false; 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) { public boolean withdrawAssessment(Long planId, Long classId, Long teacherId) {
try { try {
// 验证是否有权限撤销(只能撤销自己提交的且状态为待审核的考核) // 验证是否有权限撤销(只能撤销自己提交的且状态为待审核的考核)
List<AssessmentIndicatorScoreVo> savedScores = teacherAssessmentMapper.selectSavedAssessmentScores(planId, teacherId); List<AssessmentIndicatorScoreVo> submittedScores = teacherAssessmentMapper.selectSubmittedAssessmentScores(planId, teacherId, classId);
if (savedScores == null || savedScores.isEmpty()) { if (submittedScores == null || submittedScores.isEmpty()) {
log.warn("未找到可撤销的考核提交记录,计划ID: {}, 教师ID: {}", planId, teacherId); log.warn("未找到可撤销的考核提交记录,计划ID: {}, 教师ID: {}, 班级ID: {}", planId, teacherId, classId);
return false; return false;
} }
// 检查审核状态,只有待审核状态("0")的才能撤销 // 检查审核状态,只有待审核状态("0")的才能撤销
boolean canWithdraw = savedScores.stream().anyMatch(score -> "0".equals(score.getAuditStatus())); boolean canWithdraw = submittedScores.stream().anyMatch(score -> "0".equals(score.getAuditStatus()));
if (!canWithdraw) { if (!canWithdraw) {
log.warn("考核已审核,无法撤销,计划ID: {}, 教师ID: {}", planId, teacherId); log.warn("考核已审核,无法撤销,计划ID: {}, 教师ID: {}", planId, teacherId);
return false; return false;
} }
// 逻辑删除该计划下该教师的所有评分数据 // 将待审核状态的评分记录恢复为草稿状态
teacherAssessmentMapper.deleteAssessmentScoresByPlanAndTeacher(planId, teacherId); assessmentScoreMapper.update(null,
new LambdaUpdateWrapper<BmzrAssessmentScore>()
.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; return true;
} catch (Exception e) { } catch (Exception e) {
log.error("撤销考核提交失败,计划ID: {}, 教师ID: {}", planId, teacherId, 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<StudentDisciplineRecordVo> disciplineRecords = teacherAssessmentMapper.selectStudentDisciplineRecordsByClassId(classId);
// 查询班级学生奖励记录
List<StudentRewardRecordVo> 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;
}
} }
@@ -67,7 +67,8 @@
<result property="id" column="id"/> <result property="id" column="id"/>
<result property="indicatorCode" column="indicator_code"/> <result property="indicatorCode" column="indicator_code"/>
<result property="indicatorName" column="indicator_name"/> <result property="indicatorName" column="indicator_name"/>
<result property="score" column="score"/> <result property="score" column="self_score"/>
<result property="selfScore" column="self_score"/>
<result property="selfComment" column="self_comment"/> <result property="selfComment" column="self_comment"/>
<result property="superiorScore" column="superior_score"/> <result property="superiorScore" column="superior_score"/>
<result property="superiorComment" column="superior_comment"/> <result property="superiorComment" column="superior_comment"/>
@@ -148,22 +149,28 @@
<!-- 获取考核审核基本信息 --> <!-- 获取考核审核基本信息 -->
<select id="getApprovalBasicInfo" resultMap="AssessmentApprovalDetailVoResult"> <select id="getApprovalBasicInfo" resultMap="AssessmentApprovalDetailVoResult">
SELECT SELECT
s.id, MIN(s.id) as id,
s.plan_id, s.plan_id,
s.class_id, s.class_id,
s.self_overall_comment, -- 确保获取自我总体评价(可能存在于不同指标中)
s.superior_overall_comment, COALESCE(
s.audit_status, MAX(CASE WHEN s.self_overall_comment IS NOT NULL AND s.self_overall_comment != ''
s.submit_time, THEN s.self_overall_comment END),
s.create_by, ''
s.create_time, ) as self_overall_comment,
s.update_by, MAX(s.superior_overall_comment) as superior_overall_comment,
s.update_time MAX(s.audit_status) as audit_status,
MAX(s.submit_time) as submit_time,
MAX(s.create_by) as create_by,
MAX(s.create_time) as create_time,
MAX(s.update_by) as update_by,
MAX(s.update_time) as update_time
FROM bmzr_assessment_score s FROM bmzr_assessment_score s
WHERE s.plan_id = #{planId} WHERE s.plan_id = #{planId}
AND s.class_id = #{classId} AND s.class_id = #{classId}
AND s.evaluated_user_id = #{evaluatedUserId} AND s.evaluated_user_id = #{evaluatedUserId}
AND s.deleted = 0 AND s.deleted = 0
GROUP BY s.plan_id, s.class_id, s.evaluated_user_id
LIMIT 1 LIMIT 1
</select> </select>
@@ -223,7 +230,7 @@
s.id, s.id,
i.indicator_code, i.indicator_code,
i.indicator_name, i.indicator_name,
s.self_score as score, s.self_score,
s.self_comment, s.self_comment,
s.superior_score, s.superior_score,
s.superior_comment, s.superior_comment,
@@ -278,16 +285,52 @@
AND deleted = 0 AND deleted = 0
</update> </update>
<!-- 获取考核方案下拉选项 --> <!-- 获取考核方案选项 -->
<select id="getSchemeOptions" resultMap="SchemeOptionVoResult"> <select id="getSchemeOptions" resultType="org.dromara.bzrkh.domain.vo.SchemeOptionVo">
SELECT SELECT
id, id as value,
scheme_code, scheme_name as label
scheme_name
FROM bmzr_assessment_scheme FROM bmzr_assessment_scheme
WHERE status = '0' WHERE deleted = 0
AND deleted = 0 AND status = '0'
ORDER BY create_time DESC ORDER BY create_time DESC
</select> </select>
<!-- 删除异常的审批记录(管理员专用) -->
<update id="deleteAbnormalAssessmentRecord">
UPDATE bmzr_assessment_score
SET deleted = 1,
update_time = NOW()
WHERE plan_id = #{planId}
AND evaluated_user_id = #{evaluatedUserId}
AND deleted = 0
</update>
<!-- 根据计划ID查询所有审批数据 -->
<select id="selectApprovalListByPlan" resultType="org.dromara.bzrkh.domain.vo.AssessmentApprovalVo">
SELECT DISTINCT
p.id as planId,
p.plan_name as planName,
c.id as classId,
c.class_name as className,
u.user_id as evaluatedUserId,
u.nick_name as evaluatedUserName,
u.dept_id as evaluatedDeptId,
d.dept_name as evaluatedDeptName,
sch.id as schemeId,
sch.scheme_name as schemeName,
sc.audit_status as auditStatus,
sc.create_time as createTime
FROM bmzr_assessment_score sc
LEFT JOIN bmzr_assessment_plan p ON sc.plan_id = p.id AND p.deleted = 0
LEFT JOIN xg_class_msg c ON sc.class_id = c.id AND c.deleted = 0
LEFT JOIN bmzr_assessment_scheme sch ON sc.scheme_id = sch.id AND sch.deleted = 0
LEFT JOIN sys_user u ON sc.evaluated_user_id = u.user_id
LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
WHERE sc.plan_id = #{planId}
AND sc.deleted = 0
AND sc.self_submit_time IS NOT NULL
ORDER BY sc.create_time DESC
</select>
</mapper> </mapper>
@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.bzrkh.mapper.AssessmentScoreMapper">
<!-- 自评数据基本信息结果映射 -->
<resultMap type="org.dromara.bzrkh.domain.vo.AssessmentScoreDetailVo" id="AssessmentScoreDetailVoResult">
<result property="planId" column="plan_id"/>
<result property="classId" column="class_id"/>
<result property="evaluatedUserId" column="evaluated_user_id"/>
<result property="evaluatedUserName" column="evaluated_user_name"/>
<result property="selfOverallComment" column="self_overall_comment"/>
<result property="selfSubmitTime" column="self_submit_time"/>
<result property="auditStatus" column="audit_status"/>
<result property="hasAssessmentData" column="has_assessment_data"/>
</resultMap>
<!-- 自评指标结果映射 -->
<resultMap type="org.dromara.bzrkh.domain.vo.AssessmentScoreIndicatorVo" id="AssessmentScoreIndicatorVoResult">
<result property="id" column="id"/>
<result property="indicatorId" column="indicator_id"/>
<result property="indicatorName" column="indicator_name"/>
<result property="indicatorCode" column="indicator_code"/>
<result property="description" column="description"/>
<result property="score" column="score"/>
<result property="maxScore" column="max_score"/>
<result property="selfScore" column="self_score"/>
<result property="selfComment" column="self_comment"/>
<result property="superiorScore" column="superior_score"/>
<result property="superiorComment" column="superior_comment"/>
</resultMap>
<!-- 特色工作自评结果映射 -->
<resultMap type="org.dromara.bzrkh.domain.vo.AssessmentScoreSpecialWorkVo" id="AssessmentScoreSpecialWorkVoResult">
<result property="id" column="id"/>
<result property="indicatorId" column="indicator_id"/>
<result property="indicatorCode" column="indicator_code"/>
<result property="indicatorName" column="indicator_name"/>
<result property="score" column="self_score"/>
<result property="selfScore" column="self_score"/>
<result property="selfComment" column="self_comment"/>
<result property="superiorScore" column="superior_score"/>
<result property="superiorComment" column="superior_comment"/>
</resultMap>
<!-- 获取自评数据基本信息 -->
<select id="getAssessmentScoreBasicInfo" resultMap="AssessmentScoreDetailVoResult">
SELECT
s.plan_id,
s.class_id,
s.evaluated_user_id,
s.evaluated_user_name,
-- 获取自我总体评价(优先获取非空值)
COALESCE(
MAX(CASE WHEN s.self_overall_comment IS NOT NULL AND s.self_overall_comment != ''
THEN s.self_overall_comment END),
''
) as self_overall_comment,
MAX(s.self_submit_time) as self_submit_time,
MAX(s.audit_status) as audit_status,
CASE WHEN COUNT(s.id) > 0 THEN 1 ELSE 0 END as has_assessment_data
FROM bmzr_assessment_score s
WHERE s.plan_id = #{planId}
AND s.class_id = #{classId}
AND s.evaluated_user_id = #{evaluatedUserId}
AND s.deleted = 0
AND s.self_submit_time IS NOT NULL
GROUP BY s.plan_id, s.class_id, s.evaluated_user_id, s.evaluated_user_name
LIMIT 1
</select>
<!-- 获取班主任常规工作自评数据 -->
<select id="getRoutineWorkScores" resultMap="AssessmentScoreIndicatorVoResult">
SELECT
s.id,
s.indicator_id,
i.indicator_name,
i.indicator_code,
CONCAT(i.indicator_name, CASE WHEN i.remark IS NOT NULL AND i.remark != ''
THEN CONCAT('(', i.remark, ')') ELSE '' END) as description,
i.score,
i.max_score,
s.self_score,
s.self_comment,
s.superior_score,
s.superior_comment
FROM bmzr_assessment_score s
LEFT JOIN bmzr_assessment_indicator i ON s.indicator_id = i.id AND i.deleted = 0
WHERE s.plan_id = #{planId}
AND s.class_id = #{classId}
AND s.evaluated_user_id = #{evaluatedUserId}
AND s.deleted = 0
AND s.self_submit_time IS NOT NULL
AND i.indicator_type = 'bzr-001'
ORDER BY i.sort_order ASC, s.id ASC
</select>
<!-- 获取班级管理实效自评数据 -->
<select id="getClassDeductionScore" resultMap="AssessmentScoreIndicatorVoResult">
SELECT
s.id,
s.indicator_id,
i.indicator_name,
i.indicator_code,
CONCAT(i.indicator_name, CASE WHEN i.remark IS NOT NULL AND i.remark != ''
THEN CONCAT('(', i.remark, ')') ELSE '' END) as description,
i.score,
i.max_score,
s.self_score,
s.self_comment,
s.superior_score,
s.superior_comment
FROM bmzr_assessment_score s
LEFT JOIN bmzr_assessment_indicator i ON s.indicator_id = i.id AND i.deleted = 0
WHERE s.plan_id = #{planId}
AND s.class_id = #{classId}
AND s.evaluated_user_id = #{evaluatedUserId}
AND s.deleted = 0
AND s.self_submit_time IS NOT NULL
AND i.indicator_type = 'bzr-002'
LIMIT 1
</select>
<!-- 获取特色工作自评数据 -->
<select id="getSpecialWorkScores" resultMap="AssessmentScoreSpecialWorkVoResult">
SELECT
s.id,
s.indicator_id,
i.indicator_code,
i.indicator_name,
s.self_score,
s.self_comment,
s.superior_score,
s.superior_comment
FROM bmzr_assessment_score s
LEFT JOIN bmzr_assessment_indicator i ON s.indicator_id = i.id AND i.deleted = 0
WHERE s.plan_id = #{planId}
AND s.class_id = #{classId}
AND s.evaluated_user_id = #{evaluatedUserId}
AND s.deleted = 0
AND s.self_submit_time IS NOT NULL
AND i.indicator_type = 'bzr-003'
ORDER BY i.sort_order ASC, s.id ASC
</select>
<!-- 检查是否存在自评数据 -->
<select id="countAssessmentScore" resultType="int">
SELECT COUNT(1)
FROM bmzr_assessment_score s
WHERE s.plan_id = #{planId}
AND s.class_id = #{classId}
AND s.evaluated_user_id = #{evaluatedUserId}
AND s.deleted = 0
AND s.self_submit_time IS NOT NULL
</select>
</mapper>
@@ -143,4 +143,16 @@
ORDER BY p.create_time DESC ORDER BY p.create_time DESC
</select> </select>
<!-- 根据考核计划ID批量逻辑删除关联的考核得分数据 -->
<update id="deleteAssessmentScoresByPlanIds">
UPDATE bmzr_assessment_score
SET deleted = 1,
update_time = NOW()
WHERE deleted = 0
AND plan_id IN
<foreach collection="planIds" item="planId" open="(" separator="," close=")">
#{planId}
</foreach>
</update>
</mapper> </mapper>
@@ -139,15 +139,37 @@
p.update_by, p.update_by,
p.update_time, p.update_time,
p.deleted, p.deleted,
score.audit_status as audit_status, COALESCE(score.audit_status, '') as audit_status,
score.self_submit_time as submit_time, score.self_submit_time as submit_time,
CASE WHEN score.plan_id IS NOT NULL THEN 1 ELSE 0 END as submitted CASE WHEN score.plan_id IS NOT NULL THEN 1 ELSE 0 END as submitted
FROM bmzr_assessment_plan p FROM bmzr_assessment_plan p
LEFT JOIN bmzr_assessment_scheme s ON p.scheme_id = s.id AND s.deleted = 0 LEFT JOIN bmzr_assessment_scheme s ON p.scheme_id = s.id AND s.deleted = 0
LEFT JOIN ( LEFT JOIN (
SELECT DISTINCT plan_id, audit_status, self_submit_time SELECT DISTINCT s1.plan_id, s1.audit_status, s1.self_submit_time
FROM bmzr_assessment_score FROM bmzr_assessment_score s1
WHERE evaluated_user_id = #{teacherId} AND deleted = 0 WHERE s1.evaluated_user_id = #{teacherId}
AND s1.deleted = 0
<if test="classId != null">
AND s1.class_id = #{classId}
</if>
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
<if test="classId != null">
AND s2.class_id = #{classId}
</if>
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 ) score ON p.id = score.plan_id
WHERE p.deleted = 0 WHERE p.deleted = 0
<if test="planStatus != null and planStatus != ''"> <if test="planStatus != null and planStatus != ''">
@@ -256,7 +278,7 @@
ORDER BY i.indicator_code ASC ORDER BY i.indicator_code ASC
</select> </select>
<!-- 查询已保存的评分数据 --> <!-- 查询已保存的评分数据(返回草稿状态和待审核状态的数据用于查看和编辑) -->
<select id="selectSavedAssessmentScores" resultMap="AssessmentIndicatorScoreVoResult"> <select id="selectSavedAssessmentScores" resultMap="AssessmentIndicatorScoreVoResult">
SELECT SELECT
i.id, i.id,
@@ -277,7 +299,36 @@
JOIN bmzr_assessment_indicator i ON s.indicator_id = i.id AND i.deleted = 0 JOIN bmzr_assessment_indicator i ON s.indicator_id = i.id AND i.deleted = 0
WHERE s.plan_id = #{planId} WHERE s.plan_id = #{planId}
AND s.evaluated_user_id = #{teacherId} AND s.evaluated_user_id = #{teacherId}
AND s.class_id = #{classId}
AND s.deleted = 0 AND s.deleted = 0
AND s.audit_status IN ('9', '0') -- 查找草稿状态和待审核状态的数据
</select>
<!-- 查询已提交的评分数据(仅返回待审核状态的数据用于撤销功能) -->
<select id="selectSubmittedAssessmentScores" resultMap="AssessmentIndicatorScoreVoResult">
SELECT
i.id,
i.indicator_name,
i.indicator_code,
i.remark as description,
i.score,
s.self_score,
s.self_comment,
s.self_overall_comment,
i.sort_order,
s.audit_status,
s.create_by,
s.create_time,
s.update_by,
s.update_time
FROM bmzr_assessment_score s
JOIN bmzr_assessment_indicator i ON s.indicator_id = i.id AND i.deleted = 0
WHERE s.plan_id = #{planId}
AND s.evaluated_user_id = #{teacherId}
AND s.class_id = #{classId}
AND s.deleted = 0
AND s.audit_status = '0' -- 只返回待审核状态的数据
ORDER BY i.sort_order
</select> </select>
<!-- 根据计划ID查询方案ID --> <!-- 根据计划ID查询方案ID -->
@@ -298,13 +349,14 @@
LIMIT 1 LIMIT 1
</select> </select>
<!-- 逻辑删除指定计划和教师的评分数据 --> <!-- 逻辑删除指定计划、班级和教师的评分数据 -->
<update id="deleteAssessmentScoresByPlanAndTeacher"> <update id="deleteAssessmentScoresByPlanAndTeacher">
UPDATE bmzr_assessment_score UPDATE bmzr_assessment_score
SET deleted = 1, SET deleted = 1,
update_time = NOW() update_time = NOW()
WHERE plan_id = #{planId} WHERE plan_id = #{planId}
AND evaluated_user_id = #{teacherId} AND evaluated_user_id = #{teacherId}
AND class_id = #{classId}
AND deleted = 0 AND deleted = 0
</update> </update>
@@ -321,4 +373,75 @@
AND deleted = 0 AND deleted = 0
</update> </update>
<!-- 根据班级ID查询班级名称 -->
<select id="selectClassNameById" resultType="java.lang.String">
SELECT class_name
FROM sys_class
WHERE id = #{classId}
AND deleted = 0
</select>
<!-- 根据班级ID查询学生违纪记录 -->
<select id="selectStudentDisciplineRecordsByClassId" resultType="org.dromara.bzrkh.domain.vo.StudentDisciplineRecordVo">
SELECT
id,
student_id,
student_no,
student_name,
college_id,
college_name,
major_id,
major_name,
class_id,
class_name,
discipline_type_id,
discipline_type_name,
discipline_date,
discipline_reason,
discipline_content,
score_deduction,
status,
attachment_oss_ids,
create_by,
create_time,
update_by,
update_time
FROM xskh_discipline_record
WHERE class_id = #{classId}
AND deleted = 0
AND status = '1'
ORDER BY discipline_date DESC
</select>
<!-- 根据班级ID查询学生奖励记录 -->
<select id="selectStudentRewardRecordsByClassId" resultType="org.dromara.bzrkh.domain.vo.StudentRewardRecordVo">
SELECT
id,
student_id,
student_no,
student_name,
college_id,
college_name,
major_id,
major_name,
class_id,
class_name,
reward_type_id,
reward_type_name,
reward_date,
reward_content,
score_addition,
attachment_oss_ids,
status,
create_by,
create_time,
update_by,
update_time
FROM xskh_reward_record
WHERE class_id = #{classId}
AND deleted = 0
AND status = '1'
ORDER BY reward_date DESC
</select>
</mapper> </mapper>
@@ -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 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(), '待审核状态'), (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(), '审核通过状态'), (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(), '审核不通过状态'); (3, '审核不通过', '2', 'bmzr_audit_status', '', 'danger', 'N', '0', 103, 1, now(), 1, now(), '审核不通过状态');
@@ -166,7 +166,7 @@ CREATE TABLE `bmzr_assessment_score` (
`superior_evaluator_id` bigint(20) COMMENT '上级评价人ID', `superior_evaluator_id` bigint(20) COMMENT '上级评价人ID',
`superior_submit_time` datetime COMMENT '上级评提交时间', `superior_submit_time` datetime COMMENT '上级评提交时间',
`evaluation_level` varchar(20) COMMENT '评价等级 dict_type = bmzr_evaluation_level', `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 '最终得分', `final_score` decimal(5,2) COMMENT '最终得分',
`submit_time` datetime COMMENT '提交时间', `submit_time` datetime COMMENT '提交时间',
`remark` varchar(500) COMMENT '备注', `remark` varchar(500) COMMENT '备注',
@@ -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'; 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) 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'; 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 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', 1, 'A等(优秀)', 'A', 'bmzr_evaluation_level', '', 'success', 'Y', '0', 103, 1, NOW(), 'A等优秀(占比≤20%班主任人数)'),
('000000', 2, '良好', 'good', 'bmzr_evaluation_level', '', 'primary', 'N', '0', 103, 1, NOW(), '良好等级(80-89分)'), ('000000', 2, 'B等(合格)', 'B', 'bmzr_evaluation_level', '', 'primary', 'N', '0', 103, 1, NOW(), 'B等合格(60分及以上,与C等合计≥80%)'),
('000000', 3, '合格', 'qualified', 'bmzr_evaluation_level', '', 'info', 'N', '0', 103, 1, NOW(), '合格等级(70-79分)'), ('000000', 3, 'C等(不合格)', 'C', 'bmzr_evaluation_level', '', 'danger', 'N', '0', 103, 1, NOW(), 'C等不合格(60分以下)');
('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分以下)');
-- ========================================== -- ==========================================
+19 -7
View File
@@ -1,11 +1,6 @@
import request from '@/utils/request'; import request from '@/utils/request';
import { AxiosPromise } from 'axios'; import { AxiosPromise } from 'axios';
import { import { AssessmentApprovalQuery, AssessmentApprovalVO, AssessmentApprovalDetailVO, AssessmentApprovalSubmitBO, EvaluationLevelStatsVO } from './types';
AssessmentApprovalQuery,
AssessmentApprovalVO,
AssessmentApprovalDetailVO,
AssessmentApprovalSubmitBO
} from './types';
/** /**
* 查询班主任考核审核列表 * 查询班主任考核审核列表
@@ -27,7 +22,11 @@ export const listAssessmentApproval = (query?: AssessmentApprovalQuery): AxiosPr
* @param evaluatedUserId 被评价用户ID * @param evaluatedUserId 被评价用户ID
* @returns {*} * @returns {*}
*/ */
export const getAssessmentApprovalDetail = (planId: string | number, classId: string | number, evaluatedUserId: string | number): AxiosPromise<AssessmentApprovalDetailVO> => { export const getAssessmentApprovalDetail = (
planId: string | number,
classId: string | number,
evaluatedUserId: string | number
): AxiosPromise<AssessmentApprovalDetailVO> => {
return request({ return request({
url: '/bzrkh/assessmentApproval/detail', url: '/bzrkh/assessmentApproval/detail',
method: 'get', method: 'get',
@@ -106,3 +105,16 @@ export const exportAssessmentApproval = (query?: AssessmentApprovalQuery): Axios
responseType: 'blob' responseType: 'blob'
}); });
}; };
/**
* 获取评价等级统计数据
* @param planId 计划ID
* @returns {*}
*/
export const getEvaluationLevelStats = (planId: string | number): AxiosPromise<EvaluationLevelStatsVO> => {
return request({
url: '/bzrkh/assessmentApproval/evaluationStats',
method: 'get',
params: { planId }
});
};
+24 -1
View File
@@ -149,7 +149,8 @@ export interface AssessmentApprovalSpecialWorkVO {
indicatorName?: string; indicatorName?: string;
// 自评相关 // 自评相关
score?: number; // 自评分数 score?: number; // 自评分数 (兼容原有字段)
selfScore?: number; // 自评分数 (标准字段名)
selfComment?: string; selfComment?: string;
// 上级评相关 // 上级评相关
@@ -218,3 +219,25 @@ export interface AssessmentApprovalSpecialWorkSubmitVO {
superiorScore?: number; superiorScore?: number;
superiorComment?: string; superiorComment?: string;
} }
/**
* 评价等级统计数据
*/
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(可选,用于标识当前用户)
}
@@ -95,6 +95,18 @@ export const submitAssessmentScore = (data: AssessmentSubmitVO): AxiosPromise<vo
}); });
}; };
/**
* 查询班级学生违纪记录和奖励记录
* @param classId 班级ID
*/
export const getClassStudentRecords = (classId: string | number): AxiosPromise<any> => {
return request({
url: '/bzrkh/teacherAssessment/classStudentRecords',
method: 'get',
params: { classId }
});
};
/** /**
* 撤销考核提交 * 撤销考核提交
* @param planId 计划ID * @param planId 计划ID
@@ -437,3 +437,148 @@ export interface AssessmentDetailVO {
*/ */
overallComment?: string; overallComment?: string;
} }
/**
* 班级学生违纪奖励记录
*/
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;
}
@@ -1,12 +1,5 @@
<template> <template>
<el-dialog <el-dialog :title="dialogTitle" v-model="visible" width="1200px" :close-on-click-modal="false" append-to-body @close="handleClose">
:title="dialogTitle"
v-model="visible"
width="1200px"
:close-on-click-modal="false"
append-to-body
@close="handleClose"
>
<div v-loading="loading" class="approval-dialog-content"> <div v-loading="loading" class="approval-dialog-content">
<!-- 1. 班级信息卡片 --> <!-- 1. 班级信息卡片 -->
<el-card shadow="never" class="info-card"> <el-card shadow="never" class="info-card">
@@ -62,7 +55,9 @@
</template> </template>
<el-descriptions :column="2" border> <el-descriptions :column="2" border>
<el-descriptions-item label="班级总人数">{{ approvalDetail?.classDetail?.totalStudentCount || 0 }}人</el-descriptions-item> <el-descriptions-item label="班级总人数">{{ approvalDetail?.classDetail?.totalStudentCount || 0 }}人</el-descriptions-item>
<el-descriptions-item label="人数系数">{{ formatNumber(approvalDetail?.coefficient?.studentCountCoefficient, 3) }}</el-descriptions-item> <el-descriptions-item label="人数系数">{{
formatNumber(approvalDetail?.coefficient?.studentCountCoefficient, 3)
}}</el-descriptions-item>
</el-descriptions> </el-descriptions>
</el-card> </el-card>
</el-col> </el-col>
@@ -153,7 +148,7 @@
<el-input <el-input
:value="managementEffectivenessForm.classDeduction?.toFixed(2) || '0.00'" :value="managementEffectivenessForm.classDeduction?.toFixed(2) || '0.00'"
readonly readonly
style="width: 100%; text-align: center;" style="width: 100%; text-align: center"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -162,7 +157,7 @@
<el-input <el-input
:value="managementEffectivenessForm.classDeductionHalf?.toFixed(2) || '0.00'" :value="managementEffectivenessForm.classDeductionHalf?.toFixed(2) || '0.00'"
readonly readonly
style="width: 100%; text-align: center;" style="width: 100%; text-align: center"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -183,12 +178,7 @@
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="自评意见"> <el-form-item label="自评意见">
<el-input <el-input :value="managementEffectivenessForm.selfComment" type="textarea" :rows="3" readonly />
:value="managementEffectivenessForm.selfComment"
type="textarea"
:rows="3"
readonly
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -219,7 +209,7 @@
<el-table-column prop="indicatorName" label="特色工作项目" min-width="180" align="center" :show-overflow-tooltip="true" /> <el-table-column prop="indicatorName" label="特色工作项目" min-width="180" align="center" :show-overflow-tooltip="true" />
<el-table-column label="自评分数" width="80" align="center"> <el-table-column label="自评分数" width="80" align="center">
<template #default="scope"> <template #default="scope">
<span>{{ scope.row.score || 0 }}</span> <span>{{ scope.row.score || scope.row.selfScore || 0 }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="自评意见" width="180" align="center"> <el-table-column label="自评意见" width="180" align="center">
@@ -270,11 +260,7 @@
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="月考核得分"> <el-form-item label="月考核得分">
<el-input <el-input :value="calculateMonthlyScore().toFixed(2)" readonly style="width: 100%; text-align: center" />
:value="calculateMonthlyScore().toFixed(2)"
readonly
style="width: 100%; text-align: center;"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -282,10 +268,11 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="自我总体评价"> <el-form-item label="自我总体评价">
<el-input <el-input
:value="monthlyScoreForm.selfOverallComment" :value="monthlyScoreForm.selfOverallComment || '暂无自我总体评价'"
type="textarea" type="textarea"
:rows="4" :rows="4"
readonly readonly
placeholder="暂无自我总体评价内容"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -313,16 +300,6 @@
</div> </div>
</template> </template>
<el-form :model="approvalForm" label-width="100px" class="approval-form"> <el-form :model="approvalForm" label-width="100px" class="approval-form">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="审批状态" required>
<el-radio-group v-model="approvalForm.auditStatus">
<el-radio value="1">通过</el-radio>
<el-radio value="2">拒绝</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="审批意见"> <el-form-item label="审批意见">
@@ -343,7 +320,8 @@
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button :loading="submitLoading" type="primary" @click="handleSubmit">保存审批</el-button> <el-button :loading="submitLoading" type="success" @click="() => handleApprovalSubmit('1')"> 通过 </el-button>
<el-button :loading="submitLoading" type="danger" @click="() => handleApprovalSubmit('2')"> 拒绝 </el-button>
<el-button @click="handleClose">取消</el-button> <el-button @click="handleClose">取消</el-button>
</div> </div>
</template> </template>
@@ -351,10 +329,7 @@
</template> </template>
<script setup name="ApprovalDialog" lang="ts"> <script setup name="ApprovalDialog" lang="ts">
import { import { getAssessmentApprovalDetail, submitAssessmentApproval } from '@/api/bzrkh/assessmentApproval';
getAssessmentApprovalDetail,
submitAssessmentApproval
} from '@/api/bzrkh/assessmentApproval';
import { import {
AssessmentApprovalVO, AssessmentApprovalVO,
AssessmentApprovalDetailVO, AssessmentApprovalDetailVO,
@@ -434,17 +409,17 @@ const calculateMonthlyScore = () => {
// 总系数(K) // 总系数(K)
const totalCoefficient = approvalDetail.value?.coefficient?.totalCoefficient || 0; const totalCoefficient = approvalDetail.value?.coefficient?.totalCoefficient || 0;
// 班主任常规工作自评分之和 // 班主任常规工作上级评分之和(使用上级评分,而非自评分)
const routineWorkTotal = routineWorkScores.value.reduce((sum, item) => sum + (item.selfScore || 0), 0); const routineWorkTotal = routineWorkScores.value.reduce((sum, item) => sum + (item.superiorScore || 0), 0);
// 按班级扣分50%计的分值 // 班级管理实效上级评分(使用上级评分,而非扣分逻辑)
const deductionHalf = managementEffectivenessForm.classDeductionHalf || 0; const managementEffectivenessScore = managementEffectivenessForm.superiorScore || 0;
// 特色工作总分值 // 特色工作上级评分之和(使用上级评分,而非自评分)
const specialWorkTotal = specialWorkScores.value.reduce((sum, item) => sum + (item.score || 0), 0); const specialWorkTotal = specialWorkScores.value.reduce((sum, item) => sum + (item.superiorScore || 0), 0);
// 月考核得分 = 总系数(K)* (班主任常规工作自评分之和 - 按班级扣分50%计的分值 + 特色工作总分值) // 月考核得分 = 总系数(K)* (班主任常规工作上级评分之和 + 班级管理实效上级评分 + 特色工作上级评分之和)
return totalCoefficient * (routineWorkTotal - deductionHalf + specialWorkTotal); return totalCoefficient * (routineWorkTotal + managementEffectivenessScore + specialWorkTotal);
}; };
/** 打开弹窗 */ /** 打开弹窗 */
@@ -467,43 +442,130 @@ const loadApprovalDetail = async () => {
loading.value = true; loading.value = true;
try { try {
const res = await getAssessmentApprovalDetail( const res = await getAssessmentApprovalDetail(currentRow.value.planId, currentRow.value.classId, currentRow.value.evaluatedUserId);
currentRow.value.planId,
currentRow.value.classId,
currentRow.value.evaluatedUserId
);
approvalDetail.value = res.data; approvalDetail.value = res.data;
// 初始化班主任常规工作数据 // 详细的调试日志 - 用于排查数据显示问题
routineWorkScores.value = (approvalDetail.value?.routineWorkIndicators || []).map(item => ({ console.log('=== 审批详情数据加载开始 ===');
console.log('完整审批详情数据:', approvalDetail.value);
console.log('班主任常规工作原始数据:', approvalDetail.value?.routineWorkIndicators);
console.log('特色工作原始数据:', approvalDetail.value?.specialWorkIndicators);
console.log('班级管理实效原始数据:', approvalDetail.value?.classDeductionIndicator);
console.log('自我总体评价:', approvalDetail.value?.selfOverallComment);
// 初始化班主任常规工作数据 - 确保包含所有必要字段
if (approvalDetail.value?.routineWorkIndicators && Array.isArray(approvalDetail.value.routineWorkIndicators)) {
routineWorkScores.value = approvalDetail.value.routineWorkIndicators.map((item) => {
const mappedItem = {
...item, ...item,
superiorScore: item.superiorScore || 0, // 确保数值字段不为空
superiorComment: item.superiorComment || '' selfScore: Number(item.selfScore) || 0,
})); superiorScore: Number(item.superiorScore) || Number(item.selfScore) || 0, // 默认使用自评分数
score: Number(item.score) || 0,
maxScore: Number(item.maxScore) || 0,
// 确保字符串字段不为空
selfComment: item.selfComment || '',
superiorComment: item.superiorComment || '',
indicatorName: item.indicatorName || '',
description: item.description || '',
indicatorCode: item.indicatorCode || ''
};
console.log(`常规工作指标 [${item.indicatorName}]:`, {
自评分数: mappedItem.selfScore,
自评意见: mappedItem.selfComment,
上级评分: mappedItem.superiorScore,
上级意见: mappedItem.superiorComment
});
return mappedItem;
});
console.log('班主任常规工作数据初始化完成,条目数量:', routineWorkScores.value.length);
} else {
routineWorkScores.value = [];
console.warn('班主任常规工作数据为空或格式错误');
}
// 初始化班级管理实效数据 // 初始化班级管理实效数据
if (approvalDetail.value?.classDeductionIndicator) { if (approvalDetail.value?.classDeductionIndicator) {
const indicator = approvalDetail.value.classDeductionIndicator; const indicator = approvalDetail.value.classDeductionIndicator;
managementEffectivenessForm.classDeduction = indicator.selfScore || 0; managementEffectivenessForm.classDeduction = Number(indicator.selfScore) || 0;
managementEffectivenessForm.classDeductionHalf = (indicator.selfScore || 0) * 0.5; managementEffectivenessForm.classDeductionHalf = (Number(indicator.selfScore) || 0) * 0.5;
managementEffectivenessForm.selfComment = indicator.selfComment || ''; managementEffectivenessForm.selfComment = indicator.selfComment || '';
managementEffectivenessForm.superiorScore = indicator.superiorScore || 0; // 上级评分默认使用按班级扣分50%计的分值
const classDeductionHalf = (Number(indicator.selfScore) || 0) * 0.5;
managementEffectivenessForm.superiorScore = Number(indicator.superiorScore) || classDeductionHalf;
managementEffectivenessForm.superiorComment = indicator.superiorComment || ''; managementEffectivenessForm.superiorComment = indicator.superiorComment || '';
console.log('班级管理实效数据初始化:', {
班级扣分: managementEffectivenessForm.classDeduction,
扣分50计: managementEffectivenessForm.classDeductionHalf,
自评意见: managementEffectivenessForm.selfComment,
上级评分: managementEffectivenessForm.superiorScore,
上级意见: managementEffectivenessForm.superiorComment
});
} else {
// 如果没有找到班级扣分指标,设置默认值
managementEffectivenessForm.classDeduction = 0;
managementEffectivenessForm.classDeductionHalf = 0;
managementEffectivenessForm.selfComment = '';
managementEffectivenessForm.superiorScore = 0; // 默认为0
managementEffectivenessForm.superiorComment = '';
console.warn('班级管理实效数据为空,使用默认值');
} }
// 初始化特色工作数据 // 初始化特色工作数据 - 确保包含所有必要字段
specialWorkScores.value = (approvalDetail.value?.specialWorkIndicators || []).map(item => ({ if (approvalDetail.value?.specialWorkIndicators && Array.isArray(approvalDetail.value.specialWorkIndicators)) {
specialWorkScores.value = approvalDetail.value.specialWorkIndicators.map((item) => {
const mappedItem = {
...item, ...item,
superiorScore: item.superiorScore || 0, // 自评分数字段处理 - 兼容不同字段名,确保数值类型
superiorComment: item.superiorComment || '' score: Number(item.score || item.selfScore) || 0,
})); selfScore: Number(item.selfScore || item.score) || 0,
superiorScore: Number(item.superiorScore) || Number(item.selfScore || item.score) || 0, // 默认使用自评分数
// 确保字符串字段不为空
selfComment: item.selfComment || '',
superiorComment: item.superiorComment || '',
indicatorName: item.indicatorName || '',
indicatorCode: item.indicatorCode || ''
};
console.log(`特色工作指标 [${item.indicatorCode} - ${item.indicatorName}]:`, {
自评分数: mappedItem.selfScore,
兼容分数: mappedItem.score,
自评意见: mappedItem.selfComment,
上级评分: mappedItem.superiorScore,
上级意见: mappedItem.superiorComment
});
return mappedItem;
});
console.log('特色工作数据初始化完成,条目数量:', specialWorkScores.value.length);
} else {
specialWorkScores.value = [];
console.warn('特色工作数据为空或格式错误');
}
// 初始化月考核得分数据 // 初始化月考核得分数据
monthlyScoreForm.selfOverallComment = approvalDetail.value?.selfOverallComment || ''; monthlyScoreForm.selfOverallComment = approvalDetail.value?.selfOverallComment || '';
monthlyScoreForm.superiorOverallComment = approvalDetail.value?.superiorOverallComment || ''; monthlyScoreForm.superiorOverallComment = approvalDetail.value?.superiorOverallComment || '';
console.log('月考核得分数据初始化:', {
自我总体评价: monthlyScoreForm.selfOverallComment,
上级总体评价: monthlyScoreForm.superiorOverallComment,
计算得分: calculateMonthlyScore().toFixed(2)
});
// 初始化审批状态 // 初始化审批状态
approvalForm.auditStatus = approvalDetail.value?.auditStatus || '1'; approvalForm.auditStatus = approvalDetail.value?.auditStatus || '1';
approvalForm.auditComment = '';
console.log('=== 审批详情数据加载完成 ===');
// 验证数据完整性
if (routineWorkScores.value.length === 0) {
console.warn('⚠️ 警告:班主任常规工作数据为空,可能存在数据问题');
proxy?.$modal.msgWarning('班主任常规工作数据为空,请检查数据是否正确');
}
if (specialWorkScores.value.length === 0) {
console.warn('⚠️ 警告:特色工作数据为空,可能存在数据问题');
proxy?.$modal.msgWarning('特色工作数据为空,请检查数据是否正确');
}
} catch (error) { } catch (error) {
console.error('加载审批详情失败:', error); console.error('加载审批详情失败:', error);
@@ -514,15 +576,13 @@ const loadApprovalDetail = async () => {
}; };
/** 提交审批 */ /** 提交审批 */
const handleSubmit = async () => { const handleApprovalSubmit = async (auditStatus: string) => {
try { try {
// 验证必填项 // 设置审批状态
if (!approvalForm.auditStatus) { approvalForm.auditStatus = auditStatus;
proxy?.$modal.msgWarning('请选择审批状态');
return;
}
if (approvalForm.auditStatus === '2' && !approvalForm.auditComment.trim()) { // 验证必填项
if (auditStatus === '2' && !approvalForm.auditComment.trim()) {
proxy?.$modal.msgWarning('拒绝审批时必须填写审批意见'); proxy?.$modal.msgWarning('拒绝审批时必须填写审批意见');
return; return;
} }
@@ -534,7 +594,7 @@ const handleSubmit = async () => {
planId: currentRow.value?.planId, planId: currentRow.value?.planId,
classId: currentRow.value?.classId, classId: currentRow.value?.classId,
evaluatedUserId: currentRow.value?.evaluatedUserId, evaluatedUserId: currentRow.value?.evaluatedUserId,
routineWorkApproval: routineWorkScores.value.map(item => ({ routineWorkApproval: routineWorkScores.value.map((item) => ({
id: item.id, id: item.id,
indicatorId: item.indicatorId, indicatorId: item.indicatorId,
superiorScore: item.superiorScore, superiorScore: item.superiorScore,
@@ -546,7 +606,7 @@ const handleSubmit = async () => {
superiorScore: managementEffectivenessForm.superiorScore, superiorScore: managementEffectivenessForm.superiorScore,
superiorComment: managementEffectivenessForm.superiorComment superiorComment: managementEffectivenessForm.superiorComment
}, },
specialWorkApproval: specialWorkScores.value.map(item => ({ specialWorkApproval: specialWorkScores.value.map((item) => ({
id: item.id, id: item.id,
indicatorCode: item.indicatorCode, indicatorCode: item.indicatorCode,
superiorScore: item.superiorScore, superiorScore: item.superiorScore,
@@ -561,7 +621,6 @@ const handleSubmit = async () => {
proxy?.$modal.msgSuccess('审批提交成功'); proxy?.$modal.msgSuccess('审批提交成功');
emit('success'); emit('success');
handleClose(); handleClose();
} catch (error) { } catch (error) {
console.error('提交审批失败:', error); console.error('提交审批失败:', error);
proxy?.$modal.msgError('提交审批失败'); proxy?.$modal.msgError('提交审批失败');
@@ -596,7 +655,8 @@ const handleClose = () => {
// 暴露给父组件的方法 // 暴露给父组件的方法
defineExpose({ defineExpose({
open open,
handleApprovalSubmit
}); });
</script> </script>
@@ -14,12 +14,7 @@
<el-col :lg="6" :md="12" :sm="24"> <el-col :lg="6" :md="12" :sm="24">
<el-form-item label="考核方案" prop="schemeName"> <el-form-item label="考核方案" prop="schemeName">
<el-select v-model="queryParams.schemeName" placeholder="请选择考核方案" clearable style="width: 100%"> <el-select v-model="queryParams.schemeName" placeholder="请选择考核方案" clearable style="width: 100%">
<el-option <el-option v-for="item in schemeOptions" :key="item.value" :label="item.label" :value="item.value" />
v-for="item in schemeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -98,13 +93,7 @@
></el-button> ></el-button>
</el-tooltip> </el-tooltip>
<el-tooltip content="查看" placement="top"> <el-tooltip content="查看" placement="top">
<el-button <el-button link type="success" icon="View" :disabled="loading" @click="handleView(scope.row)"></el-button>
link
type="success"
icon="View"
:disabled="loading"
@click="handleView(scope.row)"
></el-button>
</el-tooltip> </el-tooltip>
</template> </template>
</el-table-column> </el-table-column>
@@ -117,27 +106,16 @@
</el-card> </el-card>
<!-- 审批弹窗 --> <!-- 审批弹窗 -->
<ApprovalDialog <ApprovalDialog ref="approvalDialogRef" @success="handleApprovalSuccess" />
ref="approvalDialogRef"
@success="handleApprovalSuccess"
/>
<!-- 查看弹窗 --> <!-- 查看弹窗 -->
<ViewDialog <ViewDialog ref="viewDialogRef" />
ref="viewDialogRef"
/>
</div> </div>
</template> </template>
<script setup name="AssessmentApproval" lang="ts"> <script setup name="AssessmentApproval" lang="ts">
import { import { listAssessmentApproval, getAssessmentSchemeOptions } from '@/api/bzrkh/assessmentApproval';
listAssessmentApproval, import { AssessmentApprovalVO, AssessmentApprovalQuery } from '@/api/bzrkh/assessmentApproval/types';
getAssessmentSchemeOptions
} from '@/api/bzrkh/assessmentApproval';
import {
AssessmentApprovalVO,
AssessmentApprovalQuery
} from '@/api/bzrkh/assessmentApproval/types';
import ApprovalDialog from './approvalDialog.vue'; import ApprovalDialog from './approvalDialog.vue';
import ViewDialog from './viewDialog.vue'; import ViewDialog from './viewDialog.vue';
@@ -1,12 +1,5 @@
<template> <template>
<el-dialog <el-dialog :title="dialogTitle" v-model="visible" width="1200px" :close-on-click-modal="false" append-to-body @close="handleClose">
:title="dialogTitle"
v-model="visible"
width="1200px"
:close-on-click-modal="false"
append-to-body
@close="handleClose"
>
<div v-loading="loading" class="view-dialog-content"> <div v-loading="loading" class="view-dialog-content">
<!-- 1. 班级信息卡片 --> <!-- 1. 班级信息卡片 -->
<el-card shadow="never" class="info-card"> <el-card shadow="never" class="info-card">
@@ -88,7 +81,7 @@
<span>班主任常规工作(50分)</span> <span>班主任常规工作(50分)</span>
</div> </div>
</template> </template>
<el-table border :data="routineWorkScores" style="width: 100%" max-height="400" class="routine-work-table"> <el-table border :data="routineWorkScores" style="width: 100%" max-height="250" class="routine-work-table">
<el-table-column type="index" label="序号" width="60" align="center" /> <el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="indicatorName" label="指标名称" min-width="150" align="center" :show-overflow-tooltip="true" /> <el-table-column prop="indicatorName" label="指标名称" min-width="150" align="center" :show-overflow-tooltip="true" />
<el-table-column prop="description" label="指标描述" min-width="180" align="center" :show-overflow-tooltip="true" /> <el-table-column prop="description" label="指标描述" min-width="180" align="center" :show-overflow-tooltip="true" />
@@ -138,7 +131,7 @@
<el-input <el-input
:value="managementEffectivenessData.classDeduction?.toFixed(2) || '0.00'" :value="managementEffectivenessData.classDeduction?.toFixed(2) || '0.00'"
readonly readonly
style="width: 100%; text-align: center;" style="width: 100%; text-align: center"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -147,39 +140,25 @@
<el-input <el-input
:value="managementEffectivenessData.classDeductionHalf?.toFixed(2) || '0.00'" :value="managementEffectivenessData.classDeductionHalf?.toFixed(2) || '0.00'"
readonly readonly
style="width: 100%; text-align: center;" style="width: 100%; text-align: center"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="上级评分"> <el-form-item label="上级评分">
<el-input <el-input :value="managementEffectivenessData.superiorScore?.toFixed(2) || '-'" readonly style="width: 100%; text-align: center" />
:value="managementEffectivenessData.superiorScore?.toFixed(2) || '-'"
readonly
style="width: 100%; text-align: center;"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="自评意见"> <el-form-item label="自评意见">
<el-input <el-input :value="managementEffectivenessData.selfComment" type="textarea" :autosize="{ minRows: 2, maxRows: 6 }" readonly />
:value="managementEffectivenessData.selfComment"
type="textarea"
:rows="3"
readonly
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="审批意见"> <el-form-item label="审批意见">
<el-input <el-input :value="managementEffectivenessData.superiorComment" type="textarea" :autosize="{ minRows: 2, maxRows: 6 }" readonly />
:value="managementEffectivenessData.superiorComment"
type="textarea"
:rows="3"
readonly
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -193,12 +172,12 @@
<span>特色工作(加20分)</span> <span>特色工作(加20分)</span>
</div> </div>
</template> </template>
<el-table border :data="specialWorkScores" style="width: 100%" class="special-work-table"> <el-table border :data="specialWorkScores" style="width: 100%" max-height="200" class="special-work-table">
<el-table-column type="index" label="序号" width="60" align="center" /> <el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="indicatorName" label="特色工作项目" min-width="180" align="center" :show-overflow-tooltip="true" /> <el-table-column prop="indicatorName" label="特色工作项目" min-width="180" align="center" :show-overflow-tooltip="true" />
<el-table-column label="自评分数" width="80" align="center"> <el-table-column label="自评分数" width="80" align="center">
<template #default="scope"> <template #default="scope">
<span>{{ scope.row.score || 0 }}</span> <span>{{ scope.row.selfScore || 0 }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="自评意见" width="180" align="center"> <el-table-column label="自评意见" width="180" align="center">
@@ -234,33 +213,19 @@
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="月考核得分"> <el-form-item label="月考核得分">
<el-input <el-input :value="calculateMonthlyScore().toFixed(2)" readonly style="width: 100%; text-align: center" />
:value="calculateMonthlyScore().toFixed(2)"
readonly
style="width: 100%; text-align: center;"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="自我总体评价"> <el-form-item label="自我总体评价">
<el-input <el-input :value="monthlyScoreData.selfOverallComment" type="textarea" :autosize="{ minRows: 2, maxRows: 8 }" readonly />
:value="monthlyScoreData.selfOverallComment"
type="textarea"
:rows="4"
readonly
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="上级总体评价"> <el-form-item label="上级总体评价">
<el-input <el-input :value="monthlyScoreData.superiorOverallComment" type="textarea" :autosize="{ minRows: 2, maxRows: 8 }" readonly />
:value="monthlyScoreData.superiorOverallComment"
type="textarea"
:rows="4"
readonly
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -274,22 +239,36 @@
<span>审批结果</span> <span>审批结果</span>
</div> </div>
</template> </template>
<el-descriptions :column="2" border> <el-descriptions :column="3" border>
<el-descriptions-item label="审批状态"> <el-descriptions-item label="评价等级">
<dict-tag :options="bmzr_audit_status" :value="viewDetail?.auditStatus"/> <div style="display: flex; align-items: center; gap: 8px;">
<dict-tag :options="getEvaluationLevelOptions()" :value="calculateEvaluationLevel()" />
<el-tooltip placement="top">
<template #content>
<div>
<div>{{ evaluationStats ? '基于占比规则的精准评级' : '基于分数阈值的简化评级' }}</div>
<div v-if="isDictDataMissing" style="color: #f56c6c; margin-top: 4px;">
⚠️ 字典数据缺失,使用默认数据
</div>
</div>
</template>
<el-icon :color="evaluationStats ? '#67c23a' : '#e6a23c'" size="16">
<InfoFilled v-if="evaluationStats" />
<WarningFilled v-else />
</el-icon>
</el-tooltip>
</div>
</el-descriptions-item>
<el-descriptions-item label="月考核得分">
{{ calculateMonthlyScore().toFixed(2) }}分
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="审批时间"> <el-descriptions-item label="审批时间">
{{ parseTime(currentRow?.createTime, '{y}-{m}-{d} {h}:{i}:{s}') || '-' }} {{ parseTime(currentRow?.createTime, '{y}-{m}-{d} {h}:{i}:{s}') || '-' }}
</el-descriptions-item> </el-descriptions-item>
</el-descriptions> </el-descriptions>
<el-form label-width="100px" style="margin-top: 20px;" v-if="approvalData.auditComment"> <el-form label-width="100px" style="margin-top: 20px" v-if="approvalData.auditComment">
<el-form-item label="审批意见"> <el-form-item label="审批意见">
<el-input <el-input :value="approvalData.auditComment" type="textarea" :autosize="{ minRows: 2, maxRows: 6 }" readonly />
:value="approvalData.auditComment"
type="textarea"
:rows="3"
readonly
/>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
@@ -304,18 +283,47 @@
</template> </template>
<script setup name="ViewDialog" lang="ts"> <script setup name="ViewDialog" lang="ts">
import { import { InfoFilled, WarningFilled } from '@element-plus/icons-vue';
getAssessmentApprovalDetail import { getAssessmentApprovalDetail, getEvaluationLevelStats } from '@/api/bzrkh/assessmentApproval';
} from '@/api/bzrkh/assessmentApproval';
import { import {
AssessmentApprovalVO, AssessmentApprovalVO,
AssessmentApprovalDetailVO, AssessmentApprovalDetailVO,
AssessmentApprovalIndicatorVO, AssessmentApprovalIndicatorVO,
AssessmentApprovalSpecialWorkVO AssessmentApprovalSpecialWorkVO,
EvaluationLevelStatsVO
} from '@/api/bzrkh/assessmentApproval/types'; } from '@/api/bzrkh/assessmentApproval/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { bmzr_audit_status } = proxy?.useDict('bmzr_audit_status'); const { bmzr_evaluation_level } = toRefs<any>(proxy?.useDict('bmzr_evaluation_level'));
// 字典数据备用方案 - 如果字典加载失败,使用默认数据
const fallbackEvaluationLevelOptions = ref<DictDataOption[]>([
{ label: 'A等(优秀)', value: 'A', elTagType: 'success' },
{ label: 'B等(合格)', value: 'B', elTagType: 'primary' },
{ label: 'C等(不合格)', value: 'C', elTagType: 'danger' }
]);
// 获取有效的字典数据
const getEvaluationLevelOptions = (): DictDataOption[] => {
// 检查字典数据是否已加载
if (bmzr_evaluation_level.value && bmzr_evaluation_level.value.length > 0) {
console.log('✅ 使用数据库字典数据:', bmzr_evaluation_level.value);
return bmzr_evaluation_level.value;
}
// 字典数据未加载或为空时的处理
if (visible.value) { // 只在弹窗打开时输出警告
console.warn('⚠️ 字典数据为空,使用备用数据,当前状态:', {
弹窗是否打开: visible.value,
字典对象存在: !!bmzr_evaluation_level.value,
字典数据长度: bmzr_evaluation_level.value?.length || 0,
字典加载状态: isDictLoaded.value,
字典数据内容: bmzr_evaluation_level.value
});
}
return fallbackEvaluationLevelOptions.value;
};
const visible = ref(false); const visible = ref(false);
const loading = ref(false); const loading = ref(false);
@@ -324,6 +332,7 @@ const currentRow = ref<AssessmentApprovalVO>();
const viewDetail = ref<AssessmentApprovalDetailVO>(); const viewDetail = ref<AssessmentApprovalDetailVO>();
const routineWorkScores = ref<AssessmentApprovalIndicatorVO[]>([]); const routineWorkScores = ref<AssessmentApprovalIndicatorVO[]>([]);
const specialWorkScores = ref<AssessmentApprovalSpecialWorkVO[]>([]); const specialWorkScores = ref<AssessmentApprovalSpecialWorkVO[]>([]);
const evaluationStats = ref<EvaluationLevelStatsVO>();
// 班级管理实效数据 // 班级管理实效数据
const managementEffectivenessData = reactive({ const managementEffectivenessData = reactive({
@@ -350,6 +359,29 @@ const dialogTitle = computed(() => {
return `${className} - 班主任考核查看`; return `${className} - 班主任考核查看`;
}); });
// 检查字典数据是否缺失 - 只有在组件已挂载且字典确实为空时才认为缺失
const isDictDataMissing = computed(() => {
// 如果还没有尝试加载字典数据,不显示警告
if (!visible.value) return false;
// 如果字典数据已经加载成功,不显示警告
if (isDictLoaded.value) return false;
// 只有在弹窗打开且字典数据为空时才显示警告
return !bmzr_evaluation_level.value || bmzr_evaluation_level.value.length === 0;
});
// 字典数据加载状态
const isDictLoaded = ref(false);
// 监听字典数据变化
watchEffect(() => {
if (bmzr_evaluation_level.value && bmzr_evaluation_level.value.length > 0) {
console.log('字典数据已加载:', bmzr_evaluation_level.value);
isDictLoaded.value = true;
}
});
/** 获取班级层次文本 */ /** 获取班级层次文本 */
const getClassTypeText = (classType?: string) => { const getClassTypeText = (classType?: string) => {
const typeMap: Record<string, string> = { const typeMap: Record<string, string> = {
@@ -382,17 +414,106 @@ const calculateMonthlyScore = () => {
// 总系数(K) // 总系数(K)
const totalCoefficient = viewDetail.value?.coefficient?.totalCoefficient || 0; const totalCoefficient = viewDetail.value?.coefficient?.totalCoefficient || 0;
// 班主任常规工作自评分之和 // 班主任常规工作上级评分之和(查看界面显示最终审批结果,使用上级评分)
const routineWorkTotal = routineWorkScores.value.reduce((sum, item) => sum + (item.selfScore || 0), 0); const routineWorkTotal = routineWorkScores.value.reduce((sum, item) => sum + (item.superiorScore || 0), 0);
// 按班级扣分50%计的分值 // 班级管理实效上级评分(查看界面显示最终审批结果,使用上级评分)
const deductionHalf = managementEffectivenessData.classDeductionHalf || 0; const managementEffectivenessScore = managementEffectivenessData.superiorScore || 0;
// 特色工作总分值 // 特色工作上级评分之和(查看界面显示最终审批结果,使用上级评分)
const specialWorkTotal = specialWorkScores.value.reduce((sum, item) => sum + (item.score || 0), 0); const specialWorkTotal = specialWorkScores.value.reduce((sum, item) => sum + (item.superiorScore || 0), 0);
// 月考核得分 = 总系数(K)* (班主任常规工作自评分之和 - 按班级扣分50%计的分值 + 特色工作总分值) // 月考核得分 = 总系数(K)* (班主任常规工作上级评分之和 + 班级管理实效上级评分 + 特色工作上级评分之和)
return totalCoefficient * (routineWorkTotal - deductionHalf + specialWorkTotal); return totalCoefficient * (routineWorkTotal + managementEffectivenessScore + specialWorkTotal);
};
/** 计算评价等级(基于占比规则) */
const calculateEvaluationLevel = () => {
const score = calculateMonthlyScore();
console.log('=== 📊 评价等级计算调试 ===');
console.log('💯 月考核得分:', score);
console.log('📈 是否有统计数据:', !!evaluationStats.value);
console.log('👤 当前用户ID:', currentRow.value?.evaluatedUserId);
if (evaluationStats.value) {
console.log('📊 统计数据详情:', {
总教师数: evaluationStats.value.totalTeachers,
排名数据: evaluationStats.value.scoreRankings?.length || 0,
A等最大占比: evaluationStats.value.evaluationLevelRules?.aLevelMaxPercentage,
及格分数: evaluationStats.value.evaluationLevelRules?.passScore
});
}
let level = '';
let calculationMethod = '';
// 如果有统计数据且用户ID存在,使用严格的占比规则
if (evaluationStats.value &&
evaluationStats.value.totalTeachers > 0 &&
evaluationStats.value.scoreRankings.length > 0 &&
currentRow.value?.evaluatedUserId) {
level = calculateEvaluationLevelByStats(score, currentRow.value.evaluatedUserId);
calculationMethod = '📈 严格占比规则评级';
} else {
// 降级方案:基于分数的简单评级
if (score < 60) {
level = 'C'; // C等(不合格):60分以下
} else if (score >= 85) {
level = 'A'; // A等(优秀):85分以上(暂定)
} else {
level = 'B'; // B等(合格):60-85分
}
calculationMethod = '🔢 简化分数评级';
// 输出使用简化评级的原因
const reasons = [];
if (!evaluationStats.value) reasons.push('统计数据为空');
if (evaluationStats.value?.totalTeachers === 0) reasons.push('总教师数为0');
if (evaluationStats.value?.scoreRankings?.length === 0) reasons.push('排名数据为空');
if (!currentRow.value?.evaluatedUserId) reasons.push('用户ID缺失');
console.warn('⚠️ 使用简化评级的原因:', reasons.join('、'));
}
console.log('🎯 计算方法:', calculationMethod);
console.log('📋 最终评价等级:', level);
console.log('=== 📊 评价等级计算调试结束 ===');
return level;
};
/** 基于统计数据计算评价等级(严格占比规则) */
const calculateEvaluationLevelByStats = (score: number, evaluatedUserId: string | number) => {
const stats = evaluationStats.value;
if (!stats) {
console.warn('统计数据不可用,使用简单评级');
return score < 60 ? 'C' : (score >= 85 ? 'A' : 'B');
}
const { totalTeachers, scoreRankings, evaluationLevelRules } = stats;
const { aLevelMaxPercentage, passScore } = evaluationLevelRules;
// C等:不及格
if (score < passScore) {
return 'C';
}
// 查找当前用户的排名
const currentRanking = scoreRankings.find(item =>
item.evaluatedUserId === evaluatedUserId || item.score === score
);
if (!currentRanking) {
console.warn('找不到当前用户的排名信息,使用简单评级');
return score < 60 ? 'C' : (score >= 85 ? 'A' : 'B');
}
// A等:及格且排名在前20%内
if (score >= passScore && currentRanking.percentage <= aLevelMaxPercentage) {
return 'A';
}
// B等:其余及格的
return 'B';
}; };
/** 打开弹窗 */ /** 打开弹窗 */
@@ -404,6 +525,28 @@ const open = async (row: AssessmentApprovalVO) => {
currentRow.value = row; currentRow.value = row;
visible.value = true; visible.value = true;
// 检查字典数据加载状态
console.log('🔍 打开弹窗时字典数据状态:', {
字典对象存在: !!bmzr_evaluation_level.value,
字典数据长度: bmzr_evaluation_level.value?.length || 0,
字典数据内容: bmzr_evaluation_level.value
});
// 等待字典数据加载完成(最多等待2秒)
let waitCount = 0;
while ((!bmzr_evaluation_level.value || bmzr_evaluation_level.value.length === 0) && waitCount < 20) {
await new Promise(resolve => setTimeout(resolve, 100));
waitCount++;
}
if (bmzr_evaluation_level.value && bmzr_evaluation_level.value.length > 0) {
console.log('✅ 字典数据加载完成:', bmzr_evaluation_level.value);
isDictLoaded.value = true;
} else {
console.warn('⚠️ 字典数据加载超时,使用备用数据');
}
await loadViewDetail(); await loadViewDetail();
}; };
@@ -415,37 +558,156 @@ const loadViewDetail = async () => {
loading.value = true; loading.value = true;
try { try {
const res = await getAssessmentApprovalDetail( // 并行加载详情数据和统计数据
currentRow.value.planId, const [detailRes, statsRes] = await Promise.allSettled([
currentRow.value.classId, getAssessmentApprovalDetail(currentRow.value.planId, currentRow.value.classId, currentRow.value.evaluatedUserId),
currentRow.value.evaluatedUserId getEvaluationLevelStats(currentRow.value.planId)
); ]);
viewDetail.value = res.data;
// 初始化班主任常规工作数据 // 处理详情数据
routineWorkScores.value = viewDetail.value?.routineWorkIndicators || []; if (detailRes.status === 'fulfilled') {
viewDetail.value = detailRes.value.data;
} else {
console.error('加载详情数据失败:', detailRes.reason);
proxy?.$modal.msgError('加载详情数据失败');
return;
}
// 处理统计数据(非必需,失败时使用简单评级)
if (statsRes.status === 'fulfilled') {
evaluationStats.value = statsRes.value.data;
console.log('✅ 评价等级统计数据加载成功:', evaluationStats.value);
// 检查统计数据的完整性
if (!evaluationStats.value.totalTeachers || evaluationStats.value.scoreRankings.length === 0) {
console.warn('⚠️ 统计数据不完整,总教师数:', evaluationStats.value.totalTeachers,
'排名数据条数:', evaluationStats.value.scoreRankings.length);
proxy?.$modal.msgWarning('统计数据不完整,可能影响等级评定准确性');
}
} else {
console.error('❌ 评价等级统计数据加载失败,使用简单评级:', statsRes.reason);
proxy?.$modal.msgWarning('无法加载等级统计数据,将使用简化评级规则');
evaluationStats.value = undefined;
}
// 详细的调试日志 - 用于排查数据显示问题
console.log('=== 查看详情数据加载开始 ===');
console.log('完整查看详情数据:', viewDetail.value);
console.log('班主任常规工作原始数据:', viewDetail.value?.routineWorkIndicators);
console.log('特色工作原始数据:', viewDetail.value?.specialWorkIndicators);
console.log('班级管理实效原始数据:', viewDetail.value?.classDeductionIndicator);
console.log('自我总体评价:', viewDetail.value?.selfOverallComment);
// 初始化班主任常规工作数据 - 确保包含所有必要字段
if (viewDetail.value?.routineWorkIndicators && Array.isArray(viewDetail.value.routineWorkIndicators)) {
routineWorkScores.value = viewDetail.value.routineWorkIndicators.map((item) => {
const mappedItem = {
...item,
// 确保数值字段不为空
selfScore: Number(item.selfScore) || 0,
superiorScore: Number(item.superiorScore) || 0,
score: Number(item.score) || 0,
maxScore: Number(item.maxScore) || 0,
// 确保字符串字段不为空
selfComment: item.selfComment || '',
superiorComment: item.superiorComment || '',
indicatorName: item.indicatorName || '',
description: item.description || '',
indicatorCode: item.indicatorCode || ''
};
console.log(`常规工作指标 [${item.indicatorName}]:`, {
自评分数: mappedItem.selfScore,
自评意见: mappedItem.selfComment,
上级评分: mappedItem.superiorScore,
上级意见: mappedItem.superiorComment
});
return mappedItem;
});
console.log('班主任常规工作数据初始化完成,条目数量:', routineWorkScores.value.length);
} else {
routineWorkScores.value = [];
console.warn('班主任常规工作数据为空或格式错误');
}
// 初始化班级管理实效数据 // 初始化班级管理实效数据
if (viewDetail.value?.classDeductionIndicator) { if (viewDetail.value?.classDeductionIndicator) {
const indicator = viewDetail.value.classDeductionIndicator; const indicator = viewDetail.value.classDeductionIndicator;
managementEffectivenessData.classDeduction = indicator.selfScore || 0; managementEffectivenessData.classDeduction = Number(indicator.selfScore) || 0;
managementEffectivenessData.classDeductionHalf = (indicator.selfScore || 0) * 0.5; managementEffectivenessData.classDeductionHalf = (Number(indicator.selfScore) || 0) * 0.5;
managementEffectivenessData.selfComment = indicator.selfComment || ''; managementEffectivenessData.selfComment = indicator.selfComment || '';
managementEffectivenessData.superiorScore = indicator.superiorScore || 0; managementEffectivenessData.superiorScore = Number(indicator.superiorScore) || 0;
managementEffectivenessData.superiorComment = indicator.superiorComment || ''; managementEffectivenessData.superiorComment = indicator.superiorComment || '';
console.log('班级管理实效数据初始化:', {
班级扣分: managementEffectivenessData.classDeduction,
扣分50计: managementEffectivenessData.classDeductionHalf,
自评意见: managementEffectivenessData.selfComment,
上级评分: managementEffectivenessData.superiorScore,
上级意见: managementEffectivenessData.superiorComment
});
} else {
// 如果没有找到班级扣分指标,设置默认值
managementEffectivenessData.classDeduction = 0;
managementEffectivenessData.classDeductionHalf = 0;
managementEffectivenessData.selfComment = '';
managementEffectivenessData.superiorScore = 0;
managementEffectivenessData.superiorComment = '';
console.warn('班级管理实效数据为空,使用默认值');
} }
// 初始化特色工作数据 // 初始化特色工作数据 - 确保包含所有必要字段
specialWorkScores.value = viewDetail.value?.specialWorkIndicators || []; if (viewDetail.value?.specialWorkIndicators && Array.isArray(viewDetail.value.specialWorkIndicators)) {
specialWorkScores.value = viewDetail.value.specialWorkIndicators.map((item) => {
const mappedItem = {
...item,
// 确保数值字段不为空
selfScore: Number(item.selfScore) || 0,
superiorScore: Number(item.superiorScore) || 0,
score: Number(item.score) || 0,
// 确保字符串字段不为空
selfComment: item.selfComment || '',
superiorComment: item.superiorComment || '',
indicatorName: item.indicatorName || '',
indicatorCode: item.indicatorCode || ''
};
console.log(`特色工作指标 [${item.indicatorCode} - ${item.indicatorName}]:`, {
自评分数: mappedItem.selfScore,
自评意见: mappedItem.selfComment,
上级评分: mappedItem.superiorScore,
上级意见: mappedItem.superiorComment
});
return mappedItem;
});
console.log('特色工作数据初始化完成,条目数量:', specialWorkScores.value.length);
} else {
specialWorkScores.value = [];
console.warn('特色工作数据为空或格式错误');
}
// 初始化月考核得分数据 // 初始化月考核得分数据
monthlyScoreData.selfOverallComment = viewDetail.value?.selfOverallComment || ''; monthlyScoreData.selfOverallComment = viewDetail.value?.selfOverallComment || '';
monthlyScoreData.superiorOverallComment = viewDetail.value?.superiorOverallComment || ''; monthlyScoreData.superiorOverallComment = viewDetail.value?.superiorOverallComment || '';
console.log('月考核得分数据初始化:', {
自我总体评价: monthlyScoreData.selfOverallComment,
上级总体评价: monthlyScoreData.superiorOverallComment,
计算得分: calculateMonthlyScore().toFixed(2)
});
// 初始化审批数据 // 初始化审批数据
// 这里需要根据实际的后端字段调整
approvalData.auditComment = ''; approvalData.auditComment = '';
console.log('=== 查看详情数据加载完成 ===');
// 验证数据完整性
if (routineWorkScores.value.length === 0) {
console.warn('⚠️ 警告:班主任常规工作数据为空,可能存在数据问题');
proxy?.$modal.msgWarning('班主任常规工作数据为空,请检查数据是否正确');
}
if (specialWorkScores.value.length === 0) {
console.warn('⚠️ 警告:特色工作数据为空,可能存在数据问题');
proxy?.$modal.msgWarning('特色工作数据为空,请检查数据是否正确');
}
} catch (error) { } catch (error) {
console.error('加载查看详情失败:', error); console.error('加载查看详情失败:', error);
proxy?.$modal.msgError('加载查看详情失败'); proxy?.$modal.msgError('加载查看详情失败');
@@ -461,6 +723,9 @@ const handleClose = () => {
// 重置数据 // 重置数据
routineWorkScores.value = []; routineWorkScores.value = [];
specialWorkScores.value = []; specialWorkScores.value = [];
evaluationStats.value = undefined;
isDictLoaded.value = false; // 重置字典加载状态
Object.assign(managementEffectivenessData, { Object.assign(managementEffectivenessData, {
classDeduction: 0, classDeduction: 0,
classDeductionHalf: 0, classDeductionHalf: 0,
@@ -485,7 +750,7 @@ defineExpose({
<style scoped> <style scoped>
.view-dialog-content { .view-dialog-content {
max-height: 70vh; max-height: 65vh;
overflow-y: auto; overflow-y: auto;
} }
@@ -517,7 +782,7 @@ defineExpose({
/* 班主任常规工作表格样式优化 */ /* 班主任常规工作表格样式优化 */
:deep(.routine-work-table) { :deep(.routine-work-table) {
.el-table__body-wrapper { .el-table__body-wrapper {
max-height: 350px; max-height: 200px;
overflow-y: auto; overflow-y: auto;
} }
@@ -533,6 +798,11 @@ defineExpose({
/* 特色工作表格样式优化 */ /* 特色工作表格样式优化 */
:deep(.special-work-table) { :deep(.special-work-table) {
.el-table__body-wrapper {
max-height: 150px;
overflow-y: auto;
}
.el-table__row { .el-table__row {
height: auto; height: auto;
} }
+101 -40
View File
@@ -2,13 +2,8 @@
<div class="p-2 page-container"> <div class="p-2 page-container">
<!-- 班级标签页 --> <!-- 班级标签页 -->
<el-card shadow="never" class="tab-card" v-if="teacherClasses.length > 0"> <el-card shadow="never" class="tab-card" v-if="teacherClasses.length > 0">
<el-tabs v-model="activeTab" @tab-click="handleTabClick"> <el-tabs v-model="activeTab" @tab-change="handleTabChange" @tab-click="handleTabClick">
<el-tab-pane <el-tab-pane v-for="classItem in teacherClasses" :key="classItem.id" :label="classItem.className" :name="classItem.id?.toString()">
v-for="classItem in teacherClasses"
:key="classItem.id"
:label="classItem.className"
:name="classItem.id?.toString()"
>
<!-- 搜索区域 --> <!-- 搜索区域 -->
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]"> <div v-show="showSearch" class="mb-[10px]">
@@ -41,8 +36,7 @@
</template> </template>
<div class="table-container"> <div class="table-container">
<el-table v-loading="loading" border :data="assessmentPlanList" @selection-change="handleSelectionChange" @sort-change="sortChange"> <el-table v-loading="loading" border :data="assessmentPlanList" @sort-change="sortChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="计划名称" align="center" prop="planName" :show-overflow-tooltip="true" /> <el-table-column label="计划名称" align="center" prop="planName" :show-overflow-tooltip="true" />
<el-table-column label="计划编码" align="center" prop="planCode" :show-overflow-tooltip="true" /> <el-table-column label="计划编码" align="center" prop="planCode" :show-overflow-tooltip="true" />
<el-table-column label="考核方案" align="center" prop="schemeName" :show-overflow-tooltip="true" /> <el-table-column label="考核方案" align="center" prop="schemeName" :show-overflow-tooltip="true" />
@@ -67,6 +61,7 @@
<el-table-column label="审核状态" align="center" width="120"> <el-table-column label="审核状态" align="center" width="120">
<template #default="scope"> <template #default="scope">
<el-tag v-if="!scope.row.submitted" type="info" effect="plain">未提交</el-tag> <el-tag v-if="!scope.row.submitted" type="info" effect="plain">未提交</el-tag>
<el-tag v-else-if="scope.row.auditStatus === '9'" type="primary" effect="plain">草稿</el-tag>
<el-tag v-else-if="scope.row.auditStatus === '0'" type="warning" effect="plain">待审核</el-tag> <el-tag v-else-if="scope.row.auditStatus === '0'" type="warning" effect="plain">待审核</el-tag>
<el-tag v-else-if="scope.row.auditStatus === '1'" type="success" effect="plain">审核通过</el-tag> <el-tag v-else-if="scope.row.auditStatus === '1'" type="success" effect="plain">审核通过</el-tag>
<el-tag v-else-if="scope.row.auditStatus === '2'" type="danger" effect="plain">审核不通过</el-tag> <el-tag v-else-if="scope.row.auditStatus === '2'" type="danger" effect="plain">审核不通过</el-tag>
@@ -80,8 +75,22 @@
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<!-- 未提交状态:显示提交考核按钮 --> <!-- 审核通过状态:只显示查看考核按钮 -->
<template v-if="!scope.row.submitted"> <template v-if="scope.row.auditStatus === '1'">
<el-tooltip content="查看考核" placement="top">
<el-button
link
type="success"
icon="View"
:disabled="loading || !isDataReady"
@click="handleViewAssessment(scope.row)"
></el-button>
</el-tooltip>
</template>
<!-- 其他状态:显示相应的操作按钮 -->
<template v-else>
<!-- 未提交状态、草稿状态或审核不通过状态:显示提交考核按钮 -->
<template v-if="!scope.row.submitted || scope.row.auditStatus === '9' || scope.row.auditStatus === '2'">
<el-tooltip content="提交考核" placement="top"> <el-tooltip content="提交考核" placement="top">
<el-button <el-button
link link
@@ -92,14 +101,14 @@
></el-button> ></el-button>
</el-tooltip> </el-tooltip>
</template> </template>
<!-- 已提交状态:显示撤销按钮 --> <!-- 已提交状态(待审核):显示撤销按钮 -->
<template v-else> <template v-else-if="scope.row.auditStatus === '0'">
<el-tooltip content="撤销提交" placement="top"> <el-tooltip content="撤销提交" placement="top">
<el-button <el-button
link link
type="warning" type="warning"
icon="RefreshLeft" icon="RefreshLeft"
:disabled="loading || !isDataReady || scope.row.auditStatus !== '0'" :disabled="loading || !isDataReady"
@click="handleWithdrawAssessment(scope.row)" @click="handleWithdrawAssessment(scope.row)"
></el-button> ></el-button>
</el-tooltip> </el-tooltip>
@@ -114,12 +123,19 @@
></el-button> ></el-button>
</el-tooltip> </el-tooltip>
</template> </template>
</template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
<div class="pagination-container"> <div class="pagination-container">
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> <pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div> </div>
</el-card> </el-card>
</el-tab-pane> </el-tab-pane>
@@ -132,12 +148,10 @@
</el-card> </el-card>
<!-- 考核提交弹窗 --> <!-- 考核提交弹窗 -->
<SubmitDialog <SubmitDialog ref="submitDialogRef" :plan-id="currentPlanId" :class-id="currentClassId" @success="handleSubmitSuccess" />
ref="submitDialogRef"
:plan-id="currentPlanId" <!-- 考核查看弹窗 -->
:class-id="currentClassId" <ViewDialog ref="viewDialogRef" :plan-id="currentPlanId" :class-id="currentClassId" />
@success="handleSubmitSuccess"
/>
</div> </div>
</template> </template>
@@ -150,13 +164,10 @@ import {
getAssessmentDetail, getAssessmentDetail,
withdrawAssessment withdrawAssessment
} from '@/api/bzrkh/teacherAssessment'; } from '@/api/bzrkh/teacherAssessment';
import { import { TeacherClassVO, TeacherAssessmentPlanVO, TeacherAssessmentPlanQuery } from '@/api/bzrkh/teacherAssessment/types';
TeacherClassVO,
TeacherAssessmentPlanVO,
TeacherAssessmentPlanQuery
} from '@/api/bzrkh/teacherAssessment/types';
import { useUserStore } from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
import SubmitDialog from './submitDialog.vue'; import SubmitDialog from './submitDialog.vue';
import ViewDialog from './viewDialog.vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userStore = useUserStore(); const userStore = useUserStore();
@@ -174,6 +185,9 @@ const currentPlanId = ref<string | number>();
const currentClassId = ref<string | number>(); const currentClassId = ref<string | number>();
const submitDialogRef = ref(); const submitDialogRef = ref();
// 考核查看相关状态
const viewDialogRef = ref();
const queryFormRef = ref<ElFormInstance>(); const queryFormRef = ref<ElFormInstance>();
const data = reactive<PageData<any, TeacherAssessmentPlanQuery>>({ const data = reactive<PageData<any, TeacherAssessmentPlanQuery>>({
@@ -182,7 +196,8 @@ const data = reactive<PageData<any, TeacherAssessmentPlanQuery>>({
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
planName: undefined, planName: undefined,
planStatus: '1' // 只查询启用状态的计划 planStatus: '1', // 只查询启用状态的计划
classId: undefined // 添加班级ID参数
}, },
rules: {} rules: {}
}); });
@@ -207,6 +222,8 @@ const getTeacherClasses = async () => {
if (teacherClasses.value.length > 0) { if (teacherClasses.value.length > 0) {
// 默认选中第一个班级 // 默认选中第一个班级
activeTab.value = teacherClasses.value[0].id?.toString() || ''; activeTab.value = teacherClasses.value[0].id?.toString() || '';
// 设置查询参数中的班级ID
queryParams.value.classId = activeTab.value;
// 等待activeTab设置完成后再获取列表 // 等待activeTab设置完成后再获取列表
await nextTick(); await nextTick();
await getList(); await getList();
@@ -223,7 +240,21 @@ const getTeacherClasses = async () => {
const getList = async () => { const getList = async () => {
loading.value = true; loading.value = true;
try { try {
console.log('📋 查询参数:', {
classId: queryParams.value.classId,
teacherId: userStore.userId,
planName: queryParams.value.planName,
planStatus: queryParams.value.planStatus
});
const res = await listTeacherAssessmentPlans(queryParams.value); const res = await listTeacherAssessmentPlans(queryParams.value);
console.log('📊 查询结果:', {
total: res.total,
dataCount: res.rows?.length,
firstItemStatus: res.rows?.[0]?.auditStatus,
firstItemSubmitted: res.rows?.[0]?.submitted
});
assessmentPlanList.value = res.rows || []; assessmentPlanList.value = res.rows || [];
total.value = res.total || 0; total.value = res.total || 0;
} catch (error) { } catch (error) {
@@ -233,12 +264,36 @@ const getList = async () => {
} }
}; };
/** 标签页切换 */ /** 标签页值变化事件 */
const handleTabClick = (tab: any) => { const handleTabChange = async (tabName: string) => {
console.log('🔄 标签页值变化:', {
oldClassId: queryParams.value.classId,
newTabName: tabName,
activeTab: activeTab.value
});
// 重置分页和设置班级ID
queryParams.value.pageNum = 1; queryParams.value.pageNum = 1;
queryParams.value.classId = tabName;
console.log('🔄 参数设置完成:', {
classId: queryParams.value.classId,
activeTab: activeTab.value
});
// 等待参数设置完成后再查询
await nextTick();
getList(); getList();
}; };
/** 标签页点击事件 */
const handleTabClick = (tab: any) => {
console.log('🔄 标签页点击:', {
tabName: tab.props.name,
tabLabel: tab.props.label
});
};
/** 搜索按钮操作 */ /** 搜索按钮操作 */
const handleQuery = () => { const handleQuery = () => {
queryParams.value.pageNum = 1; queryParams.value.pageNum = 1;
@@ -251,10 +306,7 @@ const resetQuery = () => {
handleQuery(); handleQuery();
}; };
/** 多选框选中数据 */
const handleSelectionChange = (selection: TeacherAssessmentPlanVO[]) => {
// 不再需要处理批量选择逻辑
};
/** 排序触发事件 */ /** 排序触发事件 */
const sortChange = (column: any) => { const sortChange = (column: any) => {
@@ -287,7 +339,7 @@ const handleSubmitAssessment = async (row: TeacherAssessmentPlanVO) => {
return; return;
} }
const currentClass = teacherClasses.value.find(c => c.id?.toString() === activeTab.value); const currentClass = teacherClasses.value.find((c) => c.id?.toString() === activeTab.value);
if (!currentClass || !currentClass.id) { if (!currentClass || !currentClass.id) {
proxy?.$modal.msgError('获取班级信息失败,请刷新页面后重试'); proxy?.$modal.msgError('获取班级信息失败,请刷新页面后重试');
@@ -324,15 +376,22 @@ const handleViewAssessment = async (row: TeacherAssessmentPlanVO) => {
return; return;
} }
const currentClass = teacherClasses.value.find(c => c.id?.toString() === activeTab.value); const currentClass = teacherClasses.value.find((c) => c.id?.toString() === activeTab.value);
if (!currentClass || !currentClass.id) { if (!currentClass || !currentClass.id) {
proxy?.$modal.msgError('获取班级信息失败,请刷新页面后重试'); proxy?.$modal.msgError('获取班级信息失败,请刷新页面后重试');
return; return;
} }
// TODO: 实现查看考核逻辑 // 设置当前查看的计划ID和班级ID
proxy?.$modal.msg('查看考核功能待实现'); currentPlanId.value = row.id;
currentClassId.value = currentClass.id;
// 确保参数设置成功后再打开弹窗
await nextTick();
// 打开查看弹窗,传递审核状态用于判断显示模式
viewDialogRef.value?.open(row.auditStatus);
}; };
/** 撤销考核提交 */ /** 撤销考核提交 */
@@ -355,7 +414,7 @@ const handleWithdrawAssessment = async (row: TeacherAssessmentPlanVO) => {
return; return;
} }
const currentClass = teacherClasses.value.find(c => c.id?.toString() === activeTab.value); const currentClass = teacherClasses.value.find((c) => c.id?.toString() === activeTab.value);
if (!currentClass || !currentClass.id) { if (!currentClass || !currentClass.id) {
proxy?.$modal.msgError('获取班级信息失败,请刷新页面后重试'); proxy?.$modal.msgError('获取班级信息失败,请刷新页面后重试');
@@ -369,10 +428,12 @@ const handleWithdrawAssessment = async (row: TeacherAssessmentPlanVO) => {
// 调用撤销API // 调用撤销API
await withdrawAssessment(row.id, currentClass.id); await withdrawAssessment(row.id, currentClass.id);
proxy?.$modal.msgSuccess('撤销成功'); proxy?.$modal.msgSuccess('撤销成功!您的评分数据已保留,可以重新修改和提交。');
// 刷新列表 // 刷新列表,确保状态更新
await getList(); await getList();
console.log('撤销成功,列表已刷新');
} catch (error) { } catch (error) {
if (error !== 'cancel') { if (error !== 'cancel') {
console.error('撤销考核提交失败:', error); console.error('撤销考核提交失败:', error);
@@ -1,12 +1,5 @@
<template> <template>
<el-dialog <el-dialog :title="dialogTitle" v-model="visible" width="1200px" :close-on-click-modal="false" append-to-body @close="handleClose">
:title="dialogTitle"
v-model="visible"
width="1200px"
:close-on-click-modal="false"
append-to-body
@close="handleClose"
>
<div v-loading="loading" class="submit-dialog-content"> <div v-loading="loading" class="submit-dialog-content">
<!-- 1. 班级信息卡片 --> <!-- 1. 班级信息卡片 -->
<el-card shadow="never" class="info-card"> <el-card shadow="never" class="info-card">
@@ -62,7 +55,9 @@
</template> </template>
<el-descriptions :column="2" border> <el-descriptions :column="2" border>
<el-descriptions-item label="班级总人数">{{ assessmentDetail?.classDetail?.totalStudentCount || 0 }}人</el-descriptions-item> <el-descriptions-item label="班级总人数">{{ assessmentDetail?.classDetail?.totalStudentCount || 0 }}人</el-descriptions-item>
<el-descriptions-item label="人数系数">{{ formatNumber(assessmentDetail?.coefficient?.studentCountCoefficient, 3) }}</el-descriptions-item> <el-descriptions-item label="人数系数">{{
formatNumber(assessmentDetail?.coefficient?.studentCountCoefficient, 3)
}}</el-descriptions-item>
</el-descriptions> </el-descriptions>
</el-card> </el-card>
</el-col> </el-col>
@@ -75,7 +70,9 @@
</template> </template>
<el-descriptions :column="2" border> <el-descriptions :column="2" border>
<el-descriptions-item label="住校生人数">{{ assessmentDetail?.classDetail?.boardingStudentCount || 0 }}人</el-descriptions-item> <el-descriptions-item label="住校生人数">{{ assessmentDetail?.classDetail?.boardingStudentCount || 0 }}人</el-descriptions-item>
<el-descriptions-item label="住校生系数">{{ formatNumber(assessmentDetail?.coefficient?.boardingCoefficient, 3) }}</el-descriptions-item> <el-descriptions-item label="住校生系数">{{
formatNumber(assessmentDetail?.coefficient?.boardingCoefficient, 3)
}}</el-descriptions-item>
</el-descriptions> </el-descriptions>
</el-card> </el-card>
</el-col> </el-col>
@@ -92,7 +89,7 @@
<el-table-column type="index" label="序号" width="60" align="center" /> <el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="indicatorName" label="指标名称" min-width="180" align="center" :show-overflow-tooltip="true" /> <el-table-column prop="indicatorName" label="指标名称" min-width="180" align="center" :show-overflow-tooltip="true" />
<el-table-column prop="description" label="指标描述" min-width="200" align="center" :show-overflow-tooltip="true" /> <el-table-column prop="description" label="指标描述" min-width="200" align="center" :show-overflow-tooltip="true" />
<el-table-column prop="score" label="指标分值" width="100" align="center"> <el-table-column prop="score" label="指标分值" width="80" align="center">
<template #default="scope"> <template #default="scope">
<span>{{ scope.row.score || 0 }}</span> <span>{{ scope.row.score || 0 }}</span>
</template> </template>
@@ -108,6 +105,7 @@
style="width: 100%" style="width: 100%"
placeholder="请输入分数" placeholder="请输入分数"
size="small" size="small"
class="score-input"
/> />
</template> </template>
</el-table-column> </el-table-column>
@@ -116,11 +114,12 @@
<el-input <el-input
v-model="scope.row.selfComment" v-model="scope.row.selfComment"
type="textarea" type="textarea"
:rows="2" :rows="1"
placeholder="请输入自评意见" placeholder="请输入自评意见"
maxlength="200" maxlength="200"
show-word-limit show-word-limit
size="small" size="small"
class="comment-input"
/> />
</template> </template>
</el-table-column> </el-table-column>
@@ -154,7 +153,7 @@
<el-input <el-input
:value="managementEffectivenessForm.classDeductionHalf?.toFixed(2) || '0.00'" :value="managementEffectivenessForm.classDeductionHalf?.toFixed(2) || '0.00'"
readonly readonly
style="width: 100%; text-align: center;" style="width: 100%; text-align: center"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -188,127 +187,95 @@
<span>特色工作(加20分)</span> <span>特色工作(加20分)</span>
</div> </div>
</template> </template>
<el-form :model="specialWorkForm" label-width="240px" class="special-work-form"> <el-form :model="specialWorkForm" class="special-work-form">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="及时并妥善处理好学生违纪事件" class="no-wrap-label"> <el-form-item label="及时并妥善处理好学生违纪事件" label-width="240px" class="no-wrap-label">
<el-input-number <el-input-number
v-model="specialWorkForm.score1" v-model="specialWorkForm.score1"
:min="0" :min="0"
:max="20" :max="20"
:precision="2" :precision="2"
controls-position="right" controls-position="right"
style="width: 100%" style="width: 150px"
placeholder="请输入分值" placeholder="请输入分值"
@change="calculateTotalSpecialScore" @change="calculateTotalSpecialScore"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="自评意见"> <el-form-item label="自评意见" label-width="80px">
<el-input <el-input v-model="specialWorkForm.comment1" type="textarea" :rows="1" placeholder="请输入自评意见" maxlength="200" show-word-limit class="special-comment-input" />
v-model="specialWorkForm.comment1"
type="textarea"
:rows="2"
placeholder="请输入自评意见"
maxlength="200"
show-word-limit
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="班级活动获奖情况"> <el-form-item label="班级活动获奖情况" label-width="240px">
<el-input-number <el-input-number
v-model="specialWorkForm.score2" v-model="specialWorkForm.score2"
:min="0" :min="0"
:max="20" :max="20"
:precision="2" :precision="2"
controls-position="right" controls-position="right"
style="width: 100%" style="width: 150px"
placeholder="请输入分值" placeholder="请输入分值"
@change="calculateTotalSpecialScore" @change="calculateTotalSpecialScore"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="自评意见"> <el-form-item label="自评意见" label-width="80px">
<el-input <el-input v-model="specialWorkForm.comment2" type="textarea" :rows="1" placeholder="请输入自评意见" maxlength="200" show-word-limit class="special-comment-input" />
v-model="specialWorkForm.comment2"
type="textarea"
:rows="2"
placeholder="请输入自评意见"
maxlength="200"
show-word-limit
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="班级宣传工作有特色" class="no-wrap-label"> <el-form-item label="班级宣传工作有特色" label-width="240px" class="no-wrap-label">
<el-input-number <el-input-number
v-model="specialWorkForm.score3" v-model="specialWorkForm.score3"
:min="0" :min="0"
:max="20" :max="20"
:precision="2" :precision="2"
controls-position="right" controls-position="right"
style="width: 100%" style="width: 150px"
placeholder="请输入分值" placeholder="请输入分值"
@change="calculateTotalSpecialScore" @change="calculateTotalSpecialScore"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="自评意见"> <el-form-item label="自评意见" label-width="80px">
<el-input <el-input v-model="specialWorkForm.comment3" type="textarea" :rows="1" placeholder="请输入自评意见" maxlength="200" show-word-limit class="special-comment-input" />
v-model="specialWorkForm.comment3"
type="textarea"
:rows="2"
placeholder="请输入自评意见"
maxlength="200"
show-word-limit
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="其他"> <el-form-item label="其他" label-width="240px">
<el-input-number <el-input-number
v-model="specialWorkForm.score4" v-model="specialWorkForm.score4"
:min="0" :min="0"
:max="20" :max="20"
:precision="2" :precision="2"
controls-position="right" controls-position="right"
style="width: 100%" style="width: 150px"
placeholder="请输入分值" placeholder="请输入分值"
@change="calculateTotalSpecialScore" @change="calculateTotalSpecialScore"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="自评意见"> <el-form-item label="自评意见" label-width="80px">
<el-input <el-input v-model="specialWorkForm.comment4" type="textarea" :rows="1" placeholder="请输入自评意见" maxlength="200" show-word-limit class="special-comment-input" />
v-model="specialWorkForm.comment4"
type="textarea"
:rows="2"
placeholder="请输入自评意见"
maxlength="200"
show-word-limit
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="总分值"> <el-form-item label="总分值" label-width="240px">
<el-input <el-input :value="specialWorkForm.totalScore?.toFixed(2) || '0.00'" readonly style="width: 150px; text-align: center" />
:value="specialWorkForm.totalScore?.toFixed(2) || '0.00'"
readonly
style="width: 100%; text-align: center;"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -326,11 +293,7 @@
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="月考核得分"> <el-form-item label="月考核得分">
<el-input <el-input :value="calculateMonthlyScore().toFixed(2)" readonly style="width: 100%; text-align: center" />
:value="calculateMonthlyScore().toFixed(2)"
readonly
style="width: 100%; text-align: center;"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -354,25 +317,106 @@
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button :loading="submitLoading" type="primary" @click="handleSubmit">保存</el-button> <el-button :loading="saveLoading" type="primary" @click="handleSubmit">保存</el-button>
<el-button :loading="submitLoading" type="success" @click="handleSubmitForApproval">提交</el-button> <el-button :loading="submitLoading" type="success" @click="handleSubmitForApproval">提交</el-button>
<el-button @click="handleClose">取消</el-button> <el-button @click="handleClose">取消</el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
<!-- 学生违纪记录和奖励记录弹窗 -->
<el-dialog title="学生违规处分信息查看" v-model="studentRecordsVisible" width="1400px" :close-on-click-modal="false" append-to-body>
<div v-loading="studentRecordsLoading" class="student-records-content">
<!-- 班级信息 -->
<el-card shadow="never" class="info-header">
<div class="class-info">
<h3>{{ studentRecordsData?.className || '班级信息' }}</h3>
<div class="statistics">
<el-tag type="danger" size="large">违纪记录: {{ studentRecordsData?.disciplineCount || 0 }}条</el-tag>
<el-tag type="success" size="large" style="margin-left: 16px">奖励记录: {{ studentRecordsData?.rewardCount || 0 }}条</el-tag>
</div>
</div>
</el-card>
<!-- Tab切换 -->
<el-tabs type="border-card" style="margin-top: 16px">
<!-- 违纪记录Tab -->
<el-tab-pane label="违纪记录" name="discipline">
<el-table :data="studentRecordsData?.disciplineRecords || []" border style="width: 100%" max-height="400" empty-text="暂无违纪记录">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="studentNo" label="学号" width="120" align="center" />
<el-table-column prop="studentName" label="学生姓名" width="100" align="center" />
<el-table-column prop="disciplineTypeName" label="违纪类型" width="120" align="center" />
<el-table-column prop="disciplineDate" label="违纪日期" width="110" align="center">
<template #default="scope">
<span>{{ scope.row.disciplineDate?.split(' ')[0] || '-' }}</span>
</template>
</el-table-column>
<el-table-column prop="disciplineReason" label="违纪原因" min-width="200" :show-overflow-tooltip="true" />
<el-table-column prop="disciplineContent" label="处分内容" min-width="200" :show-overflow-tooltip="true" />
<el-table-column prop="scoreDeduction" label="扣分" width="80" align="center">
<template #default="scope">
<el-tag type="danger" size="small">{{ scope.row.scoreDeduction || 0 }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="80" align="center">
<template #default="scope">
<el-tag :type="scope.row.status === '1' ? 'danger' : 'info'" size="small">
{{ scope.row.status === '1' ? '生效' : '已撤销' }}
</el-tag>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<!-- 奖励记录Tab -->
<el-tab-pane label="奖励记录" name="reward">
<el-table :data="studentRecordsData?.rewardRecords || []" border style="width: 100%" max-height="400" empty-text="暂无奖励记录">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="studentNo" label="学号" width="120" align="center" />
<el-table-column prop="studentName" label="学生姓名" width="100" align="center" />
<el-table-column prop="rewardTypeName" label="奖励类型" width="120" align="center" />
<el-table-column prop="rewardDate" label="奖励日期" width="110" align="center">
<template #default="scope">
<span>{{ scope.row.rewardDate || '-' }}</span>
</template>
</el-table-column>
<el-table-column prop="rewardContent" label="奖励内容" min-width="300" :show-overflow-tooltip="true" />
<el-table-column prop="scoreAddition" label="加分" width="80" align="center">
<template #default="scope">
<el-tag type="success" size="small">{{ scope.row.scoreAddition || 0 }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="80" align="center">
<template #default="scope">
<el-tag :type="scope.row.status === '1' ? 'success' : 'info'" size="small">
{{ scope.row.status === '1' ? '生效' : '撤销' }}
</el-tag>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="studentRecordsVisible = false">关闭</el-button>
</div>
</template>
</el-dialog>
</template> </template>
<script setup name="SubmitDialog" lang="ts"> <script setup name="SubmitDialog" lang="ts">
import { import { getAssessmentSubmitDetail, submitAssessmentScore, submitAssessment, getClassStudentRecords } from '@/api/bzrkh/teacherAssessment';
getAssessmentSubmitDetail,
submitAssessmentScore,
submitAssessment
} from '@/api/bzrkh/teacherAssessment';
import { import {
AssessmentDetailVO, AssessmentDetailVO,
AssessmentIndicatorVO, AssessmentIndicatorVO,
SpecialWorkIndicatorVO, SpecialWorkIndicatorVO,
AssessmentSubmitVO AssessmentSubmitVO,
ClassStudentRecordsVO,
StudentDisciplineRecordVO,
StudentRewardRecordVO
} from '@/api/bzrkh/teacherAssessment/types'; } from '@/api/bzrkh/teacherAssessment/types';
interface Props { interface Props {
@@ -387,6 +431,7 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const visible = ref(false); const visible = ref(false);
const loading = ref(false); const loading = ref(false);
const saveLoading = ref(false);
const submitLoading = ref(false); const submitLoading = ref(false);
const assessmentDetail = ref<AssessmentDetailVO>(); const assessmentDetail = ref<AssessmentDetailVO>();
@@ -417,6 +462,11 @@ const monthlyScoreForm = reactive({
overallComment: '' overallComment: ''
}); });
// 学生违纪记录和奖励记录弹窗相关
const studentRecordsVisible = ref(false);
const studentRecordsLoading = ref(false);
const studentRecordsData = ref<ClassStudentRecordsVO>();
const dialogTitle = computed(() => { const dialogTitle = computed(() => {
const className = assessmentDetail.value?.classDetail?.className || ''; const className = assessmentDetail.value?.classDetail?.className || '';
return `${className} - 班主任考核提交`; return `${className} - 班主任考核提交`;
@@ -456,10 +506,8 @@ const calculateDeductionHalf = () => {
/** 计算特色工作总分 */ /** 计算特色工作总分 */
const calculateTotalSpecialScore = () => { const calculateTotalSpecialScore = () => {
specialWorkForm.totalScore = (specialWorkForm.score1 || 0) + specialWorkForm.totalScore =
(specialWorkForm.score2 || 0) + (specialWorkForm.score1 || 0) + (specialWorkForm.score2 || 0) + (specialWorkForm.score3 || 0) + (specialWorkForm.score4 || 0);
(specialWorkForm.score3 || 0) +
(specialWorkForm.score4 || 0);
}; };
/** 计算月考核得分 */ /** 计算月考核得分 */
@@ -487,6 +535,28 @@ const open = async () => {
return; return;
} }
// 先重置所有表单数据,确保干净的状态
routineWorkScores.value = [];
Object.assign(managementEffectivenessForm, {
classDeduction: 0,
classDeductionHalf: 0,
selfComment: ''
});
Object.assign(specialWorkForm, {
score1: 0,
comment1: '',
score2: 0,
comment2: '',
score3: 0,
comment3: '',
score4: 0,
comment4: '',
totalScore: 0
});
Object.assign(monthlyScoreForm, {
overallComment: ''
});
visible.value = true; visible.value = true;
await loadAssessmentDetail(); await loadAssessmentDetail();
}; };
@@ -499,7 +569,7 @@ const loadAssessmentDetail = async () => {
assessmentDetail.value = res.data; assessmentDetail.value = res.data;
// 初始化班主任常规工作数据 // 初始化班主任常规工作数据
routineWorkScores.value = (assessmentDetail.value?.routineWorkIndicators || []).map(item => ({ routineWorkScores.value = (assessmentDetail.value?.routineWorkIndicators || []).map((item) => ({
...item, ...item,
selfScore: item.selfScore || 0, selfScore: item.selfScore || 0,
selfComment: item.selfComment || '' selfComment: item.selfComment || ''
@@ -514,7 +584,10 @@ const loadAssessmentDetail = async () => {
// 初始化特色工作数据 // 初始化特色工作数据
const specialWorkIndicators = assessmentDetail.value?.specialWorkIndicators || []; const specialWorkIndicators = assessmentDetail.value?.specialWorkIndicators || [];
specialWorkIndicators.forEach(item => { console.log('特色工作指标数据:', specialWorkIndicators);
specialWorkIndicators.forEach((item) => {
console.log(`处理特色工作指标: ${item.indicatorCode}, 分数: ${item.score}, 评论: ${item.selfComment}`);
switch (item.indicatorCode) { switch (item.indicatorCode) {
case 'bzrtsgz001': case 'bzrtsgz001':
specialWorkForm.score1 = Number(item.score) || 0; specialWorkForm.score1 = Number(item.score) || 0;
@@ -540,31 +613,72 @@ const loadAssessmentDetail = async () => {
// 初始化月考核得分数据 // 初始化月考核得分数据
monthlyScoreForm.overallComment = assessmentDetail.value?.overallComment || ''; monthlyScoreForm.overallComment = assessmentDetail.value?.overallComment || '';
// 调试信息:验证数据是否正确加载 // 详细的调试信息:验证数据是否正确加载
console.log('数据回显完成:', { console.log('=== 数据回显完成 ===');
totalSpecialScore: specialWorkForm.totalScore, console.log(
'班主任常规工作数据:',
routineWorkScores.value.map((item) => ({
name: item.indicatorName,
selfScore: item.selfScore,
selfComment: item.selfComment
}))
);
console.log('班级管理实效数据:', {
classDeduction: managementEffectivenessForm.classDeduction,
selfComment: managementEffectivenessForm.selfComment
});
console.log('特色工作数据:', {
score1: specialWorkForm.score1,
comment1: specialWorkForm.comment1,
score2: specialWorkForm.score2,
comment2: specialWorkForm.comment2,
score3: specialWorkForm.score3,
comment3: specialWorkForm.comment3,
score4: specialWorkForm.score4,
comment4: specialWorkForm.comment4,
totalScore: specialWorkForm.totalScore
});
console.log('月考核数据:', {
monthlyScore: calculateMonthlyScore(), monthlyScore: calculateMonthlyScore(),
overallComment: monthlyScoreForm.overallComment overallComment: monthlyScoreForm.overallComment
}); });
console.log('==================');
} catch (error) { } catch (error) {
console.error('加载考核详情失败:', error); console.error('加载考核详情失败:', error);
proxy?.$modal.msgError('加载考核详情失败'); proxy?.$modal.msgError('加载考核详情失败,请检查网络连接或刷新页面重试');
// 加载失败时关闭对话框
visible.value = false;
} finally { } finally {
loading.value = false; loading.value = false;
} }
}; };
/** 查看学生违规处分信息 */ /** 查看学生违规处分信息 */
const handleViewStudentViolations = () => { const handleViewStudentViolations = async () => {
proxy?.$modal.msg('学生违规处分信息查看功能暂未实现'); if (!props.classId) {
proxy?.$modal.msgError('缺少班级ID参数');
return;
}
studentRecordsLoading.value = true;
try {
const res = await getClassStudentRecords(props.classId);
studentRecordsData.value = res.data;
studentRecordsVisible.value = true;
} catch (error) {
console.error('查询学生违纪记录和奖励记录失败:', error);
proxy?.$modal.msgError('查询学生违纪记录和奖励记录失败');
} finally {
studentRecordsLoading.value = false;
}
}; };
/** 保存考核数据 */ /** 保存考核数据 */
const handleSubmit = async () => { const handleSubmit = async () => {
try { try {
// 验证必填项 // 验证必填项
if (routineWorkScores.value.some(item => item.selfScore === undefined || item.selfScore === null)) { if (routineWorkScores.value.some((item) => item.selfScore === undefined || item.selfScore === null)) {
proxy?.$modal.msgWarning('请完善班主任常规工作的自评分数'); proxy?.$modal.msgWarning('请完善班主任常规工作的自评分数');
return; return;
} }
@@ -575,7 +689,7 @@ const handleSubmit = async () => {
return; return;
} }
submitLoading.value = true; saveLoading.value = true;
// 构造提交数据 // 构造提交数据
const submitData: AssessmentSubmitVO = { const submitData: AssessmentSubmitVO = {
@@ -613,15 +727,26 @@ const handleSubmit = async () => {
overallComment: monthlyScoreForm.overallComment // 自我总体评价 - 将存储到数据库 self_overall_comment 字段 overallComment: monthlyScoreForm.overallComment // 自我总体评价 - 将存储到数据库 self_overall_comment 字段
}; };
console.log('提交数据:', submitData);
await submitAssessmentScore(submitData); await submitAssessmentScore(submitData);
proxy?.$modal.msgSuccess('考核保存成功'); proxy?.$modal.msgSuccess('考核数据已保存为草稿,可继续编辑或点击提交按钮进入审批流程');
emit('success');
} catch (error) { } catch (error) {
console.error('保存考核失败:', error); console.error('保存考核失败:', error);
proxy?.$modal.msgError('保存考核失败'); // 显示详细的错误信息
let errorMessage = '保存考核失败';
if (error && typeof error === 'object' && 'response' in error) {
const httpError = error as any;
if (httpError.response?.data?.msg) {
errorMessage = httpError.response.data.msg;
}
} else if (error && typeof error === 'object' && 'message' in error) {
errorMessage = (error as Error).message;
} else if (typeof error === 'string') {
errorMessage = error;
}
proxy?.$modal.msgError(errorMessage);
} finally { } finally {
submitLoading.value = false; saveLoading.value = false;
} }
}; };
@@ -629,7 +754,7 @@ const handleSubmit = async () => {
const handleSubmitForApproval = async () => { const handleSubmitForApproval = async () => {
try { try {
// 验证必填项 // 验证必填项
if (routineWorkScores.value.some(item => item.selfScore === undefined || item.selfScore === null)) { if (routineWorkScores.value.some((item) => item.selfScore === undefined || item.selfScore === null)) {
proxy?.$modal.msgWarning('请完善班主任常规工作的自评分数'); proxy?.$modal.msgWarning('请完善班主任常规工作的自评分数');
return; return;
} }
@@ -687,10 +812,21 @@ const handleSubmitForApproval = async () => {
proxy?.$modal.msgSuccess('考核提交成功,已进入审批流程'); proxy?.$modal.msgSuccess('考核提交成功,已进入审批流程');
emit('success'); emit('success');
handleClose(); handleClose();
} catch (error) { } catch (error) {
console.error('提交审批失败:', error); console.error('提交审批失败:', error);
proxy?.$modal.msgError('提交审批失败'); // 显示详细的错误信息
let errorMessage = '提交审批失败';
if (error && typeof error === 'object' && 'response' in error) {
const httpError = error as any;
if (httpError.response?.data?.msg) {
errorMessage = httpError.response.data.msg;
}
} else if (error && typeof error === 'object' && 'message' in error) {
errorMessage = (error as Error).message;
} else if (typeof error === 'string') {
errorMessage = error;
}
proxy?.$modal.msgError(errorMessage);
} finally { } finally {
submitLoading.value = false; submitLoading.value = false;
} }
@@ -781,6 +917,28 @@ defineExpose({
width: 100% !important; width: 100% !important;
} }
/* 自评分数输入框字体调整 - 参考特色工作输入框字体 */
.score-input .el-input-number__input {
font-size: 14px !important;
font-weight: 400;
text-align: center;
}
/* 覆盖small尺寸的字体大小,与特色工作输入框保持一致 */
.el-input-number--small.score-input .el-input-number__input {
font-size: 14px !important;
}
/* 自评意见输入框高度调整 - 参考班级总人数高度 */
.comment-input .el-textarea__inner {
resize: none;
min-height: 32px !important;
height: 32px !important;
line-height: 32px;
padding: 0 8px;
font-size: 14px;
}
.el-textarea__inner { .el-textarea__inner {
resize: none; resize: none;
min-height: 60px !important; min-height: 60px !important;
@@ -805,7 +963,16 @@ defineExpose({
.el-form-item__label { .el-form-item__label {
font-weight: 500; font-weight: 500;
text-align: center; text-align: left;
}
/* 特色工作自评意见高度调整 - 参考班级总人数高度 */
.special-comment-input .el-textarea__inner {
resize: none;
min-height: 32px !important;
height: 32px !important;
line-height: 32px;
padding: 0 8px;
} }
} }
@@ -857,4 +1024,48 @@ defineExpose({
margin-bottom: 12px; margin-bottom: 12px;
} }
} }
/* 学生记录弹窗样式 */
.student-records-content {
max-height: 70vh;
overflow-y: auto;
}
.info-header {
margin-bottom: 16px;
}
.class-info {
display: flex;
justify-content: space-between;
align-items: center;
h3 {
margin: 0;
color: #303133;
font-size: 18px;
font-weight: 600;
}
.statistics {
display: flex;
align-items: center;
}
}
/* Tab样式优化 */
:deep(.el-tabs--border-card) {
border: 1px solid #dcdfe6;
border-radius: 4px;
.el-tabs__header {
background-color: #f5f7fa;
border-bottom: 1px solid #dcdfe6;
margin: 0;
}
.el-tabs__content {
padding: 16px;
}
}
</style> </style>
File diff suppressed because it is too large. Load diff