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] 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 @@ - +