|
@@ -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%">
|
|
@@ -85,34 +85,25 @@
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column label="指标编码" prop="indicatorCode" min-width="100" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="指标编码" prop="indicatorCode" min-width="100" /> -->
|
|
|
<el-table-column label="指标说明" prop="indicatorDescription" min-width="150" show-overflow-tooltip />
|
|
<el-table-column label="指标说明" prop="indicatorDescription" min-width="150" show-overflow-tooltip />
|
|
|
- <el-table-column label="最高分值" prop="planMaxScore" min-width="80" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="最高分值" prop="planMaxScore" min-width="80" /> -->
|
|
|
<el-table-column label="自评得分" width="120">
|
|
<el-table-column label="自评得分" width="120">
|
|
|
<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">
|
|
|
|
|
- {{ scope.row.selfScore || '-' }}
|
|
|
|
|
|
|
+ <div class="score-display auto-calculated">
|
|
|
|
|
+ {{ 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 = () => {
|
|
|
|
|
- // 计算自评得分
|
|
|
|
|
- let selfScore = 0;
|
|
|
|
|
- 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);
|
|
|
|
|
|
|
+/** 计算所有指标的自评得分(新算分规则) */
|
|
|
|
|
+const calculateAllIndicatorScores = async () => {
|
|
|
|
|
+ if (!form.value.selfScoreList || form.value.selfScoreList.length === 0) {
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (form.value.bonusApprovalList && form.value.bonusApprovalList.length > 0) {
|
|
|
|
|
- selfScore += form.value.bonusApprovalList.reduce((sum, item) => {
|
|
|
|
|
- const score = parseFloat(String(item.bonusScore || 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('计算指标自评得分失败,请稍后重试');
|
|
|
}
|
|
}
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
- form.value.selfScore = parseFloat(selfScore.toFixed(1));
|
|
|
|
|
|
|
+/** 计算总得分(新算分规则) */
|
|
|
|
|
+const calculateTotalScore = () => {
|
|
|
|
|
+ // 第1步:基础分100分 - 指标模块的扣分,最小为0
|
|
|
|
|
+ const baseScore = 100;
|
|
|
|
|
+ let totalIndicatorDeduction = 0;
|
|
|
|
|
+ let totalIndicatorAddition = 0;
|
|
|
|
|
|
|
|
- // 计算班主任评分
|
|
|
|
|
- let teacherScore = 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) => {
|
|
|
|
|
- const score = parseFloat(String(item.teacherScore || 0)) || 0;
|
|
|
|
|
- return sum + score;
|
|
|
|
|
- }, 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) {
|
|
|
- teacherScore += form.value.bonusApprovalList.reduce((sum, item) => {
|
|
|
|
|
- const score = parseFloat(String(item.approvalScore || 0)) || 0;
|
|
|
|
|
|
|
+ totalBonusScore = form.value.bonusApprovalList.reduce((sum, item) => {
|
|
|
|
|
+ const score = parseFloat(String(item.bonusScore || 0)) || 0;
|
|
|
return sum + score;
|
|
return sum + score;
|
|
|
}, 0);
|
|
}, 0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- form.value.teacherScore = parseFloat(teacherScore.toFixed(1));
|
|
|
|
|
|
|
+ // 最终自评得分
|
|
|
|
|
+ const finalSelfScore = step2Score + totalBonusScore;
|
|
|
|
|
+ form.value.selfScore = parseFloat(finalSelfScore.toFixed(1));
|
|
|
|
|
|
|
|
- // 总得分等于班主任评分
|
|
|
|
|
- form.value.totalScore = parseFloat(teacherScore.toFixed(1));
|
|
|
|
|
-};
|
|
|
|
|
|
|
+ console.log(
|
|
|
|
|
+ `自评得分计算详情: 基础分=${baseScore}, 指标扣分=${totalIndicatorDeduction}, 第1步结果=${step1Score}, 指标加分=${totalIndicatorAddition}, 第2步结果=${step2Score}, 附加分=${totalBonusScore}, 最终得分=${form.value.selfScore}`
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
-/** 处理自评得分输入验证 */
|
|
|
|
|
-const handleSelfScoreInput = (value: string | number, row: XskhAssessmentSelfScoreForm) => {
|
|
|
|
|
- const numValue = parseFloat(String(value)) || 0;
|
|
|
|
|
- const maxScore = parseFloat(String(row.planMaxScore)) || 0;
|
|
|
|
|
|
|
+ // 班主任评分采用相同逻辑,但使用班主任的评分数据
|
|
|
|
|
+ let teacherTotalIndicatorDeduction = 0;
|
|
|
|
|
+ let teacherTotalIndicatorAddition = 0;
|
|
|
|
|
|
|
|
- // 如果输入值超过最高分值,自动限制为最高分值
|
|
|
|
|
- if (numValue > maxScore) {
|
|
|
|
|
- row.selfScore = maxScore;
|
|
|
|
|
- ElMessage.warning(`自评得分不能超过最高分值 ${maxScore}`);
|
|
|
|
|
- } else {
|
|
|
|
|
- row.selfScore = numValue;
|
|
|
|
|
|
|
+ // 计算班主任对指标模块的评分
|
|
|
|
|
+ if (form.value.selfScoreList && form.value.selfScoreList.length > 0) {
|
|
|
|
|
+ form.value.selfScoreList.forEach((item) => {
|
|
|
|
|
+ const teacherScore = parseFloat(String(item.teacherScore || 0)) || 0;
|
|
|
|
|
+ // 班主任评分可能是综合评分,这里需要根据实际情况调整
|
|
|
|
|
+ if (teacherScore < 0) {
|
|
|
|
|
+ teacherTotalIndicatorDeduction += Math.abs(teacherScore);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ teacherTotalIndicatorAddition += teacherScore;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 重新计算总得分
|
|
|
|
|
- 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}`);
|
|
|
|
|
|
|
+ // 第1步:基础分 - 班主任评定的扣分
|
|
|
|
|
+ let teacherStep1Score = baseScore - teacherTotalIndicatorDeduction;
|
|
|
|
|
+ if (teacherStep1Score < 0) {
|
|
|
|
|
+ teacherStep1Score = 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 确保值为非负数
|
|
|
|
|
- if (value < 0) {
|
|
|
|
|
- row.selfScore = 0;
|
|
|
|
|
- target.value = '0';
|
|
|
|
|
- }
|
|
|
|
|
-};
|
|
|
|
|
|
|
+ // 第2步:加上班主任评定的加分
|
|
|
|
|
+ const teacherStep2Score = teacherStep1Score + teacherTotalIndicatorAddition;
|
|
|
|
|
|
|
|
-/** 验证所有自评得分是否超过最高分值 */
|
|
|
|
|
-const validateSelfScores = (): boolean => {
|
|
|
|
|
- if (!form.value.selfScoreList || form.value.selfScoreList.length === 0) {
|
|
|
|
|
- return true;
|
|
|
|
|
|
|
+ // 第3步:加上附加分模块的审核得分
|
|
|
|
|
+ let totalApprovalScore = 0;
|
|
|
|
|
+ if (form.value.bonusApprovalList && form.value.bonusApprovalList.length > 0) {
|
|
|
|
|
+ totalApprovalScore = form.value.bonusApprovalList.reduce((sum, item) => {
|
|
|
|
|
+ const score = parseFloat(String(item.approvalScore || 0)) || 0;
|
|
|
|
|
+ return sum + score;
|
|
|
|
|
+ }, 0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- 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;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 最终班主任评分
|
|
|
|
|
+ const finalTeacherScore = teacherStep2Score + totalApprovalScore;
|
|
|
|
|
+ form.value.teacherScore = parseFloat(finalTeacherScore.toFixed(1));
|
|
|
|
|
|
|
|
- if (selfScore < 0) {
|
|
|
|
|
- ElMessage.error(`第${i + 1}项指标"${item.indicatorName}"的自评得分不能为负数`);
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
-};
|
|
|
|
|
|
|
+ // 总得分等于班主任评分
|
|
|
|
|
+ form.value.totalScore = parseFloat(finalTeacherScore.toFixed(1));
|
|
|
|
|
|
|
|
-/** 检查单个指标的自评得分是否超过最高分值 */
|
|
|
|
|
-const isScoreExceeded = (row: XskhAssessmentSelfScoreForm): boolean => {
|
|
|
|
|
- const selfScore = parseFloat(String(row.selfScore || 0)) || 0;
|
|
|
|
|
- const maxScore = parseFloat(String(row.planMaxScore || 0)) || 0;
|
|
|
|
|
- return selfScore > maxScore;
|
|
|
|
|
|
|
+ console.log(
|
|
|
|
|
+ `班主任评分计算详情: 基础分=${baseScore}, 指标扣分=${teacherTotalIndicatorDeduction}, 第1步结果=${teacherStep1Score}, 指标加分=${teacherTotalIndicatorAddition}, 第2步结果=${teacherStep2Score}, 附加审核分=${totalApprovalScore}, 最终得分=${form.value.teacherScore}`
|
|
|
|
|
+ );
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
/** 添加附加分项目 */
|
|
/** 添加附加分项目 */
|
|
@@ -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;
|