|
|
@@ -1,21 +1,38 @@
|
|
1
|
1
|
<script lang="ts" setup>
|
|
2
|
2
|
// 导入部分
|
|
3
|
|
-import { ref, computed } from 'vue';
|
|
|
3
|
+import { ref, computed, onMounted } from 'vue';
|
|
4
|
4
|
import { Page } from '@vben/common-ui';
|
|
5
|
|
-import { ElTable, ElTableColumn, ElButton, ElInput, ElTabs, ElTabPane } from 'element-plus';
|
|
|
5
|
+import { ElTable, ElTableColumn, ElButton, ElInput, ElTabs, ElTabPane, ElSelect, ElOption } from 'element-plus';
|
|
|
6
|
+
|
|
|
7
|
+// API 导入
|
|
|
8
|
+import { scoreEntryList, updateScoreEntry } from '#/api/system/infoEntry/scoreEntry/scoreEntry';
|
|
|
9
|
+// 数据字典导入
|
|
|
10
|
+import { getDictOptions } from '#/utils/dict';
|
|
6
|
11
|
|
|
7
|
12
|
// 类型定义
|
|
8
|
13
|
interface TabOption {
|
|
9
|
14
|
label: string;
|
|
10
|
|
- value: 'stationManager' | 'stationStaff' | 'areaStaff' | 'headquarters' | 'station' | 'area';
|
|
|
15
|
+ value: string;
|
|
|
16
|
+ typeValue: string;
|
|
|
17
|
+}
|
|
|
18
|
+
|
|
|
19
|
+interface StandardItem {
|
|
|
20
|
+ score: number;
|
|
|
21
|
+ condition: string;
|
|
|
22
|
+ max_value?: number;
|
|
|
23
|
+ min_value?: number;
|
|
11
|
24
|
}
|
|
12
|
25
|
|
|
13
|
26
|
interface ScoreItem {
|
|
14
|
|
- id: number;
|
|
|
27
|
+ id: string;
|
|
|
28
|
+ type: string;
|
|
|
29
|
+ typeName: string;
|
|
15
|
30
|
dimension: string;
|
|
|
31
|
+ dimensionName: string;
|
|
16
|
32
|
indicator: string;
|
|
17
|
|
- standard: string;
|
|
18
|
|
- score: number;
|
|
|
33
|
+ indicatorName: string;
|
|
|
34
|
+ standardJson: string;
|
|
|
35
|
+ standards: StandardItem[];
|
|
19
|
36
|
isEditing?: boolean;
|
|
20
|
37
|
// 拆分后的标准字段
|
|
21
|
38
|
threshold1: number;
|
|
|
@@ -29,549 +46,161 @@ interface ScoreItem {
|
|
29
|
46
|
threshold6: number;
|
|
30
|
47
|
threshold7: number;
|
|
31
|
48
|
score4: number;
|
|
|
49
|
+ // API 响应中的其他字段
|
|
|
50
|
+ createBy?: string;
|
|
|
51
|
+ createTime?: string;
|
|
|
52
|
+ updateBy?: string;
|
|
|
53
|
+ updateTime?: string;
|
|
|
54
|
+ remark?: string;
|
|
32
|
55
|
}
|
|
33
|
56
|
|
|
|
57
|
+// 数据字典选项
|
|
|
58
|
+const typeOptions = ref<any[]>([]);
|
|
|
59
|
+const dimensionOptions = ref<any[]>([]);
|
|
|
60
|
+const indicatorOptions = ref<any[]>([]);
|
|
|
61
|
+
|
|
34
|
62
|
// 响应式数据
|
|
35
|
63
|
// Tab切换数据
|
|
36
|
|
-const activeTab = ref<'stationManager' | 'stationStaff' | 'areaStaff' | 'headquarters' | 'station' | 'area'>('stationManager');
|
|
|
64
|
+const activeTab = ref<string>('stationManager');
|
|
37
|
65
|
const tabOptions: TabOption[] = [
|
|
38
|
|
- { label: '油站管理人员', value: 'stationManager' },
|
|
39
|
|
- { label: '油站员工', value: 'stationStaff' },
|
|
40
|
|
- { label: '片区人员', value: 'areaStaff' },
|
|
41
|
|
- { label: '总部人员', value: 'headquarters' },
|
|
42
|
|
- { label: '油站', value: 'station' },
|
|
43
|
|
- { label: '片区', value: 'area' },
|
|
|
66
|
+ { label: '油站管理人员', value: 'stationManager', typeValue: 'oil_station_manager' },
|
|
|
67
|
+ { label: '油站员工', value: 'stationStaff', typeValue: 'oil_station_employee' },
|
|
|
68
|
+ { label: '片区人员', value: 'areaStaff', typeValue: 'region_personnel' },
|
|
|
69
|
+ { label: '总部人员', value: 'headquarters', typeValue: 'headquarters_personnel' },
|
|
|
70
|
+ { label: '油站', value: 'station', typeValue: 'oil_station' },
|
|
|
71
|
+ { label: '片区', value: 'area', typeValue: 'region' },
|
|
44
|
72
|
];
|
|
45
|
73
|
|
|
46
|
|
-// 油站管理人员评分数据
|
|
47
|
|
-const stationManagerScores = ref<ScoreItem[]>([
|
|
48
|
|
- {
|
|
49
|
|
- id: 1,
|
|
50
|
|
- dimension: '任务数量',
|
|
51
|
|
- indicator: '完成率',
|
|
52
|
|
- standard: '(≥ 98% :20分 区间 95% — 98% :16分 区间 90% — 95% :12分 区间 0% — 90% :0分)',
|
|
53
|
|
- score: 20,
|
|
54
|
|
- isEditing: false,
|
|
55
|
|
- // 拆分后的标准字段
|
|
56
|
|
- threshold1: 98,
|
|
57
|
|
- score1: 20,
|
|
58
|
|
- threshold2: 95,
|
|
59
|
|
- threshold3: 98,
|
|
60
|
|
- score2: 16,
|
|
61
|
|
- threshold4: 90,
|
|
62
|
|
- threshold5: 95,
|
|
63
|
|
- score3: 12,
|
|
64
|
|
- threshold6: 0,
|
|
65
|
|
- threshold7: 90,
|
|
66
|
|
- score4: 0,
|
|
67
|
|
- },
|
|
68
|
|
- {
|
|
69
|
|
- id: 2,
|
|
70
|
|
- dimension: '任务质量',
|
|
71
|
|
- indicator: '任务得分',
|
|
72
|
|
- standard: '(≥ 4.5分 :30分 区间 4分 — 4.5分 :24分 区间 3分 — 4分 :18分 区间 0分 — 3分 :0分)',
|
|
73
|
|
- score: 30,
|
|
74
|
|
- isEditing: false,
|
|
75
|
|
- // 拆分后的标准字段
|
|
76
|
|
- threshold1: 4.5,
|
|
77
|
|
- score1: 30,
|
|
78
|
|
- threshold2: 4,
|
|
79
|
|
- threshold3: 4.5,
|
|
80
|
|
- score2: 24,
|
|
81
|
|
- threshold4: 3,
|
|
82
|
|
- threshold5: 4,
|
|
83
|
|
- score3: 18,
|
|
84
|
|
- threshold6: 0,
|
|
85
|
|
- threshold7: 3,
|
|
86
|
|
- score4: 0,
|
|
87
|
|
- },
|
|
88
|
|
- {
|
|
89
|
|
- id: 3,
|
|
90
|
|
- dimension: '查阅情况',
|
|
91
|
|
- indicator: '已阅比例',
|
|
92
|
|
- standard: '(≥ 95% :20分 区间 90% — 95% :15分 区间 80% — 90% :9分 区间 0% — 80% :0分)',
|
|
93
|
|
- score: 20,
|
|
94
|
|
- isEditing: false,
|
|
95
|
|
- // 拆分后的标准字段
|
|
96
|
|
- threshold1: 95,
|
|
97
|
|
- score1: 20,
|
|
98
|
|
- threshold2: 90,
|
|
99
|
|
- threshold3: 95,
|
|
100
|
|
- score2: 15,
|
|
101
|
|
- threshold4: 80,
|
|
102
|
|
- threshold5: 90,
|
|
103
|
|
- score3: 9,
|
|
104
|
|
- threshold6: 0,
|
|
105
|
|
- threshold7: 80,
|
|
106
|
|
- score4: 0,
|
|
107
|
|
- },
|
|
108
|
|
- {
|
|
109
|
|
- id: 4,
|
|
110
|
|
- dimension: '授权',
|
|
111
|
|
- indicator: '授权点评率',
|
|
112
|
|
- standard: '(≥ 70% :30分 区间 60% — 70% :24分 区间 50% — 60% :18分 区间 0% — 50% :0分)',
|
|
113
|
|
- score: 30,
|
|
114
|
|
- isEditing: false,
|
|
115
|
|
- // 拆分后的标准字段
|
|
116
|
|
- threshold1: 70,
|
|
117
|
|
- score1: 30,
|
|
118
|
|
- threshold2: 60,
|
|
119
|
|
- threshold3: 70,
|
|
120
|
|
- score2: 24,
|
|
121
|
|
- threshold4: 50,
|
|
122
|
|
- threshold5: 60,
|
|
123
|
|
- score3: 18,
|
|
124
|
|
- threshold6: 0,
|
|
125
|
|
- threshold7: 50,
|
|
126
|
|
- score4: 0,
|
|
127
|
|
- },
|
|
128
|
|
-]);
|
|
129
|
|
-
|
|
130
|
|
-// 油站员工评分数据
|
|
131
|
|
-const stationStaffScores = ref<ScoreItem[]>([
|
|
132
|
|
- {
|
|
133
|
|
- id: 1,
|
|
134
|
|
- dimension: '任务数量',
|
|
135
|
|
- indicator: '完成率',
|
|
136
|
|
- standard: '(≥ 98% :45分 区间 95% — 98% :36分 区间 90% — 95% :27分 区间 0% — 90% :0分)',
|
|
137
|
|
- score: 45,
|
|
138
|
|
- isEditing: false,
|
|
139
|
|
- threshold1: 98,
|
|
140
|
|
- score1: 45,
|
|
141
|
|
- threshold2: 95,
|
|
142
|
|
- threshold3: 98,
|
|
143
|
|
- score2: 36,
|
|
144
|
|
- threshold4: 90,
|
|
145
|
|
- threshold5: 95,
|
|
146
|
|
- score3: 27,
|
|
147
|
|
- threshold6: 0,
|
|
148
|
|
- threshold7: 90,
|
|
149
|
|
- score4: 0,
|
|
150
|
|
- },
|
|
151
|
|
- {
|
|
152
|
|
- id: 2,
|
|
153
|
|
- dimension: '任务数量',
|
|
154
|
|
- indicator: '新增任务率',
|
|
155
|
|
- standard: '(≥ 5% :50分 区间 3% — 5% :40分 区间 1% — 3% :30分 区间 0% — 1% :0分)',
|
|
156
|
|
- score: 50,
|
|
157
|
|
- isEditing: false,
|
|
158
|
|
- threshold1: 5,
|
|
159
|
|
- score1: 50,
|
|
160
|
|
- threshold2: 3,
|
|
161
|
|
- threshold3: 5,
|
|
162
|
|
- score2: 40,
|
|
163
|
|
- threshold4: 1,
|
|
164
|
|
- threshold5: 3,
|
|
165
|
|
- score3: 30,
|
|
166
|
|
- threshold6: 0,
|
|
167
|
|
- threshold7: 1,
|
|
168
|
|
- score4: 0,
|
|
169
|
|
- },
|
|
170
|
|
- {
|
|
171
|
|
- id: 3,
|
|
172
|
|
- dimension: '任务质量',
|
|
173
|
|
- indicator: '任务得分',
|
|
174
|
|
- standard: '(≥ 4.5分 :5分 区间 4分 — 4.5分 :3分 区间 3分 — 4分 :2分 区间 0分 — 3分 :0分)',
|
|
175
|
|
- score: 5,
|
|
176
|
|
- isEditing: false,
|
|
177
|
|
- threshold1: 4.5,
|
|
178
|
|
- score1: 5,
|
|
179
|
|
- threshold2: 4,
|
|
180
|
|
- threshold3: 4.5,
|
|
181
|
|
- score2: 3,
|
|
182
|
|
- threshold4: 3,
|
|
183
|
|
- threshold5: 4,
|
|
184
|
|
- score3: 2,
|
|
185
|
|
- threshold6: 0,
|
|
186
|
|
- threshold7: 3,
|
|
187
|
|
- score4: 0,
|
|
188
|
|
- },
|
|
189
|
|
-]);
|
|
190
|
|
-
|
|
191
|
|
-// 片区人员评分数据
|
|
192
|
|
-const areaStaffScores = ref<ScoreItem[]>([
|
|
193
|
|
- {
|
|
194
|
|
- id: 1,
|
|
195
|
|
- dimension: '任务数量',
|
|
196
|
|
- indicator: '完成率',
|
|
197
|
|
- standard: '(≥ 98% :40分 区间 95% — 98% :32分 区间 90% — 95% :24分 区间 0% — 90% :0分)',
|
|
198
|
|
- score: 40,
|
|
199
|
|
- isEditing: false,
|
|
200
|
|
- threshold1: 98,
|
|
201
|
|
- score1: 40,
|
|
202
|
|
- threshold2: 95,
|
|
203
|
|
- threshold3: 98,
|
|
204
|
|
- score2: 32,
|
|
205
|
|
- threshold4: 90,
|
|
206
|
|
- threshold5: 95,
|
|
207
|
|
- score3: 24,
|
|
208
|
|
- threshold6: 0,
|
|
209
|
|
- threshold7: 90,
|
|
210
|
|
- score4: 0,
|
|
211
|
|
- },
|
|
212
|
|
- {
|
|
213
|
|
- id: 2,
|
|
214
|
|
- dimension: '任务质量',
|
|
215
|
|
- indicator: '任务得分',
|
|
216
|
|
- standard: '(≥ 4.5分 :20分 区间 4分 — 4.5分 :16分 区间 3分 — 4分 :12分 区间 0分 — 3分 :0分)',
|
|
217
|
|
- score: 20,
|
|
218
|
|
- isEditing: false,
|
|
219
|
|
- threshold1: 4.5,
|
|
220
|
|
- score1: 20,
|
|
221
|
|
- threshold2: 4,
|
|
222
|
|
- threshold3: 4.5,
|
|
223
|
|
- score2: 16,
|
|
224
|
|
- threshold4: 3,
|
|
225
|
|
- threshold5: 4,
|
|
226
|
|
- score3: 12,
|
|
227
|
|
- threshold6: 0,
|
|
228
|
|
- threshold7: 3,
|
|
229
|
|
- score4: 0,
|
|
230
|
|
- },
|
|
231
|
|
- {
|
|
232
|
|
- id: 3,
|
|
233
|
|
- dimension: '点评',
|
|
234
|
|
- indicator: '点评完成率',
|
|
235
|
|
- standard: '(≥ 95% :25分 区间 90% — 95% :20分 区间 80% — 90% :15分 区间 0% — 80% :0分)',
|
|
236
|
|
- score: 25,
|
|
237
|
|
- isEditing: false,
|
|
238
|
|
- threshold1: 95,
|
|
239
|
|
- score1: 25,
|
|
240
|
|
- threshold2: 90,
|
|
241
|
|
- threshold3: 95,
|
|
242
|
|
- score2: 20,
|
|
243
|
|
- threshold4: 80,
|
|
244
|
|
- threshold5: 90,
|
|
245
|
|
- score3: 15,
|
|
246
|
|
- threshold6: 0,
|
|
247
|
|
- threshold7: 80,
|
|
248
|
|
- score4: 0,
|
|
249
|
|
- },
|
|
250
|
|
- {
|
|
251
|
|
- id: 4,
|
|
252
|
|
- dimension: '点评',
|
|
253
|
|
- indicator: '按时点评率',
|
|
254
|
|
- standard: '(≥ 95% :0分 区间 90% — 95% :0分 区间 80% — 90% :0分 区间 0% — 80% :0分)',
|
|
255
|
|
- score: 0,
|
|
256
|
|
- isEditing: false,
|
|
257
|
|
- threshold1: 95,
|
|
|
74
|
+// 评分数据
|
|
|
75
|
+const scoreData = ref<ScoreItem[]>([]);
|
|
|
76
|
+const loading = ref<boolean>(false);
|
|
|
77
|
+
|
|
|
78
|
+// 获取当前选中tab对应的typeValue
|
|
|
79
|
+const getCurrentTypeValue = () => {
|
|
|
80
|
+ const tab = tabOptions.find(tab => tab.value === activeTab.value);
|
|
|
81
|
+ return tab ? tab.typeValue : '';
|
|
|
82
|
+};
|
|
|
83
|
+
|
|
|
84
|
+// 解析standardJson字段
|
|
|
85
|
+const parseStandardJson = (standardJson: string): StandardItem[] => {
|
|
|
86
|
+ try {
|
|
|
87
|
+ const parsed = JSON.parse(standardJson);
|
|
|
88
|
+ return parsed.standards || [];
|
|
|
89
|
+ } catch (error) {
|
|
|
90
|
+ console.error('解析standardJson失败:', error);
|
|
|
91
|
+ return [];
|
|
|
92
|
+ }
|
|
|
93
|
+};
|
|
|
94
|
+
|
|
|
95
|
+// 格式化标准项为阈值和分数
|
|
|
96
|
+const formatStandardsToThresholds = (standards: StandardItem[]): Partial<ScoreItem> => {
|
|
|
97
|
+ // 默认值
|
|
|
98
|
+ const defaults = {
|
|
|
99
|
+ threshold1: 0,
|
|
258
|
100
|
score1: 0,
|
|
259
|
|
- threshold2: 90,
|
|
260
|
|
- threshold3: 95,
|
|
|
101
|
+ threshold2: 0,
|
|
|
102
|
+ threshold3: 0,
|
|
261
|
103
|
score2: 0,
|
|
262
|
|
- threshold4: 80,
|
|
263
|
|
- threshold5: 90,
|
|
|
104
|
+ threshold4: 0,
|
|
|
105
|
+ threshold5: 0,
|
|
264
|
106
|
score3: 0,
|
|
265
|
107
|
threshold6: 0,
|
|
266
|
|
- threshold7: 80,
|
|
267
|
|
- score4: 0,
|
|
268
|
|
- },
|
|
269
|
|
- {
|
|
270
|
|
- id: 5,
|
|
271
|
|
- dimension: '逾期',
|
|
272
|
|
- indicator: '逾期未完成数',
|
|
273
|
|
- standard: '(≥ 9个 :0分 区间 6个 — 9个 :5分 区间 3个 — 6个 :10分 区间 0个 — 3个 :15分)',
|
|
274
|
|
- score: 15,
|
|
275
|
|
- isEditing: false,
|
|
276
|
|
- threshold1: 9,
|
|
277
|
|
- score1: 0,
|
|
278
|
|
- threshold2: 6,
|
|
279
|
|
- threshold3: 9,
|
|
280
|
|
- score2: 5,
|
|
281
|
|
- threshold4: 3,
|
|
282
|
|
- threshold5: 6,
|
|
283
|
|
- score3: 10,
|
|
284
|
|
- threshold6: 0,
|
|
285
|
|
- threshold7: 3,
|
|
286
|
|
- score4: 15,
|
|
287
|
|
- },
|
|
288
|
|
-]);
|
|
289
|
|
-
|
|
290
|
|
-// 总部人员评分数据
|
|
291
|
|
-const headquartersScores = ref<ScoreItem[]>([
|
|
292
|
|
- {
|
|
293
|
|
- id: 1,
|
|
294
|
|
- dimension: '任务数量',
|
|
295
|
|
- indicator: '完成率',
|
|
296
|
|
- standard: '(≥ 98% :30分 区间 95% — 98% :24分 区间 90% — 95% :18分 区间 0% — 90% :0分)',
|
|
297
|
|
- score: 30,
|
|
298
|
|
- isEditing: false,
|
|
299
|
|
- threshold1: 98,
|
|
300
|
|
- score1: 30,
|
|
301
|
|
- threshold2: 95,
|
|
302
|
|
- threshold3: 98,
|
|
303
|
|
- score2: 24,
|
|
304
|
|
- threshold4: 90,
|
|
305
|
|
- threshold5: 95,
|
|
306
|
|
- score3: 18,
|
|
307
|
|
- threshold6: 0,
|
|
308
|
|
- threshold7: 90,
|
|
309
|
|
- score4: 0,
|
|
310
|
|
- },
|
|
311
|
|
- {
|
|
312
|
|
- id: 2,
|
|
313
|
|
- dimension: '任务质量',
|
|
314
|
|
- indicator: '任务得分',
|
|
315
|
|
- standard: '(≥ 4.5分 :20分 区间 4分 — 4.5分 :16分 区间 3分 — 4分 :12分 区间 0分 — 3分 :0分)',
|
|
316
|
|
- score: 20,
|
|
317
|
|
- isEditing: false,
|
|
318
|
|
- threshold1: 4.5,
|
|
319
|
|
- score1: 20,
|
|
320
|
|
- threshold2: 4,
|
|
321
|
|
- threshold3: 4.5,
|
|
322
|
|
- score2: 16,
|
|
323
|
|
- threshold4: 3,
|
|
324
|
|
- threshold5: 4,
|
|
325
|
|
- score3: 12,
|
|
326
|
|
- threshold6: 0,
|
|
327
|
|
- threshold7: 3,
|
|
328
|
|
- score4: 0,
|
|
329
|
|
- },
|
|
330
|
|
- {
|
|
331
|
|
- id: 3,
|
|
332
|
|
- dimension: '点评',
|
|
333
|
|
- indicator: '点评完成率',
|
|
334
|
|
- standard: '(≥ 95% :30分 区间 90% — 95% :20分 区间 80% — 90% :15分 区间 0% — 80% :0分)',
|
|
335
|
|
- score: 30,
|
|
336
|
|
- isEditing: false,
|
|
337
|
|
- threshold1: 95,
|
|
338
|
|
- score1: 30,
|
|
339
|
|
- threshold2: 90,
|
|
340
|
|
- threshold3: 95,
|
|
341
|
|
- score2: 20,
|
|
342
|
|
- threshold4: 80,
|
|
343
|
|
- threshold5: 90,
|
|
344
|
|
- score3: 15,
|
|
345
|
|
- threshold6: 0,
|
|
346
|
|
- threshold7: 80,
|
|
347
|
|
- score4: 0,
|
|
348
|
|
- },
|
|
349
|
|
- {
|
|
350
|
|
- id: 4,
|
|
351
|
|
- dimension: '点评',
|
|
352
|
|
- indicator: '按时点评率',
|
|
353
|
|
- standard: '(≥ 95% :20分 区间 90% — 95% :15分 区间 80% — 90% :8分 区间 0% — 80% :0分)',
|
|
354
|
|
- score: 20,
|
|
355
|
|
- isEditing: false,
|
|
356
|
|
- threshold1: 95,
|
|
357
|
|
- score1: 20,
|
|
358
|
|
- threshold2: 90,
|
|
359
|
|
- threshold3: 95,
|
|
360
|
|
- score2: 15,
|
|
361
|
|
- threshold4: 80,
|
|
362
|
|
- threshold5: 90,
|
|
363
|
|
- score3: 8,
|
|
364
|
|
- threshold6: 0,
|
|
365
|
|
- threshold7: 80,
|
|
366
|
|
- score4: 0,
|
|
367
|
|
- },
|
|
368
|
|
-]);
|
|
369
|
|
-
|
|
370
|
|
-// 油站评分数据
|
|
371
|
|
-const stationScores = ref<ScoreItem[]>([
|
|
372
|
|
- {
|
|
373
|
|
- id: 1,
|
|
374
|
|
- dimension: '任务数量',
|
|
375
|
|
- indicator: '完成率',
|
|
376
|
|
- standard: '(≥ 98% :30分 区间 95% — 98% :24分 区间 90% — 95% :18分 区间 0% — 90% :0分)',
|
|
377
|
|
- score: 30,
|
|
378
|
|
- isEditing: false,
|
|
379
|
|
- threshold1: 98,
|
|
380
|
|
- score1: 30,
|
|
381
|
|
- threshold2: 95,
|
|
382
|
|
- threshold3: 98,
|
|
383
|
|
- score2: 24,
|
|
384
|
|
- threshold4: 90,
|
|
385
|
|
- threshold5: 95,
|
|
386
|
|
- score3: 18,
|
|
387
|
|
- threshold6: 0,
|
|
388
|
|
- threshold7: 90,
|
|
|
108
|
+ threshold7: 0,
|
|
389
|
109
|
score4: 0,
|
|
390
|
|
- },
|
|
391
|
|
- {
|
|
392
|
|
- id: 2,
|
|
393
|
|
- dimension: '任务质量',
|
|
394
|
|
- indicator: '任务得分',
|
|
395
|
|
- standard: '(≥ 4.5分 :20分 区间 4分 — 4.5分 :16分 区间 3分 — 4分 :12分 区间 0分 — 3分 :0分)',
|
|
396
|
|
- score: 20,
|
|
397
|
|
- isEditing: false,
|
|
398
|
|
- threshold1: 4.5,
|
|
399
|
|
- score1: 20,
|
|
400
|
|
- threshold2: 4,
|
|
401
|
|
- threshold3: 4.5,
|
|
402
|
|
- score2: 16,
|
|
403
|
|
- threshold4: 3,
|
|
404
|
|
- threshold5: 4,
|
|
405
|
|
- score3: 12,
|
|
406
|
|
- threshold6: 0,
|
|
407
|
|
- threshold7: 3,
|
|
408
|
|
- score4: 0,
|
|
409
|
|
- },
|
|
410
|
|
- {
|
|
411
|
|
- id: 3,
|
|
412
|
|
- dimension: '绩效',
|
|
413
|
|
- indicator: '最多相同分数率',
|
|
414
|
|
- standard: '(≥ 60% :0分 区间 40% — 60% :6分 区间 20% — 40% :8分 区间 0% — 20% :10分)',
|
|
415
|
|
- score: 10,
|
|
416
|
|
- isEditing: false,
|
|
417
|
|
- threshold1: 60,
|
|
418
|
|
- score1: 0,
|
|
419
|
|
- threshold2: 40,
|
|
420
|
|
- threshold3: 60,
|
|
421
|
|
- score2: 6,
|
|
422
|
|
- threshold4: 20,
|
|
423
|
|
- threshold5: 40,
|
|
424
|
|
- score3: 8,
|
|
425
|
|
- threshold6: 0,
|
|
426
|
|
- threshold7: 20,
|
|
427
|
|
- score4: 10,
|
|
428
|
|
- },
|
|
429
|
|
- {
|
|
430
|
|
- id: 4,
|
|
431
|
|
- dimension: '查阅情况',
|
|
432
|
|
- indicator: '已阅比例',
|
|
433
|
|
- standard: '(≥ 95% :15分 区间 90% — 95% :12分 区间 80% — 90% :9分 区间 0% — 80% :0分)',
|
|
434
|
|
- score: 15,
|
|
435
|
|
- isEditing: false,
|
|
436
|
|
- threshold1: 95,
|
|
437
|
|
- score1: 15,
|
|
438
|
|
- threshold2: 90,
|
|
439
|
|
- threshold3: 95,
|
|
440
|
|
- score2: 12,
|
|
441
|
|
- threshold4: 80,
|
|
442
|
|
- threshold5: 90,
|
|
443
|
|
- score3: 9,
|
|
444
|
|
- threshold6: 0,
|
|
445
|
|
- threshold7: 80,
|
|
446
|
|
- score4: 0,
|
|
447
|
|
- },
|
|
448
|
|
- {
|
|
449
|
|
- id: 5,
|
|
450
|
|
- dimension: '逾期',
|
|
451
|
|
- indicator: '逾期未完成数',
|
|
452
|
|
- standard: '(≥ 9个 :0分 区间 6个 — 9个 :5分 区间 3个 — 6个 :12分 区间 0个 — 3个 :20分)',
|
|
453
|
|
- score: 20,
|
|
454
|
|
- isEditing: false,
|
|
455
|
|
- threshold1: 9,
|
|
456
|
|
- score1: 0,
|
|
457
|
|
- threshold2: 6,
|
|
458
|
|
- threshold3: 9,
|
|
459
|
|
- score2: 5,
|
|
460
|
|
- threshold4: 3,
|
|
461
|
|
- threshold5: 6,
|
|
462
|
|
- score3: 12,
|
|
463
|
|
- threshold6: 0,
|
|
464
|
|
- threshold7: 3,
|
|
465
|
|
- score4: 20,
|
|
466
|
|
- },
|
|
467
|
|
-]);
|
|
468
|
|
-
|
|
469
|
|
-// 片区评分数据
|
|
470
|
|
-const areaScores = ref<ScoreItem[]>([
|
|
471
|
|
- {
|
|
472
|
|
- id: 1,
|
|
473
|
|
- dimension: '任务数量',
|
|
474
|
|
- indicator: '完成率',
|
|
475
|
|
- standard: '(≥ 98% :40分 区间 95% — 98% :32分 区间 90% — 95% :24分 区间 0% — 90% :0分)',
|
|
476
|
|
- score: 40,
|
|
477
|
|
- isEditing: false,
|
|
478
|
|
- threshold1: 98,
|
|
479
|
|
- score1: 40,
|
|
480
|
|
- threshold2: 95,
|
|
481
|
|
- threshold3: 98,
|
|
482
|
|
- score2: 32,
|
|
483
|
|
- threshold4: 90,
|
|
484
|
|
- threshold5: 95,
|
|
485
|
|
- score3: 24,
|
|
486
|
|
- threshold6: 0,
|
|
487
|
|
- threshold7: 90,
|
|
488
|
|
- score4: 0,
|
|
489
|
|
- },
|
|
490
|
|
- {
|
|
491
|
|
- id: 2,
|
|
492
|
|
- dimension: '任务质量',
|
|
493
|
|
- indicator: '任务得分',
|
|
494
|
|
- standard: '(≥ 4.5分 :20分 区间 4分 — 4.5分 :16分 区间 3分 — 4分 :12分 区间 0分 — 3分 :0分)',
|
|
495
|
|
- score: 20,
|
|
496
|
|
- isEditing: false,
|
|
497
|
|
- threshold1: 4.5,
|
|
498
|
|
- score1: 20,
|
|
499
|
|
- threshold2: 4,
|
|
500
|
|
- threshold3: 4.5,
|
|
501
|
|
- score2: 16,
|
|
502
|
|
- threshold4: 3,
|
|
503
|
|
- threshold5: 4,
|
|
504
|
|
- score3: 12,
|
|
505
|
|
- threshold6: 0,
|
|
506
|
|
- threshold7: 3,
|
|
507
|
|
- score4: 0,
|
|
508
|
|
- },
|
|
509
|
|
- {
|
|
510
|
|
- id: 3,
|
|
511
|
|
- dimension: '绩效',
|
|
512
|
|
- indicator: '最多相同分数率',
|
|
513
|
|
- standard: '(≥ 95% :0分 区间 90% — 95% :12分 区间 80% — 90% :9分 区间 0% — 80% :15分)',
|
|
514
|
|
- score: 15,
|
|
515
|
|
- isEditing: false,
|
|
516
|
|
- threshold1: 95,
|
|
517
|
|
- score1: 0,
|
|
518
|
|
- threshold2: 90,
|
|
519
|
|
- threshold3: 95,
|
|
520
|
|
- score2: 12,
|
|
521
|
|
- threshold4: 80,
|
|
522
|
|
- threshold5: 90,
|
|
523
|
|
- score3: 9,
|
|
524
|
|
- threshold6: 0,
|
|
525
|
|
- threshold7: 80,
|
|
526
|
|
- score4: 15,
|
|
527
|
|
- },
|
|
528
|
|
- {
|
|
529
|
|
- id: 4,
|
|
530
|
|
- dimension: '查阅情况',
|
|
531
|
|
- indicator: '已阅比例',
|
|
532
|
|
- standard: '(≥ 95% :15分 区间 90% — 95% :12分 区间 80% — 90% :9分 区间 0% — 80% :0分)',
|
|
533
|
|
- score: 15,
|
|
534
|
|
- isEditing: false,
|
|
535
|
|
- threshold1: 95,
|
|
536
|
|
- score1: 15,
|
|
537
|
|
- threshold2: 90,
|
|
538
|
|
- threshold3: 95,
|
|
539
|
|
- score2: 12,
|
|
540
|
|
- threshold4: 80,
|
|
541
|
|
- threshold5: 90,
|
|
542
|
|
- score3: 9,
|
|
543
|
|
- threshold6: 0,
|
|
544
|
|
- threshold7: 80,
|
|
545
|
|
- score4: 0,
|
|
546
|
|
- },
|
|
547
|
|
-]);
|
|
|
110
|
+ };
|
|
|
111
|
+
|
|
|
112
|
+ if (!standards || standards.length === 0) {
|
|
|
113
|
+ return defaults;
|
|
|
114
|
+ }
|
|
|
115
|
+
|
|
|
116
|
+ // 按min_value降序排序
|
|
|
117
|
+ const sortedStandards = [...standards].sort((a, b) => (b.min_value || 0) - (a.min_value || 0));
|
|
|
118
|
+
|
|
|
119
|
+ // 填充阈值和分数
|
|
|
120
|
+ return {
|
|
|
121
|
+ threshold1: sortedStandards[0]?.min_value || 0,
|
|
|
122
|
+ score1: sortedStandards[0]?.score || 0,
|
|
|
123
|
+ threshold2: sortedStandards[1]?.min_value || 0,
|
|
|
124
|
+ threshold3: sortedStandards[1]?.max_value || 0,
|
|
|
125
|
+ score2: sortedStandards[1]?.score || 0,
|
|
|
126
|
+ threshold4: sortedStandards[2]?.min_value || 0,
|
|
|
127
|
+ threshold5: sortedStandards[2]?.max_value || 0,
|
|
|
128
|
+ score3: sortedStandards[2]?.score || 0,
|
|
|
129
|
+ threshold6: sortedStandards[3]?.min_value || 0,
|
|
|
130
|
+ threshold7: sortedStandards[3]?.max_value || 0,
|
|
|
131
|
+ score4: sortedStandards[3]?.score || 0,
|
|
|
132
|
+ };
|
|
|
133
|
+};
|
|
|
134
|
+
|
|
|
135
|
+// 加载评分数据
|
|
|
136
|
+const loadScoreData = async () => {
|
|
|
137
|
+ const typeValue = getCurrentTypeValue();
|
|
|
138
|
+ if (!typeValue) return;
|
|
|
139
|
+
|
|
|
140
|
+ loading.value = true;
|
|
|
141
|
+ try {
|
|
|
142
|
+ const response = await scoreEntryList({ type: typeValue });
|
|
|
143
|
+ console.log('原始响应:', response);
|
|
|
144
|
+ if (response.rows) {
|
|
|
145
|
+ scoreData.value = response.rows.map((item: any) => {
|
|
|
146
|
+ const standards = parseStandardJson(item.standardJson);
|
|
|
147
|
+ const thresholds = formatStandardsToThresholds(standards);
|
|
|
148
|
+ return {
|
|
|
149
|
+ ...item,
|
|
|
150
|
+ standards,
|
|
|
151
|
+ isEditing: false,
|
|
|
152
|
+ ...thresholds,
|
|
|
153
|
+ };
|
|
|
154
|
+ });
|
|
|
155
|
+ }
|
|
|
156
|
+ } catch (error) {
|
|
|
157
|
+ console.error('加载评分数据失败:', error);
|
|
|
158
|
+ } finally {
|
|
|
159
|
+ loading.value = false;
|
|
|
160
|
+ }
|
|
|
161
|
+};
|
|
|
162
|
+
|
|
|
163
|
+// 监听tab切换,重新加载数据
|
|
|
164
|
+const handleTabChange = () => {
|
|
|
165
|
+ loadScoreData();
|
|
|
166
|
+};
|
|
548
|
167
|
|
|
549
|
168
|
// 计算当前选中的评分数据
|
|
550
|
169
|
const currentScores = computed(() => {
|
|
551
|
|
- switch (activeTab.value) {
|
|
552
|
|
- case 'stationManager':
|
|
553
|
|
- return stationManagerScores.value;
|
|
554
|
|
- case 'stationStaff':
|
|
555
|
|
- return stationStaffScores.value;
|
|
556
|
|
- case 'areaStaff':
|
|
557
|
|
- return areaStaffScores.value;
|
|
558
|
|
- case 'headquarters':
|
|
559
|
|
- return headquartersScores.value;
|
|
560
|
|
- case 'station':
|
|
561
|
|
- return stationScores.value;
|
|
562
|
|
- case 'area':
|
|
563
|
|
- return areaScores.value;
|
|
564
|
|
- default:
|
|
565
|
|
- return [];
|
|
566
|
|
- }
|
|
|
170
|
+ return scoreData.value;
|
|
567
|
171
|
});
|
|
568
|
172
|
|
|
|
173
|
+// 初始化数据
|
|
|
174
|
+onMounted(async () => {
|
|
|
175
|
+ // 加载数据字典
|
|
|
176
|
+ typeOptions.value = getDictOptions("score_standard_type");
|
|
|
177
|
+ dimensionOptions.value = getDictOptions("score_standard_dimension");
|
|
|
178
|
+ indicatorOptions.value = getDictOptions("score_standard_indicator");
|
|
|
179
|
+
|
|
|
180
|
+ // 加载初始数据
|
|
|
181
|
+ await loadScoreData();
|
|
|
182
|
+});
|
|
|
183
|
+
|
|
|
184
|
+
|
|
|
185
|
+
|
|
|
186
|
+
|
|
|
187
|
+
|
|
|
188
|
+
|
|
|
189
|
+
|
|
|
190
|
+
|
|
|
191
|
+
|
|
|
192
|
+
|
|
|
193
|
+
|
|
|
194
|
+
|
|
|
195
|
+
|
|
|
196
|
+
|
|
|
197
|
+
|
|
569
|
198
|
// 计算需要合并的行
|
|
570
|
199
|
const getRowspan = (scores: ScoreItem[], index: number): number => {
|
|
571
|
|
- const currentDimension = scores[index].dimension;
|
|
|
200
|
+ const currentDimension = scores[index].dimensionName;
|
|
572
|
201
|
let rowspan = 1;
|
|
573
|
202
|
for (let i = index + 1; i < scores.length; i++) {
|
|
574
|
|
- if (scores[i].dimension === currentDimension) {
|
|
|
203
|
+ if (scores[i].dimensionName === currentDimension) {
|
|
575
|
204
|
rowspan++;
|
|
576
|
205
|
} else {
|
|
577
|
206
|
break;
|
|
|
@@ -585,10 +214,10 @@ const tableSpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
|
|
585
|
214
|
// 只处理维度列的合并
|
|
586
|
215
|
if (columnIndex === 0) {
|
|
587
|
216
|
const scores = currentScores.value;
|
|
588
|
|
- const currentDimension = scores[rowIndex].dimension;
|
|
|
217
|
+ const currentDimension = scores[rowIndex].dimensionName;
|
|
589
|
218
|
|
|
590
|
219
|
// 检查当前行是否是连续相同维度行的第一行
|
|
591
|
|
- if (rowIndex === 0 || scores[rowIndex - 1].dimension !== currentDimension) {
|
|
|
220
|
+ if (rowIndex === 0 || scores[rowIndex - 1].dimensionName !== currentDimension) {
|
|
592
|
221
|
const rowspan = getRowspan(scores, rowIndex);
|
|
593
|
222
|
return [rowspan, 1];
|
|
594
|
223
|
} else {
|
|
|
@@ -601,7 +230,7 @@ const tableSpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
|
|
601
|
230
|
|
|
602
|
231
|
// 事件处理函数
|
|
603
|
232
|
// 编辑按钮点击事件
|
|
604
|
|
-const handleEdit = (id: number) => {
|
|
|
233
|
+const handleEdit = (id: string) => {
|
|
605
|
234
|
const scores = currentScores.value;
|
|
606
|
235
|
const item = scores.find(item => item.id === id);
|
|
607
|
236
|
if (item) {
|
|
|
@@ -610,13 +239,55 @@ const handleEdit = (id: number) => {
|
|
610
|
239
|
};
|
|
611
|
240
|
|
|
612
|
241
|
// 保存按钮点击事件
|
|
613
|
|
-const handleSave = (id: number) => {
|
|
|
242
|
+const handleSave = async (id: string) => {
|
|
614
|
243
|
const scores = currentScores.value;
|
|
615
|
244
|
const item = scores.find(item => item.id === id);
|
|
616
|
245
|
if (item) {
|
|
617
|
|
- // 更新standard字段以保持数据一致性
|
|
618
|
|
- item.standard = `≥ ${item.threshold1}% :${item.score1}分 区间 ${item.threshold2}% — ${item.threshold3}% :${item.score2}分 区间 ${item.threshold4}% — ${item.threshold5}% :${item.score3}分 区间 ${item.threshold6}% — ${item.threshold7}% :${item.score4}分`;
|
|
619
|
|
- item.isEditing = false;
|
|
|
246
|
+ // 生成新的standardJson
|
|
|
247
|
+ const standards = [
|
|
|
248
|
+ {
|
|
|
249
|
+ score: item.score1,
|
|
|
250
|
+ condition: `≥${item.threshold1}%`,
|
|
|
251
|
+ min_value: item.threshold1,
|
|
|
252
|
+ max_value: null
|
|
|
253
|
+ },
|
|
|
254
|
+ {
|
|
|
255
|
+ score: item.score2,
|
|
|
256
|
+ condition: `${item.threshold2}%—${item.threshold3}%`,
|
|
|
257
|
+ min_value: item.threshold2,
|
|
|
258
|
+ max_value: item.threshold3
|
|
|
259
|
+ },
|
|
|
260
|
+ {
|
|
|
261
|
+ score: item.score3,
|
|
|
262
|
+ condition: `${item.threshold4}%—${item.threshold5}%`,
|
|
|
263
|
+ min_value: item.threshold4,
|
|
|
264
|
+ max_value: item.threshold5
|
|
|
265
|
+ },
|
|
|
266
|
+ {
|
|
|
267
|
+ score: item.score4,
|
|
|
268
|
+ condition: `${item.threshold6}%—${item.threshold7}%`,
|
|
|
269
|
+ min_value: item.threshold6,
|
|
|
270
|
+ max_value: item.threshold7
|
|
|
271
|
+ }
|
|
|
272
|
+ ];
|
|
|
273
|
+
|
|
|
274
|
+ const updatedItem = {
|
|
|
275
|
+ id: item.id,
|
|
|
276
|
+ type: item.type,
|
|
|
277
|
+ dimension: item.dimension,
|
|
|
278
|
+ indicator: item.indicator,
|
|
|
279
|
+ standardJson: JSON.stringify({ standards })
|
|
|
280
|
+ };
|
|
|
281
|
+
|
|
|
282
|
+ try {
|
|
|
283
|
+ const response = await updateScoreEntry(updatedItem);
|
|
|
284
|
+ console.log('更新响应:', response);
|
|
|
285
|
+ item.isEditing = false;
|
|
|
286
|
+ // 重新加载数据以确保一致性
|
|
|
287
|
+ await loadScoreData();
|
|
|
288
|
+ } catch (error) {
|
|
|
289
|
+ console.error('保存失败:', error);
|
|
|
290
|
+ }
|
|
620
|
291
|
}
|
|
621
|
292
|
};
|
|
622
|
293
|
|
|
|
@@ -627,13 +298,13 @@ const handleSave = (id: number) => {
|
|
627
|
298
|
<div class="score-entry">
|
|
628
|
299
|
<!-- Tab切换区域 -->
|
|
629
|
300
|
<div class="tab-container">
|
|
630
|
|
- <ElTabs v-model="activeTab">
|
|
|
301
|
+ <ElTabs v-model="activeTab" @tab-click="handleTabChange">
|
|
631
|
302
|
<ElTabPane v-for="tab in tabOptions" :key="tab.value" :label="tab.label" :name="tab.value">
|
|
632
|
303
|
<!-- 评分表格 -->
|
|
633
|
304
|
<div class="score-table-container">
|
|
634
|
305
|
<ElTable :data="currentScores" border stripe style="width: 100%" :span-method="tableSpanMethod">
|
|
635
|
|
- <ElTableColumn prop="dimension" label="维度" width="150" />
|
|
636
|
|
- <ElTableColumn prop="indicator" label="指标" width="180" />
|
|
|
306
|
+ <ElTableColumn prop="dimensionName" label="维度" width="150" />
|
|
|
307
|
+ <ElTableColumn prop="indicatorName" label="指标" width="180" />
|
|
637
|
308
|
<ElTableColumn label="标准及分值">
|
|
638
|
309
|
<template #default="scope">
|
|
639
|
310
|
<div v-if="scope.row.isEditing" class="standard-edit">
|