weizhong 1 год назад
Родитель
Сommit
26044cc790
23 измененных файлов с 2835 добавлено и 15 удалено
  1. 36 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/controller/TeacherAssessmentController.java
  2. 136 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/BmzrAssessmentScore.java
  3. 61 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/bo/AssessmentSubmitBo.java
  4. 80 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentDetailVo.java
  5. 89 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentIndicatorScoreVo.java
  6. 78 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/ClassDetailVo.java
  7. 64 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/CoefficientVo.java
  8. 64 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/SpecialWorkIndicatorVo.java
  9. 14 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/BmzrAssessmentScoreMapper.java
  10. 82 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/TeacherAssessmentMapper.java
  11. 31 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/ITeacherAssessmentService.java
  12. 370 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/TeacherAssessmentServiceImpl.java
  13. 199 0
      backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/TeacherAssessmentMapper.xml
  14. 49 0
      backend/ruoyi-modules/ruoyi-bzrkh/班主任考核指标类型管理权限配置.sql
  15. 247 0
      backend/ruoyi-modules/ruoyi-bzrkh/班主任考核提交功能开发说明.md
  16. 87 0
      backend/ruoyi-modules/ruoyi-bzrkh/班主任考核提交功能必要数据.sql
  17. 86 0
      backend/ruoyi-modules/ruoyi-bzrkh/班主任考核提交功能权限配置.md
  18. 4 1
      docs/设计文档/database/班主任考核管理/bmzr_assessment_tables.sql
  19. 2 2
      web/src/api/bzrkh/assessmentIndicator/index.ts
  20. 36 1
      web/src/api/bzrkh/teacherAssessment/index.ts
  21. 217 0
      web/src/api/bzrkh/teacherAssessment/types.ts
  22. 104 11
      web/src/views/bzrkh/teacherAssessment/index.vue
  23. 699 0
      web/src/views/bzrkh/teacherAssessment/submitDialog.vue

+ 36 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/controller/TeacherAssessmentController.java

@@ -1,5 +1,6 @@
 package org.dromara.bzrkh.controller;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 import lombok.RequiredArgsConstructor;
@@ -14,7 +15,9 @@ import org.dromara.common.core.domain.R;
 import org.dromara.common.log.enums.BusinessType;
 import org.dromara.bzrkh.domain.vo.TeacherClassVo;
 import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo;
+import org.dromara.bzrkh.domain.vo.AssessmentDetailVo;
 import org.dromara.bzrkh.domain.bo.TeacherAssessmentQueryBo;
+import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo;
 import org.dromara.bzrkh.service.ITeacherAssessmentService;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.satoken.utils.LoginHelper;
@@ -81,6 +84,39 @@ public class TeacherAssessmentController extends BaseController {
         return R.ok(detail);
     }
 
+    /**
+     * 获取考核提交详情数据
+     */
+    @SaCheckPermission("bzrkh:teacherAssessment:detail")
+    @GetMapping("/submitDetail")
+    public R<AssessmentDetailVo> getAssessmentSubmitDetail(@RequestParam Long planId, @RequestParam Long classId) {
+        Long teacherId = LoginHelper.getUserId();
+        AssessmentDetailVo detail = teacherAssessmentService.getAssessmentSubmitDetail(planId, classId, teacherId);
+        return R.ok(detail);
+    }
+
+    /**
+     * 提交考核评分数据
+     */
+    @SaCheckPermission("bzrkh:teacherAssessment:submit")
+    @Log(title = "班主任考核管理", businessType = BusinessType.INSERT)
+    @PostMapping("/submitScore")
+    public R<Void> submitAssessmentScore(@RequestBody AssessmentSubmitBo bo) {
+        Long teacherId = LoginHelper.getUserId();
+        boolean result = teacherAssessmentService.submitAssessmentScore(bo, teacherId);
+        return toAjax(result);
+    }
+
+    /**
+     * 测试人数系数计算(临时调试接口)
+     * 用于验证特定人数的系数计算是否正确
+     */
+    @GetMapping("/testCoefficient")
+    public R<Object> testStudentCountCoefficient(@RequestParam int studentCount) {
+        BigDecimal coefficient = teacherAssessmentService.testStudentCountCoefficient(studentCount);
+        return R.ok("学生人数: " + studentCount + ", 计算系数: " + coefficient);
+    }
+
     /**
      * 提交考核请求对象
      */

+ 136 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/BmzrAssessmentScore.java

@@ -0,0 +1,136 @@
+package org.dromara.bzrkh.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import java.math.BigDecimal;
+
+import java.io.Serial;
+
+/**
+ * 班主任考核得分对象 bmzr_assessment_score
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("bmzr_assessment_score")
+public class BmzrAssessmentScore extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 考核计划ID
+     */
+    private Long planId;
+
+    /**
+     * 考核方案ID
+     */
+    private Long schemeId;
+
+    /**
+     * 考核指标ID
+     */
+    private Long indicatorId;
+
+    /**
+     * 被评价用户ID
+     */
+    private Long evaluatedUserId;
+
+    /**
+     * 被评价用户姓名
+     */
+    private String evaluatedUserName;
+
+    /**
+     * 被评价用户部门ID
+     */
+    private Long evaluatedDeptId;
+
+    /**
+     * 自评分数
+     */
+    private BigDecimal selfScore;
+
+    /**
+     * 自评意见
+     */
+    private String selfComment;
+
+    /**
+     * 自评提交时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date selfSubmitTime;
+
+    /**
+     * 上级评分数
+     */
+    private BigDecimal superiorScore;
+
+    /**
+     * 上级评意见
+     */
+    private String superiorComment;
+
+    /**
+     * 上级评价人ID
+     */
+    private Long superiorEvaluatorId;
+
+    /**
+     * 上级评提交时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date superiorSubmitTime;
+
+    /**
+     * 评价等级 dict_type = bmzr_evaluation_level
+     */
+    private String evaluationLevel;
+
+    /**
+     * 审核状态(0=待审核 1=审核通过 2=审核不通过)
+     */
+    private String auditStatus;
+
+    /**
+     * 最终得分
+     */
+    private BigDecimal finalScore;
+
+    /**
+     * 提交时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date submitTime;
+
+    /**
+     * 班级ID
+     */
+    private Long classId;
+
+    /**
+     * 自我总体评价
+     */
+    private String selfOverallComment;
+
+    /**
+     * 上级总体评价
+     */
+    private String superiorOverallComment;
+
+} 

+ 61 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/bo/AssessmentSubmitBo.java

@@ -0,0 +1,61 @@
+package org.dromara.bzrkh.domain.bo;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo;
+import org.dromara.bzrkh.domain.vo.SpecialWorkIndicatorVo;
+
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 考核提交业务对象
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class AssessmentSubmitBo extends BaseEntity {
+
+    /**
+     * 考核计划ID
+     */
+    @NotNull(message = "考核计划ID不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long planId;
+
+    /**
+     * 班级ID
+     */
+    @NotNull(message = "班级ID不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long classId;
+
+    /**
+     * 班主任常规工作指标评分
+     */
+    private List<AssessmentIndicatorScoreVo> routineWorkScores;
+
+    /**
+     * 班级扣分
+     */
+    private BigDecimal classDeduction;
+
+    /**
+     * 班级扣分意见
+     */
+    private String classDeductionComment;
+
+    /**
+     * 特色工作指标评分
+     */
+    private List<SpecialWorkIndicatorVo> specialWorkScores;
+
+    /**
+     * 总体评价
+     */
+    private String overallComment;
+} 

+ 80 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentDetailVo.java

@@ -0,0 +1,80 @@
+package org.dromara.bzrkh.domain.vo;
+
+import lombok.Data;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 考核详情视图对象
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@Data
+public class AssessmentDetailVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 班级详细信息
+     */
+    private ClassDetailVo classDetail;
+
+    /**
+     * 系数信息
+     */
+    private CoefficientVo coefficient;
+
+    /**
+     * 班主任常规工作指标列表
+     */
+    private List<AssessmentIndicatorScoreVo> routineWorkIndicators;
+
+    /**
+     * 班级扣分指标
+     */
+    private AssessmentIndicatorScoreVo classDeductionIndicator;
+
+    /**
+     * 特色工作指标列表
+     */
+    private List<SpecialWorkIndicatorVo> specialWorkIndicators;
+
+    /**
+     * 月考核得分
+     */
+    private BigDecimal monthlyScore;
+
+    /**
+     * 总体评价
+     */
+    private String overallComment;
+
+    /**
+     * 创建者
+     */
+    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;
+} 

+ 89 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentIndicatorScoreVo.java

@@ -0,0 +1,89 @@
+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.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 考核指标评分视图对象
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@Data
+public class AssessmentIndicatorScoreVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 指标ID
+     */
+    private Long id;
+
+    /**
+     * 指标名称
+     */
+    private String indicatorName;
+
+    /**
+     * 指标编码
+     */
+    private String indicatorCode;
+
+    /**
+     * 指标描述
+     */
+    private String description;
+
+    /**
+     * 指标分值
+     */
+    private BigDecimal score;
+
+    /**
+     * 自评分数
+     */
+    private BigDecimal selfScore;
+
+    /**
+     * 自评意见
+     */
+    private String selfComment;
+
+    /**
+     * 自我总体评价
+     */
+    private String selfOverallComment;
+
+    /**
+     * 排序
+     */
+    private Integer sortOrder;
+
+    /**
+     * 创建者
+     */
+    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;
+} 

+ 78 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/ClassDetailVo.java

@@ -0,0 +1,78 @@
+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;
+
+/**
+ * 班级详细信息视图对象
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@Data
+public class ClassDetailVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 班级ID
+     */
+    private Long id;
+
+    /**
+     * 学院名称
+     */
+    private String collegeName;
+
+    /**
+     * 专业名称
+     */
+    private String majorName;
+
+    /**
+     * 班级名称
+     */
+    private String className;
+
+    /**
+     * 班级层次:1-中级工 2-高级工 3-预备技师 4-技师 5-中高职一体
+     */
+    private String classType;
+
+    /**
+     * 班级总人数
+     */
+    private Integer totalStudentCount;
+
+    /**
+     * 住校生人数
+     */
+    private Integer boardingStudentCount;
+
+    /**
+     * 创建者
+     */
+    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;
+} 

+ 64 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/CoefficientVo.java

@@ -0,0 +1,64 @@
+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.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 系数信息视图对象
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@Data
+public class CoefficientVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 人数系数(K2)
+     */
+    private BigDecimal studentCountCoefficient;
+
+    /**
+     * 住校生系数(K3)
+     */
+    private BigDecimal boardingCoefficient;
+
+    /**
+     * 层次系数(K1)
+     */
+    private BigDecimal levelCoefficient;
+
+    /**
+     * 总系数(K = K1 * (K2 + K3))
+     */
+    private BigDecimal totalCoefficient;
+
+    /**
+     * 创建者
+     */
+    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;
+} 

+ 64 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/SpecialWorkIndicatorVo.java

@@ -0,0 +1,64 @@
+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.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 特色工作指标视图对象
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@Data
+public class SpecialWorkIndicatorVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 指标编码
+     */
+    private String indicatorCode;
+
+    /**
+     * 指标名称
+     */
+    private String indicatorName;
+
+    /**
+     * 分值
+     */
+    private BigDecimal score;
+
+    /**
+     * 自评意见
+     */
+    private String selfComment;
+
+    /**
+     * 创建者
+     */
+    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;
+} 

+ 14 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/BmzrAssessmentScoreMapper.java

@@ -0,0 +1,14 @@
+package org.dromara.bzrkh.mapper;
+
+import org.dromara.bzrkh.domain.BmzrAssessmentScore;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 班主任考核得分Mapper接口
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public interface BmzrAssessmentScoreMapper extends BaseMapperPlus<BmzrAssessmentScore, BmzrAssessmentScore> {
+
+} 

+ 82 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/TeacherAssessmentMapper.java

@@ -2,10 +2,14 @@ package org.dromara.bzrkh.mapper;
 
 import org.dromara.bzrkh.domain.vo.TeacherClassVo;
 import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo;
+import org.dromara.bzrkh.domain.vo.ClassDetailVo;
+import org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo;
+import org.dromara.bzrkh.domain.vo.SpecialWorkIndicatorVo;
 import org.dromara.bzrkh.domain.bo.TeacherAssessmentQueryBo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 import org.apache.ibatis.annotations.Param;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -31,4 +35,82 @@ public interface TeacherAssessmentMapper extends BaseMapperPlus<Object, Object>
      * @return 考核计划列表
      */
     List<BmzrAssessmentPlanVo> selectTeacherAssessmentPlanList(TeacherAssessmentQueryBo bo);
+
+    /**
+     * 查询班级详细信息
+     *
+     * @param classId 班级ID
+     * @return 班级详细信息
+     */
+    ClassDetailVo selectClassDetail(@Param("classId") Long classId);
+
+    /**
+     * 查询班主任常规工作指标列表
+     *
+     * @param planId 计划ID
+     * @return 指标列表
+     */
+    List<AssessmentIndicatorScoreVo> selectRoutineWorkIndicators(@Param("planId") Long planId);
+
+    /**
+     * 查询班级扣分指标
+     *
+     * @return 班级扣分指标
+     */
+    AssessmentIndicatorScoreVo selectClassDeductionIndicator();
+
+    /**
+     * 查询特色工作指标列表
+     *
+     * @return 特色工作指标列表
+     */
+    List<SpecialWorkIndicatorVo> selectSpecialWorkIndicators();
+
+    /**
+     * 查询已保存的评分数据
+     *
+     * @param planId    计划ID
+     * @param teacherId 班主任ID
+     * @return 评分数据列表
+     */
+    List<AssessmentIndicatorScoreVo> selectSavedAssessmentScores(@Param("planId") Long planId, @Param("teacherId") Long teacherId);
+
+    /**
+     * 根据计划ID查询方案ID
+     *
+     * @param planId 计划ID
+     * @return 方案ID
+     */
+    Long selectSchemeIdByPlanId(@Param("planId") Long planId);
+
+    /**
+     * 根据指标编码查询指标ID
+     *
+     * @param indicatorCode 指标编码
+     * @return 指标ID
+     */
+    Long selectIndicatorIdByCode(@Param("indicatorCode") String indicatorCode);
+
+    /**
+     * 逻辑删除指定计划和教师的评分数据
+     *
+     * @param planId    计划ID
+     * @param teacherId 教师ID
+     */
+    void deleteAssessmentScoresByPlanAndTeacher(@Param("planId") Long planId, @Param("teacherId") Long teacherId);
+
+
+
+    /**
+     * 更新评分数据的备注
+     *
+     * @param planId      计划ID
+     * @param indicatorId 指标ID
+     * @param teacherId   教师ID
+     * @param remark      备注
+     */
+    void updateAssessmentScoreRemark(@Param("planId") Long planId,
+                                    @Param("indicatorId") Long indicatorId,
+                                    @Param("teacherId") Long teacherId,
+                                    @Param("remark") String remark);
 } 

+ 31 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/ITeacherAssessmentService.java

@@ -2,10 +2,13 @@ package org.dromara.bzrkh.service;
 
 import org.dromara.bzrkh.domain.vo.TeacherClassVo;
 import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo;
+import org.dromara.bzrkh.domain.vo.AssessmentDetailVo;
 import org.dromara.bzrkh.domain.bo.TeacherAssessmentQueryBo;
+import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -52,4 +55,32 @@ public interface ITeacherAssessmentService {
      * @return 考核详情
      */
     Object getAssessmentDetail(Long planId, Long classId, Long teacherId);
+
+    /**
+     * 获取考核提交详情数据
+     *
+     * @param planId  计划ID
+     * @param classId 班级ID
+     * @param teacherId 班主任ID
+     * @return 考核提交详情
+     */
+    AssessmentDetailVo getAssessmentSubmitDetail(Long planId, Long classId, Long teacherId);
+
+    /**
+     * 提交考核评分数据
+     *
+     * @param bo 考核提交数据
+     * @param teacherId 班主任ID
+     * @return 是否成功
+     */
+    boolean submitAssessmentScore(AssessmentSubmitBo bo, Long teacherId);
+
+    /**
+     * 测试人数系数计算(临时调试方法)
+     * 用于验证特定人数的系数计算是否正确
+     *
+     * @param studentCount 学生人数
+     * @return 计算出的系数
+     */
+    BigDecimal testStudentCountCoefficient(int studentCount);
 } 

+ 370 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/TeacherAssessmentServiceImpl.java

@@ -4,14 +4,28 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.dromara.bzrkh.domain.vo.TeacherClassVo;
 import org.dromara.bzrkh.domain.vo.BmzrAssessmentPlanVo;
+import org.dromara.bzrkh.domain.vo.AssessmentDetailVo;
+import org.dromara.bzrkh.domain.vo.ClassDetailVo;
+import org.dromara.bzrkh.domain.vo.CoefficientVo;
+import org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo;
+import org.dromara.bzrkh.domain.vo.SpecialWorkIndicatorVo;
 import org.dromara.bzrkh.domain.bo.TeacherAssessmentQueryBo;
+import org.dromara.bzrkh.domain.bo.AssessmentSubmitBo;
 import org.dromara.bzrkh.mapper.TeacherAssessmentMapper;
+import org.dromara.bzrkh.mapper.BmzrAssessmentScoreMapper;
 import org.dromara.bzrkh.service.ITeacherAssessmentService;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.bzrkh.domain.BmzrAssessmentScore;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.List;
+import java.util.ArrayList;
+import java.util.Date;
 
 /**
  * 班主任考核管理Service业务层处理
@@ -19,11 +33,13 @@ import java.util.List;
  * @author ruoyi
  * @date 2025-01-27
  */
+@Slf4j
 @RequiredArgsConstructor
 @Service
 public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService {
 
     private final TeacherAssessmentMapper teacherAssessmentMapper;
+    private final BmzrAssessmentScoreMapper assessmentScoreMapper;
 
     /**
      * 查询班主任管理的班级列表
@@ -96,4 +112,358 @@ public class TeacherAssessmentServiceImpl implements ITeacherAssessmentService {
         // 4. 获取考核记录和评分
         return null;
     }
+
+    /**
+     * 获取考核提交详情数据
+     *
+     * @param planId    计划ID
+     * @param classId   班级ID
+     * @param teacherId 班主任ID
+     * @return 考核提交详情
+     */
+    @Override
+    public AssessmentDetailVo getAssessmentSubmitDetail(Long planId, Long classId, Long teacherId) {
+        AssessmentDetailVo detailVo = new AssessmentDetailVo();
+        
+        // 1. 获取班级详细信息
+        ClassDetailVo classDetail = teacherAssessmentMapper.selectClassDetail(classId);
+        detailVo.setClassDetail(classDetail);
+        
+        // 2. 计算系数信息
+        CoefficientVo coefficient = calculateCoefficient(classDetail);
+        detailVo.setCoefficient(coefficient);
+        
+        // 3. 获取班主任常规工作指标
+        List<AssessmentIndicatorScoreVo> routineWorkIndicators = teacherAssessmentMapper.selectRoutineWorkIndicators(planId);
+        detailVo.setRoutineWorkIndicators(routineWorkIndicators);
+        
+        // 4. 获取班级扣分指标
+        AssessmentIndicatorScoreVo classDeductionIndicator = teacherAssessmentMapper.selectClassDeductionIndicator();
+        detailVo.setClassDeductionIndicator(classDeductionIndicator);
+        
+        // 5. 获取特色工作指标
+        List<SpecialWorkIndicatorVo> specialWorkIndicators = teacherAssessmentMapper.selectSpecialWorkIndicators();
+        detailVo.setSpecialWorkIndicators(specialWorkIndicators);
+        
+        // 6. 获取已保存的评分数据(如果有)
+        List<AssessmentIndicatorScoreVo> savedScores = teacherAssessmentMapper.selectSavedAssessmentScores(planId, teacherId);
+        if (savedScores != null && !savedScores.isEmpty()) {
+            // 将已保存的评分数据合并到指标中
+            mergeAssessmentScores(detailVo, savedScores);
+            
+            // 获取总体评价(从任意一条记录中获取,因为都是同样的总体评价)
+            savedScores.stream()
+                .findFirst()
+                .ifPresent(saved -> detailVo.setOverallComment(saved.getSelfOverallComment()));
+        }
+        
+        return detailVo;
+    }
+
+    /**
+     * 提交考核评分数据
+     *
+     * @param bo        考核提交数据
+     * @param teacherId 班主任ID
+     * @return 是否成功
+     */
+    @Override
+    public boolean submitAssessmentScore(AssessmentSubmitBo bo, Long teacherId) {
+        try {
+            // 1. 先逻辑删除该计划下该教师的历史评分数据
+            teacherAssessmentMapper.deleteAssessmentScoresByPlanAndTeacher(bo.getPlanId(), teacherId);
+            
+            Long schemeId = teacherAssessmentMapper.selectSchemeIdByPlanId(bo.getPlanId());
+            String currentUserName = LoginHelper.getUsername();
+            Long currentDeptId = LoginHelper.getDeptId();
+            Date now = new Date();
+            
+            // 2. 插入班主任常规工作指标评分
+            if (bo.getRoutineWorkScores() != null && !bo.getRoutineWorkScores().isEmpty()) {
+                for (AssessmentIndicatorScoreVo score : bo.getRoutineWorkScores()) {
+                    BmzrAssessmentScore assessmentScore = new BmzrAssessmentScore();
+                    assessmentScore.setPlanId(bo.getPlanId());
+                    assessmentScore.setSchemeId(schemeId);
+                    assessmentScore.setIndicatorId(score.getId());
+                    assessmentScore.setEvaluatedUserId(teacherId);
+                    assessmentScore.setEvaluatedUserName(currentUserName);
+                    assessmentScore.setEvaluatedDeptId(currentDeptId);
+                    assessmentScore.setSelfScore(score.getSelfScore());
+                    assessmentScore.setSelfComment(score.getSelfComment());
+                    assessmentScore.setSelfSubmitTime(now);
+                    assessmentScore.setSubmitTime(now);
+                    assessmentScore.setAuditStatus("0");
+                    // 设置班级ID和自我总体评价
+                    assessmentScore.setClassId(bo.getClassId());
+                    assessmentScore.setSelfOverallComment(bo.getOverallComment());
+                    
+                    assessmentScoreMapper.insert(assessmentScore);
+                }
+            }
+            
+            // 3. 插入班级扣分指标评分
+            Long classDeductionIndicatorId = teacherAssessmentMapper.selectIndicatorIdByCode("bzrwjkf001");
+            if (classDeductionIndicatorId != null) {
+                BmzrAssessmentScore assessmentScore = new BmzrAssessmentScore();
+                assessmentScore.setPlanId(bo.getPlanId());
+                assessmentScore.setSchemeId(schemeId);
+                assessmentScore.setIndicatorId(classDeductionIndicatorId);
+                assessmentScore.setEvaluatedUserId(teacherId);
+                assessmentScore.setEvaluatedUserName(currentUserName);
+                assessmentScore.setEvaluatedDeptId(currentDeptId);
+                assessmentScore.setSelfScore(bo.getClassDeduction());
+                assessmentScore.setSelfComment(bo.getClassDeductionComment());
+                assessmentScore.setSelfSubmitTime(now);
+                assessmentScore.setSubmitTime(now);
+                assessmentScore.setAuditStatus("0");
+                // 设置班级ID和自我总体评价
+                assessmentScore.setClassId(bo.getClassId());
+                assessmentScore.setSelfOverallComment(bo.getOverallComment());
+                
+                assessmentScoreMapper.insert(assessmentScore);
+            }
+            
+            // 4. 插入特色工作指标评分
+            if (bo.getSpecialWorkScores() != null && !bo.getSpecialWorkScores().isEmpty()) {
+                for (SpecialWorkIndicatorVo score : bo.getSpecialWorkScores()) {
+                    Long indicatorId = teacherAssessmentMapper.selectIndicatorIdByCode(score.getIndicatorCode());
+                    if (indicatorId != null) {
+                        BmzrAssessmentScore assessmentScore = new BmzrAssessmentScore();
+                        assessmentScore.setPlanId(bo.getPlanId());
+                        assessmentScore.setSchemeId(schemeId);
+                        assessmentScore.setIndicatorId(indicatorId);
+                        assessmentScore.setEvaluatedUserId(teacherId);
+                        assessmentScore.setEvaluatedUserName(currentUserName);
+                        assessmentScore.setEvaluatedDeptId(currentDeptId);
+                        assessmentScore.setSelfScore(score.getScore());
+                        assessmentScore.setSelfComment(score.getSelfComment());
+                        assessmentScore.setSelfSubmitTime(now);
+                        assessmentScore.setSubmitTime(now);
+                        assessmentScore.setAuditStatus("0");
+                        // 设置班级ID和自我总体评价
+                        assessmentScore.setClassId(bo.getClassId());
+                        assessmentScore.setSelfOverallComment(bo.getOverallComment());
+                        
+                        assessmentScoreMapper.insert(assessmentScore);
+                    }
+                }
+            }
+            
+            // 5. 总体评价已经通过上述步骤存储到每条记录的 self_overall_comment 字段中
+            
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 计算系数信息
+     *
+     * @param classDetail 班级详细信息
+     * @return 系数信息
+     */
+    private CoefficientVo calculateCoefficient(ClassDetailVo classDetail) {
+        CoefficientVo coefficient = new CoefficientVo();
+        
+        // 计算人数系数(K2)
+        int totalStudents = classDetail.getTotalStudentCount() != null ? classDetail.getTotalStudentCount() : 0;
+        log.info("计算人数系数 - 班级ID: {}, 班级名称: {}, 学生总人数: {}", 
+                 classDetail.getId(), classDetail.getClassName(), totalStudents);
+        
+        // 数据验证:如果学生人数为0但前端显示有人数,可能是数据同步问题
+        if (totalStudents == 0) {
+            log.warn("警告:班级{}学生人数为0,请检查xg_student_msg表数据", classDetail.getClassName());
+        }
+        
+        BigDecimal studentCountCoefficient = calculateStudentCountCoefficient(totalStudents);
+        log.info("计算人数系数结果: {}", studentCountCoefficient);
+        
+        // 关键修复:确保人数系数不为0
+        if (studentCountCoefficient == null || studentCountCoefficient.compareTo(BigDecimal.ZERO) == 0) {
+            log.error("人数系数计算异常,学生人数: {},计算结果: {},进行修复", totalStudents, studentCountCoefficient);
+            // 直接重新计算并设置最低值
+            if (totalStudents > 0) {
+                // 手动计算25人的系数:1 - (36-25)*0.02 = 1 - 0.22 = 0.78
+                if (totalStudents < 36) {
+                    int missingStudents = 36 - totalStudents;
+                    BigDecimal deduction = BigDecimal.valueOf(missingStudents).multiply(BigDecimal.valueOf(0.02));
+                    studentCountCoefficient = BigDecimal.ONE.subtract(deduction);
+                    if (studentCountCoefficient.compareTo(BigDecimal.valueOf(0.7)) < 0) {
+                        studentCountCoefficient = BigDecimal.valueOf(0.7);
+                    }
+                    studentCountCoefficient = studentCountCoefficient.setScale(4, RoundingMode.HALF_UP);
+                    log.info("修复后的人数系数: {}", studentCountCoefficient);
+                } else {
+                    studentCountCoefficient = BigDecimal.valueOf(0.7).setScale(4, RoundingMode.HALF_UP);
+                }
+            } else {
+                studentCountCoefficient = BigDecimal.valueOf(0.7).setScale(4, RoundingMode.HALF_UP);
+            }
+        }
+        
+        coefficient.setStudentCountCoefficient(studentCountCoefficient);
+        
+        // 验证系数设置是否成功
+        if (coefficient.getStudentCountCoefficient() == null || 
+            coefficient.getStudentCountCoefficient().compareTo(BigDecimal.ZERO) == 0) {
+            log.error("错误:人数系数设置仍然失败,当前值: {}", coefficient.getStudentCountCoefficient());
+        }
+        
+        // 计算住校生系数(K3)
+        int boardingStudents = classDetail.getBoardingStudentCount() != null ? classDetail.getBoardingStudentCount() : 0;
+        BigDecimal boardingCoefficient = calculateBoardingCoefficient(boardingStudents);
+        coefficient.setBoardingCoefficient(boardingCoefficient);
+        
+        // 计算层次系数(K1)
+        BigDecimal levelCoefficient = calculateLevelCoefficient(classDetail.getClassType());
+        coefficient.setLevelCoefficient(levelCoefficient);
+        
+        // 计算总系数(K = K1 * (K2 + K3))
+        BigDecimal totalCoefficient = levelCoefficient.multiply(studentCountCoefficient.add(boardingCoefficient));
+        coefficient.setTotalCoefficient(totalCoefficient);
+        
+        return coefficient;
+    }
+
+    /**
+     * 计算人数系数(K2)
+     * 班级人数36~40人(含36人),系数为1;
+     * 超过40人,每增加1名学生,系数增加0.02;
+     * 少于36人,每减少1名学生,系数减少0.02;
+     * 本项系数最低0.7
+     */
+    private BigDecimal calculateStudentCountCoefficient(int studentCount) {
+        log.info("开始计算人数系数 - 输入学生人数: {}", studentCount);
+        
+        // 数据验证:如果学生人数异常,使用保护性默认值
+        if (studentCount < 0) {
+            log.warn("学生人数为负数({}),使用默认值0", studentCount);
+            studentCount = 0;
+        }
+        
+        BigDecimal coefficient;
+        if (studentCount >= 36 && studentCount <= 40) {
+            coefficient = BigDecimal.ONE;
+            log.info("人数在36-40人范围内,系数为1.0");
+        } else if (studentCount > 40) {
+            int extraStudents = studentCount - 40;
+            coefficient = BigDecimal.ONE.add(BigDecimal.valueOf(extraStudents * 0.02));
+            log.info("人数超过40人,额外{}人,系数为{}", extraStudents, coefficient);
+        } else {
+            // 少于36人的情况
+            int missingStudents = 36 - studentCount;
+            // 使用更精确的BigDecimal计算,避免精度问题
+            BigDecimal deduction = BigDecimal.valueOf(missingStudents).multiply(BigDecimal.valueOf(0.02));
+            coefficient = BigDecimal.ONE.subtract(deduction);
+            log.info("人数少于36人,缺少{}人,扣减{},计算系数为{}", missingStudents, deduction, coefficient);
+            
+            // 最低0.7
+            BigDecimal minCoefficient = BigDecimal.valueOf(0.7);
+            if (coefficient.compareTo(minCoefficient) < 0) {
+                log.info("系数{}低于最低值0.7,调整为0.7", coefficient);
+                coefficient = minCoefficient;
+            }
+        }
+        
+        BigDecimal result = coefficient.setScale(4, RoundingMode.HALF_UP);
+        log.info("最终人数系数: {}", result);
+        
+        // 额外验证:确保结果不为0
+        if (result.compareTo(BigDecimal.ZERO) == 0) {
+            log.error("严重错误:人数系数计算结果为0,学生人数: {},强制设置为最低值0.7", studentCount);
+            result = BigDecimal.valueOf(0.7).setScale(4, RoundingMode.HALF_UP);
+        }
+        
+        return result;
+    }
+
+    /**
+     * 测试人数系数计算(临时调试方法)
+     * 可以通过调用这个方法来验证具体人数的系数计算
+     */
+    public BigDecimal testStudentCountCoefficient(int studentCount) {
+        log.info("=== 测试人数系数计算 ===");
+        log.info("输入学生人数: {}", studentCount);
+        BigDecimal result = calculateStudentCountCoefficient(studentCount);
+        log.info("计算结果: {}", result);
+        log.info("=== 测试结束 ===");
+        return result;
+    }
+
+    /**
+     * 计算住校生系数(K3)
+     * 根据住校生人数,按人均0.005计算
+     */
+    private BigDecimal calculateBoardingCoefficient(int boardingCount) {
+        return BigDecimal.valueOf(boardingCount * 0.005).setScale(4, RoundingMode.HALF_UP);
+    }
+
+    /**
+     * 计算层次系数(K1)
+     * 技师班(K1=0.95),高级工班(K1=1),中级工班(K1=1.05)
+     */
+    private BigDecimal calculateLevelCoefficient(String classType) {
+        if (classType == null) {
+            return BigDecimal.ONE;
+        }
+        
+        switch (classType) {
+            case "1": // 中级工
+                return BigDecimal.valueOf(1.05);
+            case "2": // 高级工
+                return BigDecimal.ONE;
+            case "3": // 预备技师
+                return BigDecimal.valueOf(0.95);
+            case "4": // 技师
+                return BigDecimal.valueOf(0.95);
+            case "5": // 中高职一体
+                return BigDecimal.ONE;
+            default:
+                return BigDecimal.ONE;
+        }
+    }
+
+    /**
+     * 合并已保存的评分数据
+     */
+    private void mergeAssessmentScores(AssessmentDetailVo detailVo, List<AssessmentIndicatorScoreVo> savedScores) {
+        // 合并班主任常规工作指标评分
+        if (detailVo.getRoutineWorkIndicators() != null) {
+            for (AssessmentIndicatorScoreVo indicator : detailVo.getRoutineWorkIndicators()) {
+                savedScores.stream()
+                    .filter(saved -> saved.getId().equals(indicator.getId()))
+                    .findFirst()
+                    .ifPresent(saved -> {
+                        indicator.setSelfScore(saved.getSelfScore());
+                        indicator.setSelfComment(saved.getSelfComment());
+                    });
+            }
+        }
+        
+        // 合并班级扣分指标评分
+        if (detailVo.getClassDeductionIndicator() != null) {
+            savedScores.stream()
+                .filter(saved -> "bzrwjkf001".equals(saved.getIndicatorCode()))
+                .findFirst()
+                .ifPresent(saved -> {
+                    detailVo.getClassDeductionIndicator().setSelfScore(saved.getSelfScore());
+                    detailVo.getClassDeductionIndicator().setSelfComment(saved.getSelfComment());
+                });
+        }
+        
+        // 合并特色工作指标评分
+        if (detailVo.getSpecialWorkIndicators() != null) {
+            for (SpecialWorkIndicatorVo indicator : detailVo.getSpecialWorkIndicators()) {
+                savedScores.stream()
+                    .filter(saved -> indicator.getIndicatorCode().equals(saved.getIndicatorCode()))
+                    .findFirst()
+                    .ifPresent(saved -> {
+                        indicator.setScore(saved.getSelfScore());
+                        indicator.setSelfComment(saved.getSelfComment());
+                    });
+            }
+        }
+    }
 } 

+ 199 - 0
backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/TeacherAssessmentMapper.xml

@@ -45,6 +45,50 @@
         <result property="deleted" column="deleted"/>
     </resultMap>
 
+    <!-- 班级详细信息结果映射 -->
+    <resultMap type="org.dromara.bzrkh.domain.vo.ClassDetailVo" id="ClassDetailVoResult">
+        <result property="id" column="id"/>
+        <result property="collegeName" column="college_name"/>
+        <result property="majorName" column="major_name"/>
+        <result property="className" column="class_name"/>
+        <result property="classType" column="class_type"/>
+        <result property="totalStudentCount" column="total_student_count"/>
+        <result property="boardingStudentCount" column="boarding_student_count"/>
+        <result property="createBy" column="create_by"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateBy" column="update_by"/>
+        <result property="updateTime" column="update_time"/>
+    </resultMap>
+
+    <!-- 考核指标评分结果映射 -->
+    <resultMap type="org.dromara.bzrkh.domain.vo.AssessmentIndicatorScoreVo" id="AssessmentIndicatorScoreVoResult">
+        <result property="id" column="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="selfScore" column="self_score"/>
+        <result property="selfComment" column="self_comment"/>
+        <result property="selfOverallComment" column="self_overall_comment"/>
+        <result property="sortOrder" column="sort_order"/>
+        <result property="createBy" column="create_by"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateBy" column="update_by"/>
+        <result property="updateTime" column="update_time"/>
+    </resultMap>
+
+    <!-- 特色工作指标结果映射 -->
+    <resultMap type="org.dromara.bzrkh.domain.vo.SpecialWorkIndicatorVo" id="SpecialWorkIndicatorVoResult">
+        <result property="indicatorCode" column="indicator_code"/>
+        <result property="indicatorName" column="indicator_name"/>
+        <result property="score" column="score"/>
+        <result property="selfComment" column="self_comment"/>
+        <result property="createBy" column="create_by"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateBy" column="update_by"/>
+        <result property="updateTime" column="update_time"/>
+    </resultMap>
+
     <!-- 查询班主任管理的班级列表 -->
     <select id="selectTeacherClassList" parameterType="Long" resultMap="TeacherClassVoResult">
         SELECT 
@@ -109,4 +153,159 @@
         ORDER BY p.create_time DESC
     </select>
 
+    <!-- 查询班级详细信息 -->
+    <select id="selectClassDetail" parameterType="Long" resultMap="ClassDetailVoResult">
+        SELECT 
+            c.id,
+            c.college_name,
+            c.major_name,
+            c.class_name,
+            c.class_type,
+            (SELECT COUNT(1) 
+             FROM xg_student_msg s 
+             WHERE s.class_id = c.id 
+               AND s.student_status = '1' 
+               AND s.deleted = 0) as total_student_count,
+            (SELECT COUNT(1) 
+             FROM xg_student_msg s 
+             WHERE s.class_id = c.id 
+               AND s.student_status = '1' 
+               AND s.dormitory_room IS NOT NULL 
+               AND s.dormitory_room != ''
+               AND s.deleted = 0) as boarding_student_count,
+            c.create_by,
+            c.create_time,
+            c.update_by,
+            c.update_time
+        FROM xg_class_msg c
+        WHERE c.id = #{classId}
+          AND c.deleted = 0
+    </select>
+
+    <!-- 查询班主任常规工作指标列表 -->
+    <select id="selectRoutineWorkIndicators" parameterType="Long" resultMap="AssessmentIndicatorScoreVoResult">
+        SELECT 
+            i.id,
+            i.indicator_name,
+            i.indicator_code,
+            i.remark as description,
+            i.score,
+            i.sort_order,
+            NULL as self_score,
+            NULL as self_comment,
+            i.create_by,
+            i.create_time,
+            i.update_by,
+            i.update_time
+        FROM bmzr_assessment_plan p
+        JOIN bmzr_assessment_scheme_indicator si ON p.scheme_id = si.scheme_id AND si.deleted = 0
+        JOIN bmzr_assessment_indicator i ON si.indicator_id = i.id AND i.deleted = 0
+        WHERE p.id = #{planId}
+          AND p.deleted = 0
+          AND i.indicator_code NOT IN ('bzrwjkf001', 'bzrtsgz001', 'bzrtsgz002', 'bzrtsgz003', 'bzrtsgz004')
+        ORDER BY i.sort_order ASC
+    </select>
+
+    <!-- 查询班级扣分指标 -->
+    <select id="selectClassDeductionIndicator" resultMap="AssessmentIndicatorScoreVoResult">
+        SELECT 
+            i.id,
+            i.indicator_name,
+            i.indicator_code,
+            i.remark as description,
+            i.score,
+            i.sort_order,
+            NULL as self_score,
+            NULL as self_comment,
+            i.create_by,
+            i.create_time,
+            i.update_by,
+            i.update_time
+        FROM bmzr_assessment_indicator i
+        WHERE i.indicator_code = 'bzrwjkf001'
+          AND i.deleted = 0
+        LIMIT 1
+    </select>
+
+    <!-- 查询特色工作指标列表 -->
+    <select id="selectSpecialWorkIndicators" resultMap="SpecialWorkIndicatorVoResult">
+        SELECT 
+            i.indicator_code,
+            i.indicator_name,
+            0.00 as score,
+            NULL as self_comment,
+            i.create_by,
+            i.create_time,
+            i.update_by,
+            i.update_time
+        FROM bmzr_assessment_indicator i
+        WHERE i.indicator_code IN ('bzrtsgz001', 'bzrtsgz002', 'bzrtsgz003', 'bzrtsgz004')
+          AND i.deleted = 0
+        ORDER BY i.indicator_code ASC
+    </select>
+
+    <!-- 查询已保存的评分数据 -->
+    <select id="selectSavedAssessmentScores" 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.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.deleted = 0
+    </select>
+
+    <!-- 根据计划ID查询方案ID -->
+    <select id="selectSchemeIdByPlanId" parameterType="Long" resultType="Long">
+        SELECT scheme_id
+        FROM bmzr_assessment_plan
+        WHERE id = #{planId}
+          AND deleted = 0
+        LIMIT 1
+    </select>
+
+    <!-- 根据指标编码查询指标ID -->
+    <select id="selectIndicatorIdByCode" parameterType="String" resultType="Long">
+        SELECT id
+        FROM bmzr_assessment_indicator
+        WHERE indicator_code = #{indicatorCode}
+          AND deleted = 0
+        LIMIT 1
+    </select>
+
+    <!-- 逻辑删除指定计划和教师的评分数据 -->
+    <update id="deleteAssessmentScoresByPlanAndTeacher">
+        UPDATE bmzr_assessment_score
+        SET deleted = 1,
+            update_time = NOW()
+        WHERE plan_id = #{planId}
+          AND evaluated_user_id = #{teacherId}
+          AND deleted = 0
+    </update>
+
+
+
+    <!-- 更新评分数据的备注 -->
+    <update id="updateAssessmentScoreRemark">
+        UPDATE bmzr_assessment_score
+        SET remark = #{remark},
+            update_time = NOW()
+        WHERE plan_id = #{planId}
+          AND indicator_id = #{indicatorId}
+          AND evaluated_user_id = #{teacherId}
+          AND deleted = 0
+    </update>
+
 </mapper> 

+ 49 - 0
backend/ruoyi-modules/ruoyi-bzrkh/班主任考核指标类型管理权限配置.sql

@@ -0,0 +1,49 @@
+-- ==========================================
+-- 班主任考核指标类型管理权限配置
+-- 版本:V1.0.0
+-- 功能:班主任考核指标类型管理相关权限
+-- 作者:系统设计
+-- 时间:2025-01-08
+-- 模块:学工管理-班主任考核指标类型管理权限
+-- ==========================================
+
+-- 删除已存在的权限数据
+DELETE FROM sys_menu WHERE menu_name = '指标类型管理' OR parent_id IN (SELECT id FROM (SELECT id FROM sys_menu WHERE menu_name = '指标类型管理') temp);
+
+-- 1. 班主任考核指标类型管理主菜单
+INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark, tenant_id) 
+VALUES ('指标类型管理', 2000, 4, 'assessmentIndicatorType', 'bzrkh/assessmentIndicatorType/index', '', 1, 0, 'C', '0', '0', 'bzrkh:assessmentIndicatorType:list', 'list', 103, 1, NOW(), 1, NOW(), '班主任考核指标类型管理菜单', '000000');
+
+-- 获取刚插入的主菜单ID
+SET @menu_id = LAST_INSERT_ID();
+
+-- 2. 班主任考核指标类型查询按钮
+INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark, tenant_id) 
+VALUES ('班主任考核指标类型查询', @menu_id, 1, '#', '', '', 1, 0, 'F', '0', '0', 'bzrkh:assessmentIndicatorType:query', '#', 103, 1, NOW(), 1, NOW(), '', '000000');
+
+-- 3. 班主任考核指标类型新增按钮
+INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark, tenant_id) 
+VALUES ('班主任考核指标类型新增', @menu_id, 2, '#', '', '', 1, 0, 'F', '0', '0', 'bzrkh:assessmentIndicatorType:add', '#', 103, 1, NOW(), 1, NOW(), '', '000000');
+
+-- 4. 班主任考核指标类型修改按钮
+INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark, tenant_id) 
+VALUES ('班主任考核指标类型修改', @menu_id, 3, '#', '', '', 1, 0, 'F', '0', '0', 'bzrkh:assessmentIndicatorType:edit', '#', 103, 1, NOW(), 1, NOW(), '', '000000');
+
+-- 5. 班主任考核指标类型删除按钮
+INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark, tenant_id) 
+VALUES ('班主任考核指标类型删除', @menu_id, 4, '#', '', '', 1, 0, 'F', '0', '0', 'bzrkh:assessmentIndicatorType:remove', '#', 103, 1, NOW(), 1, NOW(), '', '000000');
+
+-- 6. 班主任考核指标类型导出按钮
+INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark, tenant_id) 
+VALUES ('班主任考核指标类型导出', @menu_id, 5, '#', '', '', 1, 0, 'F', '0', '0', 'bzrkh:assessmentIndicatorType:export', '#', 103, 1, NOW(), 1, NOW(), '', '000000');
+
+-- ==========================================
+-- 权限字符说明
+-- ==========================================
+-- bzrkh:assessmentIndicatorType:list     - 班主任考核指标类型查询权限
+-- bzrkh:assessmentIndicatorType:query    - 班主任考核指标类型详情查询权限
+-- bzrkh:assessmentIndicatorType:add      - 班主任考核指标类型新增权限
+-- bzrkh:assessmentIndicatorType:edit     - 班主任考核指标类型修改权限  
+-- bzrkh:assessmentIndicatorType:remove   - 班主任考核指标类型删除权限
+-- bzrkh:assessmentIndicatorType:export   - 班主任考核指标类型导出权限
+-- ========================================== 

+ 247 - 0
backend/ruoyi-modules/ruoyi-bzrkh/班主任考核提交功能开发说明.md

@@ -0,0 +1,247 @@
+# 班主任考核提交功能开发说明
+
+## 功能概述
+
+完善了班主任考核管理界面中的"提交考核"按钮功能,实现了完整的考核评分提交流程。
+
+## 开发内容
+
+### 前端部分(Vue 3 + TypeScript + Element Plus)
+
+#### 1. API类型定义扩展
+**文件位置**: `web/src/api/bzrkh/teacherAssessment/types.ts`
+
+**新增类型定义**:
+- `ClassDetailVO` - 班级详细信息
+- `CoefficientVO` - 系数信息
+- `AssessmentIndicatorVO` - 考核指标信息
+- `SpecialWorkIndicatorVO` - 特色工作指标
+- `AssessmentSubmitVO` - 考核提交数据
+- `AssessmentDetailVO` - 考核详情数据
+
+#### 2. API接口扩展
+**文件位置**: `web/src/api/bzrkh/teacherAssessment/index.ts`
+
+**新增接口**:
+- `getAssessmentSubmitDetail()` - 获取考核提交详情数据
+- `submitAssessmentScore()` - 提交考核评分数据
+
+#### 3. 提交弹窗组件
+**文件位置**: `web/src/views/bzrkh/teacherAssessment/submitDialog.vue`
+
+**功能特性**:
+- 9张卡片式布局:班级信息、人数系数、住校生系数、层次系数、总系数、班主任常规工作、班级管理实效、特色工作、月考核得分
+- 自动系数计算:根据班级人数、住校生人数、班级层次自动计算各项系数
+- 动态评分:支持自评分数输入和自评意见填写
+- 实时计算:月考核得分根据公式自动计算
+- 数据验证:表单验证确保数据完整性
+
+#### 4. 主界面集成
+**文件位置**: `web/src/views/bzrkh/teacherAssessment/index.vue`
+
+**集成内容**:
+- 引入提交弹窗组件
+- 修改提交考核按钮逻辑
+- 添加成功回调处理
+
+### 后端部分(Spring Boot 3.4.6 + MyBatis-Plus)
+
+#### 1. VO类创建
+**文件位置**: `backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/`
+
+**新增VO类**:
+- `ClassDetailVo.java` - 班级详细信息视图对象
+- `CoefficientVo.java` - 系数信息视图对象
+- `AssessmentIndicatorScoreVo.java` - 考核指标评分视图对象
+- `SpecialWorkIndicatorVo.java` - 特色工作指标视图对象
+- `AssessmentDetailVo.java` - 考核详情视图对象
+
+#### 2. BO类创建
+**文件位置**: `backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/bo/`
+
+**新增BO类**:
+- `AssessmentSubmitBo.java` - 考核提交业务对象
+
+#### 3. Controller扩展
+**文件位置**: `backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/controller/TeacherAssessmentController.java`
+
+**新增接口**:
+- `getAssessmentSubmitDetail()` - 获取考核提交详情数据
+- `submitAssessmentScore()` - 提交考核评分数据
+
+#### 4. Service接口和实现扩展
+**文件位置**: 
+- `backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/ITeacherAssessmentService.java`
+- `backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/TeacherAssessmentServiceImpl.java`
+
+**新增方法**:
+- `getAssessmentSubmitDetail()` - 获取考核提交详情数据
+- `submitAssessmentScore()` - 提交考核评分数据
+- `calculateCoefficient()` - 计算系数信息(私有方法)
+- `calculateStudentCountCoefficient()` - 计算人数系数(私有方法)
+- `calculateBoardingCoefficient()` - 计算住校生系数(私有方法)
+- `calculateLevelCoefficient()` - 计算层次系数(私有方法)
+- `mergeAssessmentScores()` - 合并已保存的评分数据(私有方法)
+
+#### 5. Mapper接口和XML扩展
+**文件位置**: 
+- `backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/mapper/TeacherAssessmentMapper.java`
+- `backend/ruoyi-modules/ruoyi-bzrkh/src/main/resources/mapper/bzrkh/TeacherAssessmentMapper.xml`
+
+**新增方法**:
+- `selectClassDetail()` - 查询班级详细信息
+- `selectRoutineWorkIndicators()` - 查询班主任常规工作指标列表
+- `selectClassDeductionIndicator()` - 查询班级扣分指标
+- `selectSpecialWorkIndicators()` - 查询特色工作指标列表
+- `selectSavedAssessmentScores()` - 查询已保存的评分数据
+- `selectSchemeIdByPlanId()` - 根据计划ID查询方案ID
+- `selectIndicatorIdByCode()` - 根据指标编码查询指标ID
+- `deleteAssessmentScoresByPlanAndTeacher()` - 逻辑删除评分数据
+- `insertAssessmentScore()` - 插入评分数据
+- `updateAssessmentScoreRemark()` - 更新评分数据备注
+
+## 核心业务逻辑
+
+### 1. 系数计算规则
+
+#### 人数系数(K2)
+- 班级人数36~40人(含36人),系数为1
+- 超过40人,每增加1名学生,系数增加0.02
+- 少于36人,每减少1名学生,系数减少0.02
+- 本项系数最低0.7
+
+#### 住校生系数(K3)
+- 根据住校生人数,按人均0.005计算
+
+#### 层次系数(K1)
+- 技师班(K1=0.95)
+- 高级工班(K1=1)
+- 中级工班(K1=1.05)
+- 预备技师班(K1=0.95)
+- 中高职一体(K1=1)
+
+#### 总系数(K)
+- 计算公式:K = K1 * (K2 + K3)
+
+### 2. 月考核得分计算
+- 计算公式:总系数(K)* (班主任常规工作自评分之和 - 按班级扣分50%计的分值 + 特色工作总分值)
+
+### 3. 数据存储逻辑
+1. 先逻辑删除该计划下该教师的历史评分数据
+2. 插入班主任常规工作指标评分
+3. 插入班级扣分指标评分
+4. 插入特色工作指标评分(4个固定指标)
+5. 将总体评价存储到备注字段
+
+## 权限配置
+
+### API接口权限
+- `bzrkh:teacherAssessment:list` - 查看班级和考核计划列表
+- `bzrkh:teacherAssessment:detail` - 查看考核详情
+- `bzrkh:teacherAssessment:submit` - 提交考核
+
+详细权限配置请参考:`班主任考核提交功能权限配置.md`
+
+## 数据准备
+
+### 必要的指标数据
+系统需要以下5个考核指标才能正常运行:
+
+1. `bzrwjkf001` - 班级扣分
+2. `bzrtsgz001` - 及时并妥善处理好学生违纪事件
+3. `bzrtsgz002` - 班级活动获奖情况
+4. `bzrtsgz003` - 班级宣传工作有特色
+5. `bzrtsgz004` - 其他
+
+数据插入脚本:`班主任考核提交功能必要数据.sql`
+
+## 部署说明
+
+### 1. 数据库脚本执行
+```sql
+-- 执行必要数据插入脚本
+source 班主任考核提交功能必要数据.sql;
+```
+
+### 2. 后端编译重启
+```bash
+# 编译ruoyi-bzrkh模块
+mvn clean compile -pl ruoyi-modules/ruoyi-bzrkh
+
+# 重启应用服务
+# (请根据实际部署方式重启服务)
+```
+
+### 3. 前端构建
+```bash
+# 前端无需重新构建,代码已支持热更新
+# 如需构建:
+npm run build:prod
+```
+
+### 4. 权限配置
+1. 登录系统管理后台
+2. 进入系统管理-菜单管理
+3. 为班主任考核相关菜单配置权限
+4. 为相关角色分配权限
+
+## 测试验证
+
+### 1. 基础功能测试
+- [ ] 班主任登录系统
+- [ ] 查看考核计划列表
+- [ ] 点击"提交考核"按钮
+- [ ] 弹窗正常显示9张卡片
+- [ ] 系数自动计算正确
+
+### 2. 评分功能测试
+- [ ] 班主任常规工作指标可正常输入评分
+- [ ] 班级扣分可正常输入,50%计算正确
+- [ ] 特色工作4个指标可正常输入评分
+- [ ] 月考核得分自动计算正确
+
+### 3. 数据保存测试
+- [ ] 提交评分数据成功
+- [ ] 数据正确保存到数据库
+- [ ] 再次打开弹窗数据正确回显
+
+## 技术亮点
+
+1. **响应式系数计算**:前端实时计算各项系数,提供直观的数据展示
+2. **组件化设计**:弹窗组件独立封装,便于维护和复用
+3. **数据一致性**:采用逻辑删除+重新插入的方式确保数据一致性
+4. **权限控制**:完整的权限控制体系,确保数据安全
+5. **用户体验**:直观的卡片式布局,清晰的数据展示
+6. **实时人数统计**:班级总人数从xg_student_msg表实时统计,确保数据准确性
+
+## 班级人数统计规则(2025-01-27更新)
+
+### 班级总人数统计
+- **数据来源**: `xg_student_msg`表
+- **统计条件**: 
+  - `class_id` = 班级ID
+  - `student_status` = '1'(正常状态)
+  - `deleted` = 0(未逻辑删除)
+- **统计方式**: COUNT(1)
+
+### 住校生人数统计
+- **数据来源**: `xg_student_msg`表
+- **统计条件**:
+  - `class_id` = 班级ID
+  - `student_status` = '1'(正常状态)
+  - `dormitory_room` IS NOT NULL AND `dormitory_room` != ''(有宿舍信息)
+  - `deleted` = 0(未逻辑删除)
+- **统计方式**: COUNT(1)
+
+## 待扩展功能
+
+1. 学生违规处分信息查看功能
+2. 考核结果审核功能
+3. 考核数据统计分析功能
+4. 考核历史记录查询功能
+
+---
+
+**开发完成时间**: 2025-01-27  
+**开发版本**: V1.0.0  
+**测试状态**: 待测试验证 

+ 87 - 0
backend/ruoyi-modules/ruoyi-bzrkh/班主任考核提交功能必要数据.sql

@@ -0,0 +1,87 @@
+-- ==========================================
+-- 班主任考核提交功能必要数据
+-- 功能:插入班主任考核提交功能所需的考核指标数据
+-- 作者:系统开发
+-- 时间:2025-01-27
+-- ==========================================
+
+-- 插入必要的考核指标数据
+-- 注意:这些指标是班主任考核提交功能必需的,请确保在数据库中存在
+
+-- 1. 班级扣分指标
+INSERT INTO `bmzr_assessment_indicator` (
+    `id`, `tenant_id`, `indicator_name`, `indicator_code`, `indicator_type`, 
+    `parent_id`, `sort_order`, `weight_ratio`, `max_score`, `score`, 
+    `allow_self_evaluation`, `allow_superior_evaluation`, `status`, `remark`, 
+    `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`
+) VALUES (
+    1882452817132150786, '000000', '班级扣分', 'bzrwjkf001', 'routine', 
+    0, 1, 1.0000, 50.00, 50.00, 
+    '1', '1', '0', '班级管理实效评分指标', 
+    103, 1, NOW(), 1, NOW(), 0
+) ON DUPLICATE KEY UPDATE 
+    indicator_name = VALUES(indicator_name),
+    update_time = NOW();
+
+-- 2. 及时并妥善处理好学生违纪事件
+INSERT INTO `bmzr_assessment_indicator` (
+    `id`, `tenant_id`, `indicator_name`, `indicator_code`, `indicator_type`, 
+    `parent_id`, `sort_order`, `weight_ratio`, `max_score`, `score`, 
+    `allow_self_evaluation`, `allow_superior_evaluation`, `status`, `remark`, 
+    `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`
+) VALUES (
+    1882452817132150787, '000000', '及时并妥善处理好学生违纪事件', 'bzrtsgz001', 'special', 
+    0, 1, 1.0000, 20.00, 20.00, 
+    '1', '1', '0', '特色工作评分指标', 
+    103, 1, NOW(), 1, NOW(), 0
+) ON DUPLICATE KEY UPDATE 
+    indicator_name = VALUES(indicator_name),
+    update_time = NOW();
+
+-- 3. 班级活动获奖情况
+INSERT INTO `bmzr_assessment_indicator` (
+    `id`, `tenant_id`, `indicator_name`, `indicator_code`, `indicator_type`, 
+    `parent_id`, `sort_order`, `weight_ratio`, `max_score`, `score`, 
+    `allow_self_evaluation`, `allow_superior_evaluation`, `status`, `remark`, 
+    `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`
+) VALUES (
+    1882452817132150788, '000000', '班级活动获奖情况', 'bzrtsgz002', 'special', 
+    0, 2, 1.0000, 20.00, 20.00, 
+    '1', '1', '0', '特色工作评分指标', 
+    103, 1, NOW(), 1, NOW(), 0
+) ON DUPLICATE KEY UPDATE 
+    indicator_name = VALUES(indicator_name),
+    update_time = NOW();
+
+-- 4. 班级宣传工作有特色
+INSERT INTO `bmzr_assessment_indicator` (
+    `id`, `tenant_id`, `indicator_name`, `indicator_code`, `indicator_type`, 
+    `parent_id`, `sort_order`, `weight_ratio`, `max_score`, `score`, 
+    `allow_self_evaluation`, `allow_superior_evaluation`, `status`, `remark`, 
+    `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`
+) VALUES (
+    1882452817132150789, '000000', '班级宣传工作有特色', 'bzrtsgz003', 'special', 
+    0, 3, 1.0000, 20.00, 20.00, 
+    '1', '1', '0', '特色工作评分指标', 
+    103, 1, NOW(), 1, NOW(), 0
+) ON DUPLICATE KEY UPDATE 
+    indicator_name = VALUES(indicator_name),
+    update_time = NOW();
+
+-- 5. 其他特色工作
+INSERT INTO `bmzr_assessment_indicator` (
+    `id`, `tenant_id`, `indicator_name`, `indicator_code`, `indicator_type`, 
+    `parent_id`, `sort_order`, `weight_ratio`, `max_score`, `score`, 
+    `allow_self_evaluation`, `allow_superior_evaluation`, `status`, `remark`, 
+    `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`
+) VALUES (
+    1882452817132150790, '000000', '其他', 'bzrtsgz004', 'special', 
+    0, 4, 1.0000, 20.00, 20.00, 
+    '1', '1', '0', '特色工作评分指标', 
+    103, 1, NOW(), 1, NOW(), 0
+) ON DUPLICATE KEY UPDATE 
+    indicator_name = VALUES(indicator_name),
+    update_time = NOW();
+
+-- 创建完成提示
+SELECT '班主任考核提交功能必要数据插入完成!' AS result; 

+ 86 - 0
backend/ruoyi-modules/ruoyi-bzrkh/班主任考核提交功能权限配置.md

@@ -0,0 +1,86 @@
+# 班主任考核提交功能权限配置
+
+## API接口权限字符
+
+### 新增的API接口权限
+以下是新增的班主任考核提交功能相关的API接口权限字符,需要在系统菜单权限中进行配置:
+
+1. **获取考核提交详情数据**
+   - 权限字符:`bzrkh:teacherAssessment:detail`
+   - 接口路径:`GET /bzrkh/teacherAssessment/submitDetail`
+   - 功能描述:获取考核提交弹窗的详情数据
+
+2. **提交考核评分数据**
+   - 权限字符:`bzrkh:teacherAssessment:submit`
+   - 接口路径:`POST /bzrkh/teacherAssessment/submitScore`
+   - 功能描述:提交班主任考核评分数据
+
+### 现有的API接口权限
+以下是现有的相关API接口权限:
+
+1. **查询班主任管理的班级列表**
+   - 权限字符:`bzrkh:teacherAssessment:list`
+   - 接口路径:`GET /bzrkh/teacherAssessment/classes`
+
+2. **查询班主任考核计划列表**
+   - 权限字符:`bzrkh:teacherAssessment:list`
+   - 接口路径:`GET /bzrkh/teacherAssessment/plans`
+
+3. **提交考核(原有)**
+   - 权限字符:`bzrkh:teacherAssessment:submit`
+   - 接口路径:`POST /bzrkh/teacherAssessment/submit`
+
+4. **查看考核详情(原有)**
+   - 权限字符:`bzrkh:teacherAssessment:detail`
+   - 接口路径:`GET /bzrkh/teacherAssessment/detail`
+
+## 菜单权限配置建议
+
+### 菜单配置
+建议在系统管理-菜单管理中配置以下菜单项:
+
+```
+父菜单:班主任考核管理
+├── 考核计划管理(已有)
+└── 班主任考核提交(新增)
+    ├── 权限字符:bzrkh:teacherAssessment:list
+    ├── 权限字符:bzrkh:teacherAssessment:detail  
+    └── 权限字符:bzrkh:teacherAssessment:submit
+```
+
+### 角色权限分配
+建议为以下角色分配相应权限:
+
+1. **班主任角色**
+   - `bzrkh:teacherAssessment:list` - 查看班级和考核计划列表
+   - `bzrkh:teacherAssessment:detail` - 查看考核详情
+   - `bzrkh:teacherAssessment:submit` - 提交考核
+
+2. **学工管理员角色**
+   - 全部权限(包括考核计划管理权限)
+
+3. **系统管理员角色**
+   - 全部权限
+
+## 数据库表说明
+
+### 涉及的主要表
+1. `bmzr_assessment_score` - 班主任考核得分表(核心业务表)
+2. `bmzr_assessment_plan` - 考核计划表
+3. `bmzr_assessment_scheme` - 考核方案表
+4. `bmzr_assessment_indicator` - 考核指标表
+5. `xg_class_msg` - 班级信息表
+6. `xg_student_msg` - 学生信息表
+
+### 关键业务逻辑
+1. **系数计算**:根据班级人数、住校生人数、班级层次自动计算系数
+2. **指标管理**:支持常规工作指标、班级扣分指标、特色工作指标
+3. **数据存储**:评分数据统一存储在`bmzr_assessment_score`表中
+4. **数据更新**:采用逻辑删除+重新插入的方式确保数据一致性
+
+## 注意事项
+
+1. 权限配置完成后需要重新登录系统生效
+2. 确保相关角色用户已分配对应的菜单权限
+3. 建议先在测试环境验证权限配置正确性
+4. 需要确保数据库中存在相关的考核指标数据(特别是5个特定编码的指标) 

+ 4 - 1
docs/设计文档/database/班主任考核管理/bmzr_assessment_tables.sql

@@ -155,11 +155,14 @@ CREATE TABLE `bmzr_assessment_score` (
   `evaluated_user_id` bigint(20) NOT NULL COMMENT '被评价用户ID',
   `evaluated_user_name` varchar(50) NOT NULL COMMENT '被评价用户姓名',
   `evaluated_dept_id` bigint(20) COMMENT '被评价用户部门ID',
+  `class_id` bigint(20) COMMENT '班级ID',
   `self_score` decimal(5,2) COMMENT '自评分数',
   `self_comment` text COMMENT '自评意见',
+  `self_overall_comment` text COMMENT '自我总体评价',
   `self_submit_time` datetime COMMENT '自评提交时间',
   `superior_score` decimal(5,2) COMMENT '上级评分数',
   `superior_comment` text COMMENT '上级评意见',
+  `superior_overall_comment` text COMMENT '上级总体评价',
   `superior_evaluator_id` bigint(20) COMMENT '上级评价人ID',
   `superior_submit_time` datetime COMMENT '上级评提交时间',
   `evaluation_level` varchar(20) COMMENT '评价等级 dict_type = bmzr_evaluation_level',
@@ -174,7 +177,7 @@ CREATE TABLE `bmzr_assessment_score` (
   `update_time` datetime COMMENT '更新时间',
   `deleted` int(1) NOT NULL DEFAULT 0 COMMENT '删除标志(0代表存在 1代表删除)',
   PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_plan_indicator_user` (`plan_id`, `indicator_id`, `evaluated_user_id`),
+  KEY `uk_plan_indicator_user` (`plan_id`, `indicator_id`, `evaluated_user_id`),
   KEY `idx_plan_id` (`plan_id`),
   KEY `idx_scheme_id` (`scheme_id`),
   KEY `idx_indicator_id` (`indicator_id`),

+ 2 - 2
web/src/api/bzrkh/assessmentIndicator/index.ts

@@ -70,7 +70,7 @@ export function delBmzrAssessmentIndicator(ids: string | number | Array<string |
  */
 export function getIndicatorTypeOptions() {
   return request({
-    url: '/bzrkh/assessmentIndicator/indicatorTypes/options',
+    url: '/bzrkh/assessmentIndicatorType/listAllIncludeDeleted',
     method: 'get'
   });
 }
@@ -81,7 +81,7 @@ export function getIndicatorTypeOptions() {
  */
 export function getParentIndicatorOptions() {
   return request({
-    url: '/bzrkh/assessmentIndicator/parentIndicators/options',
+    url: '/bzrkh/assessmentIndicator/treeselect',
     method: 'get'
   });
 } 

+ 36 - 1
web/src/api/bzrkh/teacherAssessment/index.ts

@@ -1,6 +1,13 @@
 import request from '@/utils/request';
 import { AxiosPromise } from 'axios';
-import { TeacherClassVO, TeacherAssessmentPlanVO, TeacherAssessmentPlanQuery, TeacherClassQuery } from './types';
+import { 
+  TeacherClassVO, 
+  TeacherAssessmentPlanVO, 
+  TeacherAssessmentPlanQuery, 
+  TeacherClassQuery,
+  AssessmentDetailVO,
+  AssessmentSubmitVO
+} from './types';
 
 /**
  * 查询班主任管理的班级列表
@@ -58,4 +65,32 @@ export const getAssessmentDetail = (planId: string | number, classId: string | n
       classId
     }
   });
+};
+
+/**
+ * 获取考核提交详情数据(用于提交弹窗)
+ * @param planId 计划ID
+ * @param classId 班级ID
+ */
+export const getAssessmentSubmitDetail = (planId: string | number, classId: string | number): AxiosPromise<AssessmentDetailVO> => {
+  return request({
+    url: '/bzrkh/teacherAssessment/submitDetail',
+    method: 'get',
+    params: {
+      planId,
+      classId
+    }
+  });
+};
+
+/**
+ * 提交考核评分数据
+ * @param data 考核提交数据
+ */
+export const submitAssessmentScore = (data: AssessmentSubmitVO): AxiosPromise<void> => {
+  return request({
+    url: '/bzrkh/teacherAssessment/submitScore',
+    method: 'post',
+    data
+  });
 }; 

+ 217 - 0
web/src/api/bzrkh/teacherAssessment/types.ts

@@ -204,4 +204,221 @@ export interface TeacherClassQuery {
    * 班级状态:1-正常,2-暂停,3-毕业,4-解散
    */
   classStatus?: string;
+}
+
+// ========== 新增:考核提交相关类型定义 ==========
+
+/**
+ * 班级详细信息
+ */
+export interface ClassDetailVO {
+  /**
+   * 班级ID
+   */
+  id?: string | number;
+  
+  /**
+   * 学院名称
+   */
+  collegeName?: string;
+  
+  /**
+   * 专业名称
+   */
+  majorName?: string;
+  
+  /**
+   * 班级名称
+   */
+  className?: string;
+  
+  /**
+   * 班级层次:1-中级工 2-高级工 3-预备技师 4-技师 5-中高职一体
+   */
+  classType?: string;
+  
+  /**
+   * 班级总人数
+   */
+  totalStudentCount?: number;
+  
+  /**
+   * 住校生人数
+   */
+  boardingStudentCount?: number;
+}
+
+/**
+ * 系数信息
+ */
+export interface CoefficientVO {
+  /**
+   * 人数系数(K2)
+   */
+  studentCountCoefficient?: number;
+  
+  /**
+   * 住校生系数(K3)
+   */
+  boardingCoefficient?: number;
+  
+  /**
+   * 层次系数(K1)
+   */
+  levelCoefficient?: number;
+  
+  /**
+   * 总系数(K = K1 * (K2 + K3))
+   */
+  totalCoefficient?: number;
+}
+
+/**
+ * 考核指标信息
+ */
+export interface AssessmentIndicatorVO {
+  /**
+   * 指标ID
+   */
+  id?: string | number;
+  
+  /**
+   * 指标名称
+   */
+  indicatorName?: string;
+  
+  /**
+   * 指标编码
+   */
+  indicatorCode?: string;
+  
+  /**
+   * 指标描述
+   */
+  description?: string;
+  
+  /**
+   * 指标分值
+   */
+  score?: number;
+  
+  /**
+   * 自评分数
+   */
+  selfScore?: number;
+  
+  /**
+   * 自评意见
+   */
+  selfComment?: string;
+  
+  /**
+   * 排序
+   */
+  sortOrder?: number;
+}
+
+/**
+ * 特色工作指标
+ */
+export interface SpecialWorkIndicatorVO {
+  /**
+   * 指标编码
+   */
+  indicatorCode?: string;
+  
+  /**
+   * 指标名称
+   */
+  indicatorName?: string;
+  
+  /**
+   * 分值
+   */
+  score?: number;
+  
+  /**
+   * 自评意见
+   */
+  selfComment?: string;
+}
+
+/**
+ * 考核提交数据
+ */
+export interface AssessmentSubmitVO {
+  /**
+   * 考核计划ID
+   */
+  planId?: string | number;
+  
+  /**
+   * 班级ID
+   */
+  classId?: string | number;
+  
+  /**
+   * 班主任常规工作指标评分
+   */
+  routineWorkScores?: AssessmentIndicatorVO[];
+  
+  /**
+   * 班级扣分
+   */
+  classDeduction?: number;
+  
+  /**
+   * 班级扣分意见
+   */
+  classDeductionComment?: string;
+  
+  /**
+   * 特色工作指标评分
+   */
+  specialWorkScores?: SpecialWorkIndicatorVO[];
+  
+  /**
+   * 总体评价
+   */
+  overallComment?: string;
+}
+
+/**
+ * 考核详情数据
+ */
+export interface AssessmentDetailVO {
+  /**
+   * 班级详细信息
+   */
+  classDetail?: ClassDetailVO;
+  
+  /**
+   * 系数信息
+   */
+  coefficient?: CoefficientVO;
+  
+  /**
+   * 班主任常规工作指标列表
+   */
+  routineWorkIndicators?: AssessmentIndicatorVO[];
+  
+  /**
+   * 班级扣分指标
+   */
+  classDeductionIndicator?: AssessmentIndicatorVO;
+  
+  /**
+   * 特色工作指标列表
+   */
+  specialWorkIndicators?: SpecialWorkIndicatorVO[];
+  
+  /**
+   * 月考核得分
+   */
+  monthlyScore?: number;
+  
+  /**
+   * 总体评价
+   */
+  overallComment?: string;
 } 

+ 104 - 11
web/src/views/bzrkh/teacherAssessment/index.vue

@@ -35,15 +35,15 @@
           <!-- 表格区域 -->
           <el-card shadow="never" class="button-card table-card">
             <template #header>
-              <el-row :gutter="10" class="mb8">
+              <!-- <el-row :gutter="10" class="mb8">
                 <el-col :span="1.5">
-                  <el-button type="primary" plain icon="Edit" @click="() => handleSubmitAssessment()" :disabled="!hasSelectedPlan">提交考核</el-button>
+                  <el-button type="primary" plain icon="Edit" @click="() => handleSubmitAssessment()" :disabled="!hasSelectedPlan"></el-button>
                 </el-col>
                 <el-col :span="1.5">
-                  <el-button type="success" plain icon="View" @click="() => handleViewAssessment()" :disabled="!hasSelectedPlan">查看考核</el-button>
+                  <el-button type="success" plain icon="View" @click="() => handleViewAssessment()" :disabled="!hasSelectedPlan"></el-button>
                 </el-col>
                 <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
-              </el-row>
+              </el-row> -->
             </template>
 
             <div class="table-container">
@@ -78,10 +78,22 @@
                 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
                   <template #default="scope">
                     <el-tooltip content="提交考核" placement="top">
-                      <el-button link type="primary" icon="Edit" @click="handleSubmitAssessment(scope.row)">提交考核</el-button>
+                      <el-button 
+                        link 
+                        type="primary" 
+                        icon="Edit" 
+                        :disabled="loading || !isDataReady"
+                        @click="handleSubmitAssessment(scope.row)"
+                      ></el-button>
                     </el-tooltip>
                     <el-tooltip content="查看考核" placement="top">
-                      <el-button link type="success" icon="View" @click="handleViewAssessment(scope.row)">查看考核</el-button>
+                      <el-button 
+                        link 
+                        type="success" 
+                        icon="View" 
+                        :disabled="loading || !isDataReady"
+                        @click="handleViewAssessment(scope.row)"
+                      ></el-button>
                     </el-tooltip>
                   </template>
                 </el-table-column>
@@ -100,10 +112,19 @@
     <el-card shadow="never" v-else-if="!loading && teacherClasses.length === 0">
       <el-empty description="您暂时没有担任班主任的班级" />
     </el-card>
+
+    <!-- 考核提交弹窗 -->
+    <SubmitDialog 
+      ref="submitDialogRef" 
+      :plan-id="currentPlanId" 
+      :class-id="currentClassId" 
+      @success="handleSubmitSuccess" 
+    />
   </div>
 </template>
 
 <script setup name="TeacherAssessment" lang="ts">
+import { computed, nextTick } from 'vue';
 import {
   listTeacherClasses,
   listTeacherAssessmentPlans,
@@ -116,6 +137,7 @@ import {
   TeacherAssessmentPlanQuery
 } from '@/api/bzrkh/teacherAssessment/types';
 import { useUserStore } from '@/store/modules/user';
+import SubmitDialog from './submitDialog.vue';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const userStore = useUserStore();
@@ -129,6 +151,11 @@ const selectedPlans = ref<TeacherAssessmentPlanVO[]>([]);
 const hasSelectedPlan = ref(false);
 const total = ref(0);
 
+// 考核提交相关状态
+const currentPlanId = ref<string | number>();
+const currentClassId = ref<string | number>();
+const submitDialogRef = ref();
+
 const queryFormRef = ref<ElFormInstance>();
 
 const data = reactive<PageData<any, TeacherAssessmentPlanQuery>>({
@@ -144,6 +171,11 @@ const data = reactive<PageData<any, TeacherAssessmentPlanQuery>>({
 
 const { queryParams } = toRefs(data);
 
+// 计算数据是否已准备就绪
+const isDataReady = computed(() => {
+  return teacherClasses.value.length > 0 && activeTab.value !== '';
+});
+
 /** 获取班主任管理的班级列表 */
 const getTeacherClasses = async () => {
   loading.value = true;
@@ -157,10 +189,13 @@ const getTeacherClasses = async () => {
     if (teacherClasses.value.length > 0) {
       // 默认选中第一个班级
       activeTab.value = teacherClasses.value[0].id?.toString() || '';
+      // 等待activeTab设置完成后再获取列表
+      await nextTick();
       await getList();
     }
   } catch (error) {
     console.error('获取班级列表失败:', error);
+    proxy?.$modal.msgError('获取班级列表失败,请刷新页面重试');
   } finally {
     loading.value = false;
   }
@@ -222,13 +257,41 @@ const handleSubmitAssessment = async (row?: TeacherAssessmentPlanVO) => {
     return;
   }
 
-  const planNames = plans.map(p => p.planName).join('、');
+  if (plans.length > 1) {
+    proxy?.$modal.msgWarning('每次只能提交一个考核计划');
+    return;
+  }
+
+  // 验证数据是否已准备就绪
+  if (!isDataReady.value) {
+    proxy?.$modal.msgWarning('数据加载中,请稍后再试');
+    return;
+  }
+
+  const plan = plans[0];
+  
+  // 确保计划ID存在
+  if (!plan.id) {
+    proxy?.$modal.msgError('考核计划ID无效');
+    return;
+  }
+  
   const currentClass = teacherClasses.value.find(c => c.id?.toString() === activeTab.value);
   
-  await proxy?.$modal.confirm(`确认要提交班级"${currentClass?.className}"的考核计划"${planNames}"吗?`).then(async () => {
-    // TODO: 实现提交考核逻辑
-    proxy?.$modal.msg('提交考核功能待实现');
-  });
+  if (!currentClass || !currentClass.id) {
+    proxy?.$modal.msgError('获取班级信息失败,请刷新页面后重试');
+    return;
+  }
+
+  // 设置当前考核的计划ID和班级ID
+  currentPlanId.value = plan.id;
+  currentClassId.value = currentClass.id;
+  
+  // 确保参数设置成功后再打开弹窗
+  await nextTick();
+  
+  // 打开提交弹窗
+  submitDialogRef.value?.open();
 };
 
 /** 查看考核 */
@@ -239,10 +302,40 @@ const handleViewAssessment = async (row?: TeacherAssessmentPlanVO) => {
     return;
   }
 
+  // 验证数据是否已准备就绪
+  if (!isDataReady.value) {
+    proxy?.$modal.msgWarning('数据加载中,请稍后再试');
+    return;
+  }
+
+  const plan = plans[0];
+  
+  // 确保计划ID存在
+  if (!plan.id) {
+    proxy?.$modal.msgError('考核计划ID无效');
+    return;
+  }
+  
+  const currentClass = teacherClasses.value.find(c => c.id?.toString() === activeTab.value);
+  
+  if (!currentClass || !currentClass.id) {
+    proxy?.$modal.msgError('获取班级信息失败,请刷新页面后重试');
+    return;
+  }
+
   // TODO: 实现查看考核逻辑
   proxy?.$modal.msg('查看考核功能待实现');
 };
 
+/** 考核提交成功回调 */
+const handleSubmitSuccess = () => {
+  // 刷新考核计划列表
+  getList();
+  // 清空选择
+  selectedPlans.value = [];
+  hasSelectedPlan.value = false;
+};
+
 onMounted(() => {
   getTeacherClasses();
 });

+ 699 - 0
web/src/views/bzrkh/teacherAssessment/submitDialog.vue

@@ -0,0 +1,699 @@
+<template>
+  <el-dialog
+    :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">
+      <!-- 1. 班级信息卡片 -->
+      <el-card shadow="never" class="info-card">
+        <template #header>
+          <div class="card-header">
+            <span>班级信息</span>
+          </div>
+        </template>
+        <el-descriptions :column="3" border>
+          <el-descriptions-item label="学院名称">{{ assessmentDetail?.classDetail?.collegeName || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="专业名称">{{ assessmentDetail?.classDetail?.majorName || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="班级名称">{{ assessmentDetail?.classDetail?.className || '-' }}</el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+
+      <!-- 2. 人数系数卡片 -->
+      <el-card shadow="never" class="info-card">
+        <template #header>
+          <div class="card-header">
+            <span>人数系数(K2)</span>
+          </div>
+        </template>
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="班级总人数">{{ assessmentDetail?.classDetail?.totalStudentCount || 0 }}人</el-descriptions-item>
+          <el-descriptions-item label="人数系数">{{ formatNumber(assessmentDetail?.coefficient?.studentCountCoefficient, 4) }}</el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+
+      <!-- 3. 住校生系数卡片 -->
+      <el-card shadow="never" class="info-card">
+        <template #header>
+          <div class="card-header">
+            <span>住校生系数(K3)</span>
+          </div>
+        </template>
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="住校生人数">{{ assessmentDetail?.classDetail?.boardingStudentCount || 0 }}人</el-descriptions-item>
+          <el-descriptions-item label="住校生系数">{{ formatNumber(assessmentDetail?.coefficient?.boardingCoefficient, 4) }}</el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+
+      <!-- 4. 层次系数卡片 -->
+      <el-card shadow="never" class="info-card">
+        <template #header>
+          <div class="card-header">
+            <span>层次系数(K1)</span>
+          </div>
+        </template>
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="班级学历层级">{{ getClassTypeText(assessmentDetail?.classDetail?.classType) }}</el-descriptions-item>
+          <el-descriptions-item label="层次系数">{{ formatNumber(assessmentDetail?.coefficient?.levelCoefficient, 4) }}</el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+
+      <!-- 5. 总系数卡片 -->
+      <el-card shadow="never" class="info-card">
+        <template #header>
+          <div class="card-header">
+            <span>总系数(K)</span>
+          </div>
+        </template>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="总系数">{{ formatNumber(assessmentDetail?.coefficient?.totalCoefficient, 6) }}</el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+
+      <!-- 6. 班主任常规工作(50分)卡片 -->
+      <el-card shadow="never" class="info-card">
+        <template #header>
+          <div class="card-header">
+            <span>班主任常规工作(50分)</span>
+          </div>
+        </template>
+        <el-table border :data="routineWorkScores" style="width: 100%">
+          <el-table-column type="index" label="序号" width="60" align="center" />
+          <el-table-column prop="indicatorName" label="指标名称" align="center" :show-overflow-tooltip="true" />
+          <el-table-column prop="description" label="指标描述" align="center" :show-overflow-tooltip="true" />
+          <el-table-column prop="score" label="指标分值" width="100" align="center">
+            <template #default="scope">
+              <span>{{ scope.row.score || 0 }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="自评分数" width="120" align="center">
+            <template #default="scope">
+              <el-input-number
+                v-model="scope.row.selfScore"
+                :min="0"
+                :max="scope.row.score || 100"
+                :precision="2"
+                controls-position="right"
+                style="width: 100%"
+                placeholder="请输入分数"
+              />
+            </template>
+          </el-table-column>
+          <el-table-column label="自评意见" width="200" align="center">
+            <template #default="scope">
+              <el-input
+                v-model="scope.row.selfComment"
+                type="textarea"
+                :rows="2"
+                placeholder="请输入自评意见"
+                maxlength="200"
+                show-word-limit
+              />
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-card>
+
+      <!-- 7. 班级管理实效(50分)卡片 -->
+      <el-card shadow="never" class="info-card">
+        <template #header>
+          <div class="card-header">
+            <span>班级管理实效(50分)</span>
+          </div>
+        </template>
+        <el-form :model="managementEffectivenessForm" label-width="150px">
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <el-form-item label="班级扣分">
+                <el-input-number
+                  v-model="managementEffectivenessForm.classDeduction"
+                  :min="0"
+                  :precision="2"
+                  controls-position="right"
+                  style="width: 100%"
+                  placeholder="请输入扣分"
+                  @change="calculateDeductionHalf"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="按班级扣分50%计">
+                <el-input
+                  :value="managementEffectivenessForm.classDeductionHalf?.toFixed(2) || '0.00'"
+                  readonly
+                  style="width: 100%"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item>
+                <el-button type="info" plain @click="handleViewStudentViolations">学生违规处分信息查看</el-button>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="24">
+              <el-form-item label="自评意见">
+                <el-input
+                  v-model="managementEffectivenessForm.selfComment"
+                  type="textarea"
+                  :rows="3"
+                  placeholder="请输入自评意见"
+                  maxlength="500"
+                  show-word-limit
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </el-card>
+
+      <!-- 8. 特色工作(加20分)卡片 -->
+      <el-card shadow="never" class="info-card">
+        <template #header>
+          <div class="card-header">
+            <span>特色工作(加20分)</span>
+          </div>
+        </template>
+        <el-form :model="specialWorkForm" label-width="200px">
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="及时并妥善处理好学生违纪事件">
+                <el-input-number
+                  v-model="specialWorkForm.score1"
+                  :min="0"
+                  :max="20"
+                  :precision="2"
+                  controls-position="right"
+                  style="width: 100%"
+                  placeholder="请输入分值"
+                  @change="calculateTotalSpecialScore"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="自评意见">
+                <el-input
+                  v-model="specialWorkForm.comment1"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入自评意见"
+                  maxlength="200"
+                  show-word-limit
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="班级活动获奖情况">
+                <el-input-number
+                  v-model="specialWorkForm.score2"
+                  :min="0"
+                  :max="20"
+                  :precision="2"
+                  controls-position="right"
+                  style="width: 100%"
+                  placeholder="请输入分值"
+                  @change="calculateTotalSpecialScore"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="自评意见">
+                <el-input
+                  v-model="specialWorkForm.comment2"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入自评意见"
+                  maxlength="200"
+                  show-word-limit
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="班级宣传工作有特色">
+                <el-input-number
+                  v-model="specialWorkForm.score3"
+                  :min="0"
+                  :max="20"
+                  :precision="2"
+                  controls-position="right"
+                  style="width: 100%"
+                  placeholder="请输入分值"
+                  @change="calculateTotalSpecialScore"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="自评意见">
+                <el-input
+                  v-model="specialWorkForm.comment3"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入自评意见"
+                  maxlength="200"
+                  show-word-limit
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="其他">
+                <el-input-number
+                  v-model="specialWorkForm.score4"
+                  :min="0"
+                  :max="20"
+                  :precision="2"
+                  controls-position="right"
+                  style="width: 100%"
+                  placeholder="请输入分值"
+                  @change="calculateTotalSpecialScore"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="自评意见">
+                <el-input
+                  v-model="specialWorkForm.comment4"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入自评意见"
+                  maxlength="200"
+                  show-word-limit
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="12">
+              <el-form-item label="总分值">
+                <el-input
+                  :value="specialWorkForm.totalScore?.toFixed(2) || '0.00'"
+                  readonly
+                  style="width: 100%"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </el-card>
+
+      <!-- 9. 月考核得分卡片 -->
+      <el-card shadow="never" class="info-card">
+        <template #header>
+          <div class="card-header">
+            <span>月考核得分</span>
+          </div>
+        </template>
+        <el-form :model="monthlyScoreForm" label-width="100px">
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="月考核得分">
+                <el-input
+                  :value="calculateMonthlyScore().toFixed(2)"
+                  readonly
+                  style="width: 100%"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="24">
+              <el-form-item label="总体评价">
+                <el-input
+                  v-model="monthlyScoreForm.overallComment"
+                  type="textarea"
+                  :rows="4"
+                  placeholder="请输入总体评价"
+                  maxlength="500"
+                  show-word-limit
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </el-card>
+    </div>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button :loading="submitLoading" type="primary" @click="handleSubmit">保存</el-button>
+        <el-button @click="handleClose">取消</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup name="SubmitDialog" lang="ts">
+import { 
+  getAssessmentSubmitDetail, 
+  submitAssessmentScore 
+} from '@/api/bzrkh/teacherAssessment';
+import {
+  AssessmentDetailVO,
+  AssessmentIndicatorVO,
+  SpecialWorkIndicatorVO,
+  AssessmentSubmitVO
+} from '@/api/bzrkh/teacherAssessment/types';
+
+interface Props {
+  planId?: string | number;
+  classId?: string | number;
+}
+
+const props = defineProps<Props>();
+const emit = defineEmits(['success']);
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const visible = ref(false);
+const loading = ref(false);
+const submitLoading = ref(false);
+
+const assessmentDetail = ref<AssessmentDetailVO>();
+const routineWorkScores = ref<AssessmentIndicatorVO[]>([]);
+
+// 班级管理实效表单
+const managementEffectivenessForm = reactive({
+  classDeduction: 0,
+  classDeductionHalf: 0,
+  selfComment: ''
+});
+
+// 特色工作表单
+const specialWorkForm = reactive({
+  score1: 0, // 及时并妥善处理好学生违纪事件
+  comment1: '',
+  score2: 0, // 班级活动获奖情况
+  comment2: '',
+  score3: 0, // 班级宣传工作有特色
+  comment3: '',
+  score4: 0, // 其他
+  comment4: '',
+  totalScore: 0
+});
+
+// 月考核得分表单
+const monthlyScoreForm = reactive({
+  overallComment: ''
+});
+
+const dialogTitle = computed(() => {
+  const className = assessmentDetail.value?.classDetail?.className || '';
+  return `${className} - 班主任考核提交`;
+});
+
+/** 获取班级层次文本 */
+const getClassTypeText = (classType?: string) => {
+  const typeMap: Record<string, string> = {
+    '1': '中级工班',
+    '2': '高级工班',
+    '3': '预备技师班',
+    '4': '技师班',
+    '5': '中高职一体'
+  };
+  return typeMap[classType || ''] || '未知';
+};
+
+/** 格式化数字显示 */
+const formatNumber = (value?: number | string, precision = 4) => {
+  if (value === undefined || value === null || value === '') {
+    return '0.' + '0'.repeat(precision);
+  }
+  
+  const numValue = typeof value === 'string' ? parseFloat(value) : value;
+  
+  if (isNaN(numValue)) {
+    return '0.' + '0'.repeat(precision);
+  }
+  
+  return numValue.toFixed(precision);
+};
+
+/** 计算班级扣分50%计 */
+const calculateDeductionHalf = () => {
+  managementEffectivenessForm.classDeductionHalf = (managementEffectivenessForm.classDeduction || 0) * 0.5;
+};
+
+/** 计算特色工作总分 */
+const calculateTotalSpecialScore = () => {
+  specialWorkForm.totalScore = (specialWorkForm.score1 || 0) + 
+                               (specialWorkForm.score2 || 0) + 
+                               (specialWorkForm.score3 || 0) + 
+                               (specialWorkForm.score4 || 0);
+};
+
+/** 计算月考核得分 */
+const calculateMonthlyScore = () => {
+  // 总系数(K)
+  const totalCoefficient = assessmentDetail.value?.coefficient?.totalCoefficient || 0;
+  
+  // 班主任常规工作自评分之和
+  const routineWorkTotal = routineWorkScores.value.reduce((sum, item) => sum + (item.selfScore || 0), 0);
+  
+  // 按班级扣分50%计的分值
+  const deductionHalf = managementEffectivenessForm.classDeductionHalf || 0;
+  
+  // 特色工作总分值
+  const specialWorkTotal = specialWorkForm.totalScore || 0;
+  
+  // 月考核得分 = 总系数(K)* (班主任常规工作自评分之和 - 按班级扣分50%计的分值 + 特色工作总分值)
+  return totalCoefficient * (routineWorkTotal - deductionHalf + specialWorkTotal);
+};
+
+/** 打开弹窗 */
+const open = async () => {
+  if (!props.planId || !props.classId) {
+    proxy?.$modal.msgError('参数错误:缺少计划ID或班级ID');
+    return;
+  }
+  
+  visible.value = true;
+  await loadAssessmentDetail();
+};
+
+/** 加载考核详情数据 */
+const loadAssessmentDetail = async () => {
+  loading.value = true;
+  try {
+    const res = await getAssessmentSubmitDetail(props.planId!, props.classId!);
+    assessmentDetail.value = res.data;
+    
+    // 初始化班主任常规工作数据
+    routineWorkScores.value = (assessmentDetail.value?.routineWorkIndicators || []).map(item => ({
+      ...item,
+      selfScore: item.selfScore || 0,
+      selfComment: item.selfComment || ''
+    }));
+    
+    // 初始化班级管理实效数据
+    if (assessmentDetail.value?.classDeductionIndicator) {
+      managementEffectivenessForm.classDeduction = assessmentDetail.value.classDeductionIndicator.selfScore || 0;
+      managementEffectivenessForm.selfComment = assessmentDetail.value.classDeductionIndicator.selfComment || '';
+      calculateDeductionHalf();
+    }
+    
+    // 初始化特色工作数据
+    const specialWorkIndicators = assessmentDetail.value?.specialWorkIndicators || [];
+    specialWorkIndicators.forEach(item => {
+      switch (item.indicatorCode) {
+        case 'bzrtsgz001':
+          specialWorkForm.score1 = Number(item.score) || 0;
+          specialWorkForm.comment1 = item.selfComment || '';
+          break;
+        case 'bzrtsgz002':
+          specialWorkForm.score2 = Number(item.score) || 0;
+          specialWorkForm.comment2 = item.selfComment || '';
+          break;
+        case 'bzrtsgz003':
+          specialWorkForm.score3 = Number(item.score) || 0;
+          specialWorkForm.comment3 = item.selfComment || '';
+          break;
+        case 'bzrtsgz004':
+          specialWorkForm.score4 = Number(item.score) || 0;
+          specialWorkForm.comment4 = item.selfComment || '';
+          break;
+      }
+    });
+    // 确保特色工作总分重新计算
+    calculateTotalSpecialScore();
+    
+    // 初始化月考核得分数据
+    monthlyScoreForm.overallComment = assessmentDetail.value?.overallComment || '';
+    
+    // 调试信息:验证数据是否正确加载
+    console.log('数据回显完成:', {
+      totalSpecialScore: specialWorkForm.totalScore,
+      monthlyScore: calculateMonthlyScore(),
+      overallComment: monthlyScoreForm.overallComment
+    });
+    
+  } catch (error) {
+    console.error('加载考核详情失败:', error);
+    proxy?.$modal.msgError('加载考核详情失败');
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 查看学生违规处分信息 */
+const handleViewStudentViolations = () => {
+  proxy?.$modal.msg('学生违规处分信息查看功能暂未实现');
+};
+
+/** 提交考核 */
+const handleSubmit = async () => {
+  try {
+    // 验证必填项
+    if (routineWorkScores.value.some(item => item.selfScore === undefined || item.selfScore === null)) {
+      proxy?.$modal.msgWarning('请完善班主任常规工作的自评分数');
+      return;
+    }
+    
+    // 验证必要参数
+    if (!props.planId || !props.classId) {
+      proxy?.$modal.msgError('缺少必要参数:计划ID或班级ID');
+      return;
+    }
+
+    submitLoading.value = true;
+
+    // 构造提交数据
+    const submitData: AssessmentSubmitVO = {
+      planId: props.planId, // 考核计划ID
+      classId: props.classId, // 班级ID - 将存储到数据库 class_id 字段
+      routineWorkScores: routineWorkScores.value,
+      classDeduction: managementEffectivenessForm.classDeduction,
+      classDeductionComment: managementEffectivenessForm.selfComment,
+      specialWorkScores: [
+        {
+          indicatorCode: 'bzrtsgz001',
+          indicatorName: '及时并妥善处理好学生违纪事件',
+          score: specialWorkForm.score1,
+          selfComment: specialWorkForm.comment1
+        },
+        {
+          indicatorCode: 'bzrtsgz002',
+          indicatorName: '班级活动获奖情况',
+          score: specialWorkForm.score2,
+          selfComment: specialWorkForm.comment2
+        },
+        {
+          indicatorCode: 'bzrtsgz003',
+          indicatorName: '班级宣传工作有特色',
+          score: specialWorkForm.score3,
+          selfComment: specialWorkForm.comment3
+        },
+        {
+          indicatorCode: 'bzrtsgz004',
+          indicatorName: '其他',
+          score: specialWorkForm.score4,
+          selfComment: specialWorkForm.comment4
+        }
+      ],
+      overallComment: monthlyScoreForm.overallComment // 自我总体评价 - 将存储到数据库 self_overall_comment 字段
+    };
+
+    await submitAssessmentScore(submitData);
+    proxy?.$modal.msgSuccess('考核提交成功');
+    emit('success');
+    handleClose();
+    
+  } catch (error) {
+    console.error('提交考核失败:', error);
+    proxy?.$modal.msgError('提交考核失败');
+  } finally {
+    submitLoading.value = false;
+  }
+};
+
+/** 关闭弹窗 */
+const handleClose = () => {
+  visible.value = false;
+  // 重置表单数据
+  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: ''
+  });
+};
+
+// 暴露给父组件的方法
+defineExpose({
+  open
+});
+</script>
+
+<style scoped>
+.submit-dialog-content {
+  max-height: 70vh;
+  overflow-y: auto;
+}
+
+.info-card {
+  margin-bottom: 16px;
+}
+
+.info-card:last-child {
+  margin-bottom: 0;
+}
+
+.card-header {
+  font-weight: 600;
+  color: #303133;
+}
+
+/* 表格样式 */
+:deep(.el-table) {
+  border-radius: 4px;
+}
+
+:deep(.el-table th) {
+  background-color: #f5f7fa;
+  color: #606266;
+  font-weight: 600;
+}
+
+/* 表单样式 */
+:deep(.el-form-item__label) {
+  font-weight: 500;
+}
+
+/* 只读输入框样式 */
+:deep(.el-input.is-disabled .el-input__wrapper) {
+  background-color: #f5f7fa;
+}
+
+/* 响应式布局 */
+@media (max-width: 768px) {
+  .submit-dialog-content {
+    padding: 0 10px;
+  }
+  
+  .info-card {
+    margin-bottom: 12px;
+  }
+}
+</style>