|
|
@@ -47,7 +47,7 @@
|
|
47
|
47
|
<div v-if="currentTab === 'non-cadre'">
|
|
48
|
48
|
<el-table v-loading="loading" :data="nonCadreList" border fit highlight-current-row
|
|
49
|
49
|
style="width: 100%; margin-top: 20px;">
|
|
50
|
|
- <el-table-column label="大队" prop="brigade" align="center" min-width="100" />
|
|
|
50
|
+ <el-table-column label="大队" prop="brigadeName" align="center" min-width="100" />
|
|
51
|
51
|
<el-table-column label="用工形式" prop="employmentType" align="center" min-width="100">
|
|
52
|
52
|
<template #default="scope">
|
|
53
|
53
|
<dict-tag :options="employment_type" :value="scope.row.employmentType" />
|
|
|
@@ -188,7 +188,7 @@
|
|
188
|
188
|
<el-col :span="8">
|
|
189
|
189
|
<el-form-item label="考核月份" prop="assessmentMonth" label-width="100px">
|
|
190
|
190
|
<el-date-picker v-model="nonCadreForm.assessmentMonth" type="month" placeholder="请选择考核月份"
|
|
191
|
|
- value-format="YYYY-MM" style="width: 100%" />
|
|
|
191
|
+ value-format="YYYY-MM" style="width: 100%" @change="handleAssessmentMonthChange" />
|
|
192
|
192
|
</el-form-item>
|
|
193
|
193
|
</el-col>
|
|
194
|
194
|
<el-col :span="8">
|
|
|
@@ -259,15 +259,14 @@
|
|
259
|
259
|
</el-row>
|
|
260
|
260
|
|
|
261
|
261
|
<!-- 考核指标区域 -->
|
|
262
|
|
- <div class="section-title blue" style="cursor: pointer;" @click="addIndicator">考核指标</div>
|
|
|
262
|
+ <div class="section-title blue" style="cursor: pointer;" @click="addIndicator">考核指标+</div>
|
|
263
|
263
|
<div class="indicators-box" v-if="nonCadreForm.indicatorGroups.length > 0">
|
|
264
|
264
|
<div v-for="(group, groupIndex) in nonCadreForm.indicatorGroups" :key="groupIndex" class="indicator-group">
|
|
265
|
265
|
<div class="indicator-group-title">{{ group.title }}</div>
|
|
266
|
266
|
<div v-for="(item, itemIndex) in group.items" :key="itemIndex" class="indicator-item">
|
|
267
|
267
|
<div class="indicator-name">{{ item.indicatorName }}</div>
|
|
268
|
|
- <div class="indicator-value">{{ item.score }}/次</div>
|
|
|
268
|
+ <div class="indicator-value" v-if="item.categoryNameOne != '红线指标'">{{ item.score }}/次</div>
|
|
269
|
269
|
<div class="indicator-count">{{ item.occurCount }}次</div>
|
|
270
|
|
-
|
|
271
|
270
|
<div class="indicator-total">{{ item.scoreResult }}</div>
|
|
272
|
271
|
<div class="indicator-actions">
|
|
273
|
272
|
<el-button type="primary" link icon="Edit" @click="editIndicator(groupIndex, itemIndex)"></el-button>
|
|
|
@@ -290,7 +289,7 @@
|
|
290
|
289
|
<el-form-item label="红线指标依据">
|
|
291
|
290
|
<span class="detail-link"
|
|
292
|
291
|
@click="showDetailModal('红线指标依据', formatAccordList(nonCadreForm.redLineIndexAccordList))">
|
|
293
|
|
- {{ formatAccordList(nonCadreForm.redLineIndexAccordList) || '查看详情' }}
|
|
|
292
|
+ 查看详情
|
|
294
|
293
|
</span>
|
|
295
|
294
|
</el-form-item>
|
|
296
|
295
|
</el-col>
|
|
|
@@ -306,7 +305,7 @@
|
|
306
|
305
|
<el-form-item label="核心指标依据">
|
|
307
|
306
|
<span class="detail-link"
|
|
308
|
307
|
@click="showDetailModal('核心指标依据', formatAccordList(nonCadreForm.coreIndexAccordList))">
|
|
309
|
|
- {{ formatAccordList(nonCadreForm.coreIndexAccordList) || '查看详情' }}
|
|
|
308
|
+ 查看详情
|
|
310
|
309
|
</span>
|
|
311
|
310
|
</el-form-item>
|
|
312
|
311
|
</el-col>
|
|
|
@@ -322,7 +321,7 @@
|
|
322
|
321
|
<el-form-item label="其他指标中的安全指标(仅含SOC/站品控检查扣分)依据">
|
|
323
|
322
|
<span class="detail-link"
|
|
324
|
323
|
@click="showDetailModal('其他指标中的安全指标依据', formatAccordList(nonCadreForm.otherIndexSafetyScoreWithSocStationQcAccordList))">
|
|
325
|
|
- {{ formatAccordList(nonCadreForm.otherIndexSafetyScoreWithSocStationQcAccordList) || '查看详情' }}
|
|
|
324
|
+ 查看详情
|
|
326
|
325
|
</span>
|
|
327
|
326
|
</el-form-item>
|
|
328
|
327
|
</el-col>
|
|
|
@@ -338,7 +337,7 @@
|
|
338
|
337
|
<el-form-item label="其他指标中的非安全指标依据">
|
|
339
|
338
|
<span class="detail-link"
|
|
340
|
339
|
@click="showDetailModal('其他指标中的非安全指标依据', formatAccordList(nonCadreForm.otherIndexNonSafetyAccordList))">
|
|
341
|
|
- {{ formatAccordList(nonCadreForm.otherIndexNonSafetyAccordList) || '查看详情' }}
|
|
|
340
|
+ 查看详情
|
|
342
|
341
|
</span>
|
|
343
|
342
|
</el-form-item>
|
|
344
|
343
|
</el-col>
|
|
|
@@ -354,7 +353,7 @@
|
|
354
|
353
|
<el-form-item label="SOC/站品控检查的涉及核心、安全指标扣分依据">
|
|
355
|
354
|
<span class="detail-link"
|
|
356
|
355
|
@click="showDetailModal('SOC/站品控检查的涉及核心、安全指标扣分依据', formatAccordList(nonCadreForm.socStationQcInvolvedCoreSafetyAccordList))">
|
|
357
|
|
- {{ formatAccordList(nonCadreForm.socStationQcInvolvedCoreSafetyAccordList) || '查看详情' }}
|
|
|
356
|
+ 查看详情
|
|
358
|
357
|
</span>
|
|
359
|
358
|
</el-form-item>
|
|
360
|
359
|
</el-col>
|
|
|
@@ -391,7 +390,7 @@
|
|
391
|
390
|
<el-form-item label="奖励明细">
|
|
392
|
391
|
<span class="detail-link"
|
|
393
|
392
|
@click="showDetailModal('奖励明细', formatAccordList(nonCadreForm.rewardAccordList))">
|
|
394
|
|
- {{ formatAccordList(nonCadreForm.rewardAccordList) || '查看详情' }}
|
|
|
393
|
+ 查看详情
|
|
395
|
394
|
</span>
|
|
396
|
395
|
</el-form-item>
|
|
397
|
396
|
</el-col>
|
|
|
@@ -399,7 +398,7 @@
|
|
399
|
398
|
<el-form-item label="惩罚明细">
|
|
400
|
399
|
<span class="detail-link"
|
|
401
|
400
|
@click="showDetailModal('惩罚明细', formatAccordList(nonCadreForm.punishmentAccordList))">
|
|
402
|
|
- {{ formatAccordList(nonCadreForm.punishmentAccordList) || '查看详情' }}
|
|
|
401
|
+ 查看详情
|
|
403
|
402
|
</span>
|
|
404
|
403
|
</el-form-item>
|
|
405
|
404
|
</el-col>
|
|
|
@@ -484,16 +483,14 @@
|
|
484
|
483
|
<el-form label-width="150px" class="indicator-form" :model="indicatorDialog.form" :rules="indicatorDialog.rules">
|
|
485
|
484
|
<el-form-item label="指标名称" prop="indicatorId" required>
|
|
486
|
485
|
|
|
487
|
|
- <el-select v-model="indicatorDialog.form.indicatorId" placeholder="搜索指标名称" filterable remote reserve-keyword
|
|
488
|
|
- :remote-method="searchIndicators" :loading="indicatorDialog.loading" style="flex: 1;"
|
|
489
|
|
- @change="onIndicatorNameChange">
|
|
490
|
|
- <el-option v-for="item in indicatorDialog.indicatorOptions" :key="item.id" :label="item.name"
|
|
491
|
|
- :value="item.id" />
|
|
492
|
|
- </el-select>
|
|
|
486
|
+ <el-cascader v-model="indicatorDialog.form.indicatorId" placeholder="搜索指标名称" filterable clearable
|
|
|
487
|
+ :options="indicatorDialog.cascaderOptions" :props="indicatorDialog.cascaderProps" style="flex: 1;"
|
|
|
488
|
+ @change="onIndicatorCascaderChange">
|
|
|
489
|
+ </el-cascader>
|
|
493
|
490
|
|
|
494
|
491
|
</el-form-item>
|
|
495
|
492
|
|
|
496
|
|
- <el-form-item label="分值/单位">
|
|
|
493
|
+ <el-form-item label="分值/单位" v-if="indicatorDialog.form.categoryNameOne != '红线指标'">
|
|
497
|
494
|
<div style="display: flex; align-items: center; gap: 10px;">
|
|
498
|
495
|
<span style="font-size: 24px; font-weight: bold;">{{ indicatorDialog.form.score }}/次</span>
|
|
499
|
496
|
|
|
|
@@ -569,13 +566,14 @@
|
|
569
|
566
|
</template>
|
|
570
|
567
|
|
|
571
|
568
|
<script setup>
|
|
572
|
|
-import { ref, reactive, onMounted, getCurrentInstance, watch } from 'vue'
|
|
|
569
|
+import { ref, reactive, onMounted, getCurrentInstance, watch, nextTick } from 'vue'
|
|
573
|
570
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
574
|
571
|
|
|
575
|
572
|
// API导入(需要根据实际API路径调整)
|
|
576
|
573
|
import { listCadreAssessment, generateCadreAssessment, listNonCadreAssessment, addNonCadreAssessment, updateNonCadreAssessment, deleteNonCadreAssessment, exportNonCadreAssessment, generateNonCadreAssessment, getNonCadreAssessment } from '@/api/performance/monthlyAssess.js'
|
|
577
|
574
|
import { selectUserLeaderListByCondition, listUserPerformance } from '@/api/system/user.js'
|
|
578
|
575
|
import { listIndicator } from '@/api/system/classificationAssess.js'
|
|
|
576
|
+import { queryAssessCategoryTreeAndIndicator } from '@/api/system/classificationAssessIndicator.js'
|
|
579
|
577
|
|
|
580
|
578
|
const { proxy } = getCurrentInstance()
|
|
581
|
579
|
const { post, work_area, employment_type, assessment_team, base_performance_indicator_qc_dept_type } = proxy.useDict('post', 'work_area', 'employment_type', 'assessment_team', 'base_performance_indicator_qc_dept_type')
|
|
|
@@ -712,6 +710,14 @@ const indicatorDialog = reactive({
|
|
712
|
710
|
itemIndex: null,
|
|
713
|
711
|
loading: false,
|
|
714
|
712
|
indicatorOptions: [],
|
|
|
713
|
+ cascaderOptions: [],
|
|
|
714
|
+ cascaderProps: {
|
|
|
715
|
+ value: 'id',
|
|
|
716
|
+ label: 'name',
|
|
|
717
|
+ children: 'indicatorList',
|
|
|
718
|
+ checkStrictly: false,
|
|
|
719
|
+ emitPath: false
|
|
|
720
|
+ },
|
|
715
|
721
|
rules: {
|
|
716
|
722
|
indicatorId: [
|
|
717
|
723
|
{ required: true, message: '请选择指标名称', trigger: 'change' }
|
|
|
@@ -752,6 +758,82 @@ async function searchIndicators(query) {
|
|
752
|
758
|
}
|
|
753
|
759
|
}
|
|
754
|
760
|
|
|
|
761
|
+async function loadIndicatorCascaderOptions() {
|
|
|
762
|
+ try {
|
|
|
763
|
+ const res = await queryAssessCategoryTreeAndIndicator({})
|
|
|
764
|
+ const treeData = res.data || []
|
|
|
765
|
+ indicatorDialog.cascaderOptions = transformIndicatorTree(treeData)
|
|
|
766
|
+ } catch (error) {
|
|
|
767
|
+ console.error('加载指标树失败:', error)
|
|
|
768
|
+ indicatorDialog.cascaderOptions = []
|
|
|
769
|
+ }
|
|
|
770
|
+}
|
|
|
771
|
+
|
|
|
772
|
+function transformIndicatorTree(treeData) {
|
|
|
773
|
+ return treeData.map(node => {
|
|
|
774
|
+ const transformed = {
|
|
|
775
|
+ id: node.id,
|
|
|
776
|
+ name: node.name,
|
|
|
777
|
+ indicatorList: []
|
|
|
778
|
+ }
|
|
|
779
|
+
|
|
|
780
|
+ if (node.children && node.children.length > 0) {
|
|
|
781
|
+ transformed.indicatorList = node.children.map(child => {
|
|
|
782
|
+ const transformedChild = {
|
|
|
783
|
+ id: child.id,
|
|
|
784
|
+ name: child.name,
|
|
|
785
|
+ indicatorList: []
|
|
|
786
|
+ }
|
|
|
787
|
+
|
|
|
788
|
+ if (child.indicatorList && child.indicatorList.length > 0) {
|
|
|
789
|
+ transformedChild.indicatorList = child.indicatorList.map(indicator => ({
|
|
|
790
|
+ ...indicator, name: indicator.name, id: indicator.code, indicatorId: indicator.id, indicatorName: indicator.name, occurCount: 1, personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList: []
|
|
|
791
|
+ }))
|
|
|
792
|
+ }
|
|
|
793
|
+
|
|
|
794
|
+ return transformedChild
|
|
|
795
|
+ })
|
|
|
796
|
+ }
|
|
|
797
|
+
|
|
|
798
|
+ if (node.indicatorList && node.indicatorList.length > 0) {
|
|
|
799
|
+ transformed.indicatorList = node.indicatorList.map(indicator => ({
|
|
|
800
|
+ ...indicator, name: indicator.name, id: indicator.code, indicatorId: indicator.id, indicatorName: indicator.name, occurCount: 1, personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList: []
|
|
|
801
|
+ }))
|
|
|
802
|
+ }
|
|
|
803
|
+
|
|
|
804
|
+ return transformed
|
|
|
805
|
+ })
|
|
|
806
|
+}
|
|
|
807
|
+
|
|
|
808
|
+function onIndicatorCascaderChange(value) {
|
|
|
809
|
+ const selected = findIndicatorById(indicatorDialog.cascaderOptions, value)
|
|
|
810
|
+ if (selected) {
|
|
|
811
|
+ indicatorDialog.form = {
|
|
|
812
|
+ ...selected,
|
|
|
813
|
+ name: selected.name,
|
|
|
814
|
+ id: selected.code,
|
|
|
815
|
+ indicatorId: selected.id,
|
|
|
816
|
+ indicatorName: selected.name,
|
|
|
817
|
+ occurCount: 1,
|
|
|
818
|
+ personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList: []
|
|
|
819
|
+ }
|
|
|
820
|
+ updateTotal()
|
|
|
821
|
+ }
|
|
|
822
|
+}
|
|
|
823
|
+
|
|
|
824
|
+function findIndicatorById(tree, targetId) {
|
|
|
825
|
+ for (const node of tree) {
|
|
|
826
|
+ if (node.id === targetId) {
|
|
|
827
|
+ return node
|
|
|
828
|
+ }
|
|
|
829
|
+ if (node.indicatorList && node.indicatorList.length > 0) {
|
|
|
830
|
+ const found = findIndicatorById(node.indicatorList, targetId)
|
|
|
831
|
+ if (found) return found
|
|
|
832
|
+ }
|
|
|
833
|
+ }
|
|
|
834
|
+ return null
|
|
|
835
|
+}
|
|
|
836
|
+
|
|
755
|
837
|
|
|
756
|
838
|
|
|
757
|
839
|
// 弹窗配置
|
|
|
@@ -850,6 +932,7 @@ async function handleUserChange(userId) {
|
|
850
|
932
|
nonCadreForm.deputySupervisorName = ''
|
|
851
|
933
|
nonCadreForm.deputyManagerId = ''
|
|
852
|
934
|
nonCadreForm.deputyManagerName = ''
|
|
|
935
|
+ checkAndLoadExistingAssessment()
|
|
853
|
936
|
return
|
|
854
|
937
|
}
|
|
855
|
938
|
|
|
|
@@ -877,6 +960,72 @@ async function handleUserChange(userId) {
|
|
877
|
960
|
nonCadreForm.deputyManagerId = ''
|
|
878
|
961
|
nonCadreForm.deputyManagerName = ''
|
|
879
|
962
|
}
|
|
|
963
|
+
|
|
|
964
|
+ checkAndLoadExistingAssessment()
|
|
|
965
|
+}
|
|
|
966
|
+
|
|
|
967
|
+async function handleAssessmentMonthChange() {
|
|
|
968
|
+ checkAndLoadExistingAssessment()
|
|
|
969
|
+}
|
|
|
970
|
+
|
|
|
971
|
+async function checkAndLoadExistingAssessment() {
|
|
|
972
|
+ if (!nonCadreForm.userId || !nonCadreForm.assessmentMonth) {
|
|
|
973
|
+ return
|
|
|
974
|
+ }
|
|
|
975
|
+
|
|
|
976
|
+ try {
|
|
|
977
|
+ const assessmentMonth = nonCadreForm.assessmentMonth.replace('-', '')
|
|
|
978
|
+ const res = await listNonCadreAssessment({
|
|
|
979
|
+ userId: nonCadreForm.userId,
|
|
|
980
|
+ assessmentMonth: assessmentMonth
|
|
|
981
|
+ })
|
|
|
982
|
+
|
|
|
983
|
+ const rows = res.rows || []
|
|
|
984
|
+ if (rows.length > 0) {
|
|
|
985
|
+ const assessmentId = rows[0].id
|
|
|
986
|
+ await loadAssessmentDetail(assessmentId)
|
|
|
987
|
+ }
|
|
|
988
|
+ } catch (error) {
|
|
|
989
|
+ console.error('检查已有考核数据失败:', error)
|
|
|
990
|
+ }
|
|
|
991
|
+}
|
|
|
992
|
+
|
|
|
993
|
+async function loadAssessmentDetail(id) {
|
|
|
994
|
+ try {
|
|
|
995
|
+ const res = await getNonCadreAssessment(id)
|
|
|
996
|
+ const detailList = res.data.personnelMonthlyAssessmentIndicatorDetailList || []
|
|
|
997
|
+ const indicatorGroupsMap = {}
|
|
|
998
|
+ detailList.forEach(item => {
|
|
|
999
|
+ const categoryKey = item.categoryCodeOne || item.categoryNameOne || '未分类'
|
|
|
1000
|
+ if (!indicatorGroupsMap[categoryKey]) {
|
|
|
1001
|
+ indicatorGroupsMap[categoryKey] = {
|
|
|
1002
|
+ title: item.categoryNameOne || '未分类',
|
|
|
1003
|
+ items: []
|
|
|
1004
|
+ }
|
|
|
1005
|
+ }
|
|
|
1006
|
+ indicatorGroupsMap[categoryKey].items.push({
|
|
|
1007
|
+ ...item
|
|
|
1008
|
+ })
|
|
|
1009
|
+ })
|
|
|
1010
|
+ const indicatorGroups = Object.values(indicatorGroupsMap)
|
|
|
1011
|
+
|
|
|
1012
|
+ Object.keys(res.data).forEach(key => {
|
|
|
1013
|
+ if (key === 'assessmentMonth' && res.data[key]) {
|
|
|
1014
|
+ const val = res.data[key]
|
|
|
1015
|
+ if (typeof val === 'string' && val.length === 6 && /^\d+$/.test(val)) {
|
|
|
1016
|
+ nonCadreForm[key] = val.substring(0, 4) + '-' + val.substring(4, 6)
|
|
|
1017
|
+ } else {
|
|
|
1018
|
+ nonCadreForm[key] = val
|
|
|
1019
|
+ }
|
|
|
1020
|
+ } else if (key !== 'personnelMonthlyAssessmentIndicatorDetailList') {
|
|
|
1021
|
+ nonCadreForm[key] = res.data[key]
|
|
|
1022
|
+ }
|
|
|
1023
|
+ })
|
|
|
1024
|
+ nonCadreForm.indicatorGroups = indicatorGroups
|
|
|
1025
|
+ } catch (error) {
|
|
|
1026
|
+ console.error('获取考核详情失败:', error)
|
|
|
1027
|
+ ElMessage.error('获取考核详情失败')
|
|
|
1028
|
+ }
|
|
880
|
1029
|
}
|
|
881
|
1030
|
|
|
882
|
1031
|
// 获取数据列表
|
|
|
@@ -1031,7 +1180,7 @@ const submitForm = async () => {
|
|
1031
|
1180
|
if (submitData.assessmentMonth) {
|
|
1032
|
1181
|
submitData.assessmentMonth = submitData.assessmentMonth.replace('-', '')
|
|
1033
|
1182
|
}
|
|
1034
|
|
-
|
|
|
1183
|
+
|
|
1035
|
1184
|
if (submitData.indicatorGroups && submitData.indicatorGroups.length > 0) {
|
|
1036
|
1185
|
submitData.personnelMonthlyAssessmentIndicatorDetailList = submitData.indicatorGroups.flatMap(group =>
|
|
1037
|
1186
|
group.items.map(item => ({
|
|
|
@@ -1149,16 +1298,21 @@ const addIndicator = () => {
|
|
1149
|
1298
|
amount: 0,
|
|
1150
|
1299
|
personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList: []
|
|
1151
|
1300
|
}
|
|
|
1301
|
+ loadIndicatorCascaderOptions()
|
|
1152
|
1302
|
}
|
|
1153
|
1303
|
|
|
1154
|
1304
|
// 编辑指标 - 打开编辑模态框
|
|
1155
|
|
-const editIndicator = (groupIndex, itemIndex) => {
|
|
|
1305
|
+const editIndicator = async (groupIndex, itemIndex) => {
|
|
1156
|
1306
|
const item = nonCadreForm.indicatorGroups[groupIndex].items[itemIndex]
|
|
1157
|
1307
|
indicatorDialog.visible = true
|
|
1158
|
1308
|
indicatorDialog.title = '编辑扣分指标'
|
|
1159
|
1309
|
indicatorDialog.mode = 'edit'
|
|
1160
|
1310
|
indicatorDialog.groupIndex = groupIndex
|
|
1161
|
1311
|
indicatorDialog.itemIndex = itemIndex
|
|
|
1312
|
+
|
|
|
1313
|
+ await loadIndicatorCascaderOptions()
|
|
|
1314
|
+ await nextTick()
|
|
|
1315
|
+
|
|
1162
|
1316
|
indicatorDialog.form = { ...item }
|
|
1163
|
1317
|
if (!indicatorDialog.form.personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList) {
|
|
1164
|
1318
|
indicatorDialog.form.personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList = []
|
|
|
@@ -1222,9 +1376,9 @@ const saveIndicator = () => {
|
|
1222
|
1376
|
return
|
|
1223
|
1377
|
}
|
|
1224
|
1378
|
|
|
1225
|
|
- const rewardPunishmentType = indicatorDialog.form.score > 0 ? '1' : '0'
|
|
|
1379
|
+
|
|
1226
|
1380
|
list.forEach(detail => {
|
|
1227
|
|
- detail.rewardPunishmentType = rewardPunishmentType
|
|
|
1381
|
+ detail.rewardPunishmentType = indicatorDialog.form.rewardPunishmentType
|
|
1228
|
1382
|
})
|
|
1229
|
1383
|
|
|
1230
|
1384
|
if (indicatorDialog.mode === 'add') {
|