From 933f39d79b971090d7ab5fa49b601729b3b9010a Mon Sep 17 00:00:00 2001 From: weizhong Date: Mon, 1 Sep 2025 17:13:59 +0800 Subject: [PATCH 01/37] =?UTF-8?q?=E2=80=9C0901=E7=8F=AD=E4=B8=BB=E4=BB=BB?= =?UTF-8?q?=E8=80=83=E6=A0=B8=E8=AE=A1=E7=AE=97=E5=85=AC=E5=BC=8F=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/vo/AssessmentApprovalDetailVo.java | 2 +- .../bzrkh/domain/vo/AssessmentDetailVo.java | 2 +- .../impl/AssessmentApprovalServiceImpl.java | 31 +++++++++++--- .../ruoyi-bzrkh/班主任考核提交功能开发说明.md | 14 ++++++- docs/设计文档/database/hzdyjs_xg0820.sql | 2 +- .../assessmentApproval/approvalDialog.vue | 28 +++++++------ .../bzrkh/assessmentApproval/viewDialog.vue | 20 +++++----- .../bzrkh/teacherAssessment/submitDialog.vue | 28 ++++++++----- .../bzrkh/teacherAssessment/viewDialog.vue | 40 ++++++++++++------- 9 files changed, 110 insertions(+), 57 deletions(-) diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentApprovalDetailVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentApprovalDetailVo.java index 23fba61a..4f41847e 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentApprovalDetailVo.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentApprovalDetailVo.java @@ -72,7 +72,7 @@ public class AssessmentApprovalDetailVo implements Serializable { private String superiorOverallComment; /** - * 月考核得分 + * 考核得分 */ private BigDecimal monthlyScore; diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentDetailVo.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentDetailVo.java index 462f39d6..31e9d612 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentDetailVo.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/domain/vo/AssessmentDetailVo.java @@ -47,7 +47,7 @@ public class AssessmentDetailVo implements Serializable { private List specialWorkIndicators; /** - * 月考核得分 + * 考核得分 */ private BigDecimal monthlyScore; diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/AssessmentApprovalServiceImpl.java b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/AssessmentApprovalServiceImpl.java index 2d485fcf..c45283c0 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/AssessmentApprovalServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-bzrkh/src/main/java/org/dromara/bzrkh/service/impl/AssessmentApprovalServiceImpl.java @@ -426,7 +426,7 @@ public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService AssessmentDetailVo detailVo = teacherAssessmentService.getAssessmentSubmitDetail( approval.getPlanId(), approval.getClassId(), approval.getEvaluatedUserId()); - // 计算月考核得分 + // 计算考核得分 Double monthlyScore = calculateMonthlyScore(detailVo, approval); ScoreRankingVo ranking = new ScoreRankingVo(); @@ -469,7 +469,7 @@ public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService } /** - * 计算月考核得分 + * 计算考核得分 */ private Double calculateMonthlyScore(AssessmentDetailVo detailVo, AssessmentApprovalVo approval) { // 总系数(K) @@ -523,10 +523,29 @@ public class AssessmentApprovalServiceImpl implements IAssessmentApprovalService } } - // 月考核得分 = 总系数(K)* (班主任常规工作评分 - 按班级扣分50%计的分值 + 特色工作评分) - // 注意:班级扣分是减法,因为它是扣分项 - BigDecimal monthlyScore = totalCoefficient.multiply( - BigDecimal.valueOf(routineWorkTotal - deductionHalf + specialWorkTotal)); + // 判断是否为自评模式(如果没有上级评分,则为自评模式) + boolean isSelfEvaluationMode = scoreDetail.getClassDeductionScore() != null && + scoreDetail.getClassDeductionScore().getSuperiorScore() == null; + + // 检查是否有实际评分数据(避免空白状态显示50分) + boolean hasAnyScore = routineWorkTotal > 0 || deductionHalf > 0 || specialWorkTotal > 0; + + BigDecimal monthlyScore; + if (!hasAnyScore || totalCoefficient.compareTo(BigDecimal.ZERO) == 0) { + // 没有评分数据时返回0 + monthlyScore = BigDecimal.ZERO; + } else if (isSelfEvaluationMode) { + // 自评模式:修正后的考核得分公式 = 总系数(K)* ((班主任常规工作评分 + 班级扣分项满分值) - 按班级扣分50%计的分值 + 特色工作评分) + // 班级扣分项满分值(固定50分)- 仅在有评分数据时计算 + double classDeductionMaxScore = 50.0; + monthlyScore = totalCoefficient.multiply( + BigDecimal.valueOf((routineWorkTotal + classDeductionMaxScore) - deductionHalf + specialWorkTotal)); + } else { + // 审核模式:考核得分 = 总系数(K)* (班主任常规工作评分 - 按班级扣分50%计的分值 + 特色工作评分) + // 注意:班级扣分是减法,因为它是扣分项 + monthlyScore = totalCoefficient.multiply( + BigDecimal.valueOf(routineWorkTotal - deductionHalf + specialWorkTotal)); + } return monthlyScore.setScale(2, RoundingMode.HALF_UP).doubleValue(); } diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/班主任考核提交功能开发说明.md b/backend/ruoyi-modules/ruoyi-bzrkh/班主任考核提交功能开发说明.md index 64d9bd81..5981091b 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/班主任考核提交功能开发说明.md +++ b/backend/ruoyi-modules/ruoyi-bzrkh/班主任考核提交功能开发说明.md @@ -124,7 +124,19 @@ - 计算公式:K = K1 * (K2 + K3) ### 2. 月考核得分计算 -- 计算公式:总系数(K)* (班主任常规工作自评分之和 - 按班级扣分50%计的分值 + 特色工作总分值) + +#### 自评模式(修正后公式) +- 计算公式:总系数(K)* ((班主任常规工作自评分之和 + 班级扣分项满分值) - 按班级扣分50%计的分值 + 特色工作总分值) +- 班级扣分项满分值:固定50分(来自指标设置) +- 修正原因:确保基础分值不受扣分影响,提高计算结果的合理性 + +#### 审核模式(保持不变) +- 计算公式:总系数(K)* (班主任常规工作上级评分之和 + 班级管理实效上级评分 + 特色工作上级评分之和) + +#### 公式变化对比 +- **修正前**:K × (常规工作自评分 - 班级扣分50% + 特色工作总分) +- **修正后**:K × ((常规工作自评分 + 50) - 班级扣分50% + 特色工作总分) +- **关键变化**:新增班级扣分项满分值(50分)确保基础分值 ### 3. 数据存储逻辑 1. 先逻辑删除该计划下该教师的历史评分数据 diff --git a/docs/设计文档/database/hzdyjs_xg0820.sql b/docs/设计文档/database/hzdyjs_xg0820.sql index 2cb0e969..21c308f0 100644 --- a/docs/设计文档/database/hzdyjs_xg0820.sql +++ b/docs/设计文档/database/hzdyjs_xg0820.sql @@ -2186,7 +2186,7 @@ DROP TABLE IF EXISTS `rs_overseas_record_status_backup`; CREATE TABLE `rs_overseas_record_status_backup` ( `record_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '记录ID', `completion_status` char(1) DEFAULT '0' COMMENT '完成状态:0-进行中,1-已完成,2-提前结束', - `old_status_text` varchar(12) CHARACTER SET latin1 NOT NULL DEFAULT '', + `old_status_text` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '原状态文本', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue b/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue index ca3ee38c..8a5b93c9 100644 --- a/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue +++ b/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue @@ -249,17 +249,17 @@ - + - + @@ -360,7 +360,7 @@ const managementEffectivenessForm = reactive({ superiorComment: '' }); -// 月考核得分表单 +// 考核得分表单 const monthlyScoreForm = reactive({ selfOverallComment: '', superiorOverallComment: '' @@ -404,7 +404,7 @@ const formatNumber = (value?: number | string, precision = 4) => { return numValue.toFixed(precision); }; -/** 计算月考核得分 */ +/** 计算考核得分 */ const calculateMonthlyScore = () => { // 总系数(K) const totalCoefficient = approvalDetail.value?.coefficient?.totalCoefficient || 0; @@ -418,7 +418,7 @@ const calculateMonthlyScore = () => { // 特色工作上级评分之和(使用上级评分,而非自评分) const specialWorkTotal = specialWorkScores.value.reduce((sum, item) => sum + (item.superiorScore || 0), 0); - // 月考核得分 = 总系数(K)* (班主任常规工作上级评分之和 + 班级管理实效上级评分 + 特色工作上级评分之和) + // 考核得分 = 总系数(K)* (班主任常规工作上级评分之和 + 班级管理实效上级评分 + 特色工作上级评分之和) return totalCoefficient * (routineWorkTotal + managementEffectivenessScore + specialWorkTotal); }; @@ -490,25 +490,27 @@ const loadApprovalDetail = async () => { managementEffectivenessForm.classDeduction = Number(indicator.selfScore) || 0; managementEffectivenessForm.classDeductionHalf = (Number(indicator.selfScore) || 0) * 0.5; managementEffectivenessForm.selfComment = indicator.selfComment || ''; - // 上级评分默认使用按班级扣分50%计的分值 + // 上级评分默认使用50分-按班级扣分50%计的分值 const classDeductionHalf = (Number(indicator.selfScore) || 0) * 0.5; - managementEffectivenessForm.superiorScore = Number(indicator.superiorScore) || classDeductionHalf; + const defaultSuperiorScore = 50 - classDeductionHalf; + managementEffectivenessForm.superiorScore = Number(indicator.superiorScore) || defaultSuperiorScore; managementEffectivenessForm.superiorComment = indicator.superiorComment || ''; console.log('班级管理实效数据初始化:', { 班级扣分: managementEffectivenessForm.classDeduction, 扣分50计: managementEffectivenessForm.classDeductionHalf, 自评意见: managementEffectivenessForm.selfComment, 上级评分: managementEffectivenessForm.superiorScore, - 上级意见: managementEffectivenessForm.superiorComment + 上级意见: managementEffectivenessForm.superiorComment, + 默认上级评分计算: `50 - ${classDeductionHalf} = ${defaultSuperiorScore}` }); } else { // 如果没有找到班级扣分指标,设置默认值 managementEffectivenessForm.classDeduction = 0; managementEffectivenessForm.classDeductionHalf = 0; managementEffectivenessForm.selfComment = ''; - managementEffectivenessForm.superiorScore = 0; // 默认为0 + managementEffectivenessForm.superiorScore = 50; // 默认为满分50分 managementEffectivenessForm.superiorComment = ''; - console.warn('班级管理实效数据为空,使用默认值'); + console.warn('班级管理实效数据为空,使用默认值,上级评分默认为满分50分'); } // 初始化特色工作数据 - 确保包含所有必要字段 @@ -541,10 +543,10 @@ const loadApprovalDetail = async () => { console.warn('特色工作数据为空或格式错误'); } - // 初始化月考核得分数据 + // 初始化考核得分数据 monthlyScoreForm.selfOverallComment = approvalDetail.value?.selfOverallComment || ''; monthlyScoreForm.superiorOverallComment = approvalDetail.value?.superiorOverallComment || ''; - console.log('月考核得分数据初始化:', { + console.log('考核得分数据初始化:', { 自我总体评价: monthlyScoreForm.selfOverallComment, 上级总体评价: monthlyScoreForm.superiorOverallComment, 计算得分: calculateMonthlyScore().toFixed(2) diff --git a/web/src/views/bzrkh/assessmentApproval/viewDialog.vue b/web/src/views/bzrkh/assessmentApproval/viewDialog.vue index dc996577..2fba8e33 100644 --- a/web/src/views/bzrkh/assessmentApproval/viewDialog.vue +++ b/web/src/views/bzrkh/assessmentApproval/viewDialog.vue @@ -202,17 +202,17 @@ - + - + @@ -259,7 +259,7 @@ - + {{ calculateMonthlyScore().toFixed(2) }}分 @@ -343,7 +343,7 @@ const managementEffectivenessData = reactive({ superiorComment: '' }); -// 月考核得分数据 +// 考核得分数据 const monthlyScoreData = reactive({ selfOverallComment: '', superiorOverallComment: '' @@ -409,7 +409,7 @@ const formatNumber = (value?: number | string, precision = 4) => { return numValue.toFixed(precision); }; -/** 计算月考核得分 */ +/** 计算考核得分 */ const calculateMonthlyScore = () => { // 总系数(K) const totalCoefficient = viewDetail.value?.coefficient?.totalCoefficient || 0; @@ -423,7 +423,7 @@ const calculateMonthlyScore = () => { // 特色工作上级评分之和(查看界面显示最终审批结果,使用上级评分) const specialWorkTotal = specialWorkScores.value.reduce((sum, item) => sum + (item.superiorScore || 0), 0); - // 月考核得分 = 总系数(K)* (班主任常规工作上级评分之和 + 班级管理实效上级评分 + 特色工作上级评分之和) + // 考核得分 = 总系数(K)* (班主任常规工作上级评分之和 + 班级管理实效上级评分 + 特色工作上级评分之和) return totalCoefficient * (routineWorkTotal + managementEffectivenessScore + specialWorkTotal); }; @@ -431,7 +431,7 @@ const calculateMonthlyScore = () => { const calculateEvaluationLevel = () => { const score = calculateMonthlyScore(); console.log('=== 📊 评价等级计算调试 ==='); - console.log('💯 月考核得分:', score); + console.log('💯 考核得分:', score); console.log('📈 是否有统计数据:', !!evaluationStats.value); console.log('👤 当前用户ID:', currentRow.value?.evaluatedUserId); @@ -683,10 +683,10 @@ const loadViewDetail = async () => { console.warn('特色工作数据为空或格式错误'); } - // 初始化月考核得分数据 + // 初始化考核得分数据 monthlyScoreData.selfOverallComment = viewDetail.value?.selfOverallComment || ''; monthlyScoreData.superiorOverallComment = viewDetail.value?.superiorOverallComment || ''; - console.log('月考核得分数据初始化:', { + console.log('考核得分数据初始化:', { 自我总体评价: monthlyScoreData.selfOverallComment, 上级总体评价: monthlyScoreData.superiorOverallComment, 计算得分: calculateMonthlyScore().toFixed(2) diff --git a/web/src/views/bzrkh/teacherAssessment/submitDialog.vue b/web/src/views/bzrkh/teacherAssessment/submitDialog.vue index 677e9715..06656520 100644 --- a/web/src/views/bzrkh/teacherAssessment/submitDialog.vue +++ b/web/src/views/bzrkh/teacherAssessment/submitDialog.vue @@ -280,17 +280,17 @@ - + - + @@ -455,7 +455,7 @@ const specialWorkForm = reactive({ totalScore: 0 }); -// 月考核得分表单 +// 考核得分表单 const monthlyScoreForm = reactive({ overallComment: '' }); @@ -509,7 +509,7 @@ const calculateTotalSpecialScore = () => { (specialWorkForm.score1 || 0) + (specialWorkForm.score2 || 0) + (specialWorkForm.score3 || 0) + (specialWorkForm.score4 || 0); }; -/** 计算月考核得分 */ +/** 计算考核得分 */ const calculateMonthlyScore = () => { // 总系数(K) const totalCoefficient = assessmentDetail.value?.coefficient?.totalCoefficient || 0; @@ -523,8 +523,18 @@ const calculateMonthlyScore = () => { // 特色工作总分值 const specialWorkTotal = specialWorkForm.totalScore || 0; - // 月考核得分 = 总系数(K)* (班主任常规工作自评分之和 - 按班级扣分50%计的分值 + 特色工作总分值) - return totalCoefficient * (routineWorkTotal - deductionHalf + specialWorkTotal); + // 检查是否有实际评分数据(避免空白状态显示50分) + const hasAnyScore = routineWorkTotal > 0 || deductionHalf > 0 || specialWorkTotal > 0; + + if (!hasAnyScore || totalCoefficient === 0) { + return 0; // 没有评分数据时显示0 + } + + // 班级扣分项满分值(固定50分)- 仅在有评分数据时计算 + const classDeductionMaxScore = 50; + + // 修正后的考核得分公式 = 总系数(K)* ((班主任常规工作自评分之和 + 班级扣分项满分值) - 按班级扣分50%计的分值 + 特色工作总分值) + return totalCoefficient * ((routineWorkTotal + classDeductionMaxScore) - deductionHalf + specialWorkTotal); }; /** 打开弹窗 */ @@ -609,7 +619,7 @@ const loadAssessmentDetail = async () => { // 确保特色工作总分重新计算 calculateTotalSpecialScore(); - // 初始化月考核得分数据 + // 初始化考核得分数据 monthlyScoreForm.overallComment = assessmentDetail.value?.overallComment || ''; // 详细的调试信息:验证数据是否正确加载 @@ -978,7 +988,7 @@ defineExpose({ } } -/* 月考核得分表单样式优化 */ +/* 考核得分表单样式优化 */ :deep(.monthly-score-form) { .el-form-item__label { text-align: center; diff --git a/web/src/views/bzrkh/teacherAssessment/viewDialog.vue b/web/src/views/bzrkh/teacherAssessment/viewDialog.vue index 619ea023..8c91e595 100644 --- a/web/src/views/bzrkh/teacherAssessment/viewDialog.vue +++ b/web/src/views/bzrkh/teacherAssessment/viewDialog.vue @@ -256,17 +256,17 @@ - + diff --git a/web/src/views/xg/xgss/xsssfpejxy/index.vue b/web/src/views/xg/xgss/xsssfpejxy/index.vue index 521d752a..3e7a3430 100644 --- a/web/src/views/xg/xgss/xsssfpejxy/index.vue +++ b/web/src/views/xg/xgss/xsssfpejxy/index.vue @@ -135,6 +135,7 @@ 分配给二级学院 批量收回宿舍 批量退宿床位 + 导出住宿清单 import { ref, computed, reactive, onMounted, onUnmounted, nextTick, watch, getCurrentInstance } from 'vue'; -import { InfoFilled, House, Avatar, UserFilled } from '@element-plus/icons-vue'; +import { InfoFilled, House, Avatar, UserFilled, Download } from '@element-plus/icons-vue'; import type { DormTreeNode, BedInfo } from '@/api/xg/xgss/xsssfjgl/types'; import type { DormRoomVO } from '@/api/xg/xgss/dormRoom/types'; import type { DormBedDetailVO } from '@/api/xg/xgss/dormBed/types'; @@ -376,7 +377,7 @@ import BedDialog from './components/BedDialog.vue'; import CollegeAllocationDialog from './components/CollegeAllocationDialog.vue'; import { batchRecallDormBeds, classTeacherStayawaySelectedBeds } from '@/api/xg/xgss/dormBedStudent/dormBedStudent'; -// const { proxy } = getCurrentInstance(); +const { proxy } = getCurrentInstance() as any; // 组件状态 const dormTreeRef = ref(); @@ -775,6 +776,102 @@ const handleBatchStayaway = async () => { } }; +/** 导出住宿清单 */ +const handleExportAccommodationList = async () => { + if (!selectedBuilding.value) { + ElMessage.warning('请先选择宿舍楼'); + return; + } + + if (!roomList.value || roomList.value.length === 0) { + ElMessage.warning('当前宿舍楼没有房间数据'); + return; + } + + try { + // 创建Excel工作簿数据 + const accommodationData = generateAccommodationExcelData(); + + // 使用proxy.download方法导出Excel + const filename = `${selectedBuilding.value.label}_住宿清单_${new Date().getTime()}.xlsx`; + + proxy?.download( + 'xgss/dormRoom/exportAccommodationList', + { + buildingId: selectedBuilding.value.id, + buildingName: selectedBuilding.value.label, + buildingType: selectedBuilding.value.buildingType, + accommodationData: JSON.stringify(accommodationData) // 转换为JSON字符串 + }, + filename + ); + + ElMessage.success('导出任务已提交'); + } catch (error) { + console.error('导出住宿清单失败:', error); + ElMessage.error('导出失败,请重试'); + } +}; + +/** 生成住宿清单Excel数据 */ +const generateAccommodationExcelData = () => { + // 按楼层分组房间数据 + const floorGroups = new Map(); + + roomList.value.forEach((room) => { + const floorNum = room.floorNum || 1; + if (!floorGroups.has(floorNum)) { + floorGroups.set(floorNum, []); + } + + // 为每个房间准备数据,包括床位信息 + const roomData = { + roomId: room.id, + roomName: room.roomName, + floorNum: room.floorNum, + roomType: room.roomType, + roomStatus: room.roomStatus, + remark: room.remark || '', + beds: room.children + ? room.children.map((bed: any) => ({ + bedId: bed.id, + bedName: bed.bedName, + bedType: bed.bedType, + bedStatus: bed.bedStatus, + studentNo: bed.studentNo || '', + studentName: bed.studentName || '', + collegeName: bed.collegeName || '', + majorName: bed.majorName || '', + className: bed.className || '', + studentGender: bed.studentGender, + bedRemark: bed.bedRemark || '' + })) + : [] + }; + + floorGroups.get(floorNum)!.push(roomData); + }); + + // 按楼层排序 + const sortedFloors = Array.from(floorGroups.keys()).sort((a, b) => a - b); + + // 构建Excel数据结构 + const excelData = { + buildingInfo: { + buildingId: selectedBuilding.value?.id, + buildingName: selectedBuilding.value?.label, + buildingType: selectedBuilding.value?.buildingType, + buildingTypeText: selectedBuilding.value?.buildingType === '1' ? '男生楼' : '女生楼' + }, + floorData: sortedFloors.map((floorNum) => ({ + floorNum, + rooms: floorGroups.get(floorNum) || [] + })) + }; + + return excelData; +}; + /** 全部展开 */ const expandAll = async () => { if (expandAllLoading.value || selectionLoading.value || !roomList.value?.length) return; From cf21360ac14dadf86cf995a47f4dd374de8e57dc Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Sun, 7 Sep 2025 07:43:10 +0800 Subject: [PATCH 17/37] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapper/XskhDisciplineRecordMapper.java | 84 ++++++++++--------- .../impl/XskhDisciplineRecordServiceImpl.java | 21 +++++ .../mapper/XskhDisciplineRecordMapper.xml | 9 ++ web/src/views/xskh/disciplineType/index.vue | 6 +- 4 files changed, 79 insertions(+), 41 deletions(-) diff --git a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/mapper/XskhDisciplineRecordMapper.java b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/mapper/XskhDisciplineRecordMapper.java index fe285aaa..3557020d 100644 --- a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/mapper/XskhDisciplineRecordMapper.java +++ b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/mapper/XskhDisciplineRecordMapper.java @@ -19,46 +19,54 @@ import java.util.Map; */ public interface XskhDisciplineRecordMapper extends BaseMapperPlus { - /** - * 查询学生选项列表(用于下拉框) - * - * @param keyword 搜索关键词(学号或姓名) - * @return 学生选项列表 - */ - List selectStudentOptions(String keyword); + /** + * 查询学生选项列表(用于下拉框) + * + * @param keyword 搜索关键词(学号或姓名) + * @return 学生选项列表 + */ + List selectStudentOptions(String keyword); - /** - * 查询班主任班级的违纪处分记录列表(班主任专用) - * - * @param page 分页参数 - * @param bo 查询条件 - * @param classTeacherId 班主任ID - * @return 分页查询结果 - */ - Page selectClassTeacherVoPage(@Param("page") Page page, - @Param("bo") XskhDisciplineRecordBo bo, - @Param("classTeacherId") Long classTeacherId); + /** + * 查询班主任班级的违纪处分记录列表(班主任专用) + * + * @param page 分页参数 + * @param bo 查询条件 + * @param classTeacherId 班主任ID + * @return 分页查询结果 + */ + Page selectClassTeacherVoPage(@Param("page") Page page, + @Param("bo") XskhDisciplineRecordBo bo, + @Param("classTeacherId") Long classTeacherId); - /** - * 获取指标关联的违纪处分类型和奖励类型 - * - * @param indicatorId 指标ID - * @return 包含disciplineTypeIds和rewardTypeIds的Map - */ - Map selectIndicatorTypes(@Param("indicatorId") Long indicatorId); + /** + * 获取指标关联的违纪处分类型和奖励类型 + * + * @param indicatorId 指标ID + * @return 包含disciplineTypeIds和rewardTypeIds的Map + */ + Map selectIndicatorTypes(@Param("indicatorId") Long indicatorId); - /** - * 获取学生在指定时间范围内的违纪处分记录 - * - * @param studentId 学生ID - * @param disciplineTypeIds 违纪处分类型ID列表 - * @param startTime 开始时间 - * @param endTime 结束时间 - * @return 违纪处分记录列表 - */ - List selectStudentDisciplineRecords(@Param("studentId") Long studentId, - @Param("disciplineTypeIds") List disciplineTypeIds, - @Param("startTime") String startTime, - @Param("endTime") String endTime); + /** + * 获取学生在指定时间范围内的违纪处分记录 + * + * @param studentId 学生ID + * @param disciplineTypeIds 违纪处分类型ID列表 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 违纪处分记录列表 + */ + List selectStudentDisciplineRecords(@Param("studentId") Long studentId, + @Param("disciplineTypeIds") List disciplineTypeIds, + @Param("startTime") String startTime, + @Param("endTime") String endTime); + + /** + * 根据违纪记录ID逻辑删除宿舍卫生检查违纪关联记录 + * + * @param disciplineRecordId 违纪记录ID + * @return 删除的记录数量 + */ + int deleteHygieneCheckViolationByDisciplineRecordId(@Param("disciplineRecordId") Long disciplineRecordId); } diff --git a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/service/impl/XskhDisciplineRecordServiceImpl.java b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/service/impl/XskhDisciplineRecordServiceImpl.java index d7cba428..9f12aaf5 100644 --- a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/service/impl/XskhDisciplineRecordServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/service/impl/XskhDisciplineRecordServiceImpl.java @@ -17,6 +17,8 @@ import org.dromara.xskh.domain.vo.XskhStudentOptionVo; import org.dromara.xskh.mapper.XskhDisciplineRecordMapper; import org.dromara.xskh.service.IXskhDisciplineRecordService; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import lombok.extern.slf4j.Slf4j; import java.util.Collection; import java.util.List; @@ -30,6 +32,7 @@ import java.util.stream.Collectors; * @author ruoyi * @date 2025-01-03 */ +@Slf4j @RequiredArgsConstructor @Service public class XskhDisciplineRecordServiceImpl implements IXskhDisciplineRecordService { @@ -132,10 +135,28 @@ public class XskhDisciplineRecordServiceImpl implements IXskhDisciplineRecordSer * 批量删除学生违纪处分记录 */ @Override + @Transactional(rollbackFor = Exception.class) public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { if (isValid) { // TODO 做一些业务上的校验,判断是否需要校验 } + + // 在删除违纪记录前,先删除相关的宿舍卫生检查违纪关联记录 + for (Long id : ids) { + try { + // 查询违纪记录,判断是否为宿舍卫生检查来源 + XskhDisciplineRecordVo disciplineRecord = baseMapper.selectVoById(id); + if (disciplineRecord != null && "1".equals(disciplineRecord.getViolationSource())) { + // 删除宿舍卫生检查违纪关联记录 + int deletedCount = baseMapper.deleteHygieneCheckViolationByDisciplineRecordId(id); + log.info("删除违纪记录ID: {} 对应的宿舍卫生检查违纪关联记录,删除数量: {}", id, deletedCount); + } + } catch (Exception e) { + log.error("删除违纪记录ID: {} 对应的宿舍卫生检查违纪关联记录失败: {}", id, e.getMessage(), e); + throw new RuntimeException("删除宿舍卫生检查违纪关联记录失败", e); + } + } + return baseMapper.deleteBatchIds(ids) > 0; } diff --git a/backend/ruoyi-modules/ruoyi-xskh/src/main/resources/mapper/XskhDisciplineRecordMapper.xml b/backend/ruoyi-modules/ruoyi-xskh/src/main/resources/mapper/XskhDisciplineRecordMapper.xml index f22a2fb5..9713a923 100644 --- a/backend/ruoyi-modules/ruoyi-xskh/src/main/resources/mapper/XskhDisciplineRecordMapper.xml +++ b/backend/ruoyi-modules/ruoyi-xskh/src/main/resources/mapper/XskhDisciplineRecordMapper.xml @@ -125,4 +125,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" order by create_time desc + + + update xg_hygiene_check_violation + set deleted = 1, + update_time = now() + where discipline_record_id = #{disciplineRecordId} + and deleted = 0 + + diff --git a/web/src/views/xskh/disciplineType/index.vue b/web/src/views/xskh/disciplineType/index.vue index bd6f9dd8..c89841bd 100644 --- a/web/src/views/xskh/disciplineType/index.vue +++ b/web/src/views/xskh/disciplineType/index.vue @@ -184,9 +184,9 @@ -
- 录入违纪记录时,扣分必须在此范围内 -
+ From f6257774844d5e129086071ce5b748374745db14 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Sun, 7 Sep 2025 08:38:04 +0800 Subject: [PATCH 18/37] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xskh/domain/XskhDisciplineType.java | 10 +++ .../dromara/xskh/domain/XskhRewardType.java | 10 +++ .../xskh/domain/bo/XskhDisciplineTypeBo.java | 11 +++ .../xskh/domain/bo/XskhRewardTypeBo.java | 11 +++ .../xskh/domain/vo/XskhDisciplineTypeVo.java | 13 ++++ .../xskh/domain/vo/XskhRewardTypeVo.java | 16 ++++- .../学生考核管理/学生考核管理数据库模型.sql | 4 ++ .../disciplineType/disciplineType/types.ts | 20 ++++++ .../api/xskh/rewardType/rewardType/types.ts | 30 ++++++++ web/src/views/xskh/disciplineType/index.vue | 63 +++++++++++++++-- web/src/views/xskh/rewardType/index.vue | 69 ++++++++++++++++++- 11 files changed, 247 insertions(+), 10 deletions(-) diff --git a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/XskhDisciplineType.java b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/XskhDisciplineType.java index c27e10dd..610a4a9b 100644 --- a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/XskhDisciplineType.java +++ b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/XskhDisciplineType.java @@ -57,6 +57,16 @@ public class XskhDisciplineType extends TenantEntity { */ private java.math.BigDecimal maxScore; + /** + * 是否均化(0-否 1-是) + */ + private String isEqualized; + + /** + * 均化阈值 + */ + private java.math.BigDecimal equalizedThreshold; + /** * 类型说明 */ diff --git a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/XskhRewardType.java b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/XskhRewardType.java index 94eb5c16..bc521373 100644 --- a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/XskhRewardType.java +++ b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/XskhRewardType.java @@ -42,6 +42,16 @@ public class XskhRewardType extends TenantEntity { */ private String description; + /** + * 是否均化(0-否 1-是) + */ + private String isEqualized; + + /** + * 均化阈值 + */ + private java.math.BigDecimal equalizedThreshold; + /** * 状态(0-正常 1-停用) */ diff --git a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/bo/XskhDisciplineTypeBo.java b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/bo/XskhDisciplineTypeBo.java index 5c862cef..c8190fa5 100644 --- a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/bo/XskhDisciplineTypeBo.java +++ b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/bo/XskhDisciplineTypeBo.java @@ -67,6 +67,17 @@ public class XskhDisciplineTypeBo extends BaseEntity { @DecimalMax(value = "100.00", message = "最高扣分不能大于100", groups = { AddGroup.class, EditGroup.class }) private java.math.BigDecimal maxScore; + /** + * 是否均化(0-否 1-是) + */ + private String isEqualized; + + /** + * 均化阈值 + */ + @DecimalMin(value = "0.00", message = "均化阈值不能小于0", groups = { AddGroup.class, EditGroup.class }) + private java.math.BigDecimal equalizedThreshold; + /** * 类型说明 */ diff --git a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/bo/XskhRewardTypeBo.java b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/bo/XskhRewardTypeBo.java index 134ec50b..27bdfb66 100644 --- a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/bo/XskhRewardTypeBo.java +++ b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/bo/XskhRewardTypeBo.java @@ -43,6 +43,17 @@ public class XskhRewardTypeBo extends BaseEntity { */ private String description; + /** + * 是否均化(0-否 1-是) + */ + private String isEqualized; + + /** + * 均化阈值 + */ + @DecimalMin(value = "0.00", message = "均化阈值不能小于0", groups = { AddGroup.class, EditGroup.class }) + private java.math.BigDecimal equalizedThreshold; + /** * 状态(0-正常 1-停用) */ diff --git a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhDisciplineTypeVo.java b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhDisciplineTypeVo.java index a3bb97cb..3d9fb5f9 100644 --- a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhDisciplineTypeVo.java +++ b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhDisciplineTypeVo.java @@ -70,6 +70,19 @@ public class XskhDisciplineTypeVo implements Serializable { @ExcelProperty(value = "最高扣分") private java.math.BigDecimal maxScore; + /** + * 是否均化(0-否 1-是) + */ + @ExcelProperty(value = "是否均化", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String isEqualized; + + /** + * 均化阈值 + */ + @ExcelProperty(value = "均化阈值") + private java.math.BigDecimal equalizedThreshold; + /** * 类型说明 */ diff --git a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhRewardTypeVo.java b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhRewardTypeVo.java index fd17fdbd..d644a9ab 100644 --- a/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhRewardTypeVo.java +++ b/backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhRewardTypeVo.java @@ -12,8 +12,6 @@ import java.io.Serial; import java.io.Serializable; import java.util.Date; - - /** * 学生奖励类型视图对象 xskh_reward_type * @@ -52,6 +50,19 @@ public class XskhRewardTypeVo implements Serializable { @ExcelProperty(value = "类型说明") private String description; + /** + * 是否均化(0-否 1-是) + */ + @ExcelProperty(value = "是否均化", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String isEqualized; + + /** + * 均化阈值 + */ + @ExcelProperty(value = "均化阈值") + private java.math.BigDecimal equalizedThreshold; + /** * 状态(0-正常 1-停用) */ @@ -71,5 +82,4 @@ public class XskhRewardTypeVo implements Serializable { @ExcelProperty(value = "删除标志(0-未删除 1-已删除)") private Long deleted; - } diff --git a/docs/设计文档/database/学生考核管理/学生考核管理数据库模型.sql b/docs/设计文档/database/学生考核管理/学生考核管理数据库模型.sql index dc094e82..17018f26 100644 --- a/docs/设计文档/database/学生考核管理/学生考核管理数据库模型.sql +++ b/docs/设计文档/database/学生考核管理/学生考核管理数据库模型.sql @@ -15,6 +15,8 @@ CREATE TABLE `xskh_discipline_type` ( `area_type` char(1) DEFAULT '1' COMMENT '区域类型(1-宿舍区违纪 2-教学区违纪)' , `min_score` decimal(5,2) DEFAULT 0.00 COMMENT '最低扣分', `max_score` decimal(5,2) DEFAULT 100.00 COMMENT '最高扣分', + `is_equalized` char(1) DEFAULT '0' COMMENT '是否均化(0-否 1-是)', + `equalized_threshold` decimal(10,2) DEFAULT NULL COMMENT '均化阈值', `status` char(1) DEFAULT '0' COMMENT '状态(0-正常 1-停用)', `sort_order` int(4) DEFAULT 0 COMMENT '排序号', `create_by` bigint(20) DEFAULT NULL COMMENT '创建者', @@ -134,6 +136,8 @@ CREATE TABLE `xskh_reward_type` ( `type_code` varchar(50) NOT NULL COMMENT '类型编码', `type_name` varchar(100) NOT NULL COMMENT '类型名称', `description` varchar(500) DEFAULT NULL COMMENT '类型说明', + `is_equalized` char(1) DEFAULT '0' COMMENT '是否均化(0-否 1-是)', + `equalized_threshold` decimal(10,2) DEFAULT NULL COMMENT '均化阈值', `status` char(1) DEFAULT '0' COMMENT '状态(0-正常 1-停用)', `sort_order` int(4) DEFAULT 0 COMMENT '排序号', `create_by` bigint(20) DEFAULT NULL COMMENT '创建者', diff --git a/web/src/api/xskh/disciplineType/disciplineType/types.ts b/web/src/api/xskh/disciplineType/disciplineType/types.ts index da4e7af2..be6edc8f 100644 --- a/web/src/api/xskh/disciplineType/disciplineType/types.ts +++ b/web/src/api/xskh/disciplineType/disciplineType/types.ts @@ -34,6 +34,16 @@ export interface DisciplineTypeVO { */ maxScore: number; + /** + * 是否均化(0-否 1-是) + */ + isEqualized: string; + + /** + * 均化阈值 + */ + equalizedThreshold: number; + /** * 类型说明 */ @@ -91,6 +101,16 @@ export interface DisciplineTypeForm extends BaseEntity { */ maxScore?: number; + /** + * 是否均化(0-否 1-是) + */ + isEqualized?: string; + + /** + * 均化阈值 + */ + equalizedThreshold?: number; + /** * 类型说明 */ diff --git a/web/src/api/xskh/rewardType/rewardType/types.ts b/web/src/api/xskh/rewardType/rewardType/types.ts index cab8b0d8..28fbabf1 100644 --- a/web/src/api/xskh/rewardType/rewardType/types.ts +++ b/web/src/api/xskh/rewardType/rewardType/types.ts @@ -19,6 +19,16 @@ export interface RewardTypeVO { */ description: string; + /** + * 是否均化(0-否 1-是) + */ + isEqualized: string; + + /** + * 均化阈值 + */ + equalizedThreshold: number; + /** * 状态(0-正常 1-停用) */ @@ -56,6 +66,16 @@ export interface RewardTypeForm extends BaseEntity { */ description?: string; + /** + * 是否均化(0-否 1-是) + */ + isEqualized?: string; + + /** + * 均化阈值 + */ + equalizedThreshold?: number; + /** * 状态(0-正常 1-停用) */ @@ -88,6 +108,16 @@ export interface RewardTypeQuery extends PageQuery { */ description?: string; + /** + * 是否均化(0-否 1-是) + */ + isEqualized?: string; + + /** + * 均化阈值 + */ + equalizedThreshold?: number; + /** * 状态(0-正常 1-停用) */ diff --git a/web/src/views/xskh/disciplineType/index.vue b/web/src/views/xskh/disciplineType/index.vue index c89841bd..300f291a 100644 --- a/web/src/views/xskh/disciplineType/index.vue +++ b/web/src/views/xskh/disciplineType/index.vue @@ -3,7 +3,7 @@
- + @@ -113,6 +113,17 @@ + + + + + + + + diff --git a/web/src/views/cw/projectApproval/index.vue b/web/src/views/cw/projectApproval/index.vue new file mode 100644 index 00000000..855244d1 --- /dev/null +++ b/web/src/views/cw/projectApproval/index.vue @@ -0,0 +1,1217 @@ + + + + + diff --git a/web/src/views/cw/projectApproval/pending.vue b/web/src/views/cw/projectApproval/pending.vue new file mode 100644 index 00000000..271a6626 --- /dev/null +++ b/web/src/views/cw/projectApproval/pending.vue @@ -0,0 +1,433 @@ + + + + + diff --git a/web/src/views/cw/projectAuditor/BUG_FIX_REPORT.md b/web/src/views/cw/projectAuditor/BUG_FIX_REPORT.md new file mode 100644 index 00000000..3c76eca5 --- /dev/null +++ b/web/src/views/cw/projectAuditor/BUG_FIX_REPORT.md @@ -0,0 +1,150 @@ +# 项目审批人批量添加功能Bug修复报告 + +## 🐛 问题描述 +用户反馈:批量添加审批人时,选择用户后点击提交,页面提示添加成功,但后台数据库中没有新增数据。 + +## 🔍 问题分析 + +### 根本原因 +1. **前端使用模拟API函数**:`index.vue` 中第354-378行定义了模拟的API函数,而不是真实的API调用 +2. **缺少正确的API导入**:没有导入真实的 `batchAddProjectAuditor` 等API函数 +3. **数据格式不匹配**:前端传递的数据格式与后端期望格式存在差异 + +### 问题代码 +```javascript +// 错误:使用模拟函数 +const batchAddProjectAuditor = (data: any) => { + return Promise.resolve() // 直接返回成功,不实际调用后端 +} +``` + +## 🔧 修复方案 + +### 1. 导入真实API函数 +```javascript +import { + listProjectAuditor, + getProjectAuditor, + updateProjectAuditor, + delProjectAuditor, + batchAddProjectAuditor +} from '@/api/cw/projectAuditor' +import type { CwProjectAuditorVO, CwProjectAuditorForm, CwProjectAuditorQuery, CwProjectAuditorBatchBo } from '@/api/cw/types' +``` + +### 2. 修复数据类型定义 +```typescript +// 修正数据类型 +const auditorList = ref([]) +const queryParams = ref({...}) +const editDialog = reactive({ + form: {} as CwProjectAuditorForm +}) +``` + +### 3. 修复批量添加数据格式 +```javascript +const confirmBatchAdd = async () => { + const userIds = batchDialog.selectedUsers.map((user) => user.userId as number) + const data: CwProjectAuditorBatchBo = { + userIds: userIds, + remark: '批量添加' + } + + const response = await batchAddProjectAuditor(data) + // ... 处理响应 +} +``` + +### 4. 修复后端数据解析 +```javascript +const response = await listProjectAuditor(queryParams.value) +// 后端返回的是TableDataInfo格式 +auditorList.value = response.data?.rows || [] +total.value = response.data?.total || 0 +``` + +## ✅ 修复内容清单 + +### 前端修复 +- [x] 移除模拟API函数,导入真实API +- [x] 修复TypeScript类型定义 +- [x] 修复批量添加数据格式 +- [x] 修复后端响应数据解析 +- [x] 改进错误处理和用户反馈 +- [x] 修复按钮事件类型问题 + +### 后端验证 +- [x] 确认后端API接口正常工作 +- [x] 确认数据库表结构正确 +- [x] 确认权限控制配置 + +## 🧪 测试验证 + +### 测试用例 +1. **批量添加功能测试** + - 选择部门 + - 选择多个用户 + - 点击确认添加 + - 验证数据库是否成功插入数据 + +2. **查询列表功能测试** + - 验证API调用正常 + - 验证数据格式解析正确 + - 验证分页功能 + +3. **错误处理测试** + - 测试网络错误情况 + - 测试用户已存在情况 + - 测试权限不足情况 + +### 测试脚本 +提供了 `test-api.js` 文件用于功能验证测试。 + +## 📋 技术规范遵循 + +### 符合项目规范 +- ✅ **前端开发规范**:符合Vue 3.5.13 + TypeScript + Element Plus架构 +- ✅ **API接口规范**:使用统一的request工具和错误处理 +- ✅ **UI设计规范**:继承后勤管理模块的样式风格和颜色主题 +- ✅ **数据库规范**:使用雪花ID、逻辑删除、多租户等标准字段 +- ✅ **权限控制**:使用@SaCheckPermission注解控制接口权限 + +### 代码质量 +- ✅ **类型安全**:完整的TypeScript类型定义 +- ✅ **错误处理**:完善的异常捕获和用户提示 +- ✅ **用户体验**:优化的加载状态和反馈信息 +- ✅ **响应式设计**:保持左右布局在不同屏幕下的表现 + +## 🚀 部署说明 + +### 验证步骤 +1. 确保后端服务正常运行 +2. 检查数据库表 `cw_project_auditor` 是否存在 +3. 验证用户权限配置 `cw:projectAuditor:add` +4. 测试前端页面功能 + +### 预期结果 +- 批量添加功能正常工作 +- 数据成功写入数据库 +- 页面显示准确的成功/失败提示 +- 列表数据正确刷新 + +## 📝 修复日志 + +| 时间 | 修复内容 | 影响范围 | +|------|----------|----------| +| 2025-01-03 | 修复API调用问题 | 批量添加功能 | +| 2025-01-03 | 修复数据格式问题 | 前后端数据传递 | +| 2025-01-03 | 修复类型定义问题 | TypeScript类型安全 | +| 2025-01-03 | 修复响应解析问题 | 列表查询功能 | + +## 🎯 总结 + +本次修复解决了批量添加审批人功能的根本问题,确保: +1. **功能正常**:批量添加能够真实地向后端发送请求并保存数据 +2. **类型安全**:完整的TypeScript类型定义和检查 +3. **用户体验**:准确的成功/失败提示和数据刷新 +4. **代码质量**:符合项目开发规范和最佳实践 + +修复后的功能完全符合需求分析文档的要求,并遵循项目的前后端开发规范。 diff --git a/web/src/views/cw/projectAuditor/README.md b/web/src/views/cw/projectAuditor/README.md new file mode 100644 index 00000000..072083d1 --- /dev/null +++ b/web/src/views/cw/projectAuditor/README.md @@ -0,0 +1,58 @@ +# 项目审批人配置模块 + +## 功能概述 + +项目审批人配置模块用于管理项目申报审批流程中的审批人员池,支持从系统用户中选择并配置审批人员,为自定义审批流程提供人员支持。 + +## 主要功能 + +### 1. 审批人列表管理 +- 查询审批人列表(支持分页) +- 按用户姓名、部门、状态等条件筛选 +- 显示审批人基本信息(姓名、部门、联系方式等) +- 支持审批人状态管理(正常/停用) + +### 2. 批量添加审批人 +- 通过部门树选择部门 +- 展示部门下的可用用户列表 +- 支持多选用户批量添加为审批人 +- 自动过滤已存在的审批人 + +### 3. 审批人信息维护 +- 修改审批人联系信息 +- 更新审批人状态 +- 添加备注信息 +- 删除审批人配置 + +## 文件结构 + +``` +web/src/views/cw/projectAuditor/ +├── index.vue # 主页面组件 +└── README.md # 功能说明文档 +``` + +## API接口 + +使用的主要API接口: +- `listProjectAuditor` - 查询审批人列表 +- `getProjectAuditor` - 获取审批人详情 +- `updateProjectAuditor` - 更新审批人信息 +- `delProjectAuditor` - 删除审批人 +- `batchAddProjectAuditor` - 批量添加审批人 +- `getDeptUsers` - 获取部门用户列表 + +## 权限控制 + +页面功能对应的权限标识: +- `cw:projectAuditor:query` - 查询权限 +- `cw:projectAuditor:add` - 新增权限 +- `cw:projectAuditor:edit` - 编辑权限 +- `cw:projectAuditor:remove` - 删除权限 + +## 技术实现 + +- 基于Vue 3 Composition API +- 使用Element Plus UI组件库 +- 集成项目标准的权限控制和国际化 +- 遵循项目统一的代码规范和样式风格 diff --git a/web/src/views/cw/projectAuditor/debug.vue b/web/src/views/cw/projectAuditor/debug.vue new file mode 100644 index 00000000..2af39840 --- /dev/null +++ b/web/src/views/cw/projectAuditor/debug.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/web/src/views/cw/projectAuditor/index.vue b/web/src/views/cw/projectAuditor/index.vue new file mode 100644 index 00000000..ffd000c7 --- /dev/null +++ b/web/src/views/cw/projectAuditor/index.vue @@ -0,0 +1,952 @@ + + + + + diff --git a/web/src/views/cw/projectAuditor/test.vue b/web/src/views/cw/projectAuditor/test.vue new file mode 100644 index 00000000..e6b62ed1 --- /dev/null +++ b/web/src/views/cw/projectAuditor/test.vue @@ -0,0 +1,140 @@ + + + + + From 48da578546f0b68e9723667c19c9191e283f888d Mon Sep 17 00:00:00 2001 From: wuzhen <52326163@qq.com> Date: Sun, 7 Sep 2025 18:17:50 +0800 Subject: [PATCH 20/37] wuzhen update --- .../cw/mapper/CwProjectAuditorMapper.java | 6 + .../impl/CwProjectAuditorServiceImpl.java | 7 +- .../mapper/CwProjectAuditorMapper.xml | 21 + web/src/api/bzrkh/assessmentApproval/index.ts | 8 +- web/src/api/bzrkh/assessmentApproval/types.ts | 15 +- web/src/api/cw/projectApproval.ts | 1 + web/src/api/cw/projectAuditor.ts | 30 + web/src/api/stgl/activityteaminfo/index.ts | 2 +- web/src/api/stgl/activityteaminfo/types.ts | 2 +- web/src/api/stgl/stclass/index.ts | 2 +- web/src/api/stgl/stclass/types.ts | 2 +- .../assessmentApplication.ts | 9 +- .../assessmentApproval/assessmentApproval.ts | 2 +- web/src/api/xskh/assessmentIndicator/types.ts | 2 +- .../assessmentIndicatorType.ts | 9 +- .../api/xskh/assessmentIndicatorType/types.ts | 2 +- .../api/xskh/assessmentPlan/assessmentPlan.ts | 2 +- web/src/api/xskh/assessmentPlan/types.ts | 2 +- .../assessmentSchedule/assessmentSchedule.ts | 2 +- web/src/api/xskh/assessmentSchedule/types.ts | 2 +- web/src/components/AdvisorManager/index.vue | 10 +- web/src/components/ClubSelector/index.vue | 19 +- .../assessmentApproval/approvalDialog.vue | 19 +- .../bzrkh/assessmentApproval/viewDialog.vue | 94 ++-- .../bzrkh/assessmentIndicatorType/index.vue | 40 +- web/src/views/bzrkh/assessmentPlan/index.vue | 4 +- .../views/bzrkh/assessmentScheme/index.vue | 4 +- .../views/bzrkh/teacherAssessment/index.vue | 46 +- .../bzrkh/teacherAssessment/submitDialog.vue | 56 +- .../bzrkh/teacherAssessment/viewDialog.vue | 140 +++-- web/src/views/cw/README.md | 25 +- web/src/views/cw/application/form.vue | 2 +- web/src/views/cw/application/index.vue | 172 ++++-- web/src/views/cw/approvalRecord/index.vue | 14 +- web/src/views/cw/leaderApproval/index.vue | 4 +- web/src/views/cw/projectApproval/README.md | 19 +- .../components/ApprovalProcessSelector.vue | 2 +- web/src/views/cw/projectApproval/index.vue | 4 +- web/src/views/cw/projectApproval/pending.vue | 46 +- .../views/cw/projectAuditor/BUG_FIX_REPORT.md | 48 +- web/src/views/cw/projectAuditor/README.md | 5 + web/src/views/cw/projectAuditor/debug.vue | 8 +- web/src/views/cw/projectAuditor/index.vue | 343 ++++++----- web/src/views/cw/projectAuditor/test.vue | 32 +- .../views/jcbt/poverty/Application/index.vue | 10 +- web/src/views/jcbt/poverty/review/index.vue | 9 +- .../jcbt/scholarship/application/index.vue | 25 +- .../views/jcbt/scholarship/batch/index.vue | 52 +- .../views/jcbt/scholarship/quota/index.vue | 145 ++--- .../views/jcbt/scholarship/review/index.vue | 2 +- web/src/views/jcbt/scholarship/type/index.vue | 144 +++-- web/src/views/rs/index.vue | 22 +- web/src/views/rs/overseas/approval.vue | 15 +- web/src/views/rs/overseas/index.vue | 18 +- web/src/views/rs/overseasApproval/index.vue | 12 +- web/src/views/rs/recruitment-portal.vue | 46 +- web/src/views/rs/training/index.vue | 531 +++++++++--------- web/src/views/rs/trainingApproval/index.vue | 22 +- .../components/ActivityDetailView.vue | 63 ++- .../components/ActivityMembersDialog.vue | 44 +- .../components/ActivityRatingView.vue | 40 +- .../components/ActivityRegistrationView.vue | 78 ++- .../activity/components/PendingMembersTab.vue | 138 +++-- .../components/RegisteredMembersTab.vue | 142 ++--- web/src/views/stgl/activity/hall/index.vue | 10 +- web/src/views/stgl/activity/index.vue | 242 ++++---- .../club/info/components/JoinedMembersTab.vue | 11 +- .../components/MemberManagementDialog.vue | 63 ++- .../info/components/PendingMembersTab.vue | 106 ++-- web/src/views/stgl/club/info/index.vue | 37 +- web/src/views/stgl/my/activity/index.vue | 178 +++--- web/src/views/stgl/my/record/index.vue | 11 +- web/src/views/stgl/stclass/index.vue | 14 +- .../team/components/JoinedMembersTab.vue | 75 ++- .../components/MemberManagementDialog.vue | 63 ++- .../team/components/PendingMembersTab.vue | 91 +-- web/src/views/stgl/volunteer/team/index.vue | 2 +- .../xskh/assessmentIndicatorType/types.ts | 2 +- web/src/views/zsjy/enrollment/index.vue | 16 +- web/src/views/zsjy/graduateInfo/index.vue | 8 +- web/src/views/zsjy/internship/daily/index.vue | 16 +- .../views/zsjy/internship/msgmanage/index.vue | 26 +- .../views/zsjy/internship/pmonthly/index.vue | 49 +- web/src/views/zsjy/internship/visit/index.vue | 40 +- web/src/views/zsjy/jobPosition/index.vue | 18 +- .../views/zsjy/recruitmentPoster/index.vue | 30 +- 86 files changed, 2101 insertions(+), 1849 deletions(-) diff --git a/backend/ruoyi-modules/ruoyi-cw/src/main/java/org/dromara/cw/mapper/CwProjectAuditorMapper.java b/backend/ruoyi-modules/ruoyi-cw/src/main/java/org/dromara/cw/mapper/CwProjectAuditorMapper.java index 38c97582..277706ec 100644 --- a/backend/ruoyi-modules/ruoyi-cw/src/main/java/org/dromara/cw/mapper/CwProjectAuditorMapper.java +++ b/backend/ruoyi-modules/ruoyi-cw/src/main/java/org/dromara/cw/mapper/CwProjectAuditorMapper.java @@ -1,6 +1,7 @@ package org.dromara.cw.mapper; import org.dromara.cw.domain.CwProjectAuditor; +import org.dromara.cw.domain.UserWithDeptInfo; import org.dromara.cw.domain.vo.CwProjectAuditorVo; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.apache.ibatis.annotations.Param; @@ -25,4 +26,9 @@ public interface CwProjectAuditorMapper extends BaseMapperPlus selectAuditorStatistics(); + /** + * 查询完整的用户信息(包含部门信息)用于批量添加 + */ + List selectUsersWithDeptInfo(@Param("userIds") List userIds); + } diff --git a/backend/ruoyi-modules/ruoyi-cw/src/main/java/org/dromara/cw/service/impl/CwProjectAuditorServiceImpl.java b/backend/ruoyi-modules/ruoyi-cw/src/main/java/org/dromara/cw/service/impl/CwProjectAuditorServiceImpl.java index 40e31fa6..42c6e73d 100644 --- a/backend/ruoyi-modules/ruoyi-cw/src/main/java/org/dromara/cw/service/impl/CwProjectAuditorServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-cw/src/main/java/org/dromara/cw/service/impl/CwProjectAuditorServiceImpl.java @@ -14,6 +14,7 @@ import org.springframework.transaction.annotation.Transactional; import org.dromara.cw.domain.bo.CwProjectAuditorBo; import org.dromara.cw.domain.vo.CwProjectAuditorVo; import org.dromara.cw.domain.CwProjectAuditor; +import org.dromara.cw.domain.UserWithDeptInfo; import org.dromara.cw.mapper.CwProjectAuditorMapper; import org.dromara.cw.service.ICwProjectAuditorService; import org.dromara.system.service.ISysUserService; @@ -150,8 +151,8 @@ public class CwProjectAuditorServiceImpl implements ICwProjectAuditorService { return false; } - // 1. 获取用户信息 - List users = sysUserService.selectUserByIds(userIds, null); + // 1. 获取完整的用户信息(包含部门信息) + List users = baseMapper.selectUsersWithDeptInfo(userIds); if (users.isEmpty()) { return false; } @@ -163,7 +164,7 @@ public class CwProjectAuditorServiceImpl implements ICwProjectAuditorService { // 3. 构建新增审核人列表 List auditors = new ArrayList<>(); - for (SysUserVo user : users) { + for (UserWithDeptInfo user : users) { if (!existingUserIds.contains(user.getUserId())) { CwProjectAuditor auditor = new CwProjectAuditor(); auditor.setUserId(user.getUserId()); diff --git a/backend/ruoyi-modules/ruoyi-cw/src/main/resources/mapper/CwProjectAuditorMapper.xml b/backend/ruoyi-modules/ruoyi-cw/src/main/resources/mapper/CwProjectAuditorMapper.xml index 781cc3ad..fb8efb03 100644 --- a/backend/ruoyi-modules/ruoyi-cw/src/main/resources/mapper/CwProjectAuditorMapper.xml +++ b/backend/ruoyi-modules/ruoyi-cw/src/main/resources/mapper/CwProjectAuditorMapper.xml @@ -111,4 +111,25 @@ and deleted = 0 + + + diff --git a/web/src/api/bzrkh/assessmentApproval/index.ts b/web/src/api/bzrkh/assessmentApproval/index.ts index 133d9224..fb6a0087 100644 --- a/web/src/api/bzrkh/assessmentApproval/index.ts +++ b/web/src/api/bzrkh/assessmentApproval/index.ts @@ -1,6 +1,12 @@ import request from '@/utils/request'; import { AxiosPromise } from 'axios'; -import { AssessmentApprovalQuery, AssessmentApprovalVO, AssessmentApprovalDetailVO, AssessmentApprovalSubmitBO, EvaluationLevelStatsVO } from './types'; +import { + AssessmentApprovalQuery, + AssessmentApprovalVO, + AssessmentApprovalDetailVO, + AssessmentApprovalSubmitBO, + EvaluationLevelStatsVO +} from './types'; /** * 查询班主任考核审核列表 diff --git a/web/src/api/bzrkh/assessmentApproval/types.ts b/web/src/api/bzrkh/assessmentApproval/types.ts index ce8c6dbe..8d06ba56 100644 --- a/web/src/api/bzrkh/assessmentApproval/types.ts +++ b/web/src/api/bzrkh/assessmentApproval/types.ts @@ -224,11 +224,12 @@ export interface AssessmentApprovalSpecialWorkSubmitVO { * 评价等级统计数据 */ export interface EvaluationLevelStatsVO { - totalTeachers: number; // 总班主任数量 + totalTeachers: number; // 总班主任数量 scoreRankings: ScoreRankingVO[]; // 分数排名列表 - evaluationLevelRules: { // 评价等级规则 - aLevelMaxPercentage: number; // A等最大占比(如20%) - passScore: number; // 及格分数(如60分) + evaluationLevelRules: { + // 评价等级规则 + aLevelMaxPercentage: number; // A等最大占比(如20%) + passScore: number; // 及格分数(如60分) }; } @@ -236,8 +237,8 @@ export interface EvaluationLevelStatsVO { * 分数排名VO */ export interface ScoreRankingVO { - score: number; // 考核得分 - ranking: number; // 排名(从1开始) - percentage: number; // 百分比排名(前X%) + score: number; // 考核得分 + ranking: number; // 排名(从1开始) + percentage: number; // 百分比排名(前X%) evaluatedUserId?: string | number; // 被评价用户ID(可选,用于标识当前用户) } diff --git a/web/src/api/cw/projectApproval.ts b/web/src/api/cw/projectApproval.ts index 4e948529..e83a4cec 100644 --- a/web/src/api/cw/projectApproval.ts +++ b/web/src/api/cw/projectApproval.ts @@ -61,6 +61,7 @@ export interface CwApprovalRecordVO { */ export interface CwCustomApprovalRequest { applicationId: string | number; + applicationNo: string; auditorIds: Array; processName: string; submitterId: string | number; diff --git a/web/src/api/cw/projectAuditor.ts b/web/src/api/cw/projectAuditor.ts index 69fa3fc2..9f4a1027 100644 --- a/web/src/api/cw/projectAuditor.ts +++ b/web/src/api/cw/projectAuditor.ts @@ -63,6 +63,22 @@ export interface BatchAddRequest { remark?: string; } +/** + * 批量添加审核人详细请求对象(包含完整用户信息) + */ +export interface BatchAddDetailRequest { + users: Array<{ + userId: string | number; + userName: string; + nickName: string; + deptId: string | number; + deptName: string; + phoneNumber: string; // 注意:这里使用驼峰命名,确保与数据库字段映射 + email: string; + }>; + remark?: string; +} + /** * 状态更新请求对象 */ @@ -149,6 +165,20 @@ export function batchAddProjectAuditor(data: BatchAddRequest): AxiosPromise { +// return request({ +// url: '/cw/projectAuditor/batchAddWithDetails', +// method: 'post', +// data: data +// }); +// } + /** * 获取可用审核人列表 */ diff --git a/web/src/api/stgl/activityteaminfo/index.ts b/web/src/api/stgl/activityteaminfo/index.ts index 8cd32b24..f2046618 100644 --- a/web/src/api/stgl/activityteaminfo/index.ts +++ b/web/src/api/stgl/activityteaminfo/index.ts @@ -59,4 +59,4 @@ export function getTeamsByActivityId(activityId: string | number) { url: '/stgl/activityteaminfo/activity/' + activityId, method: 'get' }); -} \ No newline at end of file +} diff --git a/web/src/api/stgl/activityteaminfo/types.ts b/web/src/api/stgl/activityteaminfo/types.ts index 39dad5a4..1f0a8445 100644 --- a/web/src/api/stgl/activityteaminfo/types.ts +++ b/web/src/api/stgl/activityteaminfo/types.ts @@ -238,4 +238,4 @@ export interface StglActivityTeamInfoVo { * 更新时间 */ updateTime?: string; -} \ No newline at end of file +} diff --git a/web/src/api/stgl/stclass/index.ts b/web/src/api/stgl/stclass/index.ts index 6dd6a53f..aad3ff60 100644 --- a/web/src/api/stgl/stclass/index.ts +++ b/web/src/api/stgl/stclass/index.ts @@ -61,4 +61,4 @@ export function exportStglClass(query: StglClassQuery) { method: 'get', params: query }); -} \ No newline at end of file +} diff --git a/web/src/api/stgl/stclass/types.ts b/web/src/api/stgl/stclass/types.ts index b075ad4a..68ef621a 100644 --- a/web/src/api/stgl/stclass/types.ts +++ b/web/src/api/stgl/stclass/types.ts @@ -299,4 +299,4 @@ export interface StglClassDetailVO { * 年级 */ grade: string; -} \ No newline at end of file +} diff --git a/web/src/api/xskh/assessmentApplication/assessmentApplication.ts b/web/src/api/xskh/assessmentApplication/assessmentApplication.ts index 07a88751..88d997ca 100644 --- a/web/src/api/xskh/assessmentApplication/assessmentApplication.ts +++ b/web/src/api/xskh/assessmentApplication/assessmentApplication.ts @@ -1,5 +1,10 @@ import request from '@/utils/request'; -import { XskhAssessmentApplicationApprovalQuery, XskhAssessmentApplicationApprovalBo, XskhAssessmentApplicationApprovalVo, AvailableScheduleOption } from './types'; +import { + XskhAssessmentApplicationApprovalQuery, + XskhAssessmentApplicationApprovalBo, + XskhAssessmentApplicationApprovalVo, + AvailableScheduleOption +} from './types'; // 查询学生考核申请列表 export function listAssessmentApplication(query: XskhAssessmentApplicationApprovalQuery) { @@ -91,4 +96,4 @@ export function getIndicatorsByScheduleId(scheduleId: string | number) { url: `/assessment/application/indicators/${scheduleId}`, method: 'get' }); -} \ No newline at end of file +} diff --git a/web/src/api/xskh/assessmentApproval/assessmentApproval.ts b/web/src/api/xskh/assessmentApproval/assessmentApproval.ts index d3d25f68..46ed6b03 100644 --- a/web/src/api/xskh/assessmentApproval/assessmentApproval.ts +++ b/web/src/api/xskh/assessmentApproval/assessmentApproval.ts @@ -71,4 +71,4 @@ export function getAvailableAssessmentSchedules() { url: '/assessment/approval/available', method: 'get' }); -} \ No newline at end of file +} diff --git a/web/src/api/xskh/assessmentIndicator/types.ts b/web/src/api/xskh/assessmentIndicator/types.ts index 8a3c894c..b2c0fb9d 100644 --- a/web/src/api/xskh/assessmentIndicator/types.ts +++ b/web/src/api/xskh/assessmentIndicator/types.ts @@ -138,4 +138,4 @@ export interface RewardTypeOption { typeCode: string; /** 类型名称 */ typeName: string; -} \ No newline at end of file +} diff --git a/web/src/api/xskh/assessmentIndicatorType/assessmentIndicatorType.ts b/web/src/api/xskh/assessmentIndicatorType/assessmentIndicatorType.ts index 4e1ccf5d..9065fcfd 100644 --- a/web/src/api/xskh/assessmentIndicatorType/assessmentIndicatorType.ts +++ b/web/src/api/xskh/assessmentIndicatorType/assessmentIndicatorType.ts @@ -1,7 +1,12 @@ import request from '@/utils/request'; import { AxiosPromise } from 'axios'; import { TableDataInfo, R } from '@/api/types'; -import { XskhAssessmentIndicatorTypeVo, XskhAssessmentIndicatorTypeBo, XskhAssessmentIndicatorTypeQuery, XskhAssessmentIndicatorTypeForm } from './types'; +import { + XskhAssessmentIndicatorTypeVo, + XskhAssessmentIndicatorTypeBo, + XskhAssessmentIndicatorTypeQuery, + XskhAssessmentIndicatorTypeForm +} from './types'; /** * 查询学生考核指标类型列表 @@ -75,4 +80,4 @@ export function getEnabledAssessmentIndicatorTypes(): AxiosPromise> { url: '/assessment/plan/enabled', method: 'get' }); -} \ No newline at end of file +} diff --git a/web/src/api/xskh/assessmentSchedule/types.ts b/web/src/api/xskh/assessmentSchedule/types.ts index 73212fde..49ac3b92 100644 --- a/web/src/api/xskh/assessmentSchedule/types.ts +++ b/web/src/api/xskh/assessmentSchedule/types.ts @@ -142,4 +142,4 @@ export interface AssessmentPlanOption { planName: string; /** 方案说明 */ planDescription: string; -} \ No newline at end of file +} diff --git a/web/src/components/AdvisorManager/index.vue b/web/src/components/AdvisorManager/index.vue index 62105d79..64ab3eb2 100644 --- a/web/src/components/AdvisorManager/index.vue +++ b/web/src/components/AdvisorManager/index.vue @@ -15,9 +15,9 @@ - @@ -119,7 +119,7 @@ const removeAdvisor = (index: number) => { // 监听teacher选择变化,自动填充相关信息 const handleTeacherChange = (advisor: AdvisorVO, teacher: TeacherVO | null) => { console.log('handleTeacherChange called with teacher:', teacher); - + if (teacher) { // 自动填充老师信息 advisor.name = teacher.nickName || ''; @@ -127,7 +127,7 @@ const handleTeacherChange = (advisor: AdvisorVO, teacher: TeacherVO | null) => { advisor.dept = teacher.deptName || ''; advisor.email = teacher.email || '暂无邮箱'; advisor.userId = teacher.userId?.toString() || ''; - + console.log('Updated advisor:', { name: advisor.name, phone: advisor.phone, diff --git a/web/src/components/ClubSelector/index.vue b/web/src/components/ClubSelector/index.vue index 4ee98f48..b635f3c7 100644 --- a/web/src/components/ClubSelector/index.vue +++ b/web/src/components/ClubSelector/index.vue @@ -14,7 +14,12 @@ value-key="uniqueKey" style="width: 100%" > - +
{{ option.relatedClubName }} {{ getTypeLabel(option.relatedType) }} @@ -98,9 +103,13 @@ const selectedOption = ref(null); // 监听 modelValue 变化 import { watch } from 'vue'; -watch(() => props.modelValue, (newValue) => { - console.log('ClubSelector - modelValue changed:', newValue); -}, { immediate: true }); +watch( + () => props.modelValue, + (newValue) => { + console.log('ClubSelector - modelValue changed:', newValue); + }, + { immediate: true } +); // 格式化选项标签 const formatOptionLabel = (option: ClubOption): string => { @@ -172,7 +181,7 @@ const loadOptions = async () => { uniqueKey: `${item.relatedType}-${item.relatedClubId}` })); options.value = [...clubOptions.value, ...volunteerOptions.value]; - + console.log('ClubSelector - 加载选项数据完成:', { clubCount: clubOptions.value.length, volunteerCount: volunteerOptions.value.length, diff --git a/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue b/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue index 8a5b93c9..e75ea8d7 100644 --- a/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue +++ b/web/src/views/bzrkh/assessmentApproval/approvalDialog.vue @@ -267,11 +267,11 @@ - @@ -457,7 +457,7 @@ const loadApprovalDetail = async () => { if (approvalDetail.value?.routineWorkIndicators && Array.isArray(approvalDetail.value.routineWorkIndicators)) { routineWorkScores.value = approvalDetail.value.routineWorkIndicators.map((item) => { const mappedItem = { - ...item, + ...item, // 确保数值字段不为空 selfScore: Number(item.selfScore) || 0, superiorScore: Number(item.superiorScore) || Number(item.selfScore) || 0, // 默认使用自评分数 @@ -517,7 +517,7 @@ const loadApprovalDetail = async () => { if (approvalDetail.value?.specialWorkIndicators && Array.isArray(approvalDetail.value.specialWorkIndicators)) { specialWorkScores.value = approvalDetail.value.specialWorkIndicators.map((item) => { const mappedItem = { - ...item, + ...item, // 自评分数字段处理 - 兼容不同字段名,确保数值类型 score: Number(item.score || item.selfScore) || 0, selfScore: Number(item.selfScore || item.score) || 0, @@ -557,18 +557,17 @@ const loadApprovalDetail = async () => { approvalForm.auditComment = ''; console.log('=== 审批详情数据加载完成 ==='); - + // 验证数据完整性 if (routineWorkScores.value.length === 0) { console.warn('⚠️ 警告:班主任常规工作数据为空,可能存在数据问题'); proxy?.$modal.msgWarning('班主任常规工作数据为空,请检查数据是否正确'); } - + if (specialWorkScores.value.length === 0) { console.warn('⚠️ 警告:特色工作数据为空,可能存在数据问题'); proxy?.$modal.msgWarning('特色工作数据为空,请检查数据是否正确'); } - } catch (error) { console.error('加载审批详情失败:', error); proxy?.$modal.msgError('加载审批详情失败'); diff --git a/web/src/views/bzrkh/assessmentApproval/viewDialog.vue b/web/src/views/bzrkh/assessmentApproval/viewDialog.vue index 2fba8e33..d519e764 100644 --- a/web/src/views/bzrkh/assessmentApproval/viewDialog.vue +++ b/web/src/views/bzrkh/assessmentApproval/viewDialog.vue @@ -241,15 +241,13 @@ -
+
@@ -259,9 +257,7 @@
- - {{ calculateMonthlyScore().toFixed(2) }}分 - + {{ calculateMonthlyScore().toFixed(2) }}分 {{ parseTime(currentRow?.createTime, '{y}-{m}-{d} {h}:{i}:{s}') || '-' }} @@ -310,9 +306,10 @@ const getEvaluationLevelOptions = (): DictDataOption[] => { console.log('✅ 使用数据库字典数据:', bmzr_evaluation_level.value); return bmzr_evaluation_level.value; } - + // 字典数据未加载或为空时的处理 - if (visible.value) { // 只在弹窗打开时输出警告 + if (visible.value) { + // 只在弹窗打开时输出警告 console.warn('⚠️ 字典数据为空,使用备用数据,当前状态:', { 弹窗是否打开: visible.value, 字典对象存在: !!bmzr_evaluation_level.value, @@ -321,7 +318,7 @@ const getEvaluationLevelOptions = (): DictDataOption[] => { 字典数据内容: bmzr_evaluation_level.value }); } - + return fallbackEvaluationLevelOptions.value; }; @@ -363,10 +360,10 @@ const dialogTitle = computed(() => { const isDictDataMissing = computed(() => { // 如果还没有尝试加载字典数据,不显示警告 if (!visible.value) return false; - + // 如果字典数据已经加载成功,不显示警告 if (isDictLoaded.value) return false; - + // 只有在弹窗打开且字典数据为空时才显示警告 return !bmzr_evaluation_level.value || bmzr_evaluation_level.value.length === 0; }); @@ -434,7 +431,7 @@ const calculateEvaluationLevel = () => { console.log('💯 考核得分:', score); console.log('📈 是否有统计数据:', !!evaluationStats.value); console.log('👤 当前用户ID:', currentRow.value?.evaluatedUserId); - + if (evaluationStats.value) { console.log('📊 统计数据详情:', { 总教师数: evaluationStats.value.totalTeachers, @@ -443,15 +440,17 @@ const calculateEvaluationLevel = () => { 及格分数: evaluationStats.value.evaluationLevelRules?.passScore }); } - + let level = ''; let calculationMethod = ''; - + // 如果有统计数据且用户ID存在,使用严格的占比规则 - if (evaluationStats.value && - evaluationStats.value.totalTeachers > 0 && - evaluationStats.value.scoreRankings.length > 0 && - currentRow.value?.evaluatedUserId) { + if ( + evaluationStats.value && + evaluationStats.value.totalTeachers > 0 && + evaluationStats.value.scoreRankings.length > 0 && + currentRow.value?.evaluatedUserId + ) { level = calculateEvaluationLevelByStats(score, currentRow.value.evaluatedUserId); calculationMethod = '📈 严格占比规则评级'; } else { @@ -464,17 +463,17 @@ const calculateEvaluationLevel = () => { level = 'B'; // B等(合格):60-85分 } calculationMethod = '🔢 简化分数评级'; - + // 输出使用简化评级的原因 const reasons = []; if (!evaluationStats.value) reasons.push('统计数据为空'); if (evaluationStats.value?.totalTeachers === 0) reasons.push('总教师数为0'); if (evaluationStats.value?.scoreRankings?.length === 0) reasons.push('排名数据为空'); if (!currentRow.value?.evaluatedUserId) reasons.push('用户ID缺失'); - + console.warn('⚠️ 使用简化评级的原因:', reasons.join('、')); } - + console.log('🎯 计算方法:', calculationMethod); console.log('📋 最终评价等级:', level); console.log('=== 📊 评价等级计算调试结束 ==='); @@ -486,32 +485,30 @@ const calculateEvaluationLevelByStats = (score: number, evaluatedUserId: string const stats = evaluationStats.value; if (!stats) { console.warn('统计数据不可用,使用简单评级'); - return score < 60 ? 'C' : (score >= 85 ? 'A' : 'B'); + return score < 60 ? 'C' : score >= 85 ? 'A' : 'B'; } - + const { totalTeachers, scoreRankings, evaluationLevelRules } = stats; const { aLevelMaxPercentage, passScore } = evaluationLevelRules; - + // C等:不及格 if (score < passScore) { return 'C'; } - + // 查找当前用户的排名 - const currentRanking = scoreRankings.find(item => - item.evaluatedUserId === evaluatedUserId || item.score === score - ); - + const currentRanking = scoreRankings.find((item) => item.evaluatedUserId === evaluatedUserId || item.score === score); + if (!currentRanking) { console.warn('找不到当前用户的排名信息,使用简单评级'); - return score < 60 ? 'C' : (score >= 85 ? 'A' : 'B'); + return score < 60 ? 'C' : score >= 85 ? 'A' : 'B'; } - + // A等:及格且排名在前20%内 if (score >= passScore && currentRanking.percentage <= aLevelMaxPercentage) { return 'A'; } - + // B等:其余及格的 return 'B'; }; @@ -525,28 +522,28 @@ const open = async (row: AssessmentApprovalVO) => { currentRow.value = row; visible.value = true; - + // 检查字典数据加载状态 console.log('🔍 打开弹窗时字典数据状态:', { 字典对象存在: !!bmzr_evaluation_level.value, 字典数据长度: bmzr_evaluation_level.value?.length || 0, 字典数据内容: bmzr_evaluation_level.value }); - + // 等待字典数据加载完成(最多等待2秒) let waitCount = 0; while ((!bmzr_evaluation_level.value || bmzr_evaluation_level.value.length === 0) && waitCount < 20) { - await new Promise(resolve => setTimeout(resolve, 100)); + await new Promise((resolve) => setTimeout(resolve, 100)); waitCount++; } - + if (bmzr_evaluation_level.value && bmzr_evaluation_level.value.length > 0) { console.log('✅ 字典数据加载完成:', bmzr_evaluation_level.value); isDictLoaded.value = true; } else { console.warn('⚠️ 字典数据加载超时,使用备用数据'); } - + await loadViewDetail(); }; @@ -577,11 +574,15 @@ const loadViewDetail = async () => { if (statsRes.status === 'fulfilled') { evaluationStats.value = statsRes.value.data; console.log('✅ 评价等级统计数据加载成功:', evaluationStats.value); - + // 检查统计数据的完整性 if (!evaluationStats.value.totalTeachers || evaluationStats.value.scoreRankings.length === 0) { - console.warn('⚠️ 统计数据不完整,总教师数:', evaluationStats.value.totalTeachers, - '排名数据条数:', evaluationStats.value.scoreRankings.length); + console.warn( + '⚠️ 统计数据不完整,总教师数:', + evaluationStats.value.totalTeachers, + '排名数据条数:', + evaluationStats.value.scoreRankings.length + ); proxy?.$modal.msgWarning('统计数据不完整,可能影响等级评定准确性'); } } else { @@ -696,18 +697,17 @@ const loadViewDetail = async () => { approvalData.auditComment = ''; console.log('=== 查看详情数据加载完成 ==='); - + // 验证数据完整性 if (routineWorkScores.value.length === 0) { console.warn('⚠️ 警告:班主任常规工作数据为空,可能存在数据问题'); proxy?.$modal.msgWarning('班主任常规工作数据为空,请检查数据是否正确'); } - + if (specialWorkScores.value.length === 0) { console.warn('⚠️ 警告:特色工作数据为空,可能存在数据问题'); proxy?.$modal.msgWarning('特色工作数据为空,请检查数据是否正确'); } - } catch (error) { console.error('加载查看详情失败:', error); proxy?.$modal.msgError('加载查看详情失败'); @@ -724,8 +724,8 @@ const handleClose = () => { routineWorkScores.value = []; specialWorkScores.value = []; evaluationStats.value = undefined; - isDictLoaded.value = false; // 重置字典加载状态 - + isDictLoaded.value = false; // 重置字典加载状态 + Object.assign(managementEffectivenessData, { classDeduction: 0, classDeductionHalf: 0, @@ -802,7 +802,7 @@ defineExpose({ max-height: 150px; overflow-y: auto; } - + .el-table__row { height: auto; } diff --git a/web/src/views/bzrkh/assessmentIndicatorType/index.vue b/web/src/views/bzrkh/assessmentIndicatorType/index.vue index 01bf2e01..43f12139 100644 --- a/web/src/views/bzrkh/assessmentIndicatorType/index.vue +++ b/web/src/views/bzrkh/assessmentIndicatorType/index.vue @@ -7,12 +7,22 @@ - + - + @@ -194,7 +204,7 @@ const handleQuery = () => { pageNum: queryParams.value.pageNum, pageSize: queryParams.value.pageSize }); - + queryParams.value.pageNum = 1; getList(); }; @@ -202,24 +212,26 @@ const handleQuery = () => { /** 查询班主任考核指标类型列表 */ const getList = async () => { loading.value = true; - + // 构建查询参数,正确处理空字符串和undefined/null值 const queryData = { pageNum: queryParams.value.pageNum, pageSize: queryParams.value.pageSize, // 修复:正确处理空字符串,只过滤undefined和null - ...(queryParams.value.indicatorTypeCode !== undefined && queryParams.value.indicatorTypeCode !== null && { indicatorTypeCode: queryParams.value.indicatorTypeCode }), - ...(queryParams.value.indicatorTypeName !== undefined && queryParams.value.indicatorTypeName !== null && { indicatorTypeName: queryParams.value.indicatorTypeName }), + ...(queryParams.value.indicatorTypeCode !== undefined && + queryParams.value.indicatorTypeCode !== null && { indicatorTypeCode: queryParams.value.indicatorTypeCode }), + ...(queryParams.value.indicatorTypeName !== undefined && + queryParams.value.indicatorTypeName !== null && { indicatorTypeName: queryParams.value.indicatorTypeName }), ...(queryParams.value.status !== undefined && queryParams.value.status !== null && { status: queryParams.value.status }) }; - + console.log('📋 发送查询请求,参数:', queryData); console.log('🔍 原始查询参数:', { indicatorTypeCode: `"${queryParams.value.indicatorTypeCode}"`, indicatorTypeName: `"${queryParams.value.indicatorTypeName}"`, status: `"${queryParams.value.status}"` }); - + try { const res = await listAssessmentIndicatorType(queryData); console.log('📊 查询结果:', { @@ -227,7 +239,7 @@ const getList = async () => { dataCount: res.rows?.length, firstItem: res.rows?.[0] }); - + assessmentIndicatorTypeList.value = res.rows; total.value = res.total; } catch (error) { @@ -253,23 +265,23 @@ const reset = () => { /** 重置按钮操作 */ const resetQuery = () => { console.log('🔄 重置查询参数'); - + // 重置表单字段 queryFormRef.value?.resetFields(); - + // 手动重置查询参数对象,确保清空所有搜索条件 queryParams.value.indicatorTypeCode = undefined; queryParams.value.indicatorTypeName = undefined; queryParams.value.status = undefined; queryParams.value.pageNum = 1; - + console.log('🔄 重置后的查询参数:', { indicatorTypeCode: queryParams.value.indicatorTypeCode, indicatorTypeName: queryParams.value.indicatorTypeName, status: queryParams.value.status, pageNum: queryParams.value.pageNum }); - + // 重新查询 getList(); }; @@ -349,7 +361,7 @@ onMounted(() => { pageNum: queryParams.value.pageNum, pageSize: queryParams.value.pageSize }); - + getList(); }); diff --git a/web/src/views/bzrkh/assessmentPlan/index.vue b/web/src/views/bzrkh/assessmentPlan/index.vue index 1e1f55d1..7eee5bb4 100644 --- a/web/src/views/bzrkh/assessmentPlan/index.vue +++ b/web/src/views/bzrkh/assessmentPlan/index.vue @@ -454,7 +454,7 @@ const submitForm = () => { /** 删除按钮操作 */ const handleDelete = async (row?: AssessmentPlanVO) => { const _ids = row?.id || ids.value; - + let confirmMessage = ''; if (row) { const semesterText = row.semester === '1' ? '上学期' : '下学期'; @@ -462,7 +462,7 @@ const handleDelete = async (row?: AssessmentPlanVO) => { } else { confirmMessage = `是否确认删除选中的${ids.value.length}条考核计划?`; } - + await proxy?.$modal.confirm(confirmMessage).then(async () => { await delAssessmentPlan(_ids).then(() => { getList(); diff --git a/web/src/views/bzrkh/assessmentScheme/index.vue b/web/src/views/bzrkh/assessmentScheme/index.vue index 4a025634..54492165 100644 --- a/web/src/views/bzrkh/assessmentScheme/index.vue +++ b/web/src/views/bzrkh/assessmentScheme/index.vue @@ -382,14 +382,14 @@ const submitForm = () => { /** 删除按钮操作 */ const handleDelete = async (row?: BmzrAssessmentSchemeVO) => { const _ids = row?.id || ids.value; - + let confirmMessage = ''; if (row) { confirmMessage = `是否确认删除考核方案"${row.schemeName}"(${row.academicYear}学年第${row.semester}学期)?`; } else { confirmMessage = `是否确认删除选中的${ids.value.length}条考核方案?`; } - + try { await proxy?.$modal.confirm(confirmMessage); await delBmzrAssessmentScheme(_ids); diff --git a/web/src/views/bzrkh/teacherAssessment/index.vue b/web/src/views/bzrkh/teacherAssessment/index.vue index 491eef44..b350f94f 100644 --- a/web/src/views/bzrkh/teacherAssessment/index.vue +++ b/web/src/views/bzrkh/teacherAssessment/index.vue @@ -95,14 +95,14 @@ @@ -155,7 +155,7 @@ - +
@@ -241,13 +241,13 @@ const getTeacherClasses = async () => { queryParams.value.planName = undefined; // 确保搜索条件被重置 queryParams.value.pageNum = 1; queryParams.value.classId = activeTab.value; - + console.log('🔄 初始化完成:', { activeTab: activeTab.value, classId: queryParams.value.classId, planName: queryParams.value.planName }); - + // 等待activeTab设置完成后再获取列表 await nextTick(); await getList(); @@ -270,9 +270,9 @@ const getList = async () => { teacherId: userStore.userId, // 确保包含teacherId planStatus: '1' // 确保包含planStatus }; - + console.log('📋 查询参数:', queryData); - + const res = await listTeacherAssessmentPlans(queryData); console.log('📊 查询结果:', { total: res.total, @@ -280,7 +280,7 @@ const getList = async () => { firstItemStatus: res.rows?.[0]?.auditStatus, firstItemSubmitted: res.rows?.[0]?.submitted }); - + assessmentPlanList.value = res.rows || []; total.value = res.total || 0; } catch (error) { @@ -298,18 +298,18 @@ const handleTabChange = async (tabName: string) => { activeTab: activeTab.value, oldPlanName: queryParams.value.planName }); - + // 重置分页和搜索条件,设置新的班级ID queryParams.value.pageNum = 1; queryParams.value.planName = undefined; // 重置搜索条件,避免标签页间共享 queryParams.value.classId = tabName; - + console.log('🔄 参数设置完成:', { classId: queryParams.value.classId, activeTab: activeTab.value, planName: queryParams.value.planName }); - + // 等待参数设置完成后再查询 await nextTick(); getList(); @@ -332,20 +332,20 @@ const handleQuery = () => { /** 重置按钮操作 */ const resetQuery = () => { console.log('🔄 开始重置查询参数'); - + try { // 保存当前班级ID和计划状态(这些不应该被重置) const currentClassId = queryParams.value.classId; const currentPlanStatus = queryParams.value.planStatus; - + // 手动重置查询参数到初始状态 queryParams.value.planName = undefined; queryParams.value.pageNum = 1; - + // 恢复不应该被重置的参数 queryParams.value.classId = currentClassId; queryParams.value.planStatus = currentPlanStatus; - + console.log('🔄 重置后的查询参数:', { planName: queryParams.value.planName, pageNum: queryParams.value.pageNum, @@ -353,7 +353,7 @@ const resetQuery = () => { planStatus: queryParams.value.planStatus, teacherId: userStore.userId }); - + // 等待DOM更新完成后再刷新数据 nextTick(() => { console.log('🔄 开始强制刷新数据'); @@ -367,8 +367,6 @@ const resetQuery = () => { } }; - - /** 排序触发事件 */ const sortChange = (column: any) => { const { prop, order } = column; diff --git a/web/src/views/bzrkh/teacherAssessment/submitDialog.vue b/web/src/views/bzrkh/teacherAssessment/submitDialog.vue index 06656520..a84009e9 100644 --- a/web/src/views/bzrkh/teacherAssessment/submitDialog.vue +++ b/web/src/views/bzrkh/teacherAssessment/submitDialog.vue @@ -185,7 +185,7 @@ 特色工作(加20分)
- + @@ -203,7 +203,15 @@ - + @@ -224,7 +232,15 @@
- +
@@ -245,7 +261,15 @@
- +
@@ -266,15 +290,23 @@ - + - - + +
@@ -316,7 +348,9 @@ @@ -525,7 +559,7 @@ const calculateMonthlyScore = () => { // 检查是否有实际评分数据(避免空白状态显示50分) const hasAnyScore = routineWorkTotal > 0 || deductionHalf > 0 || specialWorkTotal > 0; - + if (!hasAnyScore || totalCoefficient === 0) { return 0; // 没有评分数据时显示0 } @@ -534,7 +568,7 @@ const calculateMonthlyScore = () => { const classDeductionMaxScore = 50; // 修正后的考核得分公式 = 总系数(K)* ((班主任常规工作自评分之和 + 班级扣分项满分值) - 按班级扣分50%计的分值 + 特色工作总分值) - return totalCoefficient * ((routineWorkTotal + classDeductionMaxScore) - deductionHalf + specialWorkTotal); + return totalCoefficient * (routineWorkTotal + classDeductionMaxScore - deductionHalf + specialWorkTotal); }; /** 打开弹窗 */ @@ -935,7 +969,7 @@ defineExpose({ font-weight: 400; text-align: center; } - + /* 覆盖small尺寸的字体大小,与特色工作输入框保持一致 */ .el-input-number--small.score-input .el-input-number__input { font-size: 14px !important; diff --git a/web/src/views/bzrkh/teacherAssessment/viewDialog.vue b/web/src/views/bzrkh/teacherAssessment/viewDialog.vue index 8c91e595..267a3e6b 100644 --- a/web/src/views/bzrkh/teacherAssessment/viewDialog.vue +++ b/web/src/views/bzrkh/teacherAssessment/viewDialog.vue @@ -55,9 +55,7 @@ {{ getCurrentClassDetail()?.totalStudentCount || 0 }}人 - {{ - formatNumber(getCurrentCoefficient()?.studentCountCoefficient, 3) - }} + {{ formatNumber(getCurrentCoefficient()?.studentCountCoefficient, 3) }}
@@ -70,9 +68,7 @@ {{ getCurrentClassDetail()?.boardingStudentCount || 0 }}人 - {{ - formatNumber(getCurrentCoefficient()?.boardingCoefficient, 3) - }} + {{ formatNumber(getCurrentCoefficient()?.boardingCoefficient, 3) }} @@ -165,10 +161,10 @@ - @@ -176,12 +172,12 @@ - + - + @@ -280,17 +276,17 @@ - + - + - + @@ -307,15 +303,13 @@ -
+
@@ -325,16 +319,14 @@
- - {{ calculateMonthlyScore().toFixed(2) }}分 - + {{ calculateMonthlyScore().toFixed(2) }}分 {{ parseTime(approvalDetail?.submitTime, '{y}-{m}-{d} {h}:{i}:{s}') || '-' }} - + @@ -434,11 +426,7 @@ import { InfoFilled, WarningFilled } from '@element-plus/icons-vue'; import { getAssessmentSubmitDetail, getClassStudentRecords } from '@/api/bzrkh/teacherAssessment'; import { getAssessmentApprovalDetail, getEvaluationLevelStats } from '@/api/bzrkh/assessmentApproval'; -import { - AssessmentDetailVO, - AssessmentIndicatorVO, - ClassStudentRecordsVO -} from '@/api/bzrkh/teacherAssessment/types'; +import { AssessmentDetailVO, AssessmentIndicatorVO, ClassStudentRecordsVO } from '@/api/bzrkh/teacherAssessment/types'; import { AssessmentApprovalDetailVO, AssessmentApprovalIndicatorVO, @@ -471,9 +459,10 @@ const getEvaluationLevelOptions = (): DictDataOption[] => { console.log('✅ 使用数据库字典数据:', bmzr_evaluation_level.value); return bmzr_evaluation_level.value; } - + // 字典数据未加载或为空时的处理 - if (visible.value) { // 只在弹窗打开时输出警告 + if (visible.value) { + // 只在弹窗打开时输出警告 console.warn('⚠️ 字典数据为空,使用备用数据,当前状态:', { 弹窗是否打开: visible.value, 字典对象存在: !!bmzr_evaluation_level.value, @@ -482,7 +471,7 @@ const getEvaluationLevelOptions = (): DictDataOption[] => { 字典数据内容: bmzr_evaluation_level.value }); } - + return fallbackEvaluationLevelOptions.value; }; @@ -511,10 +500,10 @@ const isDictLoaded = ref(false); const isDictDataMissing = computed(() => { // 如果还没有尝试加载字典数据,不显示警告 if (!visible.value) return false; - + // 如果字典数据已经加载成功,不显示警告 if (isDictLoaded.value) return false; - + // 只有在弹窗打开且字典数据为空时才显示警告 return !bmzr_evaluation_level.value || bmzr_evaluation_level.value.length === 0; }); @@ -556,16 +545,16 @@ const specialWorkForm = reactive({ totalScore: 0 }); - // 考核得分表单(只读) - const monthlyScoreForm = reactive({ - overallComment: '' - }); +// 考核得分表单(只读) +const monthlyScoreForm = reactive({ + overallComment: '' +}); - // 审批模式下的考核得分数据 - const approvalMonthlyScoreData = reactive({ - selfOverallComment: '', - superiorOverallComment: '' - }); +// 审批模式下的考核得分数据 +const approvalMonthlyScoreData = reactive({ + selfOverallComment: '', + superiorOverallComment: '' +}); // 学生违纪记录和奖励记录弹窗相关 const studentRecordsVisible = ref(false); @@ -666,7 +655,7 @@ const calculateMonthlyScore = () => { // 检查是否有实际评分数据(避免空白状态显示50分) const hasAnyScore = routineWorkTotal > 0 || deductionHalf > 0 || specialWorkTotal > 0; - + if (!hasAnyScore || totalCoefficient === 0) { return 0; // 没有评分数据时显示0 } @@ -675,7 +664,7 @@ const calculateMonthlyScore = () => { const classDeductionMaxScore = 50; // 修正后的考核得分公式 = 总系数(K)* ((班主任常规工作自评分之和 + 班级扣分项满分值) - 按班级扣分50%计的分值 + 特色工作总分值) - return totalCoefficient * ((routineWorkTotal + classDeductionMaxScore) - deductionHalf + specialWorkTotal); + return totalCoefficient * (routineWorkTotal + classDeductionMaxScore - deductionHalf + specialWorkTotal); } }; @@ -685,7 +674,7 @@ const calculateEvaluationLevel = () => { console.log('=== 📊 评价等级计算调试 ==='); console.log('💯 考核得分:', score); console.log('📈 是否有统计数据:', !!evaluationStats.value); - + if (evaluationStats.value) { console.log('📊 统计数据详情:', { 总教师数: evaluationStats.value.totalTeachers, @@ -694,14 +683,12 @@ const calculateEvaluationLevel = () => { 及格分数: evaluationStats.value.evaluationLevelRules?.passScore }); } - + let level = ''; let calculationMethod = ''; - + // 如果有统计数据,使用严格的占比规则 - if (evaluationStats.value && - evaluationStats.value.totalTeachers > 0 && - evaluationStats.value.scoreRankings.length > 0) { + if (evaluationStats.value && evaluationStats.value.totalTeachers > 0 && evaluationStats.value.scoreRankings.length > 0) { level = calculateEvaluationLevelByStats(score); calculationMethod = '📈 严格占比规则评级'; } else { @@ -714,16 +701,16 @@ const calculateEvaluationLevel = () => { level = 'B'; // B等(合格):60-85分 } calculationMethod = '🔢 简化分数评级'; - + // 输出使用简化评级的原因 const reasons = []; if (!evaluationStats.value) reasons.push('统计数据为空'); if (evaluationStats.value?.totalTeachers === 0) reasons.push('总教师数为0'); if (evaluationStats.value?.scoreRankings?.length === 0) reasons.push('排名数据为空'); - + console.warn('⚠️ 使用简化评级的原因:', reasons.join('、')); } - + console.log('🎯 计算方法:', calculationMethod); console.log('📋 最终评价等级:', level); console.log('=== 📊 评价等级计算调试结束 ==='); @@ -735,30 +722,30 @@ const calculateEvaluationLevelByStats = (score: number) => { const stats = evaluationStats.value; if (!stats) { console.warn('统计数据不可用,使用简单评级'); - return score < 60 ? 'C' : (score >= 85 ? 'A' : 'B'); + return score < 60 ? 'C' : score >= 85 ? 'A' : 'B'; } - + const { totalTeachers, scoreRankings, evaluationLevelRules } = stats; const { aLevelMaxPercentage, passScore } = evaluationLevelRules; - + // C等:不及格 if (score < passScore) { return 'C'; } - + // 查找当前分数的排名 - const currentRanking = scoreRankings.find(item => item.score === score); - + const currentRanking = scoreRankings.find((item) => item.score === score); + if (!currentRanking) { console.warn('找不到当前分数的排名信息,使用简单评级'); - return score < 60 ? 'C' : (score >= 85 ? 'A' : 'B'); + return score < 60 ? 'C' : score >= 85 ? 'A' : 'B'; } - + // A等:及格且排名在前20%内 if (score >= passScore && currentRanking.percentage <= aLevelMaxPercentage) { return 'A'; } - + // B等:其余及格的 return 'B'; }; @@ -783,7 +770,7 @@ const open = async (auditStatus?: string) => { routineWorkScores.value = []; approvalRoutineWorkScores.value = []; approvalSpecialWorkScores.value = []; - + Object.assign(managementEffectivenessForm, { classDeduction: 0, classDeductionHalf: 0, @@ -816,7 +803,7 @@ const open = async (auditStatus?: string) => { }); visible.value = true; - + // 检查字典数据加载状态 console.log('🔍 打开弹窗时字典数据状态:', { 字典对象存在: !!bmzr_evaluation_level.value, @@ -824,21 +811,21 @@ const open = async (auditStatus?: string) => { 字典加载状态: isDictLoaded.value, 字典数据内容: bmzr_evaluation_level.value }); - + // 等待字典数据加载完成(最多等待2秒) let waitCount = 0; while ((!bmzr_evaluation_level.value || bmzr_evaluation_level.value.length === 0) && waitCount < 20) { - await new Promise(resolve => setTimeout(resolve, 100)); + await new Promise((resolve) => setTimeout(resolve, 100)); waitCount++; } - + if (bmzr_evaluation_level.value && bmzr_evaluation_level.value.length > 0) { console.log('✅ 字典数据加载完成:', bmzr_evaluation_level.value); isDictLoaded.value = true; } else { console.warn('⚠️ 字典数据加载超时,使用备用数据'); } - + // 根据显示模式加载不同的数据 if (viewMode.value === 'approval') { await loadApprovalDetail(); @@ -854,7 +841,7 @@ const loadApprovalDetail = async () => { // 从userStore获取当前用户ID作为被评价用户ID const userStore = useUserStore(); const evaluatedUserId = userStore.userId; - + if (!evaluatedUserId) { proxy?.$modal.msgError('获取用户信息失败'); return; @@ -925,7 +912,6 @@ const loadApprovalDetail = async () => { } console.log('=== 审批详情数据加载完成 ==='); - } catch (error) { console.error('加载审批详情失败:', error); proxy?.$modal.msgError('加载审批详情失败,请检查网络连接或刷新页面重试'); @@ -981,7 +967,7 @@ const loadAssessmentDetail = async () => { break; } }); - + // 计算特色工作总分 specialWorkForm.totalScore = (specialWorkForm.score1 || 0) + (specialWorkForm.score2 || 0) + (specialWorkForm.score3 || 0) + (specialWorkForm.score4 || 0); @@ -1033,8 +1019,8 @@ const handleClose = () => { approvalRoutineWorkScores.value = []; approvalSpecialWorkScores.value = []; evaluationStats.value = undefined; - isDictLoaded.value = false; // 重置字典加载状态 - + isDictLoaded.value = false; // 重置字典加载状态 + Object.assign(managementEffectivenessForm, { classDeduction: 0, classDeductionHalf: 0, @@ -1128,13 +1114,13 @@ defineExpose({ .total-score { font-size: 16px; font-weight: 600; - color: #409EFF; + color: #409eff; } .monthly-score { font-size: 18px; font-weight: 600; - color: #67C23A; + color: #67c23a; } /* 表格样式 */ @@ -1183,7 +1169,7 @@ defineExpose({ max-height: 150px; overflow-y: auto; } - + .el-table__row { height: auto; } @@ -1280,4 +1266,4 @@ defineExpose({ padding: 16px; } } - \ No newline at end of file + diff --git a/web/src/views/cw/README.md b/web/src/views/cw/README.md index 47f3cb14..e46fe239 100644 --- a/web/src/views/cw/README.md +++ b/web/src/views/cw/README.md @@ -33,6 +33,7 @@ web/src/api/cw/ ## 🚀 核心功能 ### 1. 项目审批人配置管理 (`projectAuditor/`) + - **审批人池管理**: 从系统用户中选择并配置审批人员 - **批量添加**: 通过部门树选择用户,支持批量添加审批人 - **跨部门选择**: 支持在不同部门间选择用户,选择状态会自动保持 @@ -40,23 +41,27 @@ web/src/api/cw/ - **权限控制**: 基于RBAC的细粒度权限控制 ### 2. 项目审批流程管理 (`projectApproval/`) + - **流程监控**: 查看所有审批流程状态和进度(待实现) - **流程详情**: 查看审批记录和时间轴展示(待实现) - **流程终止**: 管理员可终止进行中的审批流程(待实现) ### 3. 我的待审批 (`projectApproval/pending.vue`) + - **待审批列表**: 显示当前用户需要审批的项目 - **项目详情**: 查看项目完整信息和审批历史 - **审批操作**: 支持通过/拒绝,必填审批意见 - **批量审批**: 支持批量通过或拒绝多个项目(待实现) ### 4. 审批流程选择组件 (`components/ApprovalProcessSelector.vue`) + - **自定义流程配置**: 支持用户从审批人池中选择审核人 - **可视化流程预览**: 直观展示审批顺序和流程走向 - **审核人管理**: 支持添加、删除、排序审核人 - **流程验证**: 验证审批流程的合理性和完整性 ### 5. 项目申报集成 (`application/form.vue` - 已修改) + - **流程选择对话框**: 在提交时弹出审批流程选择界面 - **数据保存**: 先保存申报数据,再配置审批流程 - **流程启动**: 自动启动配置的审批流程 @@ -65,6 +70,7 @@ web/src/api/cw/ ## 📋 实现特色 ### 🔧 技术特色 + 1. **Vue 3.5.13 Composition API**: 使用最新的组合式API,代码结构清晰 2. **TypeScript支持**: 完整的类型定义,提供良好的开发体验 3. **Element Plus UI**: 统一的UI组件库,符合后勤管理模块设计规范 @@ -72,6 +78,7 @@ web/src/api/cw/ 5. **组件化开发**: 高度复用的组件设计,易于维护和扩展 ### 🎨 用户体验特色 + 1. **跨部门选择**: 审批人选择支持在多个部门间切换,保持选择状态 2. **可视化流程**: 审批流程以图形化方式展示,直观易懂 3. **实时验证**: 表单验证和流程验证,及时提供反馈 @@ -79,6 +86,7 @@ web/src/api/cw/ 5. **状态恢复**: 切换部门后自动恢复之前的选择状态 ### 🚀 性能特色 + 1. **按需加载**: 组件和API按需加载,优化性能 2. **智能缓存**: 合理的数据缓存策略,减少重复请求 3. **批量操作**: 支持批量添加、删除等操作,提升效率 @@ -87,16 +95,19 @@ web/src/api/cw/ ## 🔄 核心流程 ### 审批人配置流程 + ``` 管理员登录 → 进入审批人配置 → 选择部门 → 批量选择用户 → 确认添加 → 配置完成 ``` ### 项目申报审批流程 + ``` 填写申报信息 → 点击提交 → 选择审批流程 → 配置审核人 → 确认提交 → 流程启动 ``` ### 审批执行流程 + ``` 审核人收到通知 → 查看待审批列表 → 查看项目详情 → 执行审批操作 → 填写意见 → 提交审批 ``` @@ -104,16 +115,19 @@ web/src/api/cw/ ## 🛠️ 后端支持 ### 数据库设计 + 1. **cw_project_auditor**: 项目审核人配置表 2. **cw_project_approval_process**: 项目审批流程表 3. **cw_approval_record**: 审批记录表(已扩展支持自定义流程) ### API接口 + 1. **审核人配置**: 16个标准API接口(CRUD + 业务功能 + 辅助功能) 2. **审批流程**: 10个核心API接口(流程管理 + 审批执行) 3. **权限控制**: 基于Sa-Token的权限管理 ### 数据安全 + 1. **多租户隔离**: 严格的数据隔离机制 2. **权限控制**: 细粒度的功能权限控制 3. **操作日志**: 完整的操作记录和审计 @@ -121,18 +135,21 @@ web/src/api/cw/ ## 📊 技术规范 ### 前端规范 + - **组件命名**: PascalCase,清晰的语义化命名 - **文件组织**: 按功能模块组织,层次分明 - **样式管理**: Scoped CSS,避免样式冲突 - **状态管理**: Reactive响应式状态,简洁高效 ### 后端规范 + - **接口设计**: RESTful风格,统一响应格式 - **数据验证**: Bean Validation参数校验 - **异常处理**: 统一的异常处理机制 - **事务管理**: 合理的事务边界控制 ### 代码质量 + - **TypeScript**: 完整的类型检查 - **ESLint**: 代码风格检查 - **Prettier**: 代码格式化 @@ -141,18 +158,21 @@ web/src/api/cw/ ## 🎯 后续优化 ### 功能扩展 + 1. **审批流程管理页面**: 完整的流程监控和管理界面 2. **批量审批功能**: 支持批量处理多个项目 3. **审批历史查询**: 完整的审批记录查询功能 4. **移动端支持**: 基于uni-app的移动端审批应用 ### 性能优化 + 1. **虚拟滚动**: 大数据量列表的性能优化 2. **缓存策略**: 更智能的数据缓存机制 3. **懒加载**: 按需加载组件和数据 4. **CDN集成**: 静态资源CDN加速 ### 用户体验 + 1. **快捷操作**: 键盘快捷键支持 2. **拖拽排序**: 审核人拖拽排序功能 3. **消息通知**: 实时消息推送 @@ -161,18 +181,21 @@ web/src/api/cw/ ## 🚀 部署说明 ### 开发环境 + 1. 确保Node.js 20.15.x+,npm 10.7.x+ 2. 安装依赖:`npm install` 3. 启动开发服务器:`npm run dev` 4. 访问:http://localhost ### 生产环境 + 1. 构建项目:`npm run build` 2. 部署到Nginx或其他Web服务器 3. 配置反向代理到后端API 4. 确保数据库脚本已执行 ### 数据库部署 + 1. 执行数据库脚本:`docs/数据库修复脚本.sql` 2. 配置权限菜单和角色权限 3. 创建测试用户和审核人数据 @@ -187,4 +210,4 @@ web/src/api/cw/ **📝 维护日期**: 2025-01-03 **📁 文件**: 完整的前后端实现 + 数据库脚本 + API文档 -**🔄 状态**: 核心功能完成,待进一步测试和优化 \ No newline at end of file +**🔄 状态**: 核心功能完成,待进一步测试和优化 diff --git a/web/src/views/cw/application/form.vue b/web/src/views/cw/application/form.vue index 10f46c4b..9639b93d 100644 --- a/web/src/views/cw/application/form.vue +++ b/web/src/views/cw/application/form.vue @@ -1158,7 +1158,7 @@ const confirmApprovalSubmit = async () => { // 构建审批流程数据 const approvalData = { applicationId: form.id, - applicationNo: form.applicationNo, // 新增:申报编号 + applicationNo: form.applicationNo, // 新增:申报编号 auditorIds: processConfig.auditorIds, processName: processConfig.processName || `${form.projectName}审批流程`, submitterId: userStore.userId, diff --git a/web/src/views/cw/application/index.vue b/web/src/views/cw/application/index.vue index 97cf69fe..8e09d93b 100644 --- a/web/src/views/cw/application/index.vue +++ b/web/src/views/cw/application/index.vue @@ -122,10 +122,14 @@ 修改 - 删除 + 删除 - 提交审批 + 提交审批 导出 @@ -135,7 +139,15 @@
- + @@ -169,31 +181,13 @@ - + - + - +
@@ -234,6 +228,20 @@
+ + + + + +
@@ -247,8 +255,11 @@ import { submitApplication, getApplicationStatistics } from '@/api/cw/projectApplication'; +import { startCustomApprovalProcess, type CwCustomApprovalRequest } from '@/api/cw/projectApproval'; +import { getInfo } from '@/api/login'; import ApplicationForm from './form.vue'; import ApplicationSummary from './summary.vue'; +import ApprovalProcessSelector from '../projectApproval/components/ApprovalProcessSelector.vue'; import Pagination from '@/components/Pagination/index.vue'; export default { @@ -256,6 +267,7 @@ export default { components: { ApplicationForm, ApplicationSummary, + ApprovalProcessSelector, Pagination }, data() { @@ -300,7 +312,14 @@ export default { totalCount: 0, approvedCount: 0, pendingCount: 0, - draftCount: 0 + draftCount: 0, + // 审批流程选择对话框 + approvalProcessDialog: { + visible: false, + applicationId: null, + applicationNo: null, + selectedAuditors: [] + } }; }, created() { @@ -476,21 +495,92 @@ export default { }, /** 提交审批 */ handleSubmit(row) { - const applications = row?.applicationNo - ? [row.applicationNo] - : this.applicationList.filter((item) => this.ids.includes(item.id)).map((item) => item.applicationNo); + if (row) { + // 单个提交 + this.approvalProcessDialog.applicationId = row.id; + this.approvalProcessDialog.applicationNo = row.applicationNo; + this.approvalProcessDialog.visible = true; + this.approvalProcessDialog.selectedAuditors = []; + } else { + // 批量提交 - 暂不支持 + this.$modal.msgWarning('批量提交审批功能暂未开放,请单个提交'); + } + }, + /** 确认提交审批 */ + async confirmSubmitApproval() { + try { + const processSelector = this.$refs.approvalProcessSelectorRef; + if (!processSelector) { + this.$modal.msgError('审批流程选择组件未加载'); + return; + } - this.$modal - .confirm('是否确认提交申报编号为"' + applications.join('", "') + '"的数据项?') - .then(() => { - return submitApplication(row?.id || this.ids); - }) - .then(() => { - this.getList(); - this.getStatistics(); // 提交后更新统计 - this.$modal.msgSuccess('提交成功'); - }) - .catch(() => {}); + // 验证审批流程 + const validation = processSelector.validateProcess(); + if (!validation.valid) { + this.$modal.msgError(validation.message); + return; + } + + // 获取当前用户信息 + let userInfo = null; + try { + const userResponse = await getInfo(); + if (userResponse.code === 200 && userResponse.data && userResponse.data.user) { + userInfo = userResponse.data.user; + } + } catch (userError) { + console.error('获取用户信息失败:', userError); + this.$modal.msgError('获取用户信息失败,请重新登录'); + return; + } + + if (!userInfo || !userInfo.userId) { + this.$modal.msgError('用户信息不完整,请重新登录'); + return; + } + + // 获取审批流程配置 + const processConfig = processSelector.getProcessConfig(); + + // 构建请求数据 + const approvalData: CwCustomApprovalRequest = { + applicationId: this.approvalProcessDialog.applicationId, + applicationNo: this.approvalProcessDialog.applicationNo, + processName: processConfig.processName, + auditorIds: processConfig.auditorIds, + submitterId: userInfo.userId, + submitterName: userInfo.nickName || userInfo.userName + }; + + console.log('启动审批流程数据:', approvalData); + + // 启动审批流程 + const result = await startCustomApprovalProcess(approvalData); + console.log('启动审批流程结果:', result); + + // 关闭对话框 + this.approvalProcessDialog.visible = false; + this.approvalProcessDialog.applicationId = null; + this.approvalProcessDialog.applicationNo = null; + this.approvalProcessDialog.selectedAuditors = []; + + // 刷新列表和统计 + this.getList(); + this.getStatistics(); + + this.$modal.msgSuccess('审批流程启动成功'); + } catch (error) { + console.error('启动审批流程失败:', error); + this.$modal.msgError('启动审批流程失败:' + (error.message || '未知错误')); + } + }, + /** 取消提交审批 */ + cancelSubmitApproval() { + this.approvalProcessDialog.visible = false; + this.approvalProcessDialog.applicationId = null; + this.approvalProcessDialog.applicationNo = null; + this.approvalProcessDialog.selectedAuditors = []; }, /** 撤回申请 */ handleWithdraw(row) { @@ -642,7 +732,9 @@ export default { /* 卡片样式 */ :deep(.el-card) { border: 1px solid #e4e7ed; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04); + box-shadow: + 0 2px 4px rgba(0, 0, 0, 0.12), + 0 0 6px rgba(0, 0, 0, 0.04); } /* 表格卡片头部样式 */ diff --git a/web/src/views/cw/approvalRecord/index.vue b/web/src/views/cw/approvalRecord/index.vue index 73f218c6..4b1b6ad7 100644 --- a/web/src/views/cw/approvalRecord/index.vue +++ b/web/src/views/cw/approvalRecord/index.vue @@ -98,7 +98,15 @@
- +
@@ -377,7 +385,9 @@ export default { .table-card { margin-top: 0; border-radius: 8px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04); + box-shadow: + 0 2px 4px rgba(0, 0, 0, 0.12), + 0 0 6px rgba(0, 0, 0, 0.04); } .table-card :deep(.el-card__body) { diff --git a/web/src/views/cw/leaderApproval/index.vue b/web/src/views/cw/leaderApproval/index.vue index 2aa754a3..96e1632f 100644 --- a/web/src/views/cw/leaderApproval/index.vue +++ b/web/src/views/cw/leaderApproval/index.vue @@ -157,8 +157,8 @@ - 通过 - 退回申请人 + 通过 + 退回申请人 diff --git a/web/src/views/cw/projectApproval/README.md b/web/src/views/cw/projectApproval/README.md index d8adf7e3..4e81dfa4 100644 --- a/web/src/views/cw/projectApproval/README.md +++ b/web/src/views/cw/projectApproval/README.md @@ -7,23 +7,27 @@ ## 主要功能 ### 1. 审批流程管理 + - 查询审批流程列表(支持分页) - 按申报编号、流程状态、提交人等条件筛选 - 显示审批进度和流程状态 - 支持终止正在进行的审批流程 ### 2. 待我审批 + - 查看分配给当前用户的待审批任务 - 执行审批操作(通过/打回) - 填写审批意见 - 查看申报详情和审批记录 ### 3. 我的已审批 + - 查看当前用户已完成的审批记录 - 显示审批动作和意见 - 统计审批效率和处理时长 ### 4. 审批记录跟踪 + - 完整的审批时间线展示 - 每个审批节点的详细信息 - 审批意见和处理结果记录 @@ -39,21 +43,25 @@ web/src/views/cw/projectApproval/ ## 功能特性 ### 1. 多标签页设计 + - **审批流程管理**: 查看所有审批流程的整体情况 - **待我审批**: 专注于当前用户需要处理的审批任务 - **我的已审批**: 查看历史审批记录和统计 ### 2. 统计卡片 + - 总流程数、等待开始、进行中、已完成等状态统计 - 平均处理时长、待我审批数量等关键指标 - 本月完成数量、已终止流程等趋势数据 ### 3. 审批操作 + - 支持批量审批和单个审批 - 必填审批意见,确保审批质量 - 实时更新审批状态和流程进度 ### 4. 流程可视化 + - 进度条显示审批进度 - 时间线展示审批历史 - 状态标签清晰标识各阶段 @@ -61,6 +69,7 @@ web/src/views/cw/projectApproval/ ## API接口 使用的主要API接口: + - `listProjectApproval` - 查询审批流程列表 - `listPendingApprovals` - 查询待我审批列表 - `listProcessedApprovals` - 查询我的已审批列表 @@ -72,6 +81,7 @@ web/src/views/cw/projectApproval/ ## 权限控制 页面功能对应的权限标识: + - `cw:projectApproval:list` - 查询权限 - `cw:projectApproval:add` - 启动流程权限 - `cw:projectApproval:approve` - 审批权限 @@ -81,18 +91,21 @@ web/src/views/cw/projectApproval/ ## 状态说明 ### 流程状态 + - `waiting` - 等待开始 -- `running` - 进行中 +- `running` - 进行中 - `completed` - 已完成 - `terminated` - 已终止 ### 节点状态 + - `waiting` - 等待审批 - `approved` - 已通过 - `rejected` - 已拒绝 - `pending` - 待处理 ### 审批动作 + - `approve` - 审批通过 - `reject` - 打回申请 @@ -114,6 +127,7 @@ web/src/views/cw/projectApproval/ ## 使用说明 ### 审批人员操作流程 + 1. 登录系统,进入项目审批管理页面 2. 点击"待我审批"标签页查看待处理任务 3. 点击具体记录查看申报详情 @@ -121,6 +135,7 @@ web/src/views/cw/projectApproval/ 5. 提交审批结果,系统自动推进流程 ### 管理员操作流程 + 1. 在"审批流程管理"标签页查看所有流程状态 2. 可以终止异常或不需要的审批流程 3. 通过统计卡片监控审批效率和积压情况 @@ -131,4 +146,4 @@ web/src/views/cw/projectApproval/ 1. 审批意见为必填项,且至少5个字符 2. 审批操作不可撤销,请谨慎操作 3. 终止流程会影响项目申报状态,需谨慎使用 -4. 导出功能需要相应权限,请联系管理员配置 \ No newline at end of file +4. 导出功能需要相应权限,请联系管理员配置 diff --git a/web/src/views/cw/projectApproval/components/ApprovalProcessSelector.vue b/web/src/views/cw/projectApproval/components/ApprovalProcessSelector.vue index 2a740a7a..fecbbf7c 100644 --- a/web/src/views/cw/projectApproval/components/ApprovalProcessSelector.vue +++ b/web/src/views/cw/projectApproval/components/ApprovalProcessSelector.vue @@ -2,7 +2,7 @@
- 自定义审批流程 + 自定义审批流程 diff --git a/web/src/views/cw/projectApproval/index.vue b/web/src/views/cw/projectApproval/index.vue index 855244d1..4cb86591 100644 --- a/web/src/views/cw/projectApproval/index.vue +++ b/web/src/views/cw/projectApproval/index.vue @@ -307,11 +307,11 @@ - + 审批通过 - + 打回申请 diff --git a/web/src/views/cw/projectApproval/pending.vue b/web/src/views/cw/projectApproval/pending.vue index 271a6626..5e484174 100644 --- a/web/src/views/cw/projectApproval/pending.vue +++ b/web/src/views/cw/projectApproval/pending.vue @@ -21,11 +21,7 @@ - + @@ -64,13 +60,7 @@ - +
@@ -87,25 +77,18 @@ - + 审批通过 - + 审批拒绝 - +
@@ -113,27 +96,15 @@ - +
- +
@@ -181,15 +192,15 @@ :total="total" :page="queryParams.pageNum" :limit="queryParams.pageSize" - @update:page="(val) => queryParams.pageNum = val" - @update:limit="(val) => queryParams.pageSize = val" + @update:page="(val) => (queryParams.pageNum = val)" + @update:limit="(val) => (queryParams.pageSize = val)" @pagination="getList" />
- +
@@ -221,24 +232,42 @@ - - - - - + + + + + + + + @@ -261,7 +290,7 @@ @close="removeSelectedUser(user)" class="selected-user-tag" > - {{ user.nickName }}({{ user.userName }}) + {{ user.nickName }}({{ user.userName }}) - {{ user.deptName || '未知部门' }}
@@ -271,12 +300,7 @@ - +