8.0 KiB
8.0 KiB
绩效指标分值占比为0%问题修复记录
日期: 2025-08-01
操作人员: Assistant
修复类型: 前端绩效指标组件优化
🚨 问题描述
用户在提交申报时提示"绩效总目标不能为空",经检查发现绩效指标的总分值占比为0%,说明绩效指标组件没有正确保存和计算分值。
🔍 问题分析
根本原因
- 权重初始化问题:
weightPercentage字段初始化为null,导致计算时被忽略 - 效益指标收集不完整: 只收集当前选择的效益指标tab,其他tab的数据丢失
- 数据类型不一致: 权重值没有强制转换为数字类型
- 绩效目标字段为空: 后端BO验证要求绩效总目标和当年绩效目标不能为空
问题调用链
用户填写绩效指标 → 权重为null → 计算总分值为0% →
收集效益指标不完整 → 保存到后端的数据不完整 →
提交时绩效目标字段为空 → BO验证失败
🔧 解决方案
1. 修复权重字段初始化
文件: web/src/views/cw/application/components/PerformanceIndicators.vue
createEmptyIndicator(type, typeName) {
return {
indicatorType: type,
indicatorTypeName: typeName,
goalName: '',
targetValue: '',
unit: '',
- weightPercentage: null,
+ weightPercentage: 0, // 初始化为0而不是null,确保计算正确
description: ''
};
},
修复理由:
- 初始化为数字0,确保计算逻辑正常工作
- 避免null值导致的计算问题
- 保证数据类型一致性
2. 完善效益指标收集逻辑
- // 收集效益指标 (只收集当前选择的tab)
- if (this.effectIndicators[this.activeEffectTab]) {
- this.effectIndicators[this.activeEffectTab].forEach(item => {
+ // 收集所有效益指标(不仅仅是当前选择的tab)
+ Object.keys(this.effectIndicators).forEach(type => {
+ if (this.effectIndicators[type]) {
+ this.effectIndicators[type].forEach(item => {
if (item.goalName && item.targetValue) {
- allIndicators.push({ ...item });
+ // 确保权重值为数字类型
+ const indicator = { ...item };
+ indicator.weightPercentage = Number(indicator.weightPercentage) || 0;
+ allIndicators.push(indicator);
}
});
}
+ });
修复理由:
- 收集所有已填写的效益指标,不仅仅是当前选择的tab
- 确保权重值为数字类型,避免字符串导致的计算错误
- 提高数据完整性和准确性
3. 优化总分值计算逻辑
computed: {
totalWeight() {
let total = 0;
// 产出指标
Object.values(this.outputIndicators).forEach(indicators => {
indicators.forEach(item => {
- if (item.weightPercentage) {
+ if (item.goalName && item.targetValue && item.weightPercentage) {
total += Number(item.weightPercentage);
}
});
});
- // 效益指标 (只计算当前选择的tab)
- if (this.effectIndicators[this.activeEffectTab]) {
- this.effectIndicators[this.activeEffectTab].forEach(item => {
- if (item.weightPercentage) {
+ // 所有效益指标(计算所有已填写的,不仅仅是当前选择的tab)
+ Object.keys(this.effectIndicators).forEach(type => {
+ if (this.effectIndicators[type]) {
+ this.effectIndicators[type].forEach(item => {
+ if (item.goalName && item.targetValue && item.weightPercentage) {
total += Number(item.weightPercentage);
}
});
}
+ });
修复理由:
- 计算所有已填写的指标权重,不遗漏任何数据
- 增加目标名称和目标值的检查,确保只计算有效指标
- 统一计算逻辑,避免数据不一致
4. 自动生成绩效目标内容
文件: web/src/views/cw/application/form.vue
// 处理绩效指标变化
const handlePerformanceIndicatorsChange = (indicators) => {
// 自动生成绩效总目标(如果为空)
if (!form.totalPerformanceGoal || form.totalPerformanceGoal.trim() === '') {
const outputCount = indicators.filter(item =>
['quantity', 'quality', 'timeliness', 'cost'].includes(item.indicatorType)
).length
const effectCount = indicators.filter(item =>
['economic', 'social', 'environmental'].includes(item.indicatorType)
).length
const satisfactionCount = indicators.filter(item =>
item.indicatorType === 'satisfaction'
).length
form.totalPerformanceGoal = `通过本项目的实施,预期实现以下绩效目标:产出指标${outputCount}项,效益指标${effectCount}项,满意度指标${satisfactionCount}项,确保项目按期完成并达到预期效果。`
}
// 自动生成当年绩效目标(如果为空)
if (!form.currentYearGoal || form.currentYearGoal.trim() === '') {
const currentYear = new Date().getFullYear()
form.currentYearGoal = `${currentYear}年度绩效目标:确保项目关键节点按计划推进,各项指标达到设定标准,为项目整体目标的实现奠定坚实基础。`
}
}
修复理由:
- 根据实际填写的绩效指标自动生成目标内容
- 避免用户遗忘填写绩效目标导致的验证失败
- 提供有意义的默认内容,用户可以进一步编辑
5. 添加变化事件通知
console.log('Emitting indicators:', allIndicators);
this.$emit('update:modelValue', allIndicators);
+ this.$emit('change', allIndicators);
修复理由:
- 通知父组件绩效指标发生变化
- 触发自动生成绩效目标的逻辑
- 实现组件间的数据联动
✅ 验证步骤
1. 测试绩效指标功能
- 进入项目申报页面,添加绩效指标
- 为每个指标设置权重值
- 检查总分值占比是否正确计算
- 切换效益指标的不同tab,验证数据是否保持
2. 测试自动生成功能
- 填写绩效指标后,检查绩效总目标是否自动生成
- 验证生成的内容是否符合实际填写的指标数量
- 确认用户可以手动修改生成的内容
3. 测试提交功能
- 完整填写项目申报信息和绩效指标
- 点击提交,验证不再出现"绩效总目标不能为空"错误
- 确认总分值占比达到100%
🎯 技术改进
数据完整性保证
- 初始值规范化: 所有数值字段初始化为0而不是null
- 类型强制转换: 确保数值计算的准确性
- 全量数据收集: 不遗漏任何已填写的指标数据
用户体验优化
- 智能内容生成: 根据用户输入自动生成合理的默认内容
- 实时反馈: 总分值占比实时显示,帮助用户调整
- 数据联动: 绩效指标变化自动触发相关字段更新
组件架构优化
- 事件驱动: 使用change事件实现组件间通信
- 数据流清晰: 明确的数据传递和处理逻辑
- 职责分离: 绩效指标组件专注于指标管理,目标生成在父组件
📋 后续优化建议
1. 验证规则优化
// 可以考虑在组件中添加更智能的验证
validateIndicators() {
const totalWeight = this.totalWeight
if (Math.abs(totalWeight - 100) > 0.1) {
return {
valid: false,
message: `绩效指标总分值占比必须等于100%,当前为${totalWeight}%`
}
}
return { valid: true }
}
2. 模板化绩效目标
// 可以根据项目类型提供不同的模板
generatePerformanceGoalTemplate(projectType, indicators) {
const templates = {
'infrastructure': '基础设施项目绩效目标模板...',
'software': '软件开发项目绩效目标模板...',
'default': '通用项目绩效目标模板...'
}
return templates[projectType] || templates.default
}
3. 数据持久化优化
- 添加本地存储备份,避免数据丢失
- 实现更频繁的自动保存
- 提供数据恢复功能
这次修复从根本上解决了绩效指标分值占比为0%的问题,通过完善数据收集、优化计算逻辑和智能内容生成,确保了项目申报功能的完整性和用户体验。