Quellcode durchsuchen

perf,feat: 完成人事绩效模块多页面功能迭代与接口优化

1.  新增部门职能部门筛选表单项与绩效用户列表接口
2.  重构月度考核API参数传递方式,新增非干部考核详情与自动生成接口
3.  重写绩效汇总页面API与表格图表逻辑,适配新后端接口
4.  优化非干部月度考核页面表单与交互逻辑,修复ID绑定问题
huoyi vor 1 Monat
Ursprung
Commit
5a12523a61

+ 23 - 8
src/api/performance/monthlyAssess.js

@@ -10,11 +10,11 @@ export function listCadreAssessment(query) {
10 10
 }
11 11
 
12 12
 // 生成本月考核数据
13
-export function generateCadreAssessment(params) {
13
+export function generateCadreAssessment(data) {
14 14
   return request({
15 15
     url: '/personnel/cadre-assessment/generate',
16 16
     method: 'post',
17
-    params: params
17
+    data: data
18 18
   })
19 19
 }
20 20
 
@@ -27,19 +27,19 @@ export function listNonCadreAssessment(query) {
27 27
   })
28 28
 }
29 29
 //新增非干部月度考核
30
-export function addNonCadreAssessment(params) {
30
+export function addNonCadreAssessment(data) {
31 31
   return request({
32 32
     url: '/personnel/assessment',
33 33
     method: 'post',
34
-    params: params
34
+    data: data
35 35
   })
36 36
 }
37 37
 //修改非干部月度考核
38
-export function updateNonCadreAssessment(params) {
38
+export function updateNonCadreAssessment(data) {
39 39
   return request({
40 40
     url: '/personnel/assessment',
41 41
     method: 'put',
42
-    params: params
42
+    data: data
43 43
   })
44 44
 }
45 45
 //删除非干部月度考核
@@ -50,10 +50,25 @@ export function deleteNonCadreAssessment(ids) {
50 50
   })
51 51
 }
52 52
 //导出非干部月度考核列表
53
-export function exportNonCadreAssessment(params) {
53
+export function exportNonCadreAssessment(data) {
54 54
   return request({
55 55
     url: '/personnel/assessment/export',
56 56
     method: 'post',
57
-    params: params
57
+    data: data
58
+  })
59
+}
60
+//获取非干部月度考核详细信息
61
+export function getNonCadreAssessment(id) {
62
+  return request({
63
+    url: `/personnel/assessment/${id}`,
64
+    method: 'get'
65
+  })
66
+}
67
+
68
+//自动生成指定月份非干部月度考核数据
69
+export function generateNonCadreAssessment(query) {
70
+  return request({
71
+    url: `/personnel/assessment/autoGenerate/${query.month}`,
72
+    method: 'get',
58 73
   })
59 74
 }

+ 101 - 8
src/api/performance/monthlyAssessSum.js

@@ -1,20 +1,113 @@
1 1
 import request from '@/utils/request'
2 2
 
3
-// 获取非干部月度考核汇总数据
4
-export function getNonCadreMonthlyAssessSummary(query) {
3
+export function getScoreDistribution(query) {
5 4
   return request({
6
-    url: '/performance/non-cadre-monthly-assess-summary',
5
+    url: '/personnel/non-cadre-assessment/score-summary/score-distribution',
7 6
     method: 'get',
8 7
     params: query
9 8
   })
10 9
 }
11 10
 
12
-// 导出非干部月度考核汇总数据
13
-export function exportNonCadreMonthlyAssessSummary(query) {
11
+export function getDeptParticipation(query) {
14 12
   return request({
15
-    url: '/performance/non-cadre-monthly-assess-summary/export',
13
+    url: '/personnel/non-cadre-assessment/score-summary/dept-participation',
16 14
     method: 'get',
17
-    params: query,
18
-    responseType: 'blob'
15
+    params: query
16
+  })
17
+}
18
+
19
+export function getDeptScoreDistribution(query) {
20
+  return request({
21
+    url: '/personnel/non-cadre-assessment/score-summary/dept-score-distribution',
22
+    method: 'get',
23
+    params: query
24
+  })
25
+}
26
+
27
+export function getAssessmentSummary(query) {
28
+  return request({
29
+    url: '/personnel/non-cadre-assessment/score-summary/assessment-summary',
30
+    method: 'get',
31
+    params: query
32
+  })
33
+}
34
+
35
+export function getActualImprovementDistribution(query) {
36
+  return request({
37
+    url: '/personnel/non-cadre-assessment/score-summary/actual-improvement-distribution',
38
+    method: 'get',
39
+    params: query
40
+  })
41
+}
42
+
43
+export function getActualIncompetentDistribution(query) {
44
+  return request({
45
+    url: '/personnel/non-cadre-assessment/score-summary/actual-incompetent-distribution',
46
+    method: 'get',
47
+    params: query
48
+  })
49
+}
50
+
51
+export function getAssessmentTeamImprovementDistribution(query) {
52
+  return request({
53
+    url: '/personnel/non-cadre-assessment/score-summary/assessment-team-improvement-distribution',
54
+    method: 'get',
55
+    params: query
56
+  })
57
+}
58
+
59
+export function getAssessmentTeamIncompetentDistribution(query) {
60
+  return request({
61
+    url: '/personnel/non-cadre-assessment/score-summary/assessment-team-incompetent-distribution',
62
+    method: 'get',
63
+    params: query
64
+  })
65
+}
66
+
67
+export function getDeptAssessmentTeamStatistics(query) {
68
+  return request({
69
+    url: '/personnel/non-cadre-assessment/score-summary/dept-assessment-team-statistics',
70
+    method: 'get',
71
+    params: query
72
+  })
73
+}
74
+
75
+export function getBrigadeImprovementDistribution(query) {
76
+  return request({
77
+    url: '/personnel/non-cadre-assessment/score-summary/brigade-improvement-distribution',
78
+    method: 'get',
79
+    params: query
80
+  })
81
+}
82
+
83
+export function getBrigadeIncompetentDistribution(query) {
84
+  return request({
85
+    url: '/personnel/non-cadre-assessment/score-summary/brigade-incompetent-distribution',
86
+    method: 'get',
87
+    params: query
88
+  })
89
+}
90
+
91
+export function getFunctionalDeptSummary(query) {
92
+  return request({
93
+    url: '/personnel/non-cadre-assessment/score-summary/functional-dept-summary',
94
+    method: 'get',
95
+    params: query
96
+  })
97
+}
98
+
99
+export function getFunctionalDeptPersonnelDistribution(query) {
100
+  return request({
101
+    url: '/personnel/non-cadre-assessment/score-summary/functional-dept-personnel-distribution',
102
+    method: 'get',
103
+    params: query
104
+  })
105
+}
106
+
107
+export function getFunctionalDeptDistributionPie(query) {
108
+  return request({
109
+    url: '/personnel/non-cadre-assessment/score-summary/functional-dept-distribution-pie',
110
+    method: 'get',
111
+    params: query
19 112
   })
20 113
 }

+ 8 - 0
src/api/system/user.js

@@ -158,4 +158,12 @@ export function selectUserLeaderListByCondition(data) {
158 158
     method: 'post',
159 159
     data: data
160 160
   })
161
+}
162
+//查询人事绩效用户列表
163
+export function listUserPerformance(data) {
164
+  return request({
165
+    url: '/system/user/selectPersonnelUserList',
166
+    method: 'post',
167
+    data: data
168
+  })
161 169
 }

+ 268 - 126
src/views/performanceManage/monthlyAssess/index.vue

@@ -170,22 +170,23 @@
170 170
 
171 171
 
172 172
     <!-- 编辑/新增弹窗 -->
173
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="80%" :close-on-click-modal="false">
173
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="80%" :close-on-click-modal="false"
174
+      destroy-on-close>
174 175
       <!-- 非干部表单 -->
175 176
       <el-form v-if="dialog.type === 'non-cadre'" :model="nonCadreForm" ref="formRef" :rules="nonCadreRules"
176
-        label-width="180px" class="form-container">
177
+        label-width="380px" class="form-container">
177 178
         <!-- 第一部分:基础信息 -->
178 179
         <el-row :gutter="20">
179 180
           <el-col :span="8">
180
-            <el-form-item label="姓名" prop="userName">
181
-              <el-select v-model="nonCadreForm.userName" placeholder="请选择姓名" style="width: 100%" clearable filterable
181
+            <el-form-item label="姓名" prop="userId" label-width="100px">
182
+              <el-select v-model="nonCadreForm.userId" placeholder="请选择姓名" style="width: 100%" clearable filterable
182 183
                 @change="handleUserChange">
183
-                <el-option v-for="user in userList" :key="user.userId" :label="user.userName" :value="user.userName" />
184
+                <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" />
184 185
               </el-select>
185 186
             </el-form-item>
186 187
           </el-col>
187 188
           <el-col :span="8">
188
-            <el-form-item label="考核月份" prop="assessmentMonth">
189
+            <el-form-item label="考核月份" prop="assessmentMonth" label-width="100px">
189 190
               <el-date-picker v-model="nonCadreForm.assessmentMonth" type="month" placeholder="请选择考核月份"
190 191
                 value-format="YYYY-MM" style="width: 100%" />
191 192
             </el-form-item>
@@ -201,23 +202,22 @@
201 202
 
202 203
         <el-row :gutter="20">
203 204
           <el-col :span="8">
204
-            <el-form-item label="用工形式" prop="employmentType">
205
+            <el-form-item label="用工形式" prop="employmentType" label-width="100px">
205 206
               <el-select v-model="nonCadreForm.employmentType" placeholder="请选择用工形式" style="width: 100%" disabled>
206 207
                 <el-option v-for="item in employment_type" :key="item.value" :label="item.label" :value="item.value" />
207 208
               </el-select>
208 209
             </el-form-item>
209 210
           </el-col>
210 211
           <el-col :span="8">
211
-            <el-form-item label="角色" prop="roleName">
212
+            <el-form-item label="角色" prop="roleName" label-width="100px">
212 213
               <el-input v-model="nonCadreForm.roleName" disabled placeholder="角色" />
213 214
             </el-form-item>
214 215
           </el-col>
215 216
           <el-col :span="8">
216
-            <el-form-item label="分管班组长" prop="deputyTeamLeaderName">
217
-              <el-select v-model="nonCadreForm.deputyTeamLeaderName" placeholder="请选择分管班组长" style="width: 100%"
218
-                clearable>
219
-                <el-option v-for="leader in teamLeaderOptions" :key="leader.userId" :label="leader.userName"
220
-                  :value="leader.userName" />
217
+            <el-form-item label="分管班组长" prop="deputyTeamLeaderId" label-width="100px">
218
+              <el-select v-model="nonCadreForm.deputyTeamLeaderId" placeholder="请选择分管班组长" style="width: 100%" clearable>
219
+                <el-option v-for="leader in teamLeaderOptions" :key="leader.userId" :label="leader.nickName"
220
+                  :value="leader.userId" />
221 221
               </el-select>
222 222
             </el-form-item>
223 223
           </el-col>
@@ -227,28 +227,30 @@
227 227
 
228 228
         <el-row :gutter="20">
229 229
           <el-col :span="8">
230
-            <el-form-item label="分管主管" prop="deputySupervisorName">
231
-              <el-select v-model="nonCadreForm.deputySupervisorName" placeholder="请选择分管主管" style="width: 100%"
232
-                clearable>
233
-                <el-option v-for="supervisor in supervisorOptions" :key="supervisor.userId" :label="supervisor.userName"
234
-                  :value="supervisor.userName" />
230
+            <el-form-item label="分管主管" prop="deputySupervisorId" label-width="100px">
231
+              <el-select v-model="nonCadreForm.deputySupervisorId" placeholder="请选择分管主管" style="width: 100%" clearable>
232
+                <el-option v-for="supervisor in supervisorOptions" :key="supervisor.userId" :label="supervisor.nickName"
233
+                  :value="supervisor.userId" />
235 234
               </el-select>
236 235
             </el-form-item>
237 236
           </el-col>
238 237
           <el-col :span="8">
239
-            <el-form-item label="分管经理" prop="deputyManagerName">
240
-              <el-input v-model="nonCadreForm.deputyManagerName" placeholder="请输入分管经理" />
238
+            <el-form-item label="分管经理" prop="deputyManagerId" label-width="100px">
239
+              <el-select v-model="nonCadreForm.deputyManagerId" placeholder="请选择分管经理" style="width: 100%" clearable>
240
+                <el-option v-for="manager in managerOptions" :key="manager.userId" :label="manager.nickName"
241
+                  :value="manager.userId" />
242
+              </el-select>
241 243
             </el-form-item>
242 244
           </el-col>
243 245
           <el-col :span="8">
244
-            <el-form-item label="考核组" prop="assessmentTeam">
246
+            <el-form-item label="考核组" prop="assessmentTeam" label-width="100px">
245 247
               <el-select v-model="nonCadreForm.assessmentTeam" placeholder="请选择考核组" style="width: 100%">
246 248
                 <el-option v-for="item in assessment_team" :key="item.value" :label="item.label" :value="item.value" />
247 249
               </el-select>
248 250
             </el-form-item>
249 251
           </el-col>
250 252
           <el-col :span="8">
251
-            <el-form-item label="岗位" prop="post">
253
+            <el-form-item label="岗位" prop="post" label-width="100px">
252 254
               <el-select v-model="nonCadreForm.post" placeholder="请选择岗位" style="width: 100%">
253 255
                 <el-option v-for="item in post" :key="item.value" :label="item.label" :value="item.value" />
254 256
               </el-select>
@@ -262,11 +264,11 @@
262 264
           <div v-for="(group, groupIndex) in nonCadreForm.indicatorGroups" :key="groupIndex" class="indicator-group">
263 265
             <div class="indicator-group-title">{{ group.title }}</div>
264 266
             <div v-for="(item, itemIndex) in group.items" :key="itemIndex" class="indicator-item">
265
-              <div class="indicator-name">{{ item.name }}</div>
267
+              <div class="indicator-name">{{ item.indicatorName }}</div>
266 268
               <div class="indicator-value">{{ item.score }}/次</div>
267
-              <div class="indicator-count">{{ item.count }}次</div>
268
-              <div class="indicator-source">{{ item.source }}</div>
269
-              <div class="indicator-total">{{ item.total }}</div>
269
+              <div class="indicator-count">{{ item.occurCount }}次</div>
270
+              <div class="indicator-qcDeptType">{{ item.qcDeptType }}</div>
271
+              <div class="indicator-total">{{ item.scoreResult }}</div>
270 272
               <div class="indicator-actions">
271 273
                 <el-button type="primary" link icon="Edit" @click="editIndicator(groupIndex, itemIndex)"></el-button>
272 274
                 <el-button type="danger" link icon="Delete" @click="deleteIndicator(groupIndex, itemIndex)"></el-button>
@@ -286,8 +288,9 @@
286 288
             </el-col>
287 289
             <el-col :span="12">
288 290
               <el-form-item label="红线指标依据">
289
-                <span class="detail-link" @click="showDetailModal('红线指标依据', nonCadreForm.redLineBasis)">
290
-                  {{ nonCadreForm.redLineBasis || '查看详情' }}
291
+                <span class="detail-link"
292
+                  @click="showDetailModal('红线指标依据', formatAccordList(nonCadreForm.redLineIndexAccordList))">
293
+                  {{ formatAccordList(nonCadreForm.redLineIndexAccordList) || '查看详情' }}
291 294
                 </span>
292 295
               </el-form-item>
293 296
             </el-col>
@@ -301,8 +304,9 @@
301 304
             </el-col>
302 305
             <el-col :span="12">
303 306
               <el-form-item label="核心指标依据">
304
-                <span class="detail-link" @click="showDetailModal('核心指标依据', nonCadreForm.coreIndicatorBasis)">
305
-                  {{ nonCadreForm.coreIndicatorBasis || '查看详情' }}
307
+                <span class="detail-link"
308
+                  @click="showDetailModal('核心指标依据', formatAccordList(nonCadreForm.coreIndexAccordList))">
309
+                  {{ formatAccordList(nonCadreForm.coreIndexAccordList) || '查看详情' }}
306 310
                 </span>
307 311
               </el-form-item>
308 312
             </el-col>
@@ -316,8 +320,9 @@
316 320
             </el-col>
317 321
             <el-col :span="12">
318 322
               <el-form-item label="其他指标中的安全指标(仅含SOC/站品控检查扣分)依据">
319
-                <span class="detail-link" @click="showDetailModal('其他指标中的安全指标依据', nonCadreForm.safetyWithSocBasis)">
320
-                  {{ nonCadreForm.safetyWithSocBasis || '查看详情' }}
323
+                <span class="detail-link"
324
+                  @click="showDetailModal('其他指标中的安全指标依据', formatAccordList(nonCadreForm.otherIndexSafetyScoreWithSocStationQcAccordList))">
325
+                  {{ formatAccordList(nonCadreForm.otherIndexSafetyScoreWithSocStationQcAccordList) || '查看详情' }}
321 326
                 </span>
322 327
               </el-form-item>
323 328
             </el-col>
@@ -331,8 +336,9 @@
331 336
             </el-col>
332 337
             <el-col :span="12">
333 338
               <el-form-item label="其他指标中的非安全指标依据">
334
-                <span class="detail-link" @click="showDetailModal('其他指标中的非安全指标依据', nonCadreForm.nonSafetyIndicatorBasis)">
335
-                  {{ nonCadreForm.nonSafetyIndicatorBasis || '查看详情' }}
339
+                <span class="detail-link"
340
+                  @click="showDetailModal('其他指标中的非安全指标依据', formatAccordList(nonCadreForm.otherIndexNonSafetyAccordList))">
341
+                  {{ formatAccordList(nonCadreForm.otherIndexNonSafetyAccordList) || '查看详情' }}
336 342
                 </span>
337 343
               </el-form-item>
338 344
             </el-col>
@@ -346,8 +352,9 @@
346 352
             </el-col>
347 353
             <el-col :span="12">
348 354
               <el-form-item label="SOC/站品控检查的涉及核心、安全指标扣分依据">
349
-                <span class="detail-link" @click="showDetailModal('SOC/站品控检查的涉及核心、安全指标扣分依据', nonCadreForm.socSafetyCoreDeductionBasis)">
350
-                  {{ nonCadreForm.socSafetyCoreDeductionBasis || '查看详情' }}
355
+                <span class="detail-link"
356
+                  @click="showDetailModal('SOC/站品控检查的涉及核心、安全指标扣分依据', formatAccordList(nonCadreForm.socStationQcInvolvedCoreSafetyAccordList))">
357
+                  {{ formatAccordList(nonCadreForm.socStationQcInvolvedCoreSafetyAccordList) || '查看详情' }}
351 358
                 </span>
352 359
               </el-form-item>
353 360
             </el-col>
@@ -382,15 +389,17 @@
382 389
           <el-row :gutter="20">
383 390
             <el-col :span="12">
384 391
               <el-form-item label="奖励明细">
385
-                <span class="detail-link" @click="showDetailModal('奖励明细', nonCadreForm.rewardDetailsSummary)">
386
-                  {{ nonCadreForm.rewardDetailsSummary || '查看详情' }}
392
+                <span class="detail-link"
393
+                  @click="showDetailModal('奖励明细', formatAccordList(nonCadreForm.rewardAccordList))">
394
+                  {{ formatAccordList(nonCadreForm.rewardAccordList) || '查看详情' }}
387 395
                 </span>
388 396
               </el-form-item>
389 397
             </el-col>
390 398
             <el-col :span="12">
391 399
               <el-form-item label="惩罚明细">
392
-                <span class="detail-link" @click="showDetailModal('惩罚明细', nonCadreForm.penaltyDetailsSummary)">
393
-                  {{ nonCadreForm.penaltyDetailsSummary || '查看详情' }}
400
+                <span class="detail-link"
401
+                  @click="showDetailModal('惩罚明细', formatAccordList(nonCadreForm.punishmentAccordList))">
402
+                  {{ formatAccordList(nonCadreForm.punishmentAccordList) || '查看详情' }}
394 403
                 </span>
395 404
               </el-form-item>
396 405
             </el-col>
@@ -473,13 +482,13 @@
473 482
     <!-- 第二个模态框:添加/编辑扣分指标 -->
474 483
     <el-dialog :title="indicatorDialog.title" v-model="indicatorDialog.visible" width="60%">
475 484
       <el-form label-width="150px" class="indicator-form">
476
-        <el-form-item label="指标名称">
485
+        <el-form-item label="指标名称" prop="indicatorId">
477 486
           <div style="display: flex; align-items: center; gap: 10px; width: 100%;">
478
-            <el-select v-model="indicatorDialog.form.name" placeholder="搜索指标名称" filterable remote reserve-keyword
487
+            <el-select v-model="indicatorDialog.form.indicatorId" placeholder="搜索指标名称" filterable remote reserve-keyword
479 488
               :remote-method="searchIndicators" :loading="indicatorDialog.loading" style="flex: 1;"
480 489
               @change="onIndicatorNameChange">
481 490
               <el-option v-for="item in indicatorDialog.indicatorOptions" :key="item.id" :label="item.name"
482
-                :value="item.name" />
491
+                :value="item.id" />
483 492
             </el-select>
484 493
           </div>
485 494
         </el-form-item>
@@ -493,14 +502,14 @@
493 502
 
494 503
         <el-form-item label="发生次数">
495 504
           <div style="display: flex; align-items: center; gap: 10px;">
496
-            <el-input-number v-model="indicatorDialog.form.count" :min="1" style="width: 200px;"
505
+            <el-input-number v-model="indicatorDialog.form.occurCount" :min="1" style="width: 200px;"
497 506
               @change="updateTotal" />
498 507
 
499 508
           </div>
500 509
         </el-form-item>
501 510
 
502 511
         <el-form-item label="检查部门">
503
-          <el-select v-model="indicatorDialog.form.source" placeholder="请选择" style="width: 200px;">
512
+          <el-select v-model="indicatorDialog.form.qcDeptType" placeholder="请选择" style="width: 200px;">
504 513
             <el-option v-for="item in base_performance_indicator_qc_dept_type" :key="item.value" :label="item.label"
505 514
               :value="item.value" />
506 515
           </el-select>
@@ -540,7 +549,7 @@
540 549
     <!-- 详情模态框 -->
541 550
     <el-dialog :title="detailModal.title" v-model="detailModal.visible" width="60%">
542 551
       <div class="detail-content">
543
-        {{ detailModal.content || '暂无内容' }}
552
+        {{ detailModal?.content || '暂无内容' }}
544 553
       </div>
545 554
       <template #footer>
546 555
         <div class="dialog-footer">
@@ -556,8 +565,8 @@ import { ref, reactive, onMounted, getCurrentInstance, watch } from 'vue'
556 565
 import { ElMessage, ElMessageBox } from 'element-plus'
557 566
 
558 567
 // API导入(需要根据实际API路径调整)
559
-import { listCadreAssessment, generateCadreAssessment, listNonCadreAssessment, addNonCadreAssessment, updateNonCadreAssessment, deleteNonCadreAssessment, exportNonCadreAssessment } from '@/api/performance/monthlyAssess.js'
560
-import { selectUserLeaderListByCondition, listAllUser } from '@/api/system/user.js'
568
+import { listCadreAssessment, generateCadreAssessment, listNonCadreAssessment, addNonCadreAssessment, updateNonCadreAssessment, deleteNonCadreAssessment, exportNonCadreAssessment, generateNonCadreAssessment, getNonCadreAssessment } from '@/api/performance/monthlyAssess.js'
569
+import { selectUserLeaderListByCondition, listUserPerformance } from '@/api/system/user.js'
561 570
 import { listIndicator } from '@/api/system/classificationAssess.js'
562 571
 
563 572
 const { proxy } = getCurrentInstance()
@@ -575,6 +584,8 @@ watch(() => currentTab.value, () => {
575 584
   getList()
576 585
 })
577 586
 
587
+
588
+
578 589
 // 查询参数
579 590
 const queryParams = reactive({
580 591
   pageNum: 1,
@@ -583,18 +594,24 @@ const queryParams = reactive({
583 594
   assessmentMonth: ''
584 595
 })
585 596
 
586
-// 非干部表单数据
587
-const nonCadreForm = reactive({
597
+const currentMonthDefault = `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, '0')}`
598
+
599
+const getEmptyNonCadreForm = () => ({
600
+  id: '',
588 601
   userId: '',
589 602
   userName: '',
603
+  roleKey: '',
604
+  roleId: '',
605
+  roleName: '',
590 606
   employmentType: '',
591 607
   post: '',
592
-  assessmentMonth: '',
608
+  assessmentMonth: currentMonthDefault,
593 609
   assessmentTeam: '',
594 610
   deputyTeamLeaderId: '',
595 611
   deputyTeamLeaderName: '',
596 612
   deputySupervisorId: '',
597 613
   deputySupervisorName: '',
614
+  deputyManagerId: '',
598 615
   deputyManagerName: '',
599 616
   inChargeEmployeeCount: 0,
600 617
   totalScore: 0,
@@ -607,14 +624,64 @@ const nonCadreForm = reactive({
607 624
   punishmentAmount: 0,
608 625
   assessmentRemark: '',
609 626
   applicationMethodRemark: '',
610
-  indicatorGroups: []
627
+  indicatorGroups: [],
628
+  redLineTriggerCount: '',
629
+  coreIndicatorScore: '',
630
+  safetyWithSocScore: '',
631
+  nonSafetyIndicatorScore: '',
632
+  socSafetyCoreDeduction: '',
633
+  nonCoreSafetyCoreDeduction: '',
634
+  averageDeduction: '',
635
+  rewardDetailsSummary: '',
636
+  penaltyDetailsSummary: '',
637
+  redLineIndexAccordList: [],
638
+  coreIndexAccordList: [],
639
+  otherIndexSafetyScoreWithSocStationQcAccordList: [],
640
+  otherIndexNonSafetyAccordList: [],
641
+  socStationQcInvolvedCoreSafetyAccordList: [],
642
+  rewardAccordList: [],
643
+  punishmentAccordList: []
611 644
 })
612 645
 
646
+const nonCadreForm = reactive(getEmptyNonCadreForm())
647
+
648
+watch(() => nonCadreForm.assessmentMonth, (newVal) => {
649
+  if (newVal) {
650
+    const month = newVal.replace('-', '')
651
+    loadUserList(month)
652
+  }
653
+})
654
+
655
+watch(() => nonCadreForm.deputyTeamLeaderId, (newVal) => {
656
+  if (newVal) {
657
+    const leader = teamLeaderOptions.value.find(u => u.userId === newVal)
658
+    nonCadreForm.deputyTeamLeaderName = leader?.nickName || ''
659
+  } else {
660
+    nonCadreForm.deputyTeamLeaderName = ''
661
+  }
662
+})
663
+
664
+watch(() => nonCadreForm.deputySupervisorId, (newVal) => {
665
+  if (newVal) {
666
+    const supervisor = supervisorOptions.value.find(u => u.userId === newVal)
667
+    nonCadreForm.deputySupervisorName = supervisor?.nickName || ''
668
+  } else {
669
+    nonCadreForm.deputySupervisorName = ''
670
+  }
671
+})
672
+
673
+watch(() => nonCadreForm.deputyManagerId, (newVal) => {
674
+  if (newVal) {
675
+    const manager = managerOptions.value.find(u => u.userId === newVal)
676
+    nonCadreForm.deputyManagerName = manager?.nickName || ''
677
+  } else {
678
+    nonCadreForm.deputyManagerName = ''
679
+  }
680
+})
613 681
 
614 682
 
615 683
 function addIndicatorToGroup(item) {
616 684
   const categoryName = item.categoryNameOne || '未分类'
617
-
618 685
   let group = nonCadreForm.indicatorGroups.length == 0 ? null : nonCadreForm.indicatorGroups.find(g => g.title === categoryName);
619 686
 
620 687
   if (!group) {
@@ -638,11 +705,12 @@ const indicatorDialog = reactive({
638 705
   loading: false,
639 706
   indicatorOptions: [],
640 707
   form: {
708
+    indicatorId: '',
641 709
     name: '',
642
-    score: -3,
643
-    count: 1,
644
-    source: '',
645
-    total: 0,
710
+    score: 0,
711
+    occurCount: 1,
712
+    qcDeptType: '',
713
+    scoreResult: 0,
646 714
     rewardDetails: '',
647 715
     reward: 0,
648 716
     penaltyDetails: '',
@@ -668,24 +736,7 @@ async function searchIndicators(query) {
668 736
   }
669 737
 }
670 738
 
671
-// 干部表单数据
672
-const cadreForm = reactive({
673
-  employeeName: '',
674
-  position: '',
675
-  area: '',
676
-  assessmentMonth: '',
677
-  redLineDeduction: 0,
678
-  redLineExemption: '',
679
-  violationRankingDeduction: 0,
680
-  violationRankingExemption: '',
681
-  skillRankingDeduction: 0,
682
-  skillRankingExemption: '',
683
-  totalScore: 0,
684
-  assessmentResult: '',
685
-  applicationMethod: '',
686
-  assessmentResultRemark: '',
687
-  applicationMethodRemark: ''
688
-})
739
+
689 740
 
690 741
 // 弹窗配置
691 742
 const dialog = reactive({
@@ -708,6 +759,16 @@ const showDetailModal = (title, content) => {
708 759
   detailModal.visible = true
709 760
 }
710 761
 
762
+const formatAccordList = (list) => {
763
+  if (!list || !Array.isArray(list) || list.length === 0) return ''
764
+  return list.map(item => {
765
+    const name = item.indicatorName || item.name || ''
766
+    const score = item.score !== undefined ? item.score : ''
767
+    const count = item.occurCount !== undefined ? item.occurCount : ''
768
+    return `${name} ${score}分 x ${count}次`
769
+  }).join('\n')
770
+}
771
+
711 772
 // 数据列表
712 773
 const nonCadreList = ref([])
713 774
 const cadreList = ref([])
@@ -715,22 +776,20 @@ const cadreList = ref([])
715 776
 const userList = ref([])
716 777
 const teamLeaderOptions = ref([])
717 778
 const supervisorOptions = ref([])
779
+const managerOptions = ref([])
718 780
 
719 781
 
720 782
 
721 783
 // 非干部表单验证规则
722 784
 const nonCadreRules = {
723
-  userName: [{ required: true, message: '员工姓名不能为空', trigger: 'change' }],
724
-  employmentType: [{ required: true, message: '用工形式不能为空', trigger: 'change' }],
725
-  assessmentTeam: [{ required: true, message: '考核组不能为空', trigger: 'change' }],
726
-  assessmentMonth: [{ required: true, message: '考核月份不能为空', trigger: 'change' }]
785
+  userId: [{ required: true, message: '姓名不能为空', trigger: 'change' }]
727 786
 }
728 787
 
729 788
 
730 789
 
731
-async function loadUserList() {
790
+async function loadUserList(month) {
732 791
   try {
733
-    const res = await listAllUser()
792
+    const res = await listUserPerformance({ month })
734 793
     userList.value = res.data || []
735 794
   } catch (error) {
736 795
     console.error('获取员工列表失败:', error)
@@ -755,23 +814,52 @@ async function loadSupervisorOptions(userId) {
755 814
   }
756 815
 }
757 816
 
758
-async function handleUserChange(userName) {
759
-  if (!userName) {
817
+async function loadManagerOptions(userId) {
818
+  try {
819
+    const res = await selectUserLeaderListByCondition({ roleKeyList: ['jingli'], userId })
820
+    managerOptions.value = res.data || []
821
+  } catch (error) {
822
+    console.error('获取经理列表失败:', error)
823
+  }
824
+}
825
+
826
+async function handleUserChange(userId) {
827
+  if (!userId) {
760 828
     teamLeaderOptions.value = []
761 829
     supervisorOptions.value = []
830
+    managerOptions.value = []
831
+    nonCadreForm.deputyTeamLeaderId = ''
762 832
     nonCadreForm.deputyTeamLeaderName = ''
833
+    nonCadreForm.deputySupervisorId = ''
763 834
     nonCadreForm.deputySupervisorName = ''
835
+    nonCadreForm.deputyManagerId = ''
836
+    nonCadreForm.deputyManagerName = ''
764 837
     return
765 838
   }
766 839
 
767
-  const user = userList.value.find(u => u.userName === userName)
768
-  if (user && user.userId) {
840
+  const user = userList.value.find(u => u.userId === userId)
841
+  if (user && user.nickName) {
769 842
     await Promise.all([
770 843
       loadTeamLeaderOptions(user.userId),
771
-      loadSupervisorOptions(user.userId)
844
+      loadSupervisorOptions(user.userId),
845
+      loadManagerOptions(user.userId)
772 846
     ])
847
+    const role = user.roles && user.roles[0] || {}
848
+    nonCadreForm.userName = user.nickName
849
+    nonCadreForm.roleName = role?.roleName
850
+    nonCadreForm.roleKey = role?.roleKey
851
+    nonCadreForm.roleId = role?.roleId
852
+    nonCadreForm.employmentType = user.employmentType
853
+    nonCadreForm.post = user.post
854
+    nonCadreForm.assessmentTeam = user.assessmentTeam
855
+    nonCadreForm.assessmentTeamDesc = user.assessmentTeamDesc
856
+
857
+    nonCadreForm.deputyTeamLeaderId = ''
773 858
     nonCadreForm.deputyTeamLeaderName = ''
859
+    nonCadreForm.deputySupervisorId = ''
774 860
     nonCadreForm.deputySupervisorName = ''
861
+    nonCadreForm.deputyManagerId = ''
862
+    nonCadreForm.deputyManagerName = ''
775 863
   }
776 864
 }
777 865
 
@@ -832,40 +920,67 @@ const handleAdd = () => {
832 920
   dialog.title = currentTab.value === 'non-cadre' ? '新增非干部月度考核' : '新增干部月度考核'
833 921
 
834 922
   if (currentTab.value === 'non-cadre') {
835
-    loadUserList()
923
+    const emptyForm = getEmptyNonCadreForm()
924
+    Object.keys(emptyForm).forEach(key => {
925
+      nonCadreForm[key] = emptyForm[key]
926
+    })
927
+    const month = nonCadreForm.assessmentMonth.replace('-', '')
928
+    loadUserList(month)
836 929
     teamLeaderOptions.value = []
837 930
     supervisorOptions.value = []
838
-  }
839
-
840
-  // 重置表单数据
841
-  if (currentTab.value === 'non-cadre') {
842
-
843
-    nonCadreForm.indicatorGroups = []
931
+    managerOptions.value = []
844 932
   }
845 933
 }
846 934
 
847 935
 // 编辑
848
-const handleEdit = (row, type) => {
936
+const handleEdit = async (row, type) => {
849 937
   dialog.visible = true
850 938
   dialog.type = type
851 939
   dialog.title = '编辑非干部月度考核'
852 940
 
853 941
   if (type === 'non-cadre') {
854
-    loadUserList().then(() => {
855
-      if (row.userName) {
856
-        loadTeamLeaderOptions(row.userId)
857
-        loadSupervisorOptions(row.userId)
858
-      }
859
-    })
860
-  }
861
-
862
-  // 填充表单数据
863
-  if (type === 'non-cadre') {
864
-    Object.keys(nonCadreForm).forEach(key => {
865
-      if (row[key] !== undefined) {
866
-        nonCadreForm[key] = row[key]
867
-      }
868
-    })
942
+    const month = nonCadreForm.assessmentMonth.replace('-', '')
943
+    loadUserList(month)
944
+    loadTeamLeaderOptions(row.userId)
945
+    loadSupervisorOptions(row.userId)
946
+    loadManagerOptions(row.userId)
947
+
948
+    try {
949
+      const res = await getNonCadreAssessment(row.id)
950
+
951
+      const detailList = res.data.personnelMonthlyAssessmentIndicatorDetailList || []
952
+      const indicatorGroupsMap = {}
953
+      detailList.forEach(item => {
954
+        const categoryKey = item.categoryCodeOne || item.categoryNameOne || '未分类'
955
+        if (!indicatorGroupsMap[categoryKey]) {
956
+          indicatorGroupsMap[categoryKey] = {
957
+            title: item.categoryNameOne || '未分类',
958
+            items: []
959
+          }
960
+        }
961
+        indicatorGroupsMap[categoryKey].items.push({
962
+          ...item
963
+        })
964
+      })
965
+      const indicatorGroups = Object.values(indicatorGroupsMap)
966
+
967
+      Object.keys(res.data).forEach(key => {
968
+        if (key === 'assessmentMonth' && res.data[key]) {
969
+          const val = res.data[key]
970
+          if (typeof val === 'string' && val.length === 6 && /^\d+$/.test(val)) {
971
+            nonCadreForm[key] = val.substring(0, 4) + '-' + val.substring(4, 6)
972
+          } else {
973
+            nonCadreForm[key] = val
974
+          }
975
+        } else if (key !== 'personnelMonthlyAssessmentIndicatorDetailList') {
976
+          nonCadreForm[key] = res.data[key]
977
+        }
978
+      })
979
+      nonCadreForm.indicatorGroups = indicatorGroups
980
+    } catch (error) {
981
+      console.error('获取详情失败:', error)
982
+      ElMessage.error('获取详情失败')
983
+    }
869 984
   }
870 985
 }
871 986
 
@@ -895,15 +1010,29 @@ const submitForm = async () => {
895 1010
 
896 1011
   try {
897 1012
     if (dialog.type === 'non-cadre') {
1013
+      const submitData = { ...nonCadreForm }
1014
+
1015
+      if (submitData.assessmentMonth) {
1016
+        submitData.assessmentMonth = submitData.assessmentMonth.replace('-', '')
1017
+      }
1018
+
1019
+      if (submitData.indicatorGroups && submitData.indicatorGroups.length > 0) {
1020
+        submitData.personnelMonthlyAssessmentIndicatorDetailList = submitData.indicatorGroups.flatMap(group =>
1021
+          group.items.map(item => ({
1022
+            ...item
1023
+          }))
1024
+        )
1025
+        delete submitData.indicatorGroups
1026
+      }
1027
+
898 1028
       if (dialog.title === '新增非干部月度考核') {
899
-        await addNonCadreAssessment(nonCadreForm)
1029
+        await addNonCadreAssessment(submitData)
900 1030
         ElMessage.success('新增成功')
901 1031
       } else {
902
-        await updateNonCadreAssessment(nonCadreForm)
1032
+        await updateNonCadreAssessment(submitData)
903 1033
         ElMessage.success('更新成功')
904 1034
       }
905 1035
     } else {
906
-      // 干部数据API(待实现)
907 1036
       ElMessage.success('操作成功')
908 1037
     }
909 1038
 
@@ -941,20 +1070,27 @@ const handleExport = async () => {
941 1070
 // 生成本月考核表
942 1071
 const generateMonthlyAssessment = async () => {
943 1072
   try {
944
-    ElMessageBox.confirm('是否生成本月干部考核数据?', '提示', {
1073
+    const tabText = currentTab.value === 'non-cadre' ? '非干部' : '干部'
1074
+    ElMessageBox.confirm(`是否生成本月${tabText}考核数据?`, '提示', {
945 1075
       confirmButtonText: '确定',
946 1076
       cancelButtonText: '取消',
947 1077
       type: 'warning'
948 1078
     }).then(async () => {
949 1079
       loading.value = true
950
-      // 使用当前年月的日期
951 1080
       const now = new Date()
952
-      const params = {
953
-        year: now.getFullYear(),
954
-        month: now.getMonth() + 1
1081
+      const currentMonth = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}`
1082
+
1083
+      if (currentTab.value === 'non-cadre') {
1084
+        const res = await generateNonCadreAssessment({ month: currentMonth })
1085
+        ElMessage.success('生成成功')
1086
+      } else {
1087
+        const params = {
1088
+          year: now.getFullYear(),
1089
+          month: now.getMonth() + 1
1090
+        }
1091
+        const res = await generateCadreAssessment(params)
1092
+        ElMessage.success('生成成功')
955 1093
       }
956
-      const res = await generateCadreAssessment(params)
957
-      ElMessage.success('生成成功')
958 1094
       getList()
959 1095
     }).catch(() => { })
960 1096
   } catch (error) {
@@ -986,9 +1122,9 @@ const addIndicator = () => {
986 1122
   indicatorDialog.form = {
987 1123
     name: '',
988 1124
     score: -3,
989
-    count: 1,
990
-    source: '',
991
-    total: 0,
1125
+    occurCount: 1,
1126
+    qcDeptType: '',
1127
+    scoreResult: 0,
992 1128
     rewardDetails: '',
993 1129
     reward: 0,
994 1130
     penaltyDetails: '',
@@ -1021,20 +1157,26 @@ const deleteIndicator = (groupIndex, itemIndex) => {
1021 1157
 
1022 1158
 // 指标名称变化时更新分值
1023 1159
 const onIndicatorNameChange = (value) => {
1024
-  const selected = indicatorDialog.indicatorOptions.find(item => item.name === value)
1160
+  console.log(value, indicatorDialog.indicatorOptions, "indicatorDialog.indicatorOptions")
1161
+  const selected = indicatorDialog.indicatorOptions.find(item => item.id === value)
1025 1162
   if (selected) {
1026
-    indicatorDialog.form = { ...selected, count: 1 }
1163
+    indicatorDialog.form = { ...selected, occurCount: 1 }
1027 1164
     updateTotal()
1028 1165
   }
1029 1166
 }
1030 1167
 
1031 1168
 // 更新总分
1032 1169
 const updateTotal = () => {
1033
-  indicatorDialog.form.total = indicatorDialog.form.score * indicatorDialog.form.count
1170
+  indicatorDialog.form.scoreResult = indicatorDialog.form.score * indicatorDialog.form.occurCount
1034 1171
 }
1035 1172
 
1036 1173
 // 保存指标
1037 1174
 const saveIndicator = () => {
1175
+  if (!indicatorDialog.form.indicatorId) {
1176
+    ElMessage.error('请选择指标名称')
1177
+    return
1178
+  }
1179
+
1038 1180
   if (indicatorDialog.mode === 'add') {
1039 1181
     addIndicatorToGroup({ ...indicatorDialog.form })
1040 1182
     ElMessage.success('添加成功')
@@ -1186,7 +1328,7 @@ onMounted(() => {
1186 1328
 
1187 1329
 .indicator-value,
1188 1330
 .indicator-count,
1189
-.indicator-source,
1331
+.indicator-qcDeptType,
1190 1332
 .indicator-total {
1191 1333
   flex: 1;
1192 1334
   font-size: 16px;

+ 259 - 69
src/views/performanceManage/monthlyAssessSum/index.vue

@@ -29,9 +29,9 @@
29 29
       
30 30
       <!-- 第一行:两个区块 -->
31 31
       <div class="chart-row">
32
-        <!-- 整体分分布柱状图 -->
32
+        <!-- 整体分分布柱状图 -->
33 33
         <el-card class="chart-card">
34
-          <div class="chart-header">整体分分布柱状图</div>
34
+          <div class="chart-header">整体分分布柱状图</div>
35 35
           <div ref="overallBarChart" class="chart-container"></div>
36 36
         </el-card>
37 37
         
@@ -44,9 +44,9 @@
44 44
 
45 45
       <!-- 第二行:两个区块 -->
46 46
       <div class="chart-row">
47
-        <!-- 各部门分分布对比图 -->
47
+        <!-- 各部门分分布对比图 -->
48 48
         <el-card class="chart-card">
49
-          <div class="chart-header">各部门分分布对比图</div>
49
+          <div class="chart-header">各部门分分布对比图</div>
50 50
           <div ref="departmentComparisonChart" class="chart-container"></div>
51 51
         </el-card>
52 52
         
@@ -54,11 +54,9 @@
54 54
         <el-card class="chart-card">
55 55
           <div class="chart-header">汇总表</div>
56 56
           <el-table :data="summaryTableData" border style="width: 100%; margin-top: 10px;">
57
-            <el-table-column prop="range" label="区间" align="center" min-width="100" />
58
-            <el-table-column prop="simulationScore" label="2026年1月模拟分数汇总" align="center" min-width="150" />
59
-            <el-table-column prop="team1" label="一队" align="center" min-width="100" />
60
-            <el-table-column prop="team2" label="二队" align="center" min-width="100" />
61
-            <el-table-column prop="team3" label="三队" align="center" min-width="100" />
57
+            <el-table-column prop="rangeLabel" label="区间" align="center" min-width="100" />
58
+            <el-table-column prop="totalCount" :label="summaryTableTitle" align="center" min-width="150" />
59
+            <el-table-column v-for="col in summaryTableColumns" :key="col.deptId" :prop="'team' + col.deptId" :label="col.deptName" align="center" min-width="100" />
62 60
           </el-table>
63 61
         </el-card>
64 62
       </div>
@@ -72,14 +70,14 @@
72 70
       <el-card class="summary-table-card">
73 71
         <div class="chart-header">汇总统计</div>
74 72
         <el-table :data="classificationTableData" border style="width: 100%; margin-top: 10px;">
75
-          <el-table-column prop="assessmentGroup" label="考核组人数" align="center" min-width="120" />
76
-          <el-table-column prop="calculatedImprovement" label="测算待改进人数" align="center" min-width="140" />
77
-          <el-table-column prop="totalImprovement" label="待改进总人数" align="center" min-width="120" />
78
-          <el-table-column prop="exemption1" label="豁免" align="center" min-width="80" />
79
-          <el-table-column prop="actualImprovement" label="实际待改进总人数" align="center" min-width="140" />
80
-          <el-table-column prop="totalUnqualified" label="不称职总人数" align="center" min-width="120" />
81
-          <el-table-column prop="exemption2" label="豁免" align="center" min-width="80" />
82
-          <el-table-column prop="actualUnqualified" label="实际不称职人数" align="center" min-width="140" />
73
+          <el-table-column prop="assessmentTeamCount" label="考核组人数" align="center" min-width="120" />
74
+          <el-table-column prop="estimatedImprovementCount" label="测算待改进人数" align="center" min-width="140" />
75
+          <el-table-column prop="improvementTotalCount" label="待改进总人数" align="center" min-width="120" />
76
+          <el-table-column prop="improvementExemptedCount" label="待改进豁免" align="center" min-width="100" />
77
+          <el-table-column prop="actualImprovementCount" label="实际待改进总人数" align="center" min-width="140" />
78
+          <el-table-column prop="incompetentTotalCount" label="不称职总人数" align="center" min-width="120" />
79
+          <el-table-column prop="incompetentExemptedCount" label="不称职豁免" align="center" min-width="100" />
80
+          <el-table-column prop="actualIncompetentCount" label="实际不称职人数" align="center" min-width="140" />
83 81
         </el-table>
84 82
       </el-card>
85 83
 
@@ -113,16 +111,15 @@
113 111
           <!-- 左边表格 -->
114 112
           <div class="table-section">
115 113
             <el-table :data="item.tableData" border style="width: 100%;">
116
-              <el-table-column prop="brigade" label="大队" align="center" min-width="100" />
117
-              <el-table-column prop="assessmentGroup" label="考核组" align="center" min-width="100" />
118
-              <el-table-column prop="groupCount" label="考核组人数" align="center" min-width="120" />
119
-              <el-table-column prop="calculatedImprovement" label="测算待改进人数" align="center" min-width="140" />
120
-              <el-table-column prop="improvementCount" label="待改进人数" align="center" min-width="120" />
121
-              <el-table-column prop="exemption1" label="豁免" align="center" min-width="80" />
122
-              <el-table-column prop="actualImprovement" label="实际待改进人数" align="center" min-width="140" />
123
-              <el-table-column prop="unqualifiedCount" label="不称职人数" align="center" min-width="120" />
124
-              <el-table-column prop="exemption2" label="豁免" align="center" min-width="80" />
125
-              <el-table-column prop="actualUnqualified" label="实际不称职人数" align="center" min-width="140" />
114
+              <el-table-column prop="assessmentTeam" label="考核组" align="center" min-width="100" />
115
+              <el-table-column prop="assessmentTeamCount" label="考核组人数" align="center" min-width="120" />
116
+              <el-table-column prop="estimatedImprovementCount" label="测算待改进人数" align="center" min-width="140" />
117
+              <el-table-column prop="improvementTotalCount" label="待改进总人数" align="center" min-width="120" />
118
+              <el-table-column prop="improvementExemptedCount" label="待改进豁免人数" align="center" min-width="140" />
119
+              <el-table-column prop="actualImprovementCount" label="实际待改进人数" align="center" min-width="140" />
120
+              <el-table-column prop="incompetentTotalCount" label="不称职总人数" align="center" min-width="120" />
121
+              <el-table-column prop="incompetentExemptedCount" label="不称职豁免人数" align="center" min-width="140" />
122
+              <el-table-column prop="actualIncompetentCount" label="实际不称职人数" align="center" min-width="140" />
126 123
             </el-table>
127 124
           </div>
128 125
           
@@ -180,20 +177,45 @@
180 177
 </template>
181 178
 
182 179
 <script setup>
183
-import { ref, reactive, onMounted, nextTick } from 'vue'
180
+import { ref, reactive, onMounted, nextTick, computed } from 'vue'
184 181
 import { ElMessage } from 'element-plus'
185 182
 import * as echarts from 'echarts'
186 183
 
187 184
 // API导入
188
-//import {  } from '@/api/performance/monthlyAssessSum.js'
185
+import {
186
+  getScoreDistribution,
187
+  getDeptParticipation,
188
+  getDeptScoreDistribution,
189
+  getAssessmentSummary,
190
+  getActualImprovementDistribution,
191
+  getActualIncompetentDistribution,
192
+  getAssessmentTeamImprovementDistribution,
193
+  getAssessmentTeamIncompetentDistribution,
194
+  getDeptAssessmentTeamStatistics,
195
+  getBrigadeImprovementDistribution,
196
+  getBrigadeIncompetentDistribution,
197
+  getFunctionalDeptSummary,
198
+  getFunctionalDeptPersonnelDistribution,
199
+  getFunctionalDeptDistributionPie
200
+} from '@/api/performance/monthlyAssessSum.js'
189 201
 
190 202
 // 响应式数据
191 203
 const loading = ref(false)
192 204
 const queryFormRef = ref()
193 205
 
194 206
 // 查询参数
207
+const currentMonth = `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, '0')}`
208
+
195 209
 const queryParams = reactive({
196
-  assessmentMonth: ''
210
+  assessmentMonth: currentMonth
211
+})
212
+
213
+const summaryTableTitle = computed(() => {
214
+  if (queryParams.assessmentMonth) {
215
+    const [year, month] = queryParams.assessmentMonth.split('-')
216
+    return `${year}年${parseInt(month)}月模拟分数汇总`
217
+  }
218
+  return '模拟分数汇总'
197 219
 })
198 220
 
199 221
 // 图表引用
@@ -209,49 +231,20 @@ const positionPieChart2 = ref(null)
209 231
 const traversalChartsRefs = ref({})
210 232
 
211 233
 // 表格数据
212
-const summaryTableData = ref([
213
-  { range: '90-100分', simulationScore: '85', team1: '15', team2: '20', team3: '25' },
214
-  { range: '80-89分', simulationScore: '120', team1: '30', team2: '35', team3: '40' },
215
-  { range: '70-79分', simulationScore: '95', team1: '25', team2: '30', team3: '35' },
216
-  { range: '60-69分', simulationScore: '60', team1: '15', team2: '20', team3: '25' },
217
-  { range: '60分以下', simulationScore: '20', team1: '5', team2: '8', team3: '7' }
218
-])
234
+const summaryTableData = ref([])
235
+const summaryTableColumns = ref([])
219 236
 
220 237
 const classificationTableData = ref([
221
-  { 
222
-    assessmentGroup: '100', 
223
-    calculatedImprovement: '15', 
224
-    totalImprovement: '12', 
225
-    exemption1: '2', 
226
-    actualImprovement: '10', 
227
-    totalUnqualified: '5', 
228
-    exemption2: '1', 
229
-    actualUnqualified: '4'
230
-  }
238
+
231 239
 ])
232 240
 
233 241
 // 遍历数据
234 242
 const traversalData1 = ref([
235
-  {
236
-    title: '大队考核统计',
237
-    tableData: [
238
-      { brigade: '一大队', assessmentGroup: '一组', groupCount: 50, calculatedImprovement: 8, improvementCount: 6, exemption1: 1, actualImprovement: 5, unqualifiedCount: 2, exemption2: 0, actualUnqualified: 2 },
239
-      { brigade: '一大队', assessmentGroup: '二组', groupCount: 45, calculatedImprovement: 7, improvementCount: 5, exemption1: 1, actualImprovement: 4, unqualifiedCount: 1, exemption2: 0, actualUnqualified: 1 },
240
-      { brigade: '二大队', assessmentGroup: '一组', groupCount: 55, calculatedImprovement: 9, improvementCount: 7, exemption1: 1, actualImprovement: 6, unqualifiedCount: 3, exemption2: 1, actualUnqualified: 2 },
241
-      { brigade: '二大队', assessmentGroup: '二组', groupCount: 48, calculatedImprovement: 6, improvementCount: 5, exemption1: 0, actualImprovement: 5, unqualifiedCount: 2, exemption2: 0, actualUnqualified: 2 }
242
-    ]
243
-  }
243
+  
244 244
 ])
245 245
 
246 246
 const traversalData2 = ref([
247
-  {
248
-    title: '岗位考核统计',
249
-    tableData: [
250
-      { brigade: '安检员', assessmentGroup: '一组', groupCount: 60, calculatedImprovement: 10, improvementCount: 8, exemption1: 1, actualImprovement: 7, unqualifiedCount: 3, exemption2: 0, actualUnqualified: 3 },
251
-      { brigade: '安检员', assessmentGroup: '二组', groupCount: 55, calculatedImprovement: 8, improvementCount: 6, exemption1: 1, actualImprovement: 5, unqualifiedCount: 2, exemption2: 0, actualUnqualified: 2 },
252
-      { brigade: '设备操作员', assessmentGroup: '一组', groupCount: 40, calculatedImprovement: 5, improvementCount: 4, exemption1: 0, actualImprovement: 4, unqualifiedCount: 1, exemption2: 0, actualUnqualified: 1 }
253
-    ]
254
-  }
247
+  
255 248
 ])
256 249
 
257 250
 // 图表实例
@@ -266,7 +259,7 @@ let positionPieChart2Instance = null
266 259
 // 初始化图表
267 260
 const initCharts = () => {
268 261
   nextTick(() => {
269
-    // 整体分分布柱状图
262
+    // 整体分分布柱状图
270 263
     if (overallBarChart.value) {
271 264
       overallBarChartInstance = echarts.init(overallBarChart.value)
272 265
       overallBarChartInstance.setOption({
@@ -293,7 +286,7 @@ const initCharts = () => {
293 286
       })
294 287
     }
295 288
 
296
-    // 各部门分分布对比图
289
+    // 各部门分分布对比图
297 290
     if (departmentComparisonChart.value) {
298 291
       departmentComparisonChartInstance = echarts.init(departmentComparisonChart.value)
299 292
       departmentComparisonChartInstance.setOption({
@@ -485,9 +478,206 @@ const handleResize = () => {
485 478
 const getList = async () => {
486 479
   loading.value = true
487 480
   try {
488
-    // const res = await getNonCadreMonthlyScoreSum(queryParams)
489
-    // // 这里可以根据实际API返回的数据更新图表和表格数据
490
-    // console.log('获取汇总数据:', res)
481
+    const results = await Promise.allSettled([
482
+      getScoreDistribution(queryParams),
483
+      getDeptParticipation(queryParams),
484
+      getDeptScoreDistribution(queryParams),
485
+      getAssessmentSummary(queryParams),
486
+      getActualImprovementDistribution(queryParams),
487
+      getActualIncompetentDistribution(queryParams),
488
+      getAssessmentTeamImprovementDistribution(queryParams),
489
+      getAssessmentTeamIncompetentDistribution(queryParams),
490
+      getDeptAssessmentTeamStatistics(queryParams),
491
+      getBrigadeImprovementDistribution(queryParams),
492
+      getBrigadeIncompetentDistribution(queryParams),
493
+      getFunctionalDeptSummary(queryParams),
494
+      getFunctionalDeptPersonnelDistribution(queryParams),
495
+      getFunctionalDeptDistributionPie(queryParams)
496
+    ])
497
+
498
+    const [scoreDistRes, deptPartRes, deptScoreRes, assessmentSumRes, actualImproveRes, actualIncompRes, teamImproveRes, teamIncompRes, deptTeamStatRes, brigadeImproveRes, brigadeIncompRes, functionalDeptRes, functionalDeptPersonnelRes, functionalDeptPieRes] = results
499
+
500
+    if (scoreDistRes.status === 'fulfilled' && scoreDistRes.value.data) {
501
+      const data = scoreDistRes.value.data
502
+      if (overallBarChartInstance && Array.isArray(data)) {
503
+        overallBarChartInstance.setOption({
504
+          xAxis: { data: data.map(item => item.scoreRange) },
505
+          series: [{ data: data.map(item => item.count) }]
506
+        })
507
+      }
508
+    }
509
+
510
+    if (deptPartRes.status === 'fulfilled' && deptPartRes.value.data) {
511
+      const data = deptPartRes.value.data
512
+      if (participantPieChartInstance && Array.isArray(data)) {
513
+        participantPieChartInstance.setOption({
514
+          series: [{ data: data.map(item => ({ name: item.deptName, value: item.count })) }]
515
+        })
516
+      }
517
+    }
518
+
519
+    if (deptScoreRes.status === 'fulfilled' && deptScoreRes.value.data) {
520
+      const data = deptScoreRes.value.data
521
+      if (departmentComparisonChartInstance && Array.isArray(data)) {
522
+        const xAxisData = data.map(item => item.rangeLabel)
523
+        const firstDeptCounts = data.length > 0 ? data[0].deptCounts : []
524
+        
525
+        const series = firstDeptCounts.map(dept => ({
526
+          name: dept.deptName,
527
+          type: 'bar',
528
+          data: data.map(item => {
529
+            const deptData = item.deptCounts.find(d => d.deptId === dept.deptId)
530
+            return deptData ? deptData.count : 0
531
+          })
532
+        }))
533
+
534
+        departmentComparisonChartInstance.setOption({
535
+          legend: { data: firstDeptCounts.map(d => d.deptName) },
536
+          xAxis: { data: xAxisData },
537
+          series: series
538
+        })
539
+
540
+        summaryTableColumns.value = firstDeptCounts
541
+        summaryTableData.value = data.map(item => {
542
+          const row = {
543
+            rangeLabel: item.rangeLabel,
544
+            totalCount: item.totalCount
545
+          }
546
+          item.deptCounts.forEach(dept => {
547
+            row['team' + dept.deptId] = dept.count
548
+          })
549
+          return row
550
+        })
551
+      }
552
+    }
553
+
554
+    if (assessmentSumRes.status === 'fulfilled' && assessmentSumRes.value.data) {
555
+      const data = assessmentSumRes.value.data
556
+      if (data && typeof data === 'object') {
557
+        classificationTableData.value = [data]
558
+      }
559
+    }
560
+
561
+    if (actualImproveRes.status === 'fulfilled' && actualImproveRes.value.data) {
562
+      const data = actualImproveRes.value.data
563
+      if (brigadePieChart1Instance && Array.isArray(data)) {
564
+        brigadePieChart1Instance.setOption({
565
+          series: [{ data: data.map(item => ({ name: item.deptName, value: item.count })) }]
566
+        })
567
+      }
568
+    }
569
+
570
+    if (actualIncompRes.status === 'fulfilled' && actualIncompRes.value.data) {
571
+      const data = actualIncompRes.value.data
572
+      if (brigadePieChart2Instance && Array.isArray(data)) {
573
+        brigadePieChart2Instance.setOption({
574
+          series: [{ data: data.map(item => ({ name: item.deptName, value: item.count })) }]
575
+        })
576
+      }
577
+    }
578
+
579
+    if (teamImproveRes.status === 'fulfilled' && teamImproveRes.value.data) {
580
+      const data = teamImproveRes.value.data
581
+      if (positionPieChart1Instance && Array.isArray(data)) {
582
+        positionPieChart1Instance.setOption({
583
+          series: [{ data: data.map(item => ({ name: item.assessmentTeam, value: item.count })) }]
584
+        })
585
+      }
586
+    }
587
+
588
+    if (teamIncompRes.status === 'fulfilled' && teamIncompRes.value.data) {
589
+      const data = teamIncompRes.value.data
590
+      if (positionPieChart2Instance && Array.isArray(data)) {
591
+        positionPieChart2Instance.setOption({
592
+          series: [{ data: data.map(item => ({ name: item.assessmentTeam, value: item.count })) }]
593
+        })
594
+      }
595
+    }
596
+
597
+    if (deptTeamStatRes.status === 'fulfilled' && deptTeamStatRes.value.data) {
598
+      const statistics = deptTeamStatRes.value.data || []
599
+      const brigadeImproveData = brigadeImproveRes.status === 'fulfilled' ? (brigadeImproveRes.value.data || []) : []
600
+      const brigadeIncompData = brigadeIncompRes.status === 'fulfilled' ? (brigadeIncompRes.value.data || []) : []
601
+      
602
+      const brigadeMap = {}
603
+      brigadeImproveData.forEach(item => {
604
+        if (!brigadeMap[item.deptName]) {
605
+          brigadeMap[item.deptName] = { brigade: item.deptName, assessmentGroup: '', improvementCount: 0, exemption1: 0, unqualifiedCount: 0, exemption2: 0 }
606
+        }
607
+        brigadeMap[item.deptName].improvementCount += item.count
608
+        brigadeMap[item.deptName].exemption1 += (item.exemptedCount || 0)
609
+      })
610
+      brigadeIncompData.forEach(item => {
611
+        if (!brigadeMap[item.deptName]) {
612
+          brigadeMap[item.deptName] = { brigade: item.deptName, assessmentGroup: '', improvementCount: 0, exemption1: 0, unqualifiedCount: 0, exemption2: 0 }
613
+        }
614
+        brigadeMap[item.deptName].unqualifiedCount += item.count
615
+        brigadeMap[item.deptName].exemption2 += (item.exemptedCount || 0)
616
+      })
617
+      
618
+      const groupCount = statistics.reduce((sum, item) => sum + (item.count || 0), 0)
619
+      const calculatedImprovement = statistics.reduce((sum, item) => sum + (item.calculatedImprovementCount || 0), 0)
620
+      const actualImprovement = statistics.reduce((sum, item) => sum + (item.actualImprovementCount || 0), 0)
621
+      const actualUnqualified = statistics.reduce((sum, item) => sum + (item.actualIncompetentCount || 0), 0)
622
+      
623
+      const tableData = Object.values(brigadeMap).map(item => ({
624
+        ...item,
625
+        groupCount,
626
+        calculatedImprovement,
627
+        actualImprovement,
628
+        actualUnqualified
629
+      }))
630
+      
631
+      if (tableData.length > 0) {
632
+        traversalData1.value = [{ title: '大队考核统计', tableData }]
633
+      }
634
+    }
635
+
636
+    if (functionalDeptRes.status === 'fulfilled' && functionalDeptRes.value.data) {
637
+      const summaryData = functionalDeptRes.value.data || []
638
+      
639
+      traversalData2.value = summaryData.map(item => ({
640
+        title: item.deptName,
641
+        deptId: item.deptId,
642
+        tableData: item.assessmentTeams || []
643
+      }))
644
+      
645
+      const personnelData = functionalDeptPersonnelRes.status === 'fulfilled' ? (functionalDeptPersonnelRes.value.data || []) : []
646
+      const pieData = functionalDeptPieRes.status === 'fulfilled' ? (functionalDeptPieRes.value.data || []) : []
647
+      
648
+      personnelData.forEach(item => {
649
+        const deptItem = traversalData2.value.find(d => d.deptId === item.deptId)
650
+        if (deptItem) {
651
+          deptItem.personnelCount = item.assessmentTeamCount || 0
652
+          deptItem.actualImprovement = item.actualImprovementCount || 0
653
+          deptItem.actualUnqualified = item.actualIncompetentCount || 0
654
+        }
655
+      })
656
+      
657
+      nextTick(() => {
658
+        pieData.forEach(pieItem => {
659
+          const deptIndex = traversalData2.value.findIndex(d => d.deptId === pieItem.deptId)
660
+          const chartKey = `barChart_${deptIndex}`
661
+          const pieChartKey = `pieChart3_${deptIndex}`
662
+          
663
+          const filteredData = pieData.filter(p => p.deptId === pieItem.deptId).map(p => ({ name: p.assessmentTeam, value: p.count }))
664
+          
665
+          if (traversalChartsRefs.value[chartKey]) {
666
+            const barChart = echarts.init(traversalChartsRefs.value[chartKey])
667
+            barChart.setOption({
668
+              series: [{ data: filteredData }]
669
+            })
670
+          }
671
+          
672
+          if (traversalChartsRefs.value[pieChartKey]) {
673
+            const pieChart = echarts.init(traversalChartsRefs.value[pieChartKey])
674
+            pieChart.setOption({
675
+              series: [{ data: filteredData }]
676
+            })
677
+          }
678
+        })
679
+      })
680
+    }
491 681
   } catch (error) {
492 682
     console.error('获取汇总数据失败:', error)
493 683
     ElMessage.error('获取汇总数据失败')

+ 8 - 0
src/views/system/dept/index.vue

@@ -125,6 +125,14 @@
125 125
                   </el-form-item>
126 126
                </el-col>
127 127
                <el-col :span="12">
128
+                  <el-form-item label="职能部门" prop="isFunctionalDept">
129
+                     <el-select v-model="form.isFunctionalDept" placeholder="请选择">
130
+                        <el-option :label="'是'" :value="'1'" />
131
+                        <el-option :label="'否'" :value="'0'" />
132
+                     </el-select>
133
+                  </el-form-item>
134
+               </el-col>
135
+               <el-col :span="12">
128 136
                   <el-form-item label="显示排序" prop="orderNum">
129 137
                      <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
130 138
                   </el-form-item>