提交代码

This commit is contained in:
zlwu committed 2025-09-09 15:42:51 +08:00
1 parent 1c84ddaa14
commit b3de960892
12 files changed
+507 -117

No files matched your search

@@ -151,6 +151,19 @@ public class XskhDisciplineRecordController extends BaseController {
@RequestParam String disciplineTypeIds, @RequestParam String disciplineTypeIds,
@RequestParam String startTime, @RequestParam String startTime,
@RequestParam String endTime) { @RequestParam String endTime) {
return R.ok(xskhDisciplineRecordService.getStudentDisciplineRecords(studentId, disciplineTypeIds, startTime, endTime)); return R.ok(xskhDisciplineRecordService.getStudentDisciplineRecords(studentId, disciplineTypeIds, startTime,
endTime));
}
/**
* 获取指定违纪类型在指定时间范围内所有学生的最高总扣分
*/
@SaCheckPermission("disciplineRecord:disciplineRecord:query")
@GetMapping("/getMaxScoreByTypeAndPeriod/{typeId}")
public R<java.math.BigDecimal> getMaxScoreByTypeAndPeriod(
@NotNull(message = "违纪类型ID不能为空") @PathVariable Long typeId,
@RequestParam String startTime,
@RequestParam String endTime) {
return R.ok(xskhDisciplineRecordService.getMaxScoreByTypeAndPeriod(typeId, startTime, endTime));
} }
} }
@@ -143,4 +143,16 @@ public class XskhRewardRecordController extends BaseController {
@RequestParam String endTime) { @RequestParam String endTime) {
return R.ok(xskhRewardRecordService.getStudentRewardRecords(studentId, rewardTypeIds, startTime, endTime)); return R.ok(xskhRewardRecordService.getStudentRewardRecords(studentId, rewardTypeIds, startTime, endTime));
} }
/**
* 获取指定奖励类型在指定时间范围内所有学生的最高总加分
*/
@SaCheckPermission("rewardRecord:rewardRecord:query")
@GetMapping("/getMaxScoreByTypeAndPeriod/{typeId}")
public R<java.math.BigDecimal> getMaxScoreByTypeAndPeriod(
@NotNull(message = "奖励类型ID不能为空") @PathVariable Long typeId,
@RequestParam String startTime,
@RequestParam String endTime) {
return R.ok(xskhRewardRecordService.getMaxScoreByTypeAndPeriod(typeId, startTime, endTime));
}
} }
@@ -69,4 +69,16 @@ public interface XskhDisciplineRecordMapper extends BaseMapperPlus<XskhDisciplin
*/ */
int deleteHygieneCheckViolationByDisciplineRecordId(@Param("disciplineRecordId") Long disciplineRecordId); int deleteHygieneCheckViolationByDisciplineRecordId(@Param("disciplineRecordId") Long disciplineRecordId);
/**
* 获取指定违纪类型在指定时间范围内所有学生的最高总扣分
*
* @param typeId 违纪类型ID
* @param startTime 开始时间
* @param endTime 结束时间
* @return 最高总扣分
*/
java.math.BigDecimal selectMaxScoreByTypeAndPeriod(@Param("typeId") Long typeId,
@Param("startTime") String startTime,
@Param("endTime") String endTime);
} }
@@ -51,4 +51,16 @@ public interface XskhRewardRecordMapper extends BaseMapperPlus<XskhRewardRecord,
@Param("rewardTypeIds") List<Long> rewardTypeIds, @Param("rewardTypeIds") List<Long> rewardTypeIds,
@Param("startTime") String startTime, @Param("startTime") String startTime,
@Param("endTime") String endTime); @Param("endTime") String endTime);
/**
* 获取指定奖励类型在指定时间范围内所有学生的最高总加分
*
* @param typeId 奖励类型ID
* @param startTime 开始时间
* @param endTime 结束时间
* @return 最高总加分
*/
java.math.BigDecimal selectMaxScoreByTypeAndPeriod(@Param("typeId") Long typeId,
@Param("startTime") String startTime,
@Param("endTime") String endTime);
} }
@@ -91,4 +91,14 @@ public interface IXskhDisciplineRecordService {
*/ */
List<XskhDisciplineRecordVo> getStudentDisciplineRecords(Long studentId, String disciplineTypeIds, String startTime, List<XskhDisciplineRecordVo> getStudentDisciplineRecords(Long studentId, String disciplineTypeIds, String startTime,
String endTime); String endTime);
/**
* 获取指定违纪类型在指定时间范围内所有学生的最高总扣分
*
* @param typeId 违纪类型ID
* @param startTime 开始时间
* @param endTime 结束时间
* @return 最高总扣分
*/
java.math.BigDecimal getMaxScoreByTypeAndPeriod(Long typeId, String startTime, String endTime);
} }
@@ -104,4 +104,14 @@ public interface IXskhRewardRecordService {
*/ */
List<XskhRewardRecordVo> getStudentRewardRecords(Long studentId, String rewardTypeIds, String startTime, List<XskhRewardRecordVo> getStudentRewardRecords(Long studentId, String rewardTypeIds, String startTime,
String endTime); String endTime);
/**
* 获取指定奖励类型在指定时间范围内所有学生的最高总加分
*
* @param typeId 奖励类型ID
* @param startTime 开始时间
* @param endTime 结束时间
* @return 最高总加分
*/
java.math.BigDecimal getMaxScoreByTypeAndPeriod(Long typeId, String startTime, String endTime);
} }
@@ -267,4 +267,23 @@ public class XskhDisciplineRecordServiceImpl implements IXskhDisciplineRecordSer
return baseMapper.selectStudentDisciplineRecords(studentId, typeIds, startTime, endTime); return baseMapper.selectStudentDisciplineRecords(studentId, typeIds, startTime, endTime);
} }
/**
* 获取指定违纪类型在指定时间范围内所有学生的最高总扣分
*/
@Override
public java.math.BigDecimal getMaxScoreByTypeAndPeriod(Long typeId, String startTime, String endTime) {
log.info("获取违纪类型 {} 在时间范围 {} - {} 内的最高总扣分", typeId, startTime, endTime);
java.math.BigDecimal maxScore = baseMapper.selectMaxScoreByTypeAndPeriod(typeId, startTime, endTime);
// 如果查询结果为null,返回0
if (maxScore == null) {
log.info("违纪类型 {} 在指定时间范围内无数据,返回0", typeId);
return java.math.BigDecimal.ZERO;
}
log.info("违纪类型 {} 的最高总扣分为: {}", typeId, maxScore);
return maxScore;
}
} }
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Arrays; import java.util.Arrays;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.Map; import java.util.Map;
import lombok.extern.slf4j.Slf4j;
/** /**
* 学生奖励记录Service业务层处理 * 学生奖励记录Service业务层处理
@@ -31,6 +32,7 @@ import java.util.Map;
* @author ruoyi * @author ruoyi
* @date 2025-01-03 * @date 2025-01-03
*/ */
@Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
@Service @Service
public class XskhRewardRecordServiceImpl implements IXskhRewardRecordService { public class XskhRewardRecordServiceImpl implements IXskhRewardRecordService {
@@ -249,4 +251,23 @@ public class XskhRewardRecordServiceImpl implements IXskhRewardRecordService {
return baseMapper.selectStudentRewardRecords(studentId, typeIds, startTime, endTime); return baseMapper.selectStudentRewardRecords(studentId, typeIds, startTime, endTime);
} }
/**
* 获取指定奖励类型在指定时间范围内所有学生的最高总加分
*/
@Override
public java.math.BigDecimal getMaxScoreByTypeAndPeriod(Long typeId, String startTime, String endTime) {
log.info("获取奖励类型 {} 在时间范围 {} - {} 内的最高总加分", typeId, startTime, endTime);
java.math.BigDecimal maxScore = baseMapper.selectMaxScoreByTypeAndPeriod(typeId, startTime, endTime);
// 如果查询结果为null,返回0
if (maxScore == null) {
log.info("奖励类型 {} 在指定时间范围内无数据,返回0", typeId);
return java.math.BigDecimal.ZERO;
}
log.info("奖励类型 {} 的最高总加分为: {}", typeId, maxScore);
return maxScore;
}
} }
@@ -134,4 +134,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
and deleted = 0 and deleted = 0
</update> </update>
<!-- 获取指定违纪类型在指定时间范围内所有学生的最高总扣分 -->
<select id="selectMaxScoreByTypeAndPeriod" resultType="java.math.BigDecimal">
<![CDATA[
SELECT MAX(student_total_score) as max_score
FROM (
SELECT student_id, SUM(score_deduction) as student_total_score
FROM xskh_discipline_record
WHERE discipline_type_id = #{typeId}
AND discipline_date >= #{startTime}
AND discipline_date <= #{endTime}
AND status = '1'
AND deleted = 0
GROUP BY student_id
) student_scores
]]>
</select>
</mapper> </mapper>
@@ -151,4 +151,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
order by create_time desc order by create_time desc
</select> </select>
<!-- 获取指定奖励类型在指定时间范围内所有学生的最高总加分 -->
<select id="selectMaxScoreByTypeAndPeriod" resultType="java.math.BigDecimal">
<![CDATA[
SELECT MAX(student_total_score) as max_score
FROM (
SELECT student_id, SUM(score_addition) as student_total_score
FROM xskh_reward_record
WHERE reward_type_id = #{typeId}
AND reward_date >= #{startTime}
AND reward_date <= #{endTime}
AND status = '1'
AND deleted = 0
GROUP BY student_id
) student_scores
]]>
</select>
</mapper> </mapper>
+1
View File
@@ -20,6 +20,7 @@
- [学生管理员授权关系API](./学生管理员授权关系API.md) - [学生管理员授权关系API](./学生管理员授权关系API.md)
- [学生销假管理API](./学生销假管理API.md) - [学生销假管理API](./学生销假管理API.md)
- [假期留宿管理API](./假期留宿管理API.md) - **重要修复:单人留宿计算逻辑**(2025-01-03) - [假期留宿管理API](./假期留宿管理API.md) - **重要修复:单人留宿计算逻辑**(2025-01-03)
- [均化处理最高分值API](./均化处理最高分值API.md) - **新增**:支持考核申请均化处理功能(2025-01-03)
### 1. 用户认证登录 ### 1. 用户认证登录
@@ -65,7 +65,7 @@
<el-card shadow="never"> <el-card shadow="never">
<template #header> <template #header>
<div class="card-header"> <div class="card-header">
<span>指标模块 </span> <span>指标模块(基础分:100分)</span>
</div> </div>
</template> </template>
<el-table :data="form.selfScoreList" border style="width: 100%"> <el-table :data="form.selfScoreList" border style="width: 100%">
@@ -92,27 +92,18 @@
<template #header> <template #header>
<div class="column-header"> <div class="column-header">
<span>自评得分</span> <span>自评得分</span>
<el-tooltip content="自评得分为学生在统计周期内的违纪和奖励分值,不包含附加分" placement="top"> <el-tooltip
content="新算分规则:基础分100分,先扣除违纪处分,再加上奖励加分和附加分。自评得分为系统自动计算,不可手动编辑"
placement="top"
>
<el-icon class="header-icon"><QuestionFilled /></el-icon> <el-icon class="header-icon"><QuestionFilled /></el-icon>
</el-tooltip> </el-tooltip>
</div> </div>
</template> </template>
<template #default="scope"> <template #default="scope">
<div v-if="isViewMode" class="score-display"> <div class="score-display auto-calculated">
{{ scope.row.selfScore || '-' }} {{ scope.row.selfScore || '0' }}
</div> </div>
<el-input
v-else
v-model="scope.row.selfScore"
type="number"
:min="0"
:max="scope.row.planMaxScore"
:step="0.1"
@input="(value) => handleSelfScoreInput(value, scope.row)"
@blur="(event) => handleSelfScoreBlur(event, scope.row)"
:class="{ 'score-input-warning': isScoreExceeded(scope.row) }"
style="width: 100%"
/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="自评备注" min-width="120"> <el-table-column label="自评备注" min-width="120">
@@ -401,6 +392,7 @@ import {
getApplicationByStudentAndSchedule, getApplicationByStudentAndSchedule,
getIndicatorsByScheduleId getIndicatorsByScheduleId
} from '@/api/xskh/assessmentApplication/assessmentApplication'; } from '@/api/xskh/assessmentApplication/assessmentApplication';
// 注意:暂时使用request直接调用API,避免导入路径问题
// 类型定义 // 类型定义
interface XskhAssessmentApplicationApprovalForm { interface XskhAssessmentApplicationApprovalForm {
@@ -446,6 +438,9 @@ interface XskhAssessmentSelfScoreForm {
selfRemark?: string; selfRemark?: string;
teacherScore?: number; teacherScore?: number;
teacherRemark?: string; teacherRemark?: string;
// 新增字段:用于新算分规则
deductionScore?: number; // 扣分
additionScore?: number; // 加分
} }
interface XskhAssessmentBonusApprovalForm { interface XskhAssessmentBonusApprovalForm {
@@ -600,6 +595,210 @@ const getCurrentUserStudentInfo = async () => {
} }
}; };
/** 计算单个指标的自评得分(新算分规则) */
const calculateIndicatorSelfScore = async (indicatorId: string | number): Promise<{ deduction: number; addition: number }> => {
try {
// 获取指标关联的违纪处分类型和奖励类型
const indicatorTypesResponse = await request({
url: `/disciplineRecord/disciplineRecord/getIndicatorTypes/${indicatorId}`,
method: 'get'
});
if (indicatorTypesResponse.code !== 200 || !indicatorTypesResponse.data) {
console.warn(`获取指标 ${indicatorId} 的类型信息失败`);
return { deduction: 0, addition: 0 };
}
// 修复字段名映射:后端返回下划线格式,前端使用驼峰格式
const disciplineTypeIds = indicatorTypesResponse.data.discipline_type_ids || indicatorTypesResponse.data.disciplineTypeIds;
const rewardTypeIds = indicatorTypesResponse.data.reward_type_ids || indicatorTypesResponse.data.rewardTypeIds;
// 并行获取违纪处分记录和奖励记录
const [disciplineRecords, rewardRecords] = await Promise.all([getDisciplineRecords(disciplineTypeIds), getRewardRecords(rewardTypeIds)]);
// 计算违纪扣分(正数,表示扣分金额)
let disciplineDeduction = 0;
if (disciplineRecords && disciplineRecords.length > 0) {
disciplineDeduction = disciplineRecords.reduce((sum: number, record: any) => {
const deduction = parseFloat(String(record.scoreDeduction || 0)) || 0;
return sum + deduction;
}, 0);
// 检查违纪类型是否需要均化处理
if (disciplineTypeIds) {
disciplineDeduction = await applyEqualizationIfNeeded(disciplineTypeIds, disciplineDeduction, 'discipline');
}
}
// 计算奖励加分(正数,表示加分金额)
let rewardAddition = 0;
if (rewardRecords && rewardRecords.length > 0) {
rewardAddition = rewardRecords.reduce((sum: number, record: any) => {
const addition = parseFloat(String(record.scoreAddition || 0)) || 0;
return sum + addition;
}, 0);
// 检查奖励类型是否需要均化处理
if (rewardTypeIds) {
rewardAddition = await applyEqualizationIfNeeded(rewardTypeIds, rewardAddition, 'reward');
}
}
console.log(
`指标 ${indicatorId} 自评得分计算完成: 扣分=${disciplineDeduction}, 加分=${rewardAddition} (违纪扣分: ${disciplineRecords?.length || 0}条, 奖励加分: ${rewardRecords?.length || 0}条)`
);
return {
deduction: Math.round(disciplineDeduction * 10) / 10,
addition: Math.round(rewardAddition * 10) / 10
};
} catch (error) {
console.error(`计算指标 ${indicatorId} 自评得分失败:`, error);
return { deduction: 0, addition: 0 };
}
};
/** 获取学生违纪处分记录 */
const getDisciplineRecords = async (disciplineTypeIds: string): Promise<any[]> => {
if (!disciplineTypeIds || !form.value.studentId) {
return [];
}
try {
const response = await request({
url: '/disciplineRecord/disciplineRecord/getStudentDisciplineRecords',
method: 'get',
params: {
studentId: form.value.studentId,
disciplineTypeIds: disciplineTypeIds,
startTime: form.value.dataStartTime,
endTime: form.value.dataEndTime,
status: 1 // 只查询状态为1的记录
}
});
if (response.code === 200) {
return response.data || [];
} else {
console.warn('获取违纪处分记录失败:', response.msg);
return [];
}
} catch (error) {
console.error('获取违纪处分记录失败:', error);
return [];
}
};
/** 获取学生奖励记录 */
const getRewardRecords = async (rewardTypeIds: string): Promise<any[]> => {
if (!rewardTypeIds || !form.value.studentId) {
return [];
}
try {
const response = await request({
url: '/rewardRecord/rewardRecord/getStudentRewardRecords',
method: 'get',
params: {
studentId: form.value.studentId,
rewardTypeIds: rewardTypeIds,
startTime: form.value.dataStartTime,
endTime: form.value.dataEndTime,
status: 1 // 只查询状态为1的记录
}
});
if (response.code === 200) {
return response.data || [];
} else {
console.warn('获取奖励记录失败:', response.msg);
return [];
}
} catch (error) {
console.error('获取奖励记录失败:', error);
return [];
}
};
/** 应用均化处理(如果需要) */
const applyEqualizationIfNeeded = async (typeIds: string, studentScore: number, scoreType: 'discipline' | 'reward'): Promise<number> => {
if (!typeIds || studentScore === 0) {
return studentScore;
}
try {
// 将逗号分隔的类型ID字符串转换为数组
const typeIdArray = typeIds
.split(',')
.map((id) => id.trim())
.filter((id) => id);
console.log('typeIdArray:', typeIdArray);
// 遍历每个类型,检查是否需要均化
for (const typeId of typeIdArray) {
console.log('typeId:', typeId);
// 获取类型的均化设置
const typeDetailsResponse = await request({
url: scoreType === 'discipline' ? `/disciplineType/disciplineType/${typeId}` : `/rewardType/rewardType/${typeId}`,
method: 'get'
});
console.log('typeDetailsResponse:', typeDetailsResponse);
if (typeDetailsResponse.code === 200 && typeDetailsResponse.data) {
const typeInfo = typeDetailsResponse.data;
// 检查是否启用均化 (isEqualized: '1' 表示启用)
const isEqualized = typeInfo.isEqualized === '1';
const equalizedThreshold = parseFloat(String(typeInfo.equalizedThreshold || 0)) || 0;
if (isEqualized && equalizedThreshold > 0) {
console.log(`类型 ${typeId} 启用了均化处理,均化阈值: ${equalizedThreshold}`);
// 调用专门的接口获取统计周期内该类型下所有学生的最高总分值
const maxScoreResponse = await request({
url:
scoreType === 'discipline'
? `/disciplineRecord/disciplineRecord/getMaxScoreByTypeAndPeriod/${typeId}`
: `/rewardRecord/rewardRecord/getMaxScoreByTypeAndPeriod/${typeId}`,
method: 'get',
params: {
startTime: form.value.dataStartTime,
endTime: form.value.dataEndTime
}
});
if (maxScoreResponse.code === 200 && maxScoreResponse.data !== null && maxScoreResponse.data !== undefined) {
const maxScore = parseFloat(String(maxScoreResponse.data)) || 0;
console.log(`类型 ${typeId} 统计周期内学生最高总分值: ${maxScore}, 当前学生得分: ${studentScore}, 均化阈值: ${equalizedThreshold}`);
// 如果最高分值超过了均化阈值,应用均化公式
if (maxScore > equalizedThreshold) {
const equalizedScore = (studentScore * equalizedThreshold) / maxScore;
console.log(`应用均化公式: ${studentScore} * ${equalizedThreshold} / ${maxScore} = ${equalizedScore}`);
return Math.round(equalizedScore * 10) / 10; // 保留一位小数
} else {
console.log(`最高分值 ${maxScore} 未超过均化阈值 ${equalizedThreshold},不需要均化处理`);
}
} else {
console.warn(`获取类型 ${typeId} 的最高分值失败:`, maxScoreResponse.msg);
}
}
}
}
// 如果没有需要均化的类型,返回原始分值
return studentScore;
} catch (error) {
console.error(`均化处理失败 (类型: ${scoreType}, typeIds: ${typeIds}):`, error);
// 均化失败时返回原始分值,不影响正常计算
return studentScore;
}
};
/** 根据考核计划ID获取关联的指标数据 */ /** 根据考核计划ID获取关联的指标数据 */
const loadIndicatorsByScheduleId = async (scheduleId: string | number) => { const loadIndicatorsByScheduleId = async (scheduleId: string | number) => {
try { try {
@@ -607,7 +806,7 @@ const loadIndicatorsByScheduleId = async (scheduleId: string | number) => {
if (response.code === 200 && response.data) { if (response.code === 200 && response.data) {
// 将指标数据转换为自评得分列表格式 // 将指标数据转换为自评得分列表格式
form.value.selfScoreList = response.data.map((item: any) => ({ const indicatorList = response.data.map((item: any) => ({
id: undefined, id: undefined,
applicationId: undefined, applicationId: undefined,
indicatorId: item.indicatorId, indicatorId: item.indicatorId,
@@ -618,12 +817,19 @@ const loadIndicatorsByScheduleId = async (scheduleId: string | number) => {
maxScore: item.maxScore, // 修改:使用maxScore字段名,匹配后端期望 maxScore: item.maxScore, // 修改:使用maxScore字段名,匹配后端期望
planMaxScore: item.maxScore, // 保留planMaxScore用于前端显示 planMaxScore: item.maxScore, // 保留planMaxScore用于前端显示
sortOrder: item.sortOrder, sortOrder: item.sortOrder,
selfScore: 0, selfScore: 0, // 初始化为0,稍后计算
selfRemark: '', selfRemark: '',
teacherScore: 0, teacherScore: 0,
teacherRemark: '' teacherRemark: ''
})); }));
form.value.selfScoreList = indicatorList;
// 自动计算每个指标的自评得分
if (form.value.studentId && form.value.dataStartTime && form.value.dataEndTime) {
await calculateAllIndicatorScores();
}
console.log('获取到考核计划关联的指标数据:', response.data); console.log('获取到考核计划关联的指标数据:', response.data);
} else { } else {
ElMessage.warning(response.msg || '获取指标数据失败'); ElMessage.warning(response.msg || '获取指标数据失败');
@@ -638,115 +844,133 @@ const loadIndicatorsByScheduleId = async (scheduleId: string | number) => {
} }
}; };
/** 计算总得分 */ /** 计算所有指标的自评得分(新算分规则) */
const calculateTotalScore = () => { const calculateAllIndicatorScores = async () => {
// 计算自评得分 if (!form.value.selfScoreList || form.value.selfScoreList.length === 0) {
let selfScore = 0; return;
if (form.value.selfScoreList && form.value.selfScoreList.length > 0) {
selfScore += form.value.selfScoreList.reduce((sum, item) => {
const score = parseFloat(String(item.selfScore || 0)) || 0;
return sum + score;
}, 0);
} }
console.log('开始计算所有指标的自评得分(新算分规则)...');
// 并行计算所有指标的得分
const scorePromises = form.value.selfScoreList.map(async (indicator) => {
const { deduction, addition } = await calculateIndicatorSelfScore(indicator.indicatorId);
// 设置扣分和加分
indicator.deductionScore = deduction;
indicator.additionScore = addition;
// 为了兼容现有显示,selfScore设置为净得分(加分-扣分)
indicator.selfScore = addition - deduction;
return {
indicatorId: indicator.indicatorId,
deduction,
addition,
netScore: indicator.selfScore
};
});
try {
const results = await Promise.all(scorePromises);
console.log('所有指标自评得分计算完成(新算分规则):', results);
// 重新计算总得分
calculateTotalScore();
} catch (error) {
console.error('计算指标自评得分失败:', error);
ElMessage.error('计算指标自评得分失败,请稍后重试');
}
};
/** 计算总得分(新算分规则) */
const calculateTotalScore = () => {
// 第1步:基础分100分 - 指标模块的扣分,最小为0
const baseScore = 100;
let totalIndicatorDeduction = 0;
let totalIndicatorAddition = 0;
// 计算指标模块的总扣分和总加分
if (form.value.selfScoreList && form.value.selfScoreList.length > 0) {
form.value.selfScoreList.forEach((item) => {
const deduction = parseFloat(String(item.deductionScore || 0)) || 0;
const addition = parseFloat(String(item.additionScore || 0)) || 0;
totalIndicatorDeduction += deduction;
totalIndicatorAddition += addition;
});
}
// 第1步:基础分 - 扣分,结果不能小于0
let step1Score = baseScore - totalIndicatorDeduction;
if (step1Score < 0) {
step1Score = 0;
}
// 第2步:加上指标模块的加分
const step2Score = step1Score + totalIndicatorAddition;
// 第3步:加上附加分模块的分值(可正可负)
let totalBonusScore = 0;
if (form.value.bonusApprovalList && form.value.bonusApprovalList.length > 0) { if (form.value.bonusApprovalList && form.value.bonusApprovalList.length > 0) {
selfScore += form.value.bonusApprovalList.reduce((sum, item) => { totalBonusScore = form.value.bonusApprovalList.reduce((sum, item) => {
const score = parseFloat(String(item.bonusScore || 0)) || 0; const score = parseFloat(String(item.bonusScore || 0)) || 0;
return sum + score; return sum + score;
}, 0); }, 0);
} }
form.value.selfScore = parseFloat(selfScore.toFixed(1)); // 最终自评得分
const finalSelfScore = step2Score + totalBonusScore;
form.value.selfScore = parseFloat(finalSelfScore.toFixed(1));
// 计算班主任评分 console.log(
let teacherScore = 0; `自评得分计算详情: 基础分=${baseScore}, 指标扣分=${totalIndicatorDeduction}, 第1步结果=${step1Score}, 指标加分=${totalIndicatorAddition}, 第2步结果=${step2Score}, 附加分=${totalBonusScore}, 最终得分=${form.value.selfScore}`
);
// 班主任评分采用相同逻辑,但使用班主任的评分数据
let teacherTotalIndicatorDeduction = 0;
let teacherTotalIndicatorAddition = 0;
// 计算班主任对指标模块的评分
if (form.value.selfScoreList && form.value.selfScoreList.length > 0) { if (form.value.selfScoreList && form.value.selfScoreList.length > 0) {
teacherScore += form.value.selfScoreList.reduce((sum, item) => { form.value.selfScoreList.forEach((item) => {
const score = parseFloat(String(item.teacherScore || 0)) || 0; const teacherScore = parseFloat(String(item.teacherScore || 0)) || 0;
return sum + score; // 班主任评分可能是综合评分,这里需要根据实际情况调整
}, 0); if (teacherScore < 0) {
teacherTotalIndicatorDeduction += Math.abs(teacherScore);
} else {
teacherTotalIndicatorAddition += teacherScore;
}
});
} }
// 第1步:基础分 - 班主任评定的扣分
let teacherStep1Score = baseScore - teacherTotalIndicatorDeduction;
if (teacherStep1Score < 0) {
teacherStep1Score = 0;
}
// 第2步:加上班主任评定的加分
const teacherStep2Score = teacherStep1Score + teacherTotalIndicatorAddition;
// 第3步:加上附加分模块的审核得分
let totalApprovalScore = 0;
if (form.value.bonusApprovalList && form.value.bonusApprovalList.length > 0) { if (form.value.bonusApprovalList && form.value.bonusApprovalList.length > 0) {
teacherScore += form.value.bonusApprovalList.reduce((sum, item) => { totalApprovalScore = form.value.bonusApprovalList.reduce((sum, item) => {
const score = parseFloat(String(item.approvalScore || 0)) || 0; const score = parseFloat(String(item.approvalScore || 0)) || 0;
return sum + score; return sum + score;
}, 0); }, 0);
} }
form.value.teacherScore = parseFloat(teacherScore.toFixed(1)); // 最终班主任评分
const finalTeacherScore = teacherStep2Score + totalApprovalScore;
form.value.teacherScore = parseFloat(finalTeacherScore.toFixed(1));
// 总得分等于班主任评分 // 总得分等于班主任评分
form.value.totalScore = parseFloat(teacherScore.toFixed(1)); form.value.totalScore = parseFloat(finalTeacherScore.toFixed(1));
};
/** 处理自评得分输入验证 */ console.log(
const handleSelfScoreInput = (value: string | number, row: XskhAssessmentSelfScoreForm) => { `班主任评分计算详情: 基础分=${baseScore}, 指标扣分=${teacherTotalIndicatorDeduction}, 第1步结果=${teacherStep1Score}, 指标加分=${teacherTotalIndicatorAddition}, 第2步结果=${teacherStep2Score}, 附加审核分=${totalApprovalScore}, 最终得分=${form.value.teacherScore}`
const numValue = parseFloat(String(value)) || 0; );
const maxScore = parseFloat(String(row.planMaxScore)) || 0;
// 如果输入值超过最高分值,自动限制为最高分值
if (numValue > maxScore) {
row.selfScore = maxScore;
ElMessage.warning(`自评得分不能超过最高分值 ${maxScore}`);
} else {
row.selfScore = numValue;
}
// 重新计算总得分
calculateTotalScore();
};
/** 处理自评得分失焦验证 */
const handleSelfScoreBlur = (event: Event, row: XskhAssessmentSelfScoreForm) => {
const target = event.target as HTMLInputElement;
const value = parseFloat(target.value) || 0;
const maxScore = parseFloat(String(row.planMaxScore)) || 0;
// 失焦时再次验证,确保不超过最高分值
if (value > maxScore) {
row.selfScore = maxScore;
target.value = maxScore.toString();
ElMessage.warning(`自评得分已自动调整为最高分值 ${maxScore}`);
}
// 确保值为非负数
if (value < 0) {
row.selfScore = 0;
target.value = '0';
}
};
/** 验证所有自评得分是否超过最高分值 */
const validateSelfScores = (): boolean => {
if (!form.value.selfScoreList || form.value.selfScoreList.length === 0) {
return true;
}
for (let i = 0; i < form.value.selfScoreList.length; i++) {
const item = form.value.selfScoreList[i];
const selfScore = parseFloat(String(item.selfScore || 0)) || 0;
const maxScore = parseFloat(String(item.planMaxScore || 0)) || 0;
if (selfScore > maxScore) {
ElMessage.error(`第${i + 1}项指标"${item.indicatorName}"的自评得分(${selfScore})不能超过最高分值(${maxScore})`);
return false;
}
if (selfScore < 0) {
ElMessage.error(`第${i + 1}项指标"${item.indicatorName}"的自评得分不能为负数`);
return false;
}
}
return true;
};
/** 检查单个指标的自评得分是否超过最高分值 */
const isScoreExceeded = (row: XskhAssessmentSelfScoreForm): boolean => {
const selfScore = parseFloat(String(row.selfScore || 0)) || 0;
const maxScore = parseFloat(String(row.planMaxScore || 0)) || 0;
return selfScore > maxScore;
}; };
/** 添加附加分项目 */ /** 添加附加分项目 */
@@ -1096,6 +1320,11 @@ const openDialog = async (id?: string | number, title?: string, schedule?: Asses
teacherScore: item.teacherScore || 0, teacherScore: item.teacherScore || 0,
teacherRemark: item.teacherRemark || '' teacherRemark: item.teacherRemark || ''
})); }));
// 重新计算自评得分(确保数据是最新的)
if (form.value.studentId && form.value.dataStartTime && form.value.dataEndTime) {
await calculateAllIndicatorScores();
}
} }
// 确保附加分列表正确回显 // 确保附加分列表正确回显
@@ -1164,6 +1393,11 @@ const openDialog = async (id?: string | number, title?: string, schedule?: Asses
teacherScore: item.teacherScore || 0, teacherScore: item.teacherScore || 0,
teacherRemark: item.teacherRemark || '' teacherRemark: item.teacherRemark || ''
})); }));
// 重新计算自评得分(确保数据是最新的)
if (form.value.studentId && form.value.dataStartTime && form.value.dataEndTime) {
await calculateAllIndicatorScores();
}
} }
// 确保附加分列表正确回显 // 确保附加分列表正确回显
@@ -1258,11 +1492,6 @@ const safeConvertId = (id: string | number | undefined): string | undefined => {
const handleSave = async () => { const handleSave = async () => {
assessmentApplicationFormRef.value?.validate(async (valid) => { assessmentApplicationFormRef.value?.validate(async (valid) => {
if (valid) { if (valid) {
// 验证自评得分是否超过最高分值
if (!validateSelfScores()) {
return;
}
try { try {
// 处理附件数据,将fileList中的ossId合并为evidenceFile字段 // 处理附件数据,将fileList中的ossId合并为evidenceFile字段
if (form.value.bonusApprovalList && form.value.bonusApprovalList.length > 0) { if (form.value.bonusApprovalList && form.value.bonusApprovalList.length > 0) {
@@ -1310,11 +1539,6 @@ const handleSave = async () => {
const handleSubmit = async () => { const handleSubmit = async () => {
assessmentApplicationFormRef.value?.validate(async (valid) => { assessmentApplicationFormRef.value?.validate(async (valid) => {
if (valid) { if (valid) {
// 验证自评得分是否超过最高分值
if (!validateSelfScores()) {
return;
}
try { try {
// 处理附件数据,将fileList中的ossId合并为evidenceFile字段 // 处理附件数据,将fileList中的ossId合并为evidenceFile字段
if (form.value.bonusApprovalList && form.value.bonusApprovalList.length > 0) { if (form.value.bonusApprovalList && form.value.bonusApprovalList.length > 0) {
@@ -1764,6 +1988,28 @@ defineExpose({
justify-content: center; justify-content: center;
} }
/* 自动计算得分样式 */
.score-display.auto-calculated {
/* background: #f0f9ff; */
/* order: 1px solid #38bdf8; */
/* color: #0369a1; */
font-weight: 600;
position: relative;
}
.score-display.auto-calculated::after {
/* content: '自动计算'; */
position: absolute;
top: -8px;
right: -8px;
background: #38bdf8;
color: white;
font-size: 10px;
padding: 1px 4px;
border-radius: 2px;
font-weight: normal;
}
/* 备注展示样式 */ /* 备注展示样式 */
.remark-display { .remark-display {
padding: 8px 12px; padding: 8px 12px;