Kaynağa Gözat

任务报表

miaofuhao 2 ay önce
ebeveyn
işleme
31b77a3c1d

+ 751 - 10
apps/web-ele/src/views/operationRadar/taskReport/districtPersonnelReport/index.vue

@@ -1,17 +1,758 @@
1 1
 <script lang="ts" setup>
2
+// 导入部分
3
+import type { VxeGridProps } from '#/adapter/vxe-table';
4
+
5
+import { onMounted, ref, watch } from 'vue';
6
+
2 7
 import { Page } from '@vben/common-ui';
8
+
9
+import {
10
+  ElButton,
11
+  ElRadioButton,
12
+  ElRadioGroup,
13
+  ElSelect,
14
+  ElSpace,
15
+} from 'element-plus';
16
+
17
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
18
+
19
+// 类型定义
20
+interface ReportTypeOption {
21
+  label: string;
22
+  value: 'evaluation' | 'full-indicator';
23
+}
24
+
25
+interface PeriodTypeOption {
26
+  label: string;
27
+  value: 'month' | 'week';
28
+}
29
+
30
+interface TaskReportData {
31
+  id: number;
32
+  name: string;
33
+  district: string;
34
+  totalScore: number;
35
+  completionRate: {
36
+    ratio: string;
37
+    score: number;
38
+  };
39
+  taskScore: {
40
+    obtainedScore: number;
41
+    score: number;
42
+  };
43
+  readRate: {
44
+    ratio: string;
45
+    score: number;
46
+  };
47
+  maxSameScoreRate: {
48
+    ratio: string;
49
+    score: number;
50
+  };
51
+  overdueCount: {
52
+    count: number;
53
+    score: number;
54
+  };
55
+}
56
+
57
+// 全指标报表数据类型
58
+interface FullIndicatorReportData {
59
+  id: number;
60
+  name: string;
61
+  district: string;
62
+  // 任务数量
63
+  taskQuantity: {
64
+    authorizedRate: string;
65
+    completedOnTime: number;
66
+    completedOverdue: number;
67
+    newTaskRate: string;
68
+    notCompleted: number;
69
+    overdueRate: string;
70
+    totalCompletionRate: string;
71
+    totalTasks: number;
72
+  };
73
+  // 任务质量
74
+  taskQuality: {
75
+    commentCount: number;
76
+    ledgerAverage: number;
77
+    taskScore: number;
78
+  };
79
+  // 授权
80
+  authorization: {
81
+    authorizationComments: number;
82
+    authorizedCount: number;
83
+    authorizedRate: string;
84
+  };
85
+  // 查阅
86
+  查阅: {
87
+    readableCount: number;
88
+    readCount: number;
89
+    readRate: string;
90
+    查阅Count: number;
91
+  };
92
+  // 绩效
93
+  performance: {
94
+    maxSameScoreRate: string;
95
+    performanceCommentRate: string;
96
+  };
97
+}
98
+
99
+// 响应式数据
100
+// 报表类型切换
101
+const reportType = ref<'evaluation' | 'full-indicator'>('evaluation');
102
+const reportTypeOptions: ReportTypeOption[] = [
103
+  { label: '任务评估报表', value: 'evaluation' },
104
+  { label: '任务全指标报表', value: 'full-indicator' },
105
+];
106
+
107
+// 时间类型切换
108
+const periodType = ref<'month' | 'week'>('week');
109
+const periodTypeOptions: PeriodTypeOption[] = [
110
+  { label: '周', value: 'week' },
111
+  { label: '月', value: 'month' },
112
+];
113
+const currentPeriod = ref('11月13日-11月19日');
114
+
115
+// 搜索条件
116
+const selectedName = ref<string>('');
117
+const nameOptions = ref<{ label: string; value: string }[]>([
118
+  { label: '李经理', value: '李经理' },
119
+  { label: '王经理', value: '王经理' },
120
+  { label: '张经理', value: '张经理' },
121
+  { label: '刘经理', value: '刘经理' },
122
+]);
123
+
124
+// 辅助函数
125
+// 格式化日期为中文格式(MM月dd日)
126
+const formatDate = (date: Date): string => {
127
+  const month = date.getMonth() + 1;
128
+  const day = date.getDate();
129
+  return `${month}月${day}日`;
130
+};
131
+
132
+// 更新时间范围的函数
133
+const updateTimeRange = (type: 'month' | 'week'): void => {
134
+  const today = new Date();
135
+  let startDate: Date;
136
+  const endDate = today;
137
+
138
+  if (type === 'week') {
139
+    // 计算最近一周(今天往前推7天)
140
+    startDate = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
141
+    currentPeriod.value = `${formatDate(startDate)}-${formatDate(endDate)}`;
142
+  } else {
143
+    // 计算最近一个月(上个月的今天到今天)
144
+    startDate = new Date(
145
+      today.getFullYear(),
146
+      today.getMonth() - 1,
147
+      today.getDate(),
148
+    );
149
+    currentPeriod.value = `${formatDate(startDate)}-${formatDate(endDate)}`;
150
+  }
151
+};
152
+
153
+// 重置搜索条件
154
+const resetSearch = () => {
155
+  periodType.value = 'week';
156
+  selectedName.value = '';
157
+  updateTimeRange(periodType.value);
158
+};
159
+
160
+// 虚拟数据
161
+const MOCK_DATA: TaskReportData[] = [
162
+  {
163
+    id: 1,
164
+    name: '李经理',
165
+    district: '默认片区',
166
+    totalScore: 44,
167
+    completionRate: { ratio: '95.52%', score: 24 },
168
+    taskScore: { score: 0, obtainedScore: 0 },
169
+    readRate: { ratio: '0.00%', score: 0 },
170
+    maxSameScoreRate: { ratio: '56.11%', score: 8 },
171
+    overdueCount: { count: 3, score: 12 },
172
+  },
173
+  {
174
+    id: 2,
175
+    name: '王经理',
176
+    district: '片区1',
177
+    totalScore: 8,
178
+    completionRate: { ratio: '77.14%', score: 0 },
179
+    taskScore: { score: 0, obtainedScore: 0 },
180
+    readRate: { ratio: '0.00%', score: 0 },
181
+    maxSameScoreRate: { ratio: '25%', score: 8 },
182
+    overdueCount: { count: 16, score: 0 },
183
+  },
184
+  {
185
+    id: 3,
186
+    name: '张经理',
187
+    district: '片区2',
188
+    totalScore: 50,
189
+    completionRate: { ratio: '100%', score: 25 },
190
+    taskScore: { score: 0, obtainedScore: 0 },
191
+    readRate: { ratio: '50.00%', score: 0 },
192
+    maxSameScoreRate: { ratio: '33.33%', score: 10 },
193
+    overdueCount: { count: 0, score: 15 },
194
+  },
195
+  {
196
+    id: 4,
197
+    name: '刘经理',
198
+    district: '片区3',
199
+    totalScore: 38,
200
+    completionRate: { ratio: '90.00%', score: 22 },
201
+    taskScore: { score: 0, obtainedScore: 0 },
202
+    readRate: { ratio: '33.33%', score: 0 },
203
+    maxSameScoreRate: { ratio: '66.67%', score: 6 },
204
+    overdueCount: { count: 2, score: 10 },
205
+  },
206
+];
207
+
208
+// 任务全指标报表虚拟数据
209
+const FULL_INDICATOR_MOCK_DATA: FullIndicatorReportData[] = [
210
+  {
211
+    id: 1,
212
+    name: '李经理',
213
+    district: '默认片区',
214
+    taskQuantity: {
215
+      totalTasks: 52,
216
+      completedOnTime: 48,
217
+      completedOverdue: 3,
218
+      notCompleted: 1,
219
+      totalCompletionRate: '98.08%',
220
+      overdueRate: '5.77%',
221
+      authorizedRate: '2.5%',
222
+      newTaskRate: '1.92%',
223
+    },
224
+    taskQuality: {
225
+      commentCount: 12,
226
+      taskScore: 4.5,
227
+      ledgerAverage: 85.5,
228
+    },
229
+    authorization: {
230
+      authorizedCount: 1,
231
+      authorizedRate: '1.92%',
232
+      authorizationComments: 0,
233
+    },
234
+    查阅: {
235
+      readableCount: 51,
236
+      readCount: 0,
237
+      readRate: '0.00%',
238
+      查阅Count: 2,
239
+    },
240
+    performance: {
241
+      maxSameScoreRate: '25%',
242
+      performanceCommentRate: '16.67%',
243
+    },
244
+  },
245
+  {
246
+    id: 2,
247
+    name: '王经理',
248
+    district: '片区1',
249
+    taskQuantity: {
250
+      totalTasks: 67,
251
+      completedOnTime: 58,
252
+      completedOverdue: 8,
253
+      notCompleted: 1,
254
+      totalCompletionRate: '98.51%',
255
+      overdueRate: '11.94%',
256
+      authorizedRate: '33.33%',
257
+      newTaskRate: '1.49%',
258
+    },
259
+    taskQuality: {
260
+      commentCount: 8,
261
+      taskScore: 4.2,
262
+      ledgerAverage: 88.2,
263
+    },
264
+    authorization: {
265
+      authorizedCount: 11,
266
+      authorizedRate: '16.42%',
267
+      authorizationComments: 3,
268
+    },
269
+    查阅: {
270
+      readableCount: 80,
271
+      readCount: 0,
272
+      readRate: '0.00%',
273
+      查阅Count: 1,
274
+    },
275
+    performance: {
276
+      maxSameScoreRate: '36.11%',
277
+      performanceCommentRate: '8.33%',
278
+    },
279
+  },
280
+];
281
+
282
+// 任务评估报表表格配置
283
+const taskReportColumns: VxeGridProps['columns'] = [
284
+  {
285
+    title: '姓名',
286
+    field: 'name',
287
+    minWidth: 120,
288
+    align: 'center',
289
+  },
290
+  { title: '片区', field: 'district', minWidth: 150, align: 'center' },
291
+  { title: '总分', field: 'totalScore', minWidth: 80, align: 'center' },
292
+  {
293
+    title: '完成率',
294
+    minWidth: 150,
295
+    align: 'center',
296
+    children: [
297
+      {
298
+        title: '比例',
299
+        field: 'completionRate.ratio',
300
+        minWidth: 80,
301
+        align: 'center',
302
+      },
303
+      {
304
+        title: '得分',
305
+        field: 'completionRate.score',
306
+        minWidth: 70,
307
+        align: 'center',
308
+      },
309
+    ],
310
+  },
311
+  {
312
+    title: '任务得分',
313
+    minWidth: 150,
314
+    align: 'center',
315
+    children: [
316
+      {
317
+        title: '分数',
318
+        field: 'taskScore.score',
319
+        minWidth: 80,
320
+        align: 'center',
321
+      },
322
+      {
323
+        title: '得分',
324
+        field: 'taskScore.obtainedScore',
325
+        minWidth: 70,
326
+        align: 'center',
327
+      },
328
+    ],
329
+  },
330
+  {
331
+    title: '已阅比例',
332
+    minWidth: 150,
333
+    align: 'center',
334
+    children: [
335
+      { title: '比例', field: 'readRate.ratio', minWidth: 80, align: 'center' },
336
+      { title: '得分', field: 'readRate.score', minWidth: 70, align: 'center' },
337
+    ],
338
+  },
339
+  {
340
+    title: '最多相同分数率',
341
+    minWidth: 180,
342
+    align: 'center',
343
+    children: [
344
+      {
345
+        title: '比例',
346
+        field: 'maxSameScoreRate.ratio',
347
+        minWidth: 100,
348
+        align: 'center',
349
+      },
350
+      {
351
+        title: '得分',
352
+        field: 'maxSameScoreRate.score',
353
+        minWidth: 80,
354
+        align: 'center',
355
+      },
356
+    ],
357
+  },
358
+  {
359
+    title: '逾期未完成数',
360
+    minWidth: 180,
361
+    align: 'center',
362
+    children: [
363
+      {
364
+        title: '过期数量',
365
+        field: 'overdueCount.count',
366
+        minWidth: 100,
367
+        align: 'center',
368
+      },
369
+      {
370
+        title: '过期分数',
371
+        field: 'overdueCount.score',
372
+        minWidth: 80,
373
+        align: 'center',
374
+      },
375
+    ],
376
+  },
377
+];
378
+
379
+const taskReportGridOptions: VxeGridProps = {
380
+  columns: taskReportColumns,
381
+  size: 'medium',
382
+  height: '500px',
383
+  useSearchForm: false,
384
+  proxyConfig: {
385
+    enabled: true,
386
+    autoLoad: true,
387
+    ajax: {
388
+      query: async () => {
389
+        return { items: MOCK_DATA, total: MOCK_DATA.length };
390
+      },
391
+    },
392
+  },
393
+  rowConfig: { keyField: 'id' },
394
+  toolbarConfig: {},
395
+  id: 'task-report-table',
396
+};
397
+
398
+// 任务全指标报表表格配置
399
+const fullIndicatorReportColumns: VxeGridProps['columns'] = [
400
+  {
401
+    title: '姓名',
402
+    field: 'name',
403
+    minWidth: 120,
404
+    align: 'center',
405
+    fixed: 'left',
406
+  },
407
+  {
408
+    title: '片区',
409
+    field: 'district',
410
+    minWidth: 150,
411
+    align: 'center',
412
+    fixed: 'left',
413
+  },
414
+  {
415
+    title: '任务数量',
416
+    minWidth: 400,
417
+    align: 'center',
418
+    children: [
419
+      {
420
+        title: '任务数',
421
+        field: 'taskQuantity.totalTasks',
422
+        minWidth: 80,
423
+        align: 'center',
424
+      },
425
+      {
426
+        title: '按时完成',
427
+        field: 'taskQuantity.completedOnTime',
428
+        minWidth: 80,
429
+        align: 'center',
430
+      },
431
+      {
432
+        title: '逾期完成',
433
+        field: 'taskQuantity.completedOverdue',
434
+        minWidth: 80,
435
+        align: 'center',
436
+      },
437
+      {
438
+        title: '过期未完成',
439
+        field: 'taskQuantity.notCompleted',
440
+        minWidth: 90,
441
+        align: 'center',
442
+      },
443
+      {
444
+        title: '总完成率',
445
+        field: 'taskQuantity.totalCompletionRate',
446
+        minWidth: 80,
447
+        align: 'center',
448
+      },
449
+      {
450
+        title: '逾期率',
451
+        field: 'taskQuantity.overdueRate',
452
+        minWidth: 80,
453
+        align: 'center',
454
+      },
455
+      {
456
+        title: '被授权率',
457
+        field: 'taskQuantity.authorizedRate',
458
+        minWidth: 80,
459
+        align: 'center',
460
+      },
461
+      {
462
+        title: '新增任务率',
463
+        field: 'taskQuantity.newTaskRate',
464
+        minWidth: 80,
465
+        align: 'center',
466
+      },
467
+    ],
468
+  },
469
+  {
470
+    title: '任务质量',
471
+    minWidth: 250,
472
+    align: 'center',
473
+    children: [
474
+      {
475
+        title: '收到的点评数',
476
+        field: 'taskQuality.commentCount',
477
+        minWidth: 100,
478
+        align: 'center',
479
+      },
480
+      {
481
+        title: '任务得分',
482
+        field: 'taskQuality.taskScore',
483
+        minWidth: 80,
484
+        align: 'center',
485
+      },
486
+      {
487
+        title: '台账平均数',
488
+        field: 'taskQuality.ledgerAverage',
489
+        minWidth: 80,
490
+        align: 'center',
491
+      },
492
+    ],
493
+  },
494
+  {
495
+    title: '授权',
496
+    minWidth: 250,
497
+    align: 'center',
498
+    children: [
499
+      {
500
+        title: '已授权',
501
+        field: 'authorization.authorizedCount',
502
+        minWidth: 80,
503
+        align: 'center',
504
+      },
505
+      {
506
+        title: '已授权率',
507
+        field: 'authorization.authorizedRate',
508
+        minWidth: 80,
509
+        align: 'center',
510
+      },
511
+      {
512
+        title: '授权点评',
513
+        field: 'authorization.authorizationComments',
514
+        minWidth: 80,
515
+        align: 'center',
516
+      },
517
+    ],
518
+  },
519
+  {
520
+    title: '查阅',
521
+    minWidth: 300,
522
+    align: 'center',
523
+    children: [
524
+      {
525
+        title: '可阅读',
526
+        field: '查阅.readableCount',
527
+        minWidth: 80,
528
+        align: 'center',
529
+      },
530
+      {
531
+        title: '已阅读',
532
+        field: '查阅.readCount',
533
+        minWidth: 80,
534
+        align: 'center',
535
+      },
536
+      {
537
+        title: '已阅读率',
538
+        field: '查阅.readRate',
539
+        minWidth: 80,
540
+        align: 'center',
541
+      },
542
+      {
543
+        title: '被查阅数',
544
+        field: '查阅.查阅Count',
545
+        minWidth: 80,
546
+        align: 'center',
547
+      },
548
+    ],
549
+  },
550
+  {
551
+    title: '绩效',
552
+    minWidth: 250,
553
+    align: 'center',
554
+    children: [
555
+      {
556
+        title: '最多相同分数率',
557
+        field: 'performance.maxSameScoreRate',
558
+        minWidth: 100,
559
+        align: 'center',
560
+      },
561
+      {
562
+        title: '绩效评语率',
563
+        field: 'performance.performanceCommentRate',
564
+        minWidth: 100,
565
+        align: 'center',
566
+      },
567
+    ],
568
+  },
569
+];
570
+
571
+const fullIndicatorReportGridOptions: VxeGridProps = {
572
+  columns: fullIndicatorReportColumns,
573
+  size: 'medium',
574
+  height: '500px',
575
+  useSearchForm: false,
576
+  proxyConfig: {
577
+    enabled: true,
578
+    autoLoad: true,
579
+    ajax: {
580
+      query: async () => {
581
+        return {
582
+          items: FULL_INDICATOR_MOCK_DATA,
583
+          total: FULL_INDICATOR_MOCK_DATA.length,
584
+        };
585
+      },
586
+    },
587
+  },
588
+  rowConfig: { keyField: 'id' },
589
+  toolbarConfig: {},
590
+  id: 'full-indicator-report-table',
591
+  scrollX: true,
592
+  scrollY: true,
593
+};
594
+
595
+// 创建表格实例
596
+const [TaskReportTable] = useVbenVxeGrid({
597
+  gridOptions: taskReportGridOptions,
598
+});
599
+const [FullIndicatorReportTable] = useVbenVxeGrid({
600
+  gridOptions: fullIndicatorReportGridOptions,
601
+});
602
+
603
+// 事件处理函数
604
+// 查询按钮点击事件
605
+const handleQuery = () => {
606
+  console.log('查询条件:', {
607
+    reportType: reportType.value,
608
+    periodType: periodType.value,
609
+    period: currentPeriod.value,
610
+    name: selectedName.value,
611
+  });
612
+  // TODO: 这里可以添加实际的查询逻辑,调用API获取真实数据
613
+};
614
+
615
+// 重置按钮点击事件
616
+const handleReset = () => {
617
+  resetSearch();
618
+  console.log('重置搜索条件');
619
+};
620
+
621
+// 导出按钮点击事件
622
+const handleExport = () => {
623
+  console.log('导出数据');
624
+  // TODO: 这里可以添加导出逻辑
625
+};
626
+
627
+// 生命周期钩子和监听
628
+// 监听时间类型变化 - 更新当前时段显示
629
+watch(periodType, (newType) => {
630
+  updateTimeRange(newType);
631
+});
632
+
633
+// 组件初始化 - 设置默认时间范围
634
+onMounted(() => {
635
+  updateTimeRange(periodType.value);
636
+});
3 637
 </script>
638
+
4 639
 <template>
5
-<Page>
6
-<div class="wrap">
7
-         空空如也
8
-</div>
9
-</Page>
640
+  <Page :auto-content-height="true">
641
+    <div class="task-report-container">
642
+      <!-- 报表类型切换 -->
643
+      <div class="report-type-container">
644
+        <ElRadioGroup v-model="reportType" size="large">
645
+          <ElRadioButton
646
+            v-for="option in reportTypeOptions"
647
+            :key="option.value"
648
+            :label="option.value"
649
+          >
650
+            {{ option.label }}
651
+          </ElRadioButton>
652
+        </ElRadioGroup>
653
+      </div>
654
+
655
+      <!-- 搜索区域 -->
656
+      <div class="search-container">
657
+        <ElSpace>
658
+          <div class="search-item">
659
+            <label style="width: 80px">姓名:</label>
660
+            <ElSelect
661
+              v-model="selectedName"
662
+              placeholder="请选择姓名"
663
+              clearable
664
+              filterable
665
+              :options="nameOptions"
666
+            />
667
+          </div>
668
+          <div class="search-item">
669
+            <ElRadioGroup v-model="periodType" size="large">
670
+              <ElRadioButton
671
+                v-for="option in periodTypeOptions"
672
+                :key="option.value"
673
+                :label="option.value"
674
+              >
675
+                {{ option.label }}
676
+              </ElRadioButton>
677
+            </ElRadioGroup>
678
+          </div>
679
+          <div class="search-item">
680
+            <span>{{ currentPeriod }}</span>
681
+          </div>
682
+        </ElSpace>
683
+      </div>
684
+
685
+      <!-- 操作按钮区域 -->
686
+      <div class="button-container">
687
+        <ElSpace>
688
+          <ElButton type="primary" @click="handleQuery">查询</ElButton>
689
+          <ElButton @click="handleReset">重置</ElButton>
690
+          <ElButton @click="handleExport">导出</ElButton>
691
+        </ElSpace>
692
+      </div>
693
+
694
+      <!-- 报表提示语 -->
695
+      <div class="notice-container">
696
+        <p>数据周期:次周周三早9点自动生成,按周切片,次周日早9点自动生成。</p>
697
+      </div>
698
+
699
+      <!-- 报表数据表格 -->
700
+      <div class="table-container">
701
+        <TaskReportTable v-if="reportType === 'evaluation'" />
702
+        <FullIndicatorReportTable v-else />
703
+      </div>
704
+    </div>
705
+  </Page>
10 706
 </template>
11
-<style lang="scss" scoped>
12
-.wrap {
13
-padding: 16px;
14
-background-color: #fff;
15
-border-radius: 6px;
707
+
708
+<style scoped lang="scss">
709
+.task-report-container {
710
+  min-height: calc(100vh - 120px);
711
+  padding: 16px;
712
+  background-color: #fff;
713
+
714
+  .report-type-container {
715
+    margin-bottom: 16px;
716
+  }
717
+
718
+  .search-container {
719
+    display: flex;
720
+    align-items: center;
721
+    padding: 16px;
722
+    margin-bottom: 16px;
723
+    border-radius: 6px;
724
+
725
+    .search-item {
726
+      display: flex;
727
+      align-items: center;
728
+
729
+      label {
730
+        margin-right: 8px;
731
+        font-weight: 500;
732
+      }
733
+    }
734
+  }
735
+
736
+  .button-container {
737
+    margin-bottom: 16px;
738
+  }
739
+
740
+  .notice-container {
741
+    padding: 12px 16px;
742
+    margin-bottom: 16px;
743
+    font-size: 14px;
744
+    color: #606266;
745
+    background-color: #f0f5ff;
746
+    border-left: 4px solid #409eff;
747
+    border-radius: 4px;
748
+
749
+    p {
750
+      margin: 0;
751
+    }
752
+  }
753
+
754
+  .table-container {
755
+    width: 100%;
756
+  }
16 757
 }
17 758
 </style>

+ 724 - 10
apps/web-ele/src/views/operationRadar/taskReport/districtReport/index.vue

@@ -1,17 +1,731 @@
1 1
 <script lang="ts" setup>
2
+// 导入部分
3
+import type { VxeGridProps } from '#/adapter/vxe-table';
4
+
5
+import { onMounted, ref, watch } from 'vue';
6
+
2 7
 import { Page } from '@vben/common-ui';
8
+
9
+import { ElButton, ElRadioButton, ElRadioGroup, ElSpace } from 'element-plus';
10
+
11
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
12
+
13
+// 类型定义
14
+interface ReportTypeOption {
15
+  label: string;
16
+  value: 'evaluation' | 'full-indicator';
17
+}
18
+
19
+interface PeriodTypeOption {
20
+  label: string;
21
+  value: 'month' | 'week';
22
+}
23
+
24
+interface TaskReportData {
25
+  id: number;
26
+  district: string;
27
+  districtManager: string;
28
+  totalScore: number;
29
+  completionRate: {
30
+    ratio: string;
31
+    score: number;
32
+  };
33
+  taskScore: {
34
+    obtainedScore: number;
35
+    score: number;
36
+  };
37
+  readRate: {
38
+    ratio: string;
39
+    score: number;
40
+  };
41
+  maxSameScoreRate: {
42
+    ratio: string;
43
+    score: number;
44
+  };
45
+  overdueCount: {
46
+    count: number;
47
+    score: number;
48
+  };
49
+}
50
+
51
+// 全指标报表数据类型
52
+interface FullIndicatorReportData {
53
+  id: number;
54
+  district: string;
55
+  districtManager: string;
56
+  // 任务数量
57
+  taskQuantity: {
58
+    authorizedRate: string;
59
+    completedOnTime: number;
60
+    completedOverdue: number;
61
+    newTaskRate: string;
62
+    notCompleted: number;
63
+    overdueRate: string;
64
+    totalCompletionRate: string;
65
+    totalTasks: number;
66
+  };
67
+  // 任务质量
68
+  taskQuality: {
69
+    commentCount: number;
70
+    ledgerAverage: number;
71
+    taskScore: number;
72
+  };
73
+  // 授权
74
+  authorization: {
75
+    authorizationComments: number;
76
+    authorizedCount: number;
77
+    authorizedRate: string;
78
+  };
79
+  // 查阅
80
+  查阅: {
81
+    readableCount: number;
82
+    readCount: number;
83
+    readRate: string;
84
+    查阅Count: number;
85
+  };
86
+  // 绩效
87
+  performance: {
88
+    maxSameScoreRate: string;
89
+    performanceCommentRate: string;
90
+  };
91
+}
92
+
93
+// 响应式数据
94
+// 报表类型切换
95
+const reportType = ref<'evaluation' | 'full-indicator'>('evaluation');
96
+const reportTypeOptions: ReportTypeOption[] = [
97
+  { label: '任务评估报表', value: 'evaluation' },
98
+  { label: '任务全指标报表', value: 'full-indicator' },
99
+];
100
+
101
+// 时间类型切换
102
+const periodType = ref<'month' | 'week'>('week');
103
+const periodTypeOptions: PeriodTypeOption[] = [
104
+  { label: '周', value: 'week' },
105
+  { label: '月', value: 'month' },
106
+];
107
+const currentPeriod = ref('11月13日-11月19日');
108
+
109
+// 辅助函数
110
+// 格式化日期为中文格式(MM月dd日)
111
+const formatDate = (date: Date): string => {
112
+  const month = date.getMonth() + 1;
113
+  const day = date.getDate();
114
+  return `${month}月${day}日`;
115
+};
116
+
117
+// 更新时间范围的函数
118
+const updateTimeRange = (type: 'month' | 'week'): void => {
119
+  const today = new Date();
120
+  let startDate: Date;
121
+  const endDate = today;
122
+
123
+  if (type === 'week') {
124
+    // 计算最近一周(今天往前推7天)
125
+    startDate = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
126
+    currentPeriod.value = `${formatDate(startDate)}-${formatDate(endDate)}`;
127
+  } else {
128
+    // 计算最近一个月(上个月的今天到今天)
129
+    startDate = new Date(
130
+      today.getFullYear(),
131
+      today.getMonth() - 1,
132
+      today.getDate(),
133
+    );
134
+    currentPeriod.value = `${formatDate(startDate)}-${formatDate(endDate)}`;
135
+  }
136
+};
137
+
138
+// 重置搜索条件
139
+const resetSearch = () => {
140
+  periodType.value = 'week';
141
+  updateTimeRange(periodType.value);
142
+};
143
+
144
+// 虚拟数据
145
+const MOCK_DATA: TaskReportData[] = [
146
+  {
147
+    id: 1,
148
+    district: '默认片区',
149
+    districtManager: '李经理',
150
+    totalScore: 44,
151
+    completionRate: { ratio: '95.52%', score: 24 },
152
+    taskScore: { score: 0, obtainedScore: 0 },
153
+    readRate: { ratio: '0.00%', score: 0 },
154
+    maxSameScoreRate: { ratio: '56.11%', score: 8 },
155
+    overdueCount: { count: 3, score: 12 },
156
+  },
157
+  {
158
+    id: 2,
159
+    district: '片区1',
160
+    districtManager: '王经理',
161
+    totalScore: 8,
162
+    completionRate: { ratio: '77.14%', score: 0 },
163
+    taskScore: { score: 0, obtainedScore: 0 },
164
+    readRate: { ratio: '0.00%', score: 0 },
165
+    maxSameScoreRate: { ratio: '25%', score: 8 },
166
+    overdueCount: { count: 16, score: 0 },
167
+  },
168
+  {
169
+    id: 3,
170
+    district: '片区2',
171
+    districtManager: '张经理',
172
+    totalScore: 50,
173
+    completionRate: { ratio: '100%', score: 25 },
174
+    taskScore: { score: 0, obtainedScore: 0 },
175
+    readRate: { ratio: '50.00%', score: 0 },
176
+    maxSameScoreRate: { ratio: '33.33%', score: 10 },
177
+    overdueCount: { count: 0, score: 15 },
178
+  },
179
+  {
180
+    id: 4,
181
+    district: '片区3',
182
+    districtManager: '刘经理',
183
+    totalScore: 38,
184
+    completionRate: { ratio: '90.00%', score: 22 },
185
+    taskScore: { score: 0, obtainedScore: 0 },
186
+    readRate: { ratio: '33.33%', score: 0 },
187
+    maxSameScoreRate: { ratio: '66.67%', score: 6 },
188
+    overdueCount: { count: 2, score: 10 },
189
+  },
190
+];
191
+
192
+// 任务全指标报表虚拟数据
193
+const FULL_INDICATOR_MOCK_DATA: FullIndicatorReportData[] = [
194
+  {
195
+    id: 1,
196
+    district: '默认片区',
197
+    districtManager: '李经理',
198
+    taskQuantity: {
199
+      totalTasks: 52,
200
+      completedOnTime: 48,
201
+      completedOverdue: 3,
202
+      notCompleted: 1,
203
+      totalCompletionRate: '98.08%',
204
+      overdueRate: '5.77%',
205
+      authorizedRate: '2.5%',
206
+      newTaskRate: '1.92%',
207
+    },
208
+    taskQuality: {
209
+      commentCount: 12,
210
+      taskScore: 4.5,
211
+      ledgerAverage: 85.5,
212
+    },
213
+    authorization: {
214
+      authorizedCount: 1,
215
+      authorizedRate: '1.92%',
216
+      authorizationComments: 0,
217
+    },
218
+    查阅: {
219
+      readableCount: 51,
220
+      readCount: 0,
221
+      readRate: '0.00%',
222
+      查阅Count: 2,
223
+    },
224
+    performance: {
225
+      maxSameScoreRate: '25%',
226
+      performanceCommentRate: '16.67%',
227
+    },
228
+  },
229
+  {
230
+    id: 2,
231
+    district: '片区1',
232
+    districtManager: '王经理',
233
+    taskQuantity: {
234
+      totalTasks: 67,
235
+      completedOnTime: 58,
236
+      completedOverdue: 8,
237
+      notCompleted: 1,
238
+      totalCompletionRate: '98.51%',
239
+      overdueRate: '11.94%',
240
+      authorizedRate: '33.33%',
241
+      newTaskRate: '1.49%',
242
+    },
243
+    taskQuality: {
244
+      commentCount: 8,
245
+      taskScore: 4.2,
246
+      ledgerAverage: 88.2,
247
+    },
248
+    authorization: {
249
+      authorizedCount: 11,
250
+      authorizedRate: '16.42%',
251
+      authorizationComments: 3,
252
+    },
253
+    查阅: {
254
+      readableCount: 80,
255
+      readCount: 0,
256
+      readRate: '0.00%',
257
+      查阅Count: 1,
258
+    },
259
+    performance: {
260
+      maxSameScoreRate: '36.11%',
261
+      performanceCommentRate: '8.33%',
262
+    },
263
+  },
264
+];
265
+
266
+// 任务评估报表表格配置
267
+const taskReportColumns: VxeGridProps['columns'] = [
268
+  { title: '片区', field: 'district', minWidth: 150, align: 'center' },
269
+  {
270
+    title: '片区经理',
271
+    field: 'districtManager',
272
+    minWidth: 120,
273
+    align: 'center',
274
+  },
275
+  { title: '总分', field: 'totalScore', minWidth: 80, align: 'center' },
276
+  {
277
+    title: '完成率',
278
+    minWidth: 150,
279
+    align: 'center',
280
+    children: [
281
+      {
282
+        title: '比例',
283
+        field: 'completionRate.ratio',
284
+        minWidth: 80,
285
+        align: 'center',
286
+      },
287
+      {
288
+        title: '得分',
289
+        field: 'completionRate.score',
290
+        minWidth: 70,
291
+        align: 'center',
292
+      },
293
+    ],
294
+  },
295
+  {
296
+    title: '任务得分',
297
+    minWidth: 150,
298
+    align: 'center',
299
+    children: [
300
+      {
301
+        title: '分数',
302
+        field: 'taskScore.score',
303
+        minWidth: 80,
304
+        align: 'center',
305
+      },
306
+      {
307
+        title: '得分',
308
+        field: 'taskScore.obtainedScore',
309
+        minWidth: 70,
310
+        align: 'center',
311
+      },
312
+    ],
313
+  },
314
+  {
315
+    title: '已阅比例',
316
+    minWidth: 150,
317
+    align: 'center',
318
+    children: [
319
+      { title: '比例', field: 'readRate.ratio', minWidth: 80, align: 'center' },
320
+      { title: '得分', field: 'readRate.score', minWidth: 70, align: 'center' },
321
+    ],
322
+  },
323
+  {
324
+    title: '最多相同分数率',
325
+    minWidth: 180,
326
+    align: 'center',
327
+    children: [
328
+      {
329
+        title: '比例',
330
+        field: 'maxSameScoreRate.ratio',
331
+        minWidth: 100,
332
+        align: 'center',
333
+      },
334
+      {
335
+        title: '得分',
336
+        field: 'maxSameScoreRate.score',
337
+        minWidth: 80,
338
+        align: 'center',
339
+      },
340
+    ],
341
+  },
342
+  {
343
+    title: '逾期未完成数',
344
+    minWidth: 180,
345
+    align: 'center',
346
+    children: [
347
+      {
348
+        title: '过期数量',
349
+        field: 'overdueCount.count',
350
+        minWidth: 100,
351
+        align: 'center',
352
+      },
353
+      {
354
+        title: '过期分数',
355
+        field: 'overdueCount.score',
356
+        minWidth: 80,
357
+        align: 'center',
358
+      },
359
+    ],
360
+  },
361
+];
362
+
363
+const taskReportGridOptions: VxeGridProps = {
364
+  columns: taskReportColumns,
365
+  size: 'medium',
366
+  height: '500px',
367
+  useSearchForm: false,
368
+  proxyConfig: {
369
+    enabled: true,
370
+    autoLoad: true,
371
+    ajax: {
372
+      query: async () => {
373
+        return { items: MOCK_DATA, total: MOCK_DATA.length };
374
+      },
375
+    },
376
+  },
377
+  rowConfig: { keyField: 'id' },
378
+  toolbarConfig: {},
379
+  id: 'task-report-table',
380
+};
381
+
382
+// 任务全指标报表表格配置
383
+const fullIndicatorReportColumns: VxeGridProps['columns'] = [
384
+  {
385
+    title: '片区',
386
+    field: 'district',
387
+    minWidth: 150,
388
+    align: 'center',
389
+    fixed: 'left',
390
+  },
391
+  {
392
+    title: '片区经理',
393
+    field: 'districtManager',
394
+    minWidth: 120,
395
+    align: 'center',
396
+    fixed: 'left',
397
+  },
398
+  {
399
+    title: '任务数量',
400
+    minWidth: 400,
401
+    align: 'center',
402
+    children: [
403
+      {
404
+        title: '任务数',
405
+        field: 'taskQuantity.totalTasks',
406
+        minWidth: 80,
407
+        align: 'center',
408
+      },
409
+      {
410
+        title: '按时完成',
411
+        field: 'taskQuantity.completedOnTime',
412
+        minWidth: 80,
413
+        align: 'center',
414
+      },
415
+      {
416
+        title: '逾期完成',
417
+        field: 'taskQuantity.completedOverdue',
418
+        minWidth: 80,
419
+        align: 'center',
420
+      },
421
+      {
422
+        title: '过期未完成',
423
+        field: 'taskQuantity.notCompleted',
424
+        minWidth: 90,
425
+        align: 'center',
426
+      },
427
+      {
428
+        title: '总完成率',
429
+        field: 'taskQuantity.totalCompletionRate',
430
+        minWidth: 80,
431
+        align: 'center',
432
+      },
433
+      {
434
+        title: '逾期率',
435
+        field: 'taskQuantity.overdueRate',
436
+        minWidth: 80,
437
+        align: 'center',
438
+      },
439
+      {
440
+        title: '被授权率',
441
+        field: 'taskQuantity.authorizedRate',
442
+        minWidth: 80,
443
+        align: 'center',
444
+      },
445
+      {
446
+        title: '新增任务率',
447
+        field: 'taskQuantity.newTaskRate',
448
+        minWidth: 80,
449
+        align: 'center',
450
+      },
451
+    ],
452
+  },
453
+  {
454
+    title: '任务质量',
455
+    minWidth: 250,
456
+    align: 'center',
457
+    children: [
458
+      {
459
+        title: '收到的点评数',
460
+        field: 'taskQuality.commentCount',
461
+        minWidth: 100,
462
+        align: 'center',
463
+      },
464
+      {
465
+        title: '任务得分',
466
+        field: 'taskQuality.taskScore',
467
+        minWidth: 80,
468
+        align: 'center',
469
+      },
470
+      {
471
+        title: '台账平均数',
472
+        field: 'taskQuality.ledgerAverage',
473
+        minWidth: 80,
474
+        align: 'center',
475
+      },
476
+    ],
477
+  },
478
+  {
479
+    title: '授权',
480
+    minWidth: 250,
481
+    align: 'center',
482
+    children: [
483
+      {
484
+        title: '已授权',
485
+        field: 'authorization.authorizedCount',
486
+        minWidth: 80,
487
+        align: 'center',
488
+      },
489
+      {
490
+        title: '已授权率',
491
+        field: 'authorization.authorizedRate',
492
+        minWidth: 80,
493
+        align: 'center',
494
+      },
495
+      {
496
+        title: '授权点评',
497
+        field: 'authorization.authorizationComments',
498
+        minWidth: 80,
499
+        align: 'center',
500
+      },
501
+    ],
502
+  },
503
+  {
504
+    title: '查阅',
505
+    minWidth: 300,
506
+    align: 'center',
507
+    children: [
508
+      {
509
+        title: '可阅读',
510
+        field: '查阅.readableCount',
511
+        minWidth: 80,
512
+        align: 'center',
513
+      },
514
+      {
515
+        title: '已阅读',
516
+        field: '查阅.readCount',
517
+        minWidth: 80,
518
+        align: 'center',
519
+      },
520
+      {
521
+        title: '已阅读率',
522
+        field: '查阅.readRate',
523
+        minWidth: 80,
524
+        align: 'center',
525
+      },
526
+      {
527
+        title: '被查阅数',
528
+        field: '查阅.查阅Count',
529
+        minWidth: 80,
530
+        align: 'center',
531
+      },
532
+    ],
533
+  },
534
+  {
535
+    title: '绩效',
536
+    minWidth: 250,
537
+    align: 'center',
538
+    children: [
539
+      {
540
+        title: '最多相同分数率',
541
+        field: 'performance.maxSameScoreRate',
542
+        minWidth: 100,
543
+        align: 'center',
544
+      },
545
+      {
546
+        title: '绩效评语率',
547
+        field: 'performance.performanceCommentRate',
548
+        minWidth: 100,
549
+        align: 'center',
550
+      },
551
+    ],
552
+  },
553
+];
554
+
555
+const fullIndicatorReportGridOptions: VxeGridProps = {
556
+  columns: fullIndicatorReportColumns,
557
+  size: 'medium',
558
+  height: '500px',
559
+  useSearchForm: false,
560
+  proxyConfig: {
561
+    enabled: true,
562
+    autoLoad: true,
563
+    ajax: {
564
+      query: async () => {
565
+        return {
566
+          items: FULL_INDICATOR_MOCK_DATA,
567
+          total: FULL_INDICATOR_MOCK_DATA.length,
568
+        };
569
+      },
570
+    },
571
+  },
572
+  rowConfig: { keyField: 'id' },
573
+  toolbarConfig: {},
574
+  id: 'full-indicator-report-table',
575
+  scrollX: true,
576
+  scrollY: true,
577
+};
578
+
579
+// 创建表格实例
580
+const [TaskReportTable] = useVbenVxeGrid({
581
+  gridOptions: taskReportGridOptions,
582
+});
583
+const [FullIndicatorReportTable] = useVbenVxeGrid({
584
+  gridOptions: fullIndicatorReportGridOptions,
585
+});
586
+
587
+// 事件处理函数
588
+// 查询按钮点击事件
589
+const handleQuery = () => {
590
+  console.log('查询条件:', {
591
+    reportType: reportType.value,
592
+    periodType: periodType.value,
593
+    period: currentPeriod.value,
594
+  });
595
+  // TODO: 这里可以添加实际的查询逻辑,调用API获取真实数据
596
+};
597
+
598
+// 重置按钮点击事件
599
+const handleReset = () => {
600
+  resetSearch();
601
+  console.log('重置搜索条件');
602
+};
603
+
604
+// 导出按钮点击事件
605
+const handleExport = () => {
606
+  console.log('导出数据');
607
+  // TODO: 这里可以添加导出逻辑
608
+};
609
+
610
+// 生命周期钩子和监听
611
+// 监听时间类型变化 - 更新当前时段显示
612
+watch(periodType, (newType) => {
613
+  updateTimeRange(newType);
614
+});
615
+
616
+// 组件初始化 - 设置默认时间范围
617
+onMounted(() => {
618
+  updateTimeRange(periodType.value);
619
+});
3 620
 </script>
621
+
4 622
 <template>
5
-<Page>
6
-<div class="wrap">
7
-         空空如也
8
-</div>
9
-</Page>
623
+  <Page :auto-content-height="true">
624
+    <div class="task-report-container">
625
+      <!-- 报表类型切换 -->
626
+      <div class="report-type-container">
627
+        <ElRadioGroup v-model="reportType" size="large">
628
+          <ElRadioButton
629
+            v-for="option in reportTypeOptions"
630
+            :key="option.value"
631
+            :label="option.value"
632
+          >
633
+            {{ option.label }}
634
+          </ElRadioButton>
635
+        </ElRadioGroup>
636
+      </div>
637
+
638
+      <!-- 搜索区域 -->
639
+      <div class="search-container">
640
+        <ElSpace>
641
+          <div class="search-item">
642
+            <ElRadioGroup v-model="periodType" size="large">
643
+              <ElRadioButton
644
+                v-for="option in periodTypeOptions"
645
+                :key="option.value"
646
+                :label="option.value"
647
+              >
648
+                {{ option.label }}
649
+              </ElRadioButton>
650
+            </ElRadioGroup>
651
+          </div>
652
+          <div class="search-item">
653
+            <span>{{ currentPeriod }}</span>
654
+          </div>
655
+        </ElSpace>
656
+      </div>
657
+
658
+      <!-- 操作按钮区域 -->
659
+      <div class="button-container">
660
+        <ElSpace>
661
+          <ElButton type="primary" @click="handleQuery">查询</ElButton>
662
+          <ElButton @click="handleReset">重置</ElButton>
663
+          <ElButton @click="handleExport">导出</ElButton>
664
+        </ElSpace>
665
+      </div>
666
+
667
+      <!-- 报表提示语 -->
668
+      <div class="notice-container">
669
+        <p>数据周期:次周周三早9点自动生成,按周切片,次周日早9点自动生成。</p>
670
+      </div>
671
+
672
+      <!-- 报表数据表格 -->
673
+      <div class="table-container">
674
+        <TaskReportTable v-if="reportType === 'evaluation'" />
675
+        <FullIndicatorReportTable v-else />
676
+      </div>
677
+    </div>
678
+  </Page>
10 679
 </template>
11
-<style lang="scss" scoped>
12
-.wrap {
13
-padding: 16px;
14
-background-color: #fff;
15
-border-radius: 6px;
680
+
681
+<style scoped lang="scss">
682
+.task-report-container {
683
+  min-height: calc(100vh - 120px);
684
+  padding: 16px;
685
+  background-color: #fff;
686
+
687
+  .report-type-container {
688
+    margin-bottom: 16px;
689
+  }
690
+
691
+  .search-container {
692
+    display: flex;
693
+    align-items: center;
694
+    padding: 16px;
695
+    margin-bottom: 16px;
696
+    border-radius: 6px;
697
+
698
+    .search-item {
699
+      display: flex;
700
+      align-items: center;
701
+
702
+      label {
703
+        margin-right: 8px;
704
+        font-weight: 500;
705
+      }
706
+    }
707
+  }
708
+
709
+  .button-container {
710
+    margin-bottom: 16px;
711
+  }
712
+
713
+  .notice-container {
714
+    padding: 12px 16px;
715
+    margin-bottom: 16px;
716
+    font-size: 14px;
717
+    color: #606266;
718
+    background-color: #f0f5ff;
719
+    border-left: 4px solid #409eff;
720
+    border-radius: 4px;
721
+
722
+    p {
723
+      margin: 0;
724
+    }
725
+  }
726
+
727
+  .table-container {
728
+    width: 100%;
729
+  }
16 730
 }
17 731
 </style>

+ 955 - 10
apps/web-ele/src/views/operationRadar/taskReport/gasStationManagerReport/index.vue

@@ -1,17 +1,962 @@
1 1
 <script lang="ts" setup>
2
+// 导入部分
3
+import type { VxeGridProps } from '#/adapter/vxe-table';
4
+
5
+import { onMounted, ref, watch } from 'vue';
6
+
2 7
 import { Page } from '@vben/common-ui';
8
+
9
+import {
10
+  ElButton,
11
+  ElOption,
12
+  ElRadioButton,
13
+  ElRadioGroup,
14
+  ElSelect,
15
+  ElSpace,
16
+} from 'element-plus';
17
+
18
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
19
+
20
+// 类型定义
21
+interface ReportTypeOption {
22
+  label: string;
23
+  value: 'evaluation' | 'full-indicator';
24
+}
25
+
26
+interface PeriodTypeOption {
27
+  label: string;
28
+  value: 'month' | 'week';
29
+}
30
+
31
+interface StationOption {
32
+  label: string;
33
+  value: string;
34
+}
35
+
36
+interface AreaOption {
37
+  label: string;
38
+  value: string;
39
+}
40
+
41
+interface TaskReportData {
42
+  id: number;
43
+  station: string;
44
+  manager: string;
45
+  area: string;
46
+  totalScore: number;
47
+  completionRate: {
48
+    ratio: string;
49
+    score: number;
50
+  };
51
+  taskScore: {
52
+    obtainedScore: number;
53
+    score: number;
54
+  };
55
+  readRate: {
56
+    ratio: string;
57
+    score: number;
58
+  };
59
+  maxSameScoreRate: {
60
+    ratio: string;
61
+    score: number;
62
+  };
63
+  overdueCount: {
64
+    count: number;
65
+    score: number;
66
+  };
67
+}
68
+
69
+// 全指标报表数据类型
70
+interface FullIndicatorReportData {
71
+  id: number;
72
+  station: string;
73
+  manager: string;
74
+  area: string;
75
+  // 任务数量
76
+  taskQuantity: {
77
+    authorizedRate: string;
78
+    completedOnTime: number;
79
+    completedOverdue: number;
80
+    newTaskRate: string;
81
+    notCompleted: number;
82
+    overdueRate: string;
83
+    totalCompletionRate: string;
84
+    totalTasks: number;
85
+  };
86
+  // 任务质量
87
+  taskQuality: {
88
+    commentCount: number;
89
+    ledgerAverage: number;
90
+    taskScore: number;
91
+  };
92
+  // 授权
93
+  authorization: {
94
+    authorizationComments: number;
95
+    authorizedCount: number;
96
+    authorizedRate: string;
97
+  };
98
+  // 查阅
99
+  查阅: {
100
+    readableCount: number;
101
+    readCount: number;
102
+    readRate: string;
103
+    查阅Count: number;
104
+  };
105
+  // 绩效
106
+  performance: {
107
+    maxSameScoreRate: string;
108
+    performanceCommentRate: string;
109
+  };
110
+}
111
+
112
+// 响应式数据
113
+// 报表类型切换
114
+const reportType = ref<'evaluation' | 'full-indicator'>('evaluation');
115
+const reportTypeOptions: ReportTypeOption[] = [
116
+  { label: '任务评估报表', value: 'evaluation' },
117
+  { label: '任务全指标报表', value: 'full-indicator' },
118
+];
119
+
120
+// 时间类型切换
121
+const periodType = ref<'month' | 'week'>('week');
122
+const periodTypeOptions: PeriodTypeOption[] = [
123
+  { label: '周', value: 'week' },
124
+  { label: '月', value: 'month' },
125
+];
126
+const currentPeriod = ref('11月13日-11月19日');
127
+
128
+// 搜索条件
129
+const selectedName = ref('');
130
+const selectedStation = ref('');
131
+const selectedArea = ref('');
132
+
133
+// 下拉选项数据
134
+const nameOptions: AreaOption[] = [
135
+  { label: '李经理', value: '李经理' },
136
+  { label: '王经理', value: '王经理' },
137
+  { label: '张经理', value: '张经理' },
138
+  { label: '刘经理', value: '刘经理' },
139
+  { label: '陈经理', value: '陈经理' },
140
+  { label: '李玫琳', value: '李玫琳' },
141
+  { label: '安宁', value: '安宁' },
142
+  { label: '张磊', value: '张磊' },
143
+];
144
+
145
+const stationOptions: StationOption[] = [
146
+  { label: '机场油站', value: 'station1' },
147
+  { label: '北京东加油站', value: 'station2' },
148
+  { label: '北京西加油站', value: 'station3' },
149
+  { label: '北京南加油站', value: 'station4' },
150
+  { label: '北京北加油站', value: 'station5' },
151
+];
152
+
153
+const areaOptions: AreaOption[] = [
154
+  { label: '默认片区', value: 'area1' },
155
+  { label: '片区1', value: 'area2' },
156
+  { label: '片区2', value: 'area3' },
157
+  { label: '片区3', value: 'area4' },
158
+];
159
+
160
+// 辅助函数
161
+// 格式化日期为中文格式(MM月dd日)
162
+const formatDate = (date: Date): string => {
163
+  const month = date.getMonth() + 1;
164
+  const day = date.getDate();
165
+  return `${month}月${day}日`;
166
+};
167
+
168
+// 更新时间范围的函数
169
+const updateTimeRange = (type: 'month' | 'week'): void => {
170
+  const today = new Date();
171
+  let startDate: Date;
172
+  const endDate = today;
173
+
174
+  if (type === 'week') {
175
+    // 计算最近一周(今天往前推7天)
176
+    startDate = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
177
+    currentPeriod.value = `${formatDate(startDate)}-${formatDate(endDate)}`;
178
+  } else {
179
+    // 计算最近一个月(上个月的今天到今天)
180
+    startDate = new Date(
181
+      today.getFullYear(),
182
+      today.getMonth() - 1,
183
+      today.getDate(),
184
+    );
185
+    currentPeriod.value = `${formatDate(startDate)}-${formatDate(endDate)}`;
186
+  }
187
+};
188
+
189
+// 重置搜索条件
190
+const resetSearch = () => {
191
+  selectedName.value = '';
192
+  selectedStation.value = '';
193
+  selectedArea.value = '';
194
+  periodType.value = 'week';
195
+  updateTimeRange(periodType.value);
196
+};
197
+
198
+// 虚拟数据
199
+const MOCK_DATA: TaskReportData[] = [
200
+  {
201
+    id: 1,
202
+    station: '北京东加油站',
203
+    manager: '李经理',
204
+    area: '默认片区',
205
+    totalScore: 44,
206
+    completionRate: { ratio: '95.52%', score: 24 },
207
+    taskScore: { score: 0, obtainedScore: 0 },
208
+    readRate: { ratio: '0.00%', score: 0 },
209
+    maxSameScoreRate: { ratio: '56.11%', score: 8 },
210
+    overdueCount: { count: 3, score: 12 },
211
+  },
212
+  {
213
+    id: 2,
214
+    station: '北京西加油站',
215
+    manager: '王经理',
216
+    area: '默认片区',
217
+    totalScore: 8,
218
+    completionRate: { ratio: '77.14%', score: 0 },
219
+    taskScore: { score: 0, obtainedScore: 0 },
220
+    readRate: { ratio: '0.00%', score: 0 },
221
+    maxSameScoreRate: { ratio: '25%', score: 8 },
222
+    overdueCount: { count: 16, score: 0 },
223
+  },
224
+  {
225
+    id: 3,
226
+    station: '机场油站',
227
+    manager: '张经理',
228
+    area: '片区1',
229
+    totalScore: 50,
230
+    completionRate: { ratio: '100%', score: 25 },
231
+    taskScore: { score: 0, obtainedScore: 0 },
232
+    readRate: { ratio: '50.00%', score: 0 },
233
+    maxSameScoreRate: { ratio: '33.33%', score: 10 },
234
+    overdueCount: { count: 0, score: 15 },
235
+  },
236
+  {
237
+    id: 4,
238
+    station: '北京南加油站',
239
+    manager: '刘经理',
240
+    area: '片区2',
241
+    totalScore: 38,
242
+    completionRate: { ratio: '90.00%', score: 22 },
243
+    taskScore: { score: 0, obtainedScore: 0 },
244
+    readRate: { ratio: '33.33%', score: 0 },
245
+    maxSameScoreRate: { ratio: '66.67%', score: 6 },
246
+    overdueCount: { count: 2, score: 10 },
247
+  },
248
+  {
249
+    id: 5,
250
+    station: '北京北加油站',
251
+    manager: '陈经理',
252
+    area: '片区3',
253
+    totalScore: 42,
254
+    completionRate: { ratio: '93.33%', score: 23 },
255
+    taskScore: { score: 0, obtainedScore: 0 },
256
+    readRate: { ratio: '25.00%', score: 0 },
257
+    maxSameScoreRate: { ratio: '40.00%', score: 8 },
258
+    overdueCount: { count: 1, score: 11 },
259
+  },
260
+];
261
+
262
+// 任务全指标报表虚拟数据
263
+const FULL_INDICATOR_MOCK_DATA: FullIndicatorReportData[] = [
264
+  {
265
+    id: 1,
266
+    station: '未来路加油',
267
+    manager: '李玫琳',
268
+    area: '默认片区',
269
+    taskQuantity: {
270
+      totalTasks: 52,
271
+      completedOnTime: 48,
272
+      completedOverdue: 3,
273
+      notCompleted: 1,
274
+      totalCompletionRate: '98.08%',
275
+      overdueRate: '5.77%',
276
+      authorizedRate: '2.5%',
277
+      newTaskRate: '1.92%',
278
+    },
279
+    taskQuality: {
280
+      commentCount: 12,
281
+      taskScore: 4.5,
282
+      ledgerAverage: 85.5,
283
+    },
284
+    authorization: {
285
+      authorizedCount: 1,
286
+      authorizedRate: '1.92%',
287
+      authorizationComments: 0,
288
+    },
289
+    查阅: {
290
+      readableCount: 51,
291
+      readCount: 0,
292
+      readRate: '0.00%',
293
+      查阅Count: 2,
294
+    },
295
+    performance: {
296
+      maxSameScoreRate: '25%',
297
+      performanceCommentRate: '16.67%',
298
+    },
299
+  },
300
+  {
301
+    id: 2,
302
+    station: '龙飞虎加',
303
+    manager: '安宁',
304
+    area: '默认片区',
305
+    taskQuantity: {
306
+      totalTasks: 67,
307
+      completedOnTime: 58,
308
+      completedOverdue: 8,
309
+      notCompleted: 1,
310
+      totalCompletionRate: '98.51%',
311
+      overdueRate: '11.94%',
312
+      authorizedRate: '33.33%',
313
+      newTaskRate: '1.49%',
314
+    },
315
+    taskQuality: {
316
+      commentCount: 8,
317
+      taskScore: 4.2,
318
+      ledgerAverage: 88.2,
319
+    },
320
+    authorization: {
321
+      authorizedCount: 11,
322
+      authorizedRate: '16.42%',
323
+      authorizationComments: 3,
324
+    },
325
+    查阅: {
326
+      readableCount: 80,
327
+      readCount: 0,
328
+      readRate: '0.00%',
329
+      查阅Count: 1,
330
+    },
331
+    performance: {
332
+      maxSameScoreRate: '36.11%',
333
+      performanceCommentRate: '8.33%',
334
+    },
335
+  },
336
+  {
337
+    id: 3,
338
+    station: '法站',
339
+    manager: '张磊',
340
+    area: '默认片区',
341
+    taskQuantity: {
342
+      totalTasks: 125,
343
+      completedOnTime: 112,
344
+      completedOverdue: 12,
345
+      notCompleted: 1,
346
+      totalCompletionRate: '99.20%',
347
+      overdueRate: '9.60%',
348
+      authorizedRate: '16.44%',
349
+      newTaskRate: '0.80%',
350
+    },
351
+    taskQuality: {
352
+      commentCount: 15,
353
+      taskScore: 4.7,
354
+      ledgerAverage: 90.5,
355
+    },
356
+    authorization: {
357
+      authorizedCount: 12,
358
+      authorizedRate: '9.60%',
359
+      authorizationComments: 5,
360
+    },
361
+    查阅: {
362
+      readableCount: 131,
363
+      readCount: 0,
364
+      readRate: '0.00%',
365
+      查阅Count: 3,
366
+    },
367
+    performance: {
368
+      maxSameScoreRate: '31.67%',
369
+      performanceCommentRate: '11.67%',
370
+    },
371
+  },
372
+  {
373
+    id: 4,
374
+    station: '机场油站',
375
+    manager: '王经理',
376
+    area: '片区1',
377
+    taskQuantity: {
378
+      totalTasks: 89,
379
+      completedOnTime: 78,
380
+      completedOverdue: 10,
381
+      notCompleted: 1,
382
+      totalCompletionRate: '98.88%',
383
+      overdueRate: '11.24%',
384
+      authorizedRate: '22.47%',
385
+      newTaskRate: '1.12%',
386
+    },
387
+    taskQuality: {
388
+      commentCount: 20,
389
+      taskScore: 4.3,
390
+      ledgerAverage: 87.8,
391
+    },
392
+    authorization: {
393
+      authorizedCount: 10,
394
+      authorizedRate: '11.24%',
395
+      authorizationComments: 4,
396
+    },
397
+    查阅: {
398
+      readableCount: 95,
399
+      readCount: 5,
400
+      readRate: '5.26%',
401
+      查阅Count: 2,
402
+    },
403
+    performance: {
404
+      maxSameScoreRate: '38.33%',
405
+      performanceCommentRate: '13.33%',
406
+    },
407
+  },
408
+  {
409
+    id: 5,
410
+    station: '北京南加油',
411
+    manager: '刘经理',
412
+    area: '片区2',
413
+    taskQuantity: {
414
+      totalTasks: 45,
415
+      completedOnTime: 39,
416
+      completedOverdue: 5,
417
+      notCompleted: 1,
418
+      totalCompletionRate: '97.78%',
419
+      overdueRate: '11.11%',
420
+      authorizedRate: '15.56%',
421
+      newTaskRate: '2.22%',
422
+    },
423
+    taskQuality: {
424
+      commentCount: 7,
425
+      taskScore: 4.1,
426
+      ledgerAverage: 84.2,
427
+    },
428
+    authorization: {
429
+      authorizedCount: 6,
430
+      authorizedRate: '13.33%',
431
+      authorizationComments: 2,
432
+    },
433
+    查阅: {
434
+      readableCount: 48,
435
+      readCount: 3,
436
+      readRate: '6.25%',
437
+      查阅Count: 1,
438
+    },
439
+    performance: {
440
+      maxSameScoreRate: '28.33%',
441
+      performanceCommentRate: '10.00%',
442
+    },
443
+  },
444
+];
445
+
446
+// 任务评估报表表格配置
447
+const taskReportColumns: VxeGridProps['columns'] = [
448
+  { title: '姓名', field: 'manager', minWidth: 120, align: 'center' },
449
+  { title: '油站', field: 'station', minWidth: 150, align: 'center' },
450
+  { title: '片区', field: 'area', minWidth: 120, align: 'center' },
451
+  { title: '总分', field: 'totalScore', minWidth: 80, align: 'center' },
452
+  {
453
+    title: '完成率',
454
+    minWidth: 150,
455
+    align: 'center',
456
+    children: [
457
+      {
458
+        title: '比例',
459
+        field: 'completionRate.ratio',
460
+        minWidth: 80,
461
+        align: 'center',
462
+      },
463
+      {
464
+        title: '得分',
465
+        field: 'completionRate.score',
466
+        minWidth: 70,
467
+        align: 'center',
468
+      },
469
+    ],
470
+  },
471
+  {
472
+    title: '任务得分',
473
+    minWidth: 150,
474
+    align: 'center',
475
+    children: [
476
+      {
477
+        title: '分数',
478
+        field: 'taskScore.score',
479
+        minWidth: 80,
480
+        align: 'center',
481
+      },
482
+      {
483
+        title: '得分',
484
+        field: 'taskScore.obtainedScore',
485
+        minWidth: 70,
486
+        align: 'center',
487
+      },
488
+    ],
489
+  },
490
+  {
491
+    title: '已阅比例',
492
+    minWidth: 150,
493
+    align: 'center',
494
+    children: [
495
+      { title: '比例', field: 'readRate.ratio', minWidth: 80, align: 'center' },
496
+      { title: '得分', field: 'readRate.score', minWidth: 70, align: 'center' },
497
+    ],
498
+  },
499
+  {
500
+    title: '最多相同分数率',
501
+    minWidth: 180,
502
+    align: 'center',
503
+    children: [
504
+      {
505
+        title: '比例',
506
+        field: 'maxSameScoreRate.ratio',
507
+        minWidth: 100,
508
+        align: 'center',
509
+      },
510
+      {
511
+        title: '得分',
512
+        field: 'maxSameScoreRate.score',
513
+        minWidth: 80,
514
+        align: 'center',
515
+      },
516
+    ],
517
+  },
518
+  {
519
+    title: '逾期未完成数',
520
+    minWidth: 180,
521
+    align: 'center',
522
+    children: [
523
+      {
524
+        title: '过期数量',
525
+        field: 'overdueCount.count',
526
+        minWidth: 100,
527
+        align: 'center',
528
+      },
529
+      {
530
+        title: '过期分数',
531
+        field: 'overdueCount.score',
532
+        minWidth: 80,
533
+        align: 'center',
534
+      },
535
+    ],
536
+  },
537
+];
538
+
539
+const taskReportGridOptions: VxeGridProps = {
540
+  columns: taskReportColumns,
541
+  size: 'medium',
542
+  height: '500px',
543
+  useSearchForm: false,
544
+  proxyConfig: {
545
+    enabled: true,
546
+    autoLoad: true,
547
+    ajax: {
548
+      query: async () => {
549
+        return { items: MOCK_DATA, total: MOCK_DATA.length };
550
+      },
551
+    },
552
+  },
553
+  rowConfig: { keyField: 'id' },
554
+  toolbarConfig: {},
555
+  id: 'task-report-table',
556
+};
557
+
558
+// 任务全指标报表表格配置
559
+const fullIndicatorReportColumns: VxeGridProps['columns'] = [
560
+  {
561
+    title: '姓名',
562
+    field: 'manager',
563
+    minWidth: 120,
564
+    align: 'center',
565
+    fixed: 'left',
566
+  },
567
+  {
568
+    title: '油站',
569
+    field: 'station',
570
+    minWidth: 150,
571
+    align: 'center',
572
+    fixed: 'left',
573
+  },
574
+  {
575
+    title: '片区',
576
+    field: 'area',
577
+    minWidth: 120,
578
+    align: 'center',
579
+    fixed: 'left',
580
+  },
581
+  {
582
+    title: '任务数量',
583
+    minWidth: 400,
584
+    align: 'center',
585
+    children: [
586
+      {
587
+        title: '任务数',
588
+        field: 'taskQuantity.totalTasks',
589
+        minWidth: 80,
590
+        align: 'center',
591
+      },
592
+      {
593
+        title: '按时完成',
594
+        field: 'taskQuantity.completedOnTime',
595
+        minWidth: 80,
596
+        align: 'center',
597
+      },
598
+      {
599
+        title: '逾期完成',
600
+        field: 'taskQuantity.completedOverdue',
601
+        minWidth: 80,
602
+        align: 'center',
603
+      },
604
+      {
605
+        title: '过期未完成',
606
+        field: 'taskQuantity.notCompleted',
607
+        minWidth: 90,
608
+        align: 'center',
609
+      },
610
+      {
611
+        title: '总完成率',
612
+        field: 'taskQuantity.totalCompletionRate',
613
+        minWidth: 80,
614
+        align: 'center',
615
+      },
616
+      {
617
+        title: '逾期率',
618
+        field: 'taskQuantity.overdueRate',
619
+        minWidth: 80,
620
+        align: 'center',
621
+      },
622
+      {
623
+        title: '被授权率',
624
+        field: 'taskQuantity.authorizedRate',
625
+        minWidth: 80,
626
+        align: 'center',
627
+      },
628
+      {
629
+        title: '新增任务率',
630
+        field: 'taskQuantity.newTaskRate',
631
+        minWidth: 80,
632
+        align: 'center',
633
+      },
634
+    ],
635
+  },
636
+  {
637
+    title: '任务质量',
638
+    minWidth: 250,
639
+    align: 'center',
640
+    children: [
641
+      {
642
+        title: '收到的点评数',
643
+        field: 'taskQuality.commentCount',
644
+        minWidth: 100,
645
+        align: 'center',
646
+      },
647
+      {
648
+        title: '任务得分',
649
+        field: 'taskQuality.taskScore',
650
+        minWidth: 80,
651
+        align: 'center',
652
+      },
653
+      {
654
+        title: '台账平均数',
655
+        field: 'taskQuality.ledgerAverage',
656
+        minWidth: 80,
657
+        align: 'center',
658
+      },
659
+    ],
660
+  },
661
+  {
662
+    title: '授权',
663
+    minWidth: 250,
664
+    align: 'center',
665
+    children: [
666
+      {
667
+        title: '已授权',
668
+        field: 'authorization.authorizedCount',
669
+        minWidth: 80,
670
+        align: 'center',
671
+      },
672
+      {
673
+        title: '已授权率',
674
+        field: 'authorization.authorizedRate',
675
+        minWidth: 80,
676
+        align: 'center',
677
+      },
678
+      {
679
+        title: '授权点评',
680
+        field: 'authorization.authorizationComments',
681
+        minWidth: 80,
682
+        align: 'center',
683
+      },
684
+    ],
685
+  },
686
+  {
687
+    title: '查阅',
688
+    minWidth: 300,
689
+    align: 'center',
690
+    children: [
691
+      {
692
+        title: '可阅读',
693
+        field: '查阅.readableCount',
694
+        minWidth: 80,
695
+        align: 'center',
696
+      },
697
+      {
698
+        title: '已阅读',
699
+        field: '查阅.readCount',
700
+        minWidth: 80,
701
+        align: 'center',
702
+      },
703
+      {
704
+        title: '已阅读率',
705
+        field: '查阅.readRate',
706
+        minWidth: 80,
707
+        align: 'center',
708
+      },
709
+      {
710
+        title: '被查阅数',
711
+        field: '查阅.查阅Count',
712
+        minWidth: 80,
713
+        align: 'center',
714
+      },
715
+    ],
716
+  },
717
+  {
718
+    title: '绩效',
719
+    minWidth: 250,
720
+    align: 'center',
721
+    children: [
722
+      {
723
+        title: '最多相同分数率',
724
+        field: 'performance.maxSameScoreRate',
725
+        minWidth: 100,
726
+        align: 'center',
727
+      },
728
+      {
729
+        title: '绩效评语率',
730
+        field: 'performance.performanceCommentRate',
731
+        minWidth: 100,
732
+        align: 'center',
733
+      },
734
+    ],
735
+  },
736
+];
737
+
738
+const fullIndicatorReportGridOptions: VxeGridProps = {
739
+  columns: fullIndicatorReportColumns,
740
+  size: 'medium',
741
+  height: '500px',
742
+  useSearchForm: false,
743
+  proxyConfig: {
744
+    enabled: true,
745
+    autoLoad: true,
746
+    ajax: {
747
+      query: async () => {
748
+        return {
749
+          items: FULL_INDICATOR_MOCK_DATA,
750
+          total: FULL_INDICATOR_MOCK_DATA.length,
751
+        };
752
+      },
753
+    },
754
+  },
755
+  rowConfig: { keyField: 'id' },
756
+  toolbarConfig: {},
757
+  id: 'full-indicator-report-table',
758
+  scrollX: true,
759
+  scrollY: true,
760
+};
761
+
762
+// 创建表格实例
763
+const [TaskReportTable] = useVbenVxeGrid({
764
+  gridOptions: taskReportGridOptions,
765
+});
766
+const [FullIndicatorReportTable] = useVbenVxeGrid({
767
+  gridOptions: fullIndicatorReportGridOptions,
768
+});
769
+
770
+// 事件处理函数
771
+// 查询按钮点击事件
772
+const handleQuery = () => {
773
+  console.log('查询条件:', {
774
+    reportType: reportType.value,
775
+    name: selectedName.value,
776
+    station: selectedStation.value,
777
+    area: selectedArea.value,
778
+    periodType: periodType.value,
779
+    period: currentPeriod.value,
780
+  });
781
+  // TODO: 这里可以添加实际的查询逻辑,调用API获取真实数据
782
+};
783
+
784
+// 重置按钮点击事件
785
+const handleReset = () => {
786
+  resetSearch();
787
+  console.log('重置搜索条件');
788
+};
789
+
790
+// 导出按钮点击事件
791
+const handleExport = () => {
792
+  console.log('导出数据');
793
+  // TODO: 这里可以添加导出逻辑
794
+};
795
+
796
+// 生命周期钩子和监听
797
+// 监听时间类型变化 - 更新当前时段显示
798
+watch(periodType, (newType) => {
799
+  updateTimeRange(newType);
800
+});
801
+
802
+// 组件初始化 - 设置默认时间范围
803
+onMounted(() => {
804
+  updateTimeRange(periodType.value);
805
+});
3 806
 </script>
807
+
4 808
 <template>
5
-<Page>
6
-<div class="wrap">
7
-         空空如也
8
-</div>
9
-</Page>
809
+  <Page :auto-content-height="true">
810
+    <div class="task-report-container">
811
+      <!-- 报表类型切换 -->
812
+      <div class="report-type-container">
813
+        <ElRadioGroup v-model="reportType" size="large">
814
+          <ElRadioButton
815
+            v-for="option in reportTypeOptions"
816
+            :key="option.value"
817
+            :label="option.value"
818
+          >
819
+            {{ option.label }}
820
+          </ElRadioButton>
821
+        </ElRadioGroup>
822
+      </div>
823
+
824
+      <!-- 搜索区域 -->
825
+      <div class="search-container">
826
+        <ElSpace>
827
+          <div class="search-item">
828
+            <label>姓名:</label>
829
+            <ElSelect
830
+              v-model="selectedName"
831
+              placeholder="请选择姓名"
832
+              style="width: 180px"
833
+            >
834
+              <ElOption
835
+                v-for="option in nameOptions"
836
+                :key="option.value"
837
+                :label="option.label"
838
+                :value="option.value"
839
+              />
840
+            </ElSelect>
841
+          </div>
842
+          <div class="search-item">
843
+            <label>油站:</label>
844
+            <ElSelect
845
+              v-model="selectedStation"
846
+              placeholder="请选择油站"
847
+              style="width: 180px"
848
+            >
849
+              <ElOption
850
+                v-for="option in stationOptions"
851
+                :key="option.value"
852
+                :label="option.label"
853
+                :value="option.value"
854
+              />
855
+            </ElSelect>
856
+          </div>
857
+          <div class="search-item">
858
+            <label>片区:</label>
859
+            <ElSelect
860
+              v-model="selectedArea"
861
+              placeholder="请选择片区"
862
+              style="width: 180px"
863
+            >
864
+              <ElOption
865
+                v-for="option in areaOptions"
866
+                :key="option.value"
867
+                :label="option.label"
868
+                :value="option.value"
869
+              />
870
+            </ElSelect>
871
+          </div>
872
+          <div class="search-item">
873
+            <ElRadioGroup v-model="periodType" size="large">
874
+              <ElRadioButton
875
+                v-for="option in periodTypeOptions"
876
+                :key="option.value"
877
+                :label="option.value"
878
+              >
879
+                {{ option.label }}
880
+              </ElRadioButton>
881
+            </ElRadioGroup>
882
+          </div>
883
+          <div class="search-item">
884
+            <span>{{ currentPeriod }}</span>
885
+          </div>
886
+        </ElSpace>
887
+      </div>
888
+
889
+      <!-- 操作按钮区域 -->
890
+      <div class="button-container">
891
+        <ElSpace>
892
+          <ElButton type="primary" @click="handleQuery">查询</ElButton>
893
+          <ElButton @click="handleReset">重置</ElButton>
894
+          <ElButton @click="handleExport">导出</ElButton>
895
+        </ElSpace>
896
+      </div>
897
+
898
+      <!-- 报表提示语 -->
899
+      <div class="notice-container">
900
+        <p>数据周期:次周周三早9点自动生成,按周切片,次周日早9点自动生成。</p>
901
+      </div>
902
+
903
+      <!-- 报表数据表格 -->
904
+      <div class="table-container">
905
+        <TaskReportTable v-if="reportType === 'evaluation'" />
906
+        <FullIndicatorReportTable v-else />
907
+      </div>
908
+    </div>
909
+  </Page>
10 910
 </template>
11
-<style lang="scss" scoped>
12
-.wrap {
13
-padding: 16px;
14
-background-color: #fff;
15
-border-radius: 6px;
911
+
912
+<style scoped lang="scss">
913
+.task-report-container {
914
+  min-height: calc(100vh - 120px);
915
+  padding: 16px;
916
+  background-color: #fff;
917
+
918
+  .report-type-container {
919
+    margin-bottom: 16px;
920
+  }
921
+
922
+  .search-container {
923
+    display: flex;
924
+    align-items: center;
925
+    padding: 16px;
926
+    margin-bottom: 16px;
927
+    border-radius: 6px;
928
+
929
+    .search-item {
930
+      display: flex;
931
+      align-items: center;
932
+
933
+      label {
934
+        margin-right: 8px;
935
+        font-weight: 500;
936
+      }
937
+    }
938
+  }
939
+
940
+  .button-container {
941
+    margin-bottom: 16px;
942
+  }
943
+
944
+  .notice-container {
945
+    padding: 12px 16px;
946
+    margin-bottom: 16px;
947
+    font-size: 14px;
948
+    color: #606266;
949
+    background-color: #f0f5ff;
950
+    border-left: 4px solid #409eff;
951
+    border-radius: 4px;
952
+
953
+    p {
954
+      margin: 0;
955
+    }
956
+  }
957
+
958
+  .table-container {
959
+    width: 100%;
960
+  }
16 961
 }
17 962
 </style>

+ 955 - 10
apps/web-ele/src/views/operationRadar/taskReport/gasStationStaffReport/index.vue

@@ -1,17 +1,962 @@
1 1
 <script lang="ts" setup>
2
+// 导入部分
3
+import type { VxeGridProps } from '#/adapter/vxe-table';
4
+
5
+import { onMounted, ref, watch } from 'vue';
6
+
2 7
 import { Page } from '@vben/common-ui';
8
+
9
+import {
10
+  ElButton,
11
+  ElOption,
12
+  ElRadioButton,
13
+  ElRadioGroup,
14
+  ElSelect,
15
+  ElSpace,
16
+} from 'element-plus';
17
+
18
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
19
+
20
+// 类型定义
21
+interface ReportTypeOption {
22
+  label: string;
23
+  value: 'evaluation' | 'full-indicator';
24
+}
25
+
26
+interface PeriodTypeOption {
27
+  label: string;
28
+  value: 'month' | 'week';
29
+}
30
+
31
+interface StationOption {
32
+  label: string;
33
+  value: string;
34
+}
35
+
36
+interface AreaOption {
37
+  label: string;
38
+  value: string;
39
+}
40
+
41
+interface TaskReportData {
42
+  id: number;
43
+  station: string;
44
+  manager: string;
45
+  area: string;
46
+  totalScore: number;
47
+  completionRate: {
48
+    ratio: string;
49
+    score: number;
50
+  };
51
+  taskScore: {
52
+    obtainedScore: number;
53
+    score: number;
54
+  };
55
+  readRate: {
56
+    ratio: string;
57
+    score: number;
58
+  };
59
+  maxSameScoreRate: {
60
+    ratio: string;
61
+    score: number;
62
+  };
63
+  overdueCount: {
64
+    count: number;
65
+    score: number;
66
+  };
67
+}
68
+
69
+// 全指标报表数据类型
70
+interface FullIndicatorReportData {
71
+  id: number;
72
+  station: string;
73
+  manager: string;
74
+  area: string;
75
+  // 任务数量
76
+  taskQuantity: {
77
+    authorizedRate: string;
78
+    completedOnTime: number;
79
+    completedOverdue: number;
80
+    newTaskRate: string;
81
+    notCompleted: number;
82
+    overdueRate: string;
83
+    totalCompletionRate: string;
84
+    totalTasks: number;
85
+  };
86
+  // 任务质量
87
+  taskQuality: {
88
+    commentCount: number;
89
+    ledgerAverage: number;
90
+    taskScore: number;
91
+  };
92
+  // 授权
93
+  authorization: {
94
+    authorizationComments: number;
95
+    authorizedCount: number;
96
+    authorizedRate: string;
97
+  };
98
+  // 查阅
99
+  查阅: {
100
+    readableCount: number;
101
+    readCount: number;
102
+    readRate: string;
103
+    查阅Count: number;
104
+  };
105
+  // 绩效
106
+  performance: {
107
+    maxSameScoreRate: string;
108
+    performanceCommentRate: string;
109
+  };
110
+}
111
+
112
+// 响应式数据
113
+// 报表类型切换
114
+const reportType = ref<'evaluation' | 'full-indicator'>('evaluation');
115
+const reportTypeOptions: ReportTypeOption[] = [
116
+  { label: '任务评估报表', value: 'evaluation' },
117
+  { label: '任务全指标报表', value: 'full-indicator' },
118
+];
119
+
120
+// 时间类型切换
121
+const periodType = ref<'month' | 'week'>('week');
122
+const periodTypeOptions: PeriodTypeOption[] = [
123
+  { label: '周', value: 'week' },
124
+  { label: '月', value: 'month' },
125
+];
126
+const currentPeriod = ref('11月13日-11月19日');
127
+
128
+// 搜索条件
129
+const selectedName = ref('');
130
+const selectedStation = ref('');
131
+const selectedArea = ref('');
132
+
133
+// 下拉选项数据
134
+const nameOptions: AreaOption[] = [
135
+  { label: '李经理', value: '李经理' },
136
+  { label: '王经理', value: '王经理' },
137
+  { label: '张经理', value: '张经理' },
138
+  { label: '刘经理', value: '刘经理' },
139
+  { label: '陈经理', value: '陈经理' },
140
+  { label: '李玫琳', value: '李玫琳' },
141
+  { label: '安宁', value: '安宁' },
142
+  { label: '张磊', value: '张磊' },
143
+];
144
+
145
+const stationOptions: StationOption[] = [
146
+  { label: '机场油站', value: 'station1' },
147
+  { label: '北京东加油站', value: 'station2' },
148
+  { label: '北京西加油站', value: 'station3' },
149
+  { label: '北京南加油站', value: 'station4' },
150
+  { label: '北京北加油站', value: 'station5' },
151
+];
152
+
153
+const areaOptions: AreaOption[] = [
154
+  { label: '默认片区', value: 'area1' },
155
+  { label: '片区1', value: 'area2' },
156
+  { label: '片区2', value: 'area3' },
157
+  { label: '片区3', value: 'area4' },
158
+];
159
+
160
+// 辅助函数
161
+// 格式化日期为中文格式(MM月dd日)
162
+const formatDate = (date: Date): string => {
163
+  const month = date.getMonth() + 1;
164
+  const day = date.getDate();
165
+  return `${month}月${day}日`;
166
+};
167
+
168
+// 更新时间范围的函数
169
+const updateTimeRange = (type: 'month' | 'week'): void => {
170
+  const today = new Date();
171
+  let startDate: Date;
172
+  const endDate = today;
173
+
174
+  if (type === 'week') {
175
+    // 计算最近一周(今天往前推7天)
176
+    startDate = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
177
+    currentPeriod.value = `${formatDate(startDate)}-${formatDate(endDate)}`;
178
+  } else {
179
+    // 计算最近一个月(上个月的今天到今天)
180
+    startDate = new Date(
181
+      today.getFullYear(),
182
+      today.getMonth() - 1,
183
+      today.getDate(),
184
+    );
185
+    currentPeriod.value = `${formatDate(startDate)}-${formatDate(endDate)}`;
186
+  }
187
+};
188
+
189
+// 重置搜索条件
190
+const resetSearch = () => {
191
+  selectedName.value = '';
192
+  selectedStation.value = '';
193
+  selectedArea.value = '';
194
+  periodType.value = 'week';
195
+  updateTimeRange(periodType.value);
196
+};
197
+
198
+// 虚拟数据
199
+const MOCK_DATA: TaskReportData[] = [
200
+  {
201
+    id: 1,
202
+    station: '北京东加油站',
203
+    manager: '李经理',
204
+    area: '默认片区',
205
+    totalScore: 44,
206
+    completionRate: { ratio: '95.52%', score: 24 },
207
+    taskScore: { score: 0, obtainedScore: 0 },
208
+    readRate: { ratio: '0.00%', score: 0 },
209
+    maxSameScoreRate: { ratio: '56.11%', score: 8 },
210
+    overdueCount: { count: 3, score: 12 },
211
+  },
212
+  {
213
+    id: 2,
214
+    station: '北京西加油站',
215
+    manager: '王经理',
216
+    area: '默认片区',
217
+    totalScore: 8,
218
+    completionRate: { ratio: '77.14%', score: 0 },
219
+    taskScore: { score: 0, obtainedScore: 0 },
220
+    readRate: { ratio: '0.00%', score: 0 },
221
+    maxSameScoreRate: { ratio: '25%', score: 8 },
222
+    overdueCount: { count: 16, score: 0 },
223
+  },
224
+  {
225
+    id: 3,
226
+    station: '机场油站',
227
+    manager: '张经理',
228
+    area: '片区1',
229
+    totalScore: 50,
230
+    completionRate: { ratio: '100%', score: 25 },
231
+    taskScore: { score: 0, obtainedScore: 0 },
232
+    readRate: { ratio: '50.00%', score: 0 },
233
+    maxSameScoreRate: { ratio: '33.33%', score: 10 },
234
+    overdueCount: { count: 0, score: 15 },
235
+  },
236
+  {
237
+    id: 4,
238
+    station: '北京南加油站',
239
+    manager: '刘经理',
240
+    area: '片区2',
241
+    totalScore: 38,
242
+    completionRate: { ratio: '90.00%', score: 22 },
243
+    taskScore: { score: 0, obtainedScore: 0 },
244
+    readRate: { ratio: '33.33%', score: 0 },
245
+    maxSameScoreRate: { ratio: '66.67%', score: 6 },
246
+    overdueCount: { count: 2, score: 10 },
247
+  },
248
+  {
249
+    id: 5,
250
+    station: '北京北加油站',
251
+    manager: '陈经理',
252
+    area: '片区3',
253
+    totalScore: 42,
254
+    completionRate: { ratio: '93.33%', score: 23 },
255
+    taskScore: { score: 0, obtainedScore: 0 },
256
+    readRate: { ratio: '25.00%', score: 0 },
257
+    maxSameScoreRate: { ratio: '40.00%', score: 8 },
258
+    overdueCount: { count: 1, score: 11 },
259
+  },
260
+];
261
+
262
+// 任务全指标报表虚拟数据
263
+const FULL_INDICATOR_MOCK_DATA: FullIndicatorReportData[] = [
264
+  {
265
+    id: 1,
266
+    station: '未来路加油',
267
+    manager: '李玫琳',
268
+    area: '默认片区',
269
+    taskQuantity: {
270
+      totalTasks: 52,
271
+      completedOnTime: 48,
272
+      completedOverdue: 3,
273
+      notCompleted: 1,
274
+      totalCompletionRate: '98.08%',
275
+      overdueRate: '5.77%',
276
+      authorizedRate: '2.5%',
277
+      newTaskRate: '1.92%',
278
+    },
279
+    taskQuality: {
280
+      commentCount: 12,
281
+      taskScore: 4.5,
282
+      ledgerAverage: 85.5,
283
+    },
284
+    authorization: {
285
+      authorizedCount: 1,
286
+      authorizedRate: '1.92%',
287
+      authorizationComments: 0,
288
+    },
289
+    查阅: {
290
+      readableCount: 51,
291
+      readCount: 0,
292
+      readRate: '0.00%',
293
+      查阅Count: 2,
294
+    },
295
+    performance: {
296
+      maxSameScoreRate: '25%',
297
+      performanceCommentRate: '16.67%',
298
+    },
299
+  },
300
+  {
301
+    id: 2,
302
+    station: '龙飞虎加',
303
+    manager: '安宁',
304
+    area: '默认片区',
305
+    taskQuantity: {
306
+      totalTasks: 67,
307
+      completedOnTime: 58,
308
+      completedOverdue: 8,
309
+      notCompleted: 1,
310
+      totalCompletionRate: '98.51%',
311
+      overdueRate: '11.94%',
312
+      authorizedRate: '33.33%',
313
+      newTaskRate: '1.49%',
314
+    },
315
+    taskQuality: {
316
+      commentCount: 8,
317
+      taskScore: 4.2,
318
+      ledgerAverage: 88.2,
319
+    },
320
+    authorization: {
321
+      authorizedCount: 11,
322
+      authorizedRate: '16.42%',
323
+      authorizationComments: 3,
324
+    },
325
+    查阅: {
326
+      readableCount: 80,
327
+      readCount: 0,
328
+      readRate: '0.00%',
329
+      查阅Count: 1,
330
+    },
331
+    performance: {
332
+      maxSameScoreRate: '36.11%',
333
+      performanceCommentRate: '8.33%',
334
+    },
335
+  },
336
+  {
337
+    id: 3,
338
+    station: '法站',
339
+    manager: '张磊',
340
+    area: '默认片区',
341
+    taskQuantity: {
342
+      totalTasks: 125,
343
+      completedOnTime: 112,
344
+      completedOverdue: 12,
345
+      notCompleted: 1,
346
+      totalCompletionRate: '99.20%',
347
+      overdueRate: '9.60%',
348
+      authorizedRate: '16.44%',
349
+      newTaskRate: '0.80%',
350
+    },
351
+    taskQuality: {
352
+      commentCount: 15,
353
+      taskScore: 4.7,
354
+      ledgerAverage: 90.5,
355
+    },
356
+    authorization: {
357
+      authorizedCount: 12,
358
+      authorizedRate: '9.60%',
359
+      authorizationComments: 5,
360
+    },
361
+    查阅: {
362
+      readableCount: 131,
363
+      readCount: 0,
364
+      readRate: '0.00%',
365
+      查阅Count: 3,
366
+    },
367
+    performance: {
368
+      maxSameScoreRate: '31.67%',
369
+      performanceCommentRate: '11.67%',
370
+    },
371
+  },
372
+  {
373
+    id: 4,
374
+    station: '机场油站',
375
+    manager: '王经理',
376
+    area: '片区1',
377
+    taskQuantity: {
378
+      totalTasks: 89,
379
+      completedOnTime: 78,
380
+      completedOverdue: 10,
381
+      notCompleted: 1,
382
+      totalCompletionRate: '98.88%',
383
+      overdueRate: '11.24%',
384
+      authorizedRate: '22.47%',
385
+      newTaskRate: '1.12%',
386
+    },
387
+    taskQuality: {
388
+      commentCount: 20,
389
+      taskScore: 4.3,
390
+      ledgerAverage: 87.8,
391
+    },
392
+    authorization: {
393
+      authorizedCount: 10,
394
+      authorizedRate: '11.24%',
395
+      authorizationComments: 4,
396
+    },
397
+    查阅: {
398
+      readableCount: 95,
399
+      readCount: 5,
400
+      readRate: '5.26%',
401
+      查阅Count: 2,
402
+    },
403
+    performance: {
404
+      maxSameScoreRate: '38.33%',
405
+      performanceCommentRate: '13.33%',
406
+    },
407
+  },
408
+  {
409
+    id: 5,
410
+    station: '北京南加油',
411
+    manager: '刘经理',
412
+    area: '片区2',
413
+    taskQuantity: {
414
+      totalTasks: 45,
415
+      completedOnTime: 39,
416
+      completedOverdue: 5,
417
+      notCompleted: 1,
418
+      totalCompletionRate: '97.78%',
419
+      overdueRate: '11.11%',
420
+      authorizedRate: '15.56%',
421
+      newTaskRate: '2.22%',
422
+    },
423
+    taskQuality: {
424
+      commentCount: 7,
425
+      taskScore: 4.1,
426
+      ledgerAverage: 84.2,
427
+    },
428
+    authorization: {
429
+      authorizedCount: 6,
430
+      authorizedRate: '13.33%',
431
+      authorizationComments: 2,
432
+    },
433
+    查阅: {
434
+      readableCount: 48,
435
+      readCount: 3,
436
+      readRate: '6.25%',
437
+      查阅Count: 1,
438
+    },
439
+    performance: {
440
+      maxSameScoreRate: '28.33%',
441
+      performanceCommentRate: '10.00%',
442
+    },
443
+  },
444
+];
445
+
446
+// 任务评估报表表格配置
447
+const taskReportColumns: VxeGridProps['columns'] = [
448
+  { title: '姓名', field: 'manager', minWidth: 120, align: 'center' },
449
+  { title: '油站', field: 'station', minWidth: 150, align: 'center' },
450
+  { title: '片区', field: 'area', minWidth: 120, align: 'center' },
451
+  { title: '总分', field: 'totalScore', minWidth: 80, align: 'center' },
452
+  {
453
+    title: '完成率',
454
+    minWidth: 150,
455
+    align: 'center',
456
+    children: [
457
+      {
458
+        title: '比例',
459
+        field: 'completionRate.ratio',
460
+        minWidth: 80,
461
+        align: 'center',
462
+      },
463
+      {
464
+        title: '得分',
465
+        field: 'completionRate.score',
466
+        minWidth: 70,
467
+        align: 'center',
468
+      },
469
+    ],
470
+  },
471
+  {
472
+    title: '任务得分',
473
+    minWidth: 150,
474
+    align: 'center',
475
+    children: [
476
+      {
477
+        title: '分数',
478
+        field: 'taskScore.score',
479
+        minWidth: 80,
480
+        align: 'center',
481
+      },
482
+      {
483
+        title: '得分',
484
+        field: 'taskScore.obtainedScore',
485
+        minWidth: 70,
486
+        align: 'center',
487
+      },
488
+    ],
489
+  },
490
+  {
491
+    title: '已阅比例',
492
+    minWidth: 150,
493
+    align: 'center',
494
+    children: [
495
+      { title: '比例', field: 'readRate.ratio', minWidth: 80, align: 'center' },
496
+      { title: '得分', field: 'readRate.score', minWidth: 70, align: 'center' },
497
+    ],
498
+  },
499
+  {
500
+    title: '最多相同分数率',
501
+    minWidth: 180,
502
+    align: 'center',
503
+    children: [
504
+      {
505
+        title: '比例',
506
+        field: 'maxSameScoreRate.ratio',
507
+        minWidth: 100,
508
+        align: 'center',
509
+      },
510
+      {
511
+        title: '得分',
512
+        field: 'maxSameScoreRate.score',
513
+        minWidth: 80,
514
+        align: 'center',
515
+      },
516
+    ],
517
+  },
518
+  {
519
+    title: '逾期未完成数',
520
+    minWidth: 180,
521
+    align: 'center',
522
+    children: [
523
+      {
524
+        title: '过期数量',
525
+        field: 'overdueCount.count',
526
+        minWidth: 100,
527
+        align: 'center',
528
+      },
529
+      {
530
+        title: '过期分数',
531
+        field: 'overdueCount.score',
532
+        minWidth: 80,
533
+        align: 'center',
534
+      },
535
+    ],
536
+  },
537
+];
538
+
539
+const taskReportGridOptions: VxeGridProps = {
540
+  columns: taskReportColumns,
541
+  size: 'medium',
542
+  height: '500px',
543
+  useSearchForm: false,
544
+  proxyConfig: {
545
+    enabled: true,
546
+    autoLoad: true,
547
+    ajax: {
548
+      query: async () => {
549
+        return { items: MOCK_DATA, total: MOCK_DATA.length };
550
+      },
551
+    },
552
+  },
553
+  rowConfig: { keyField: 'id' },
554
+  toolbarConfig: {},
555
+  id: 'task-report-table',
556
+};
557
+
558
+// 任务全指标报表表格配置
559
+const fullIndicatorReportColumns: VxeGridProps['columns'] = [
560
+  {
561
+    title: '姓名',
562
+    field: 'manager',
563
+    minWidth: 120,
564
+    align: 'center',
565
+    fixed: 'left',
566
+  },
567
+  {
568
+    title: '油站',
569
+    field: 'station',
570
+    minWidth: 150,
571
+    align: 'center',
572
+    fixed: 'left',
573
+  },
574
+  {
575
+    title: '片区',
576
+    field: 'area',
577
+    minWidth: 120,
578
+    align: 'center',
579
+    fixed: 'left',
580
+  },
581
+  {
582
+    title: '任务数量',
583
+    minWidth: 400,
584
+    align: 'center',
585
+    children: [
586
+      {
587
+        title: '任务数',
588
+        field: 'taskQuantity.totalTasks',
589
+        minWidth: 80,
590
+        align: 'center',
591
+      },
592
+      {
593
+        title: '按时完成',
594
+        field: 'taskQuantity.completedOnTime',
595
+        minWidth: 80,
596
+        align: 'center',
597
+      },
598
+      {
599
+        title: '逾期完成',
600
+        field: 'taskQuantity.completedOverdue',
601
+        minWidth: 80,
602
+        align: 'center',
603
+      },
604
+      {
605
+        title: '过期未完成',
606
+        field: 'taskQuantity.notCompleted',
607
+        minWidth: 90,
608
+        align: 'center',
609
+      },
610
+      {
611
+        title: '总完成率',
612
+        field: 'taskQuantity.totalCompletionRate',
613
+        minWidth: 80,
614
+        align: 'center',
615
+      },
616
+      {
617
+        title: '逾期率',
618
+        field: 'taskQuantity.overdueRate',
619
+        minWidth: 80,
620
+        align: 'center',
621
+      },
622
+      {
623
+        title: '被授权率',
624
+        field: 'taskQuantity.authorizedRate',
625
+        minWidth: 80,
626
+        align: 'center',
627
+      },
628
+      {
629
+        title: '新增任务率',
630
+        field: 'taskQuantity.newTaskRate',
631
+        minWidth: 80,
632
+        align: 'center',
633
+      },
634
+    ],
635
+  },
636
+  {
637
+    title: '任务质量',
638
+    minWidth: 250,
639
+    align: 'center',
640
+    children: [
641
+      {
642
+        title: '收到的点评数',
643
+        field: 'taskQuality.commentCount',
644
+        minWidth: 100,
645
+        align: 'center',
646
+      },
647
+      {
648
+        title: '任务得分',
649
+        field: 'taskQuality.taskScore',
650
+        minWidth: 80,
651
+        align: 'center',
652
+      },
653
+      {
654
+        title: '台账平均数',
655
+        field: 'taskQuality.ledgerAverage',
656
+        minWidth: 80,
657
+        align: 'center',
658
+      },
659
+    ],
660
+  },
661
+  {
662
+    title: '授权',
663
+    minWidth: 250,
664
+    align: 'center',
665
+    children: [
666
+      {
667
+        title: '已授权',
668
+        field: 'authorization.authorizedCount',
669
+        minWidth: 80,
670
+        align: 'center',
671
+      },
672
+      {
673
+        title: '已授权率',
674
+        field: 'authorization.authorizedRate',
675
+        minWidth: 80,
676
+        align: 'center',
677
+      },
678
+      {
679
+        title: '授权点评',
680
+        field: 'authorization.authorizationComments',
681
+        minWidth: 80,
682
+        align: 'center',
683
+      },
684
+    ],
685
+  },
686
+  {
687
+    title: '查阅',
688
+    minWidth: 300,
689
+    align: 'center',
690
+    children: [
691
+      {
692
+        title: '可阅读',
693
+        field: '查阅.readableCount',
694
+        minWidth: 80,
695
+        align: 'center',
696
+      },
697
+      {
698
+        title: '已阅读',
699
+        field: '查阅.readCount',
700
+        minWidth: 80,
701
+        align: 'center',
702
+      },
703
+      {
704
+        title: '已阅读率',
705
+        field: '查阅.readRate',
706
+        minWidth: 80,
707
+        align: 'center',
708
+      },
709
+      {
710
+        title: '被查阅数',
711
+        field: '查阅.查阅Count',
712
+        minWidth: 80,
713
+        align: 'center',
714
+      },
715
+    ],
716
+  },
717
+  {
718
+    title: '绩效',
719
+    minWidth: 250,
720
+    align: 'center',
721
+    children: [
722
+      {
723
+        title: '最多相同分数率',
724
+        field: 'performance.maxSameScoreRate',
725
+        minWidth: 100,
726
+        align: 'center',
727
+      },
728
+      {
729
+        title: '绩效评语率',
730
+        field: 'performance.performanceCommentRate',
731
+        minWidth: 100,
732
+        align: 'center',
733
+      },
734
+    ],
735
+  },
736
+];
737
+
738
+const fullIndicatorReportGridOptions: VxeGridProps = {
739
+  columns: fullIndicatorReportColumns,
740
+  size: 'medium',
741
+  height: '500px',
742
+  useSearchForm: false,
743
+  proxyConfig: {
744
+    enabled: true,
745
+    autoLoad: true,
746
+    ajax: {
747
+      query: async () => {
748
+        return {
749
+          items: FULL_INDICATOR_MOCK_DATA,
750
+          total: FULL_INDICATOR_MOCK_DATA.length,
751
+        };
752
+      },
753
+    },
754
+  },
755
+  rowConfig: { keyField: 'id' },
756
+  toolbarConfig: {},
757
+  id: 'full-indicator-report-table',
758
+  scrollX: true,
759
+  scrollY: true,
760
+};
761
+
762
+// 创建表格实例
763
+const [TaskReportTable] = useVbenVxeGrid({
764
+  gridOptions: taskReportGridOptions,
765
+});
766
+const [FullIndicatorReportTable] = useVbenVxeGrid({
767
+  gridOptions: fullIndicatorReportGridOptions,
768
+});
769
+
770
+// 事件处理函数
771
+// 查询按钮点击事件
772
+const handleQuery = () => {
773
+  console.log('查询条件:', {
774
+    reportType: reportType.value,
775
+    name: selectedName.value,
776
+    station: selectedStation.value,
777
+    area: selectedArea.value,
778
+    periodType: periodType.value,
779
+    period: currentPeriod.value,
780
+  });
781
+  // TODO: 这里可以添加实际的查询逻辑,调用API获取真实数据
782
+};
783
+
784
+// 重置按钮点击事件
785
+const handleReset = () => {
786
+  resetSearch();
787
+  console.log('重置搜索条件');
788
+};
789
+
790
+// 导出按钮点击事件
791
+const handleExport = () => {
792
+  console.log('导出数据');
793
+  // TODO: 这里可以添加导出逻辑
794
+};
795
+
796
+// 生命周期钩子和监听
797
+// 监听时间类型变化 - 更新当前时段显示
798
+watch(periodType, (newType) => {
799
+  updateTimeRange(newType);
800
+});
801
+
802
+// 组件初始化 - 设置默认时间范围
803
+onMounted(() => {
804
+  updateTimeRange(periodType.value);
805
+});
3 806
 </script>
807
+
4 808
 <template>
5
-<Page>
6
-<div class="wrap">
7
-         空空如也
8
-</div>
9
-</Page>
809
+  <Page :auto-content-height="true">
810
+    <div class="task-report-container">
811
+      <!-- 报表类型切换 -->
812
+      <div class="report-type-container">
813
+        <ElRadioGroup v-model="reportType" size="large">
814
+          <ElRadioButton
815
+            v-for="option in reportTypeOptions"
816
+            :key="option.value"
817
+            :label="option.value"
818
+          >
819
+            {{ option.label }}
820
+          </ElRadioButton>
821
+        </ElRadioGroup>
822
+      </div>
823
+
824
+      <!-- 搜索区域 -->
825
+      <div class="search-container">
826
+        <ElSpace>
827
+          <div class="search-item">
828
+            <label>姓名:</label>
829
+            <ElSelect
830
+              v-model="selectedName"
831
+              placeholder="请选择姓名"
832
+              style="width: 180px"
833
+            >
834
+              <ElOption
835
+                v-for="option in nameOptions"
836
+                :key="option.value"
837
+                :label="option.label"
838
+                :value="option.value"
839
+              />
840
+            </ElSelect>
841
+          </div>
842
+          <div class="search-item">
843
+            <label>油站:</label>
844
+            <ElSelect
845
+              v-model="selectedStation"
846
+              placeholder="请选择油站"
847
+              style="width: 180px"
848
+            >
849
+              <ElOption
850
+                v-for="option in stationOptions"
851
+                :key="option.value"
852
+                :label="option.label"
853
+                :value="option.value"
854
+              />
855
+            </ElSelect>
856
+          </div>
857
+          <div class="search-item">
858
+            <label>片区:</label>
859
+            <ElSelect
860
+              v-model="selectedArea"
861
+              placeholder="请选择片区"
862
+              style="width: 180px"
863
+            >
864
+              <ElOption
865
+                v-for="option in areaOptions"
866
+                :key="option.value"
867
+                :label="option.label"
868
+                :value="option.value"
869
+              />
870
+            </ElSelect>
871
+          </div>
872
+          <div class="search-item">
873
+            <ElRadioGroup v-model="periodType" size="large">
874
+              <ElRadioButton
875
+                v-for="option in periodTypeOptions"
876
+                :key="option.value"
877
+                :label="option.value"
878
+              >
879
+                {{ option.label }}
880
+              </ElRadioButton>
881
+            </ElRadioGroup>
882
+          </div>
883
+          <div class="search-item">
884
+            <span>{{ currentPeriod }}</span>
885
+          </div>
886
+        </ElSpace>
887
+      </div>
888
+
889
+      <!-- 操作按钮区域 -->
890
+      <div class="button-container">
891
+        <ElSpace>
892
+          <ElButton type="primary" @click="handleQuery">查询</ElButton>
893
+          <ElButton @click="handleReset">重置</ElButton>
894
+          <ElButton @click="handleExport">导出</ElButton>
895
+        </ElSpace>
896
+      </div>
897
+
898
+      <!-- 报表提示语 -->
899
+      <div class="notice-container">
900
+        <p>数据周期:次周周三早9点自动生成,按周切片,次周日早9点自动生成。</p>
901
+      </div>
902
+
903
+      <!-- 报表数据表格 -->
904
+      <div class="table-container">
905
+        <TaskReportTable v-if="reportType === 'evaluation'" />
906
+        <FullIndicatorReportTable v-else />
907
+      </div>
908
+    </div>
909
+  </Page>
10 910
 </template>
11
-<style lang="scss" scoped>
12
-.wrap {
13
-padding: 16px;
14
-background-color: #fff;
15
-border-radius: 6px;
911
+
912
+<style scoped lang="scss">
913
+.task-report-container {
914
+  min-height: calc(100vh - 120px);
915
+  padding: 16px;
916
+  background-color: #fff;
917
+
918
+  .report-type-container {
919
+    margin-bottom: 16px;
920
+  }
921
+
922
+  .search-container {
923
+    display: flex;
924
+    align-items: center;
925
+    padding: 16px;
926
+    margin-bottom: 16px;
927
+    border-radius: 6px;
928
+
929
+    .search-item {
930
+      display: flex;
931
+      align-items: center;
932
+
933
+      label {
934
+        margin-right: 8px;
935
+        font-weight: 500;
936
+      }
937
+    }
938
+  }
939
+
940
+  .button-container {
941
+    margin-bottom: 16px;
942
+  }
943
+
944
+  .notice-container {
945
+    padding: 12px 16px;
946
+    margin-bottom: 16px;
947
+    font-size: 14px;
948
+    color: #606266;
949
+    background-color: #f0f5ff;
950
+    border-left: 4px solid #409eff;
951
+    border-radius: 4px;
952
+
953
+    p {
954
+      margin: 0;
955
+    }
956
+  }
957
+
958
+  .table-container {
959
+    width: 100%;
960
+  }
16 961
 }
17 962
 </style>

+ 772 - 10
apps/web-ele/src/views/operationRadar/taskReport/headquartersPersonnelReport/index.vue

@@ -1,17 +1,779 @@
1 1
 <script lang="ts" setup>
2
+// 导入部分
3
+import type { VxeGridProps } from '#/adapter/vxe-table';
4
+
5
+import { onMounted, ref, watch } from 'vue';
6
+
2 7
 import { Page } from '@vben/common-ui';
8
+
9
+import {
10
+  ElButton,
11
+  ElRadioButton,
12
+  ElRadioGroup,
13
+  ElSelect,
14
+  ElSpace,
15
+} from 'element-plus';
16
+
17
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
18
+
19
+// 类型定义
20
+interface ReportTypeOption {
21
+  label: string;
22
+  value: 'evaluation' | 'full-indicator';
23
+}
24
+
25
+interface PeriodTypeOption {
26
+  label: string;
27
+  value: 'month' | 'week';
28
+}
29
+
30
+interface TaskReportData {
31
+  id: number;
32
+  name: string;
33
+  position: string;
34
+  totalScore: number;
35
+  completionRate: {
36
+    ratio: string;
37
+    score: number;
38
+  };
39
+  taskScore: {
40
+    obtainedScore: number;
41
+    score: number;
42
+  };
43
+  readRate: {
44
+    ratio: string;
45
+    score: number;
46
+  };
47
+  maxSameScoreRate: {
48
+    ratio: string;
49
+    score: number;
50
+  };
51
+  overdueCount: {
52
+    count: number;
53
+    score: number;
54
+  };
55
+}
56
+
57
+// 全指标报表数据类型
58
+interface FullIndicatorReportData {
59
+  id: number;
60
+  name: string;
61
+  position: string;
62
+  // 任务数量
63
+  taskQuantity: {
64
+    authorizedRate: string;
65
+    completedOnTime: number;
66
+    completedOverdue: number;
67
+    newTaskRate: string;
68
+    notCompleted: number;
69
+    overdueRate: string;
70
+    totalCompletionRate: string;
71
+    totalTasks: number;
72
+  };
73
+  // 任务质量
74
+  taskQuality: {
75
+    commentCount: number;
76
+    ledgerAverage: number;
77
+    taskScore: number;
78
+  };
79
+  // 授权
80
+  authorization: {
81
+    authorizationComments: number;
82
+    authorizedCount: number;
83
+    authorizedRate: string;
84
+  };
85
+  // 查阅
86
+  查阅: {
87
+    readableCount: number;
88
+    readCount: number;
89
+    readRate: string;
90
+    查阅Count: number;
91
+  };
92
+  // 绩效
93
+  performance: {
94
+    maxSameScoreRate: string;
95
+    performanceCommentRate: string;
96
+  };
97
+}
98
+
99
+// 响应式数据
100
+// 报表类型切换
101
+const reportType = ref<'evaluation' | 'full-indicator'>('evaluation');
102
+const reportTypeOptions: ReportTypeOption[] = [
103
+  { label: '任务评估报表', value: 'evaluation' },
104
+  { label: '任务全指标报表', value: 'full-indicator' },
105
+];
106
+
107
+// 时间类型切换
108
+const periodType = ref<'month' | 'week'>('week');
109
+const periodTypeOptions: PeriodTypeOption[] = [
110
+  { label: '周', value: 'week' },
111
+  { label: '月', value: 'month' },
112
+];
113
+const currentPeriod = ref('11月13日-11月19日');
114
+
115
+// 搜索条件
116
+const selectedName = ref<string>('');
117
+const nameOptions = ref<{ label: string; value: string }[]>([
118
+  { label: '李经理', value: '李经理' },
119
+  { label: '王经理', value: '王经理' },
120
+  { label: '张经理', value: '张经理' },
121
+  { label: '刘经理', value: '刘经理' },
122
+]);
123
+
124
+// 岗位选择
125
+const selectedPosition = ref<string>('');
126
+const positionOptions = ref<{ label: string; value: string }[]>([
127
+  { label: '总经理', value: '总经理' },
128
+  { label: '运营总监', value: '运营总监' },
129
+  { label: '财务经理', value: '财务经理' },
130
+  { label: '人力资源经理', value: '人力资源经理' },
131
+]);
132
+
133
+// 辅助函数
134
+// 格式化日期为中文格式(MM月dd日)
135
+const formatDate = (date: Date): string => {
136
+  const month = date.getMonth() + 1;
137
+  const day = date.getDate();
138
+  return `${month}月${day}日`;
139
+};
140
+
141
+// 更新时间范围的函数
142
+const updateTimeRange = (type: 'month' | 'week'): void => {
143
+  const today = new Date();
144
+  let startDate: Date;
145
+  const endDate = today;
146
+
147
+  if (type === 'week') {
148
+    // 计算最近一周(今天往前推7天)
149
+    startDate = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
150
+    currentPeriod.value = `${formatDate(startDate)}-${formatDate(endDate)}`;
151
+  } else {
152
+    // 计算最近一个月(上个月的今天到今天)
153
+    startDate = new Date(
154
+      today.getFullYear(),
155
+      today.getMonth() - 1,
156
+      today.getDate(),
157
+    );
158
+    currentPeriod.value = `${formatDate(startDate)}-${formatDate(endDate)}`;
159
+  }
160
+};
161
+
162
+// 重置搜索条件
163
+const resetSearch = () => {
164
+  periodType.value = 'week';
165
+  selectedName.value = '';
166
+  selectedPosition.value = '';
167
+  updateTimeRange(periodType.value);
168
+};
169
+
170
+// 虚拟数据
171
+const MOCK_DATA: TaskReportData[] = [
172
+  {
173
+    id: 1,
174
+    name: '李经理',
175
+    position: '总经理',
176
+    totalScore: 44,
177
+    completionRate: { ratio: '95.52%', score: 24 },
178
+    taskScore: { score: 0, obtainedScore: 0 },
179
+    readRate: { ratio: '0.00%', score: 0 },
180
+    maxSameScoreRate: { ratio: '56.11%', score: 8 },
181
+    overdueCount: { count: 3, score: 12 },
182
+  },
183
+  {
184
+    id: 2,
185
+    name: '王经理',
186
+    position: '运营总监',
187
+    totalScore: 8,
188
+    completionRate: { ratio: '77.14%', score: 0 },
189
+    taskScore: { score: 0, obtainedScore: 0 },
190
+    readRate: { ratio: '0.00%', score: 0 },
191
+    maxSameScoreRate: { ratio: '25%', score: 8 },
192
+    overdueCount: { count: 16, score: 0 },
193
+  },
194
+  {
195
+    id: 3,
196
+    name: '张经理',
197
+    position: '财务经理',
198
+    totalScore: 50,
199
+    completionRate: { ratio: '100%', score: 25 },
200
+    taskScore: { score: 0, obtainedScore: 0 },
201
+    readRate: { ratio: '50.00%', score: 0 },
202
+    maxSameScoreRate: { ratio: '33.33%', score: 10 },
203
+    overdueCount: { count: 0, score: 15 },
204
+  },
205
+  {
206
+    id: 4,
207
+    name: '刘经理',
208
+    position: '人力资源经理',
209
+    totalScore: 38,
210
+    completionRate: { ratio: '90.00%', score: 22 },
211
+    taskScore: { score: 0, obtainedScore: 0 },
212
+    readRate: { ratio: '33.33%', score: 0 },
213
+    maxSameScoreRate: { ratio: '66.67%', score: 6 },
214
+    overdueCount: { count: 2, score: 10 },
215
+  },
216
+];
217
+
218
+// 任务全指标报表虚拟数据
219
+const FULL_INDICATOR_MOCK_DATA: FullIndicatorReportData[] = [
220
+  {
221
+    id: 1,
222
+    name: '李经理',
223
+    position: '总经理',
224
+    taskQuantity: {
225
+      totalTasks: 52,
226
+      completedOnTime: 48,
227
+      completedOverdue: 3,
228
+      notCompleted: 1,
229
+      totalCompletionRate: '98.08%',
230
+      overdueRate: '5.77%',
231
+      authorizedRate: '2.5%',
232
+      newTaskRate: '1.92%',
233
+    },
234
+    taskQuality: {
235
+      commentCount: 12,
236
+      taskScore: 4.5,
237
+      ledgerAverage: 85.5,
238
+    },
239
+    authorization: {
240
+      authorizedCount: 1,
241
+      authorizedRate: '1.92%',
242
+      authorizationComments: 0,
243
+    },
244
+    查阅: {
245
+      readableCount: 51,
246
+      readCount: 0,
247
+      readRate: '0.00%',
248
+      查阅Count: 2,
249
+    },
250
+    performance: {
251
+      maxSameScoreRate: '25%',
252
+      performanceCommentRate: '16.67%',
253
+    },
254
+  },
255
+  {
256
+    id: 2,
257
+    name: '王经理',
258
+    position: '运营总监',
259
+    taskQuantity: {
260
+      totalTasks: 67,
261
+      completedOnTime: 58,
262
+      completedOverdue: 8,
263
+      notCompleted: 1,
264
+      totalCompletionRate: '98.51%',
265
+      overdueRate: '11.94%',
266
+      authorizedRate: '33.33%',
267
+      newTaskRate: '1.49%',
268
+    },
269
+    taskQuality: {
270
+      commentCount: 8,
271
+      taskScore: 4.2,
272
+      ledgerAverage: 88.2,
273
+    },
274
+    authorization: {
275
+      authorizedCount: 11,
276
+      authorizedRate: '16.42%',
277
+      authorizationComments: 3,
278
+    },
279
+    查阅: {
280
+      readableCount: 80,
281
+      readCount: 0,
282
+      readRate: '0.00%',
283
+      查阅Count: 1,
284
+    },
285
+    performance: {
286
+      maxSameScoreRate: '36.11%',
287
+      performanceCommentRate: '8.33%',
288
+    },
289
+  },
290
+];
291
+
292
+// 任务评估报表表格配置
293
+const taskReportColumns: VxeGridProps['columns'] = [
294
+  {
295
+    title: '姓名',
296
+    field: 'name',
297
+    minWidth: 120,
298
+    align: 'center',
299
+  },
300
+  { title: '岗位', field: 'position', minWidth: 150, align: 'center' },
301
+  { title: '总分', field: 'totalScore', minWidth: 80, align: 'center' },
302
+  {
303
+    title: '完成率',
304
+    minWidth: 150,
305
+    align: 'center',
306
+    children: [
307
+      {
308
+        title: '比例',
309
+        field: 'completionRate.ratio',
310
+        minWidth: 80,
311
+        align: 'center',
312
+      },
313
+      {
314
+        title: '得分',
315
+        field: 'completionRate.score',
316
+        minWidth: 70,
317
+        align: 'center',
318
+      },
319
+    ],
320
+  },
321
+  {
322
+    title: '任务得分',
323
+    minWidth: 150,
324
+    align: 'center',
325
+    children: [
326
+      {
327
+        title: '分数',
328
+        field: 'taskScore.score',
329
+        minWidth: 80,
330
+        align: 'center',
331
+      },
332
+      {
333
+        title: '得分',
334
+        field: 'taskScore.obtainedScore',
335
+        minWidth: 70,
336
+        align: 'center',
337
+      },
338
+    ],
339
+  },
340
+  {
341
+    title: '已阅比例',
342
+    minWidth: 150,
343
+    align: 'center',
344
+    children: [
345
+      { title: '比例', field: 'readRate.ratio', minWidth: 80, align: 'center' },
346
+      { title: '得分', field: 'readRate.score', minWidth: 70, align: 'center' },
347
+    ],
348
+  },
349
+  {
350
+    title: '最多相同分数率',
351
+    minWidth: 180,
352
+    align: 'center',
353
+    children: [
354
+      {
355
+        title: '比例',
356
+        field: 'maxSameScoreRate.ratio',
357
+        minWidth: 100,
358
+        align: 'center',
359
+      },
360
+      {
361
+        title: '得分',
362
+        field: 'maxSameScoreRate.score',
363
+        minWidth: 80,
364
+        align: 'center',
365
+      },
366
+    ],
367
+  },
368
+  {
369
+    title: '逾期未完成数',
370
+    minWidth: 180,
371
+    align: 'center',
372
+    children: [
373
+      {
374
+        title: '过期数量',
375
+        field: 'overdueCount.count',
376
+        minWidth: 100,
377
+        align: 'center',
378
+      },
379
+      {
380
+        title: '过期分数',
381
+        field: 'overdueCount.score',
382
+        minWidth: 80,
383
+        align: 'center',
384
+      },
385
+    ],
386
+  },
387
+];
388
+
389
+const taskReportGridOptions: VxeGridProps = {
390
+  columns: taskReportColumns,
391
+  size: 'medium',
392
+  height: '500px',
393
+  useSearchForm: false,
394
+  proxyConfig: {
395
+    enabled: true,
396
+    autoLoad: true,
397
+    ajax: {
398
+      query: async () => {
399
+        return { items: MOCK_DATA, total: MOCK_DATA.length };
400
+      },
401
+    },
402
+  },
403
+  rowConfig: { keyField: 'id' },
404
+  toolbarConfig: {},
405
+  id: 'task-report-table',
406
+};
407
+
408
+// 任务全指标报表表格配置
409
+const fullIndicatorReportColumns: VxeGridProps['columns'] = [
410
+  {
411
+    title: '姓名',
412
+    field: 'name',
413
+    minWidth: 120,
414
+    align: 'center',
415
+    fixed: 'left',
416
+  },
417
+  {
418
+    title: '岗位',
419
+    field: 'position',
420
+    minWidth: 150,
421
+    align: 'center',
422
+    fixed: 'left',
423
+  },
424
+  {
425
+    title: '任务数量',
426
+    minWidth: 400,
427
+    align: 'center',
428
+    children: [
429
+      {
430
+        title: '任务数',
431
+        field: 'taskQuantity.totalTasks',
432
+        minWidth: 80,
433
+        align: 'center',
434
+      },
435
+      {
436
+        title: '按时完成',
437
+        field: 'taskQuantity.completedOnTime',
438
+        minWidth: 80,
439
+        align: 'center',
440
+      },
441
+      {
442
+        title: '逾期完成',
443
+        field: 'taskQuantity.completedOverdue',
444
+        minWidth: 80,
445
+        align: 'center',
446
+      },
447
+      {
448
+        title: '过期未完成',
449
+        field: 'taskQuantity.notCompleted',
450
+        minWidth: 90,
451
+        align: 'center',
452
+      },
453
+      {
454
+        title: '总完成率',
455
+        field: 'taskQuantity.totalCompletionRate',
456
+        minWidth: 80,
457
+        align: 'center',
458
+      },
459
+      {
460
+        title: '逾期率',
461
+        field: 'taskQuantity.overdueRate',
462
+        minWidth: 80,
463
+        align: 'center',
464
+      },
465
+      {
466
+        title: '被授权率',
467
+        field: 'taskQuantity.authorizedRate',
468
+        minWidth: 80,
469
+        align: 'center',
470
+      },
471
+      {
472
+        title: '新增任务率',
473
+        field: 'taskQuantity.newTaskRate',
474
+        minWidth: 80,
475
+        align: 'center',
476
+      },
477
+    ],
478
+  },
479
+  {
480
+    title: '任务质量',
481
+    minWidth: 250,
482
+    align: 'center',
483
+    children: [
484
+      {
485
+        title: '收到的点评数',
486
+        field: 'taskQuality.commentCount',
487
+        minWidth: 100,
488
+        align: 'center',
489
+      },
490
+      {
491
+        title: '任务得分',
492
+        field: 'taskQuality.taskScore',
493
+        minWidth: 80,
494
+        align: 'center',
495
+      },
496
+      {
497
+        title: '台账平均数',
498
+        field: 'taskQuality.ledgerAverage',
499
+        minWidth: 80,
500
+        align: 'center',
501
+      },
502
+    ],
503
+  },
504
+  {
505
+    title: '授权',
506
+    minWidth: 250,
507
+    align: 'center',
508
+    children: [
509
+      {
510
+        title: '已授权',
511
+        field: 'authorization.authorizedCount',
512
+        minWidth: 80,
513
+        align: 'center',
514
+      },
515
+      {
516
+        title: '已授权率',
517
+        field: 'authorization.authorizedRate',
518
+        minWidth: 80,
519
+        align: 'center',
520
+      },
521
+      {
522
+        title: '授权点评',
523
+        field: 'authorization.authorizationComments',
524
+        minWidth: 80,
525
+        align: 'center',
526
+      },
527
+    ],
528
+  },
529
+  {
530
+    title: '查阅',
531
+    minWidth: 300,
532
+    align: 'center',
533
+    children: [
534
+      {
535
+        title: '可阅读',
536
+        field: '查阅.readableCount',
537
+        minWidth: 80,
538
+        align: 'center',
539
+      },
540
+      {
541
+        title: '已阅读',
542
+        field: '查阅.readCount',
543
+        minWidth: 80,
544
+        align: 'center',
545
+      },
546
+      {
547
+        title: '已阅读率',
548
+        field: '查阅.readRate',
549
+        minWidth: 80,
550
+        align: 'center',
551
+      },
552
+      {
553
+        title: '被查阅数',
554
+        field: '查阅.查阅Count',
555
+        minWidth: 80,
556
+        align: 'center',
557
+      },
558
+    ],
559
+  },
560
+  {
561
+    title: '绩效',
562
+    minWidth: 250,
563
+    align: 'center',
564
+    children: [
565
+      {
566
+        title: '最多相同分数率',
567
+        field: 'performance.maxSameScoreRate',
568
+        minWidth: 100,
569
+        align: 'center',
570
+      },
571
+      {
572
+        title: '绩效评语率',
573
+        field: 'performance.performanceCommentRate',
574
+        minWidth: 100,
575
+        align: 'center',
576
+      },
577
+    ],
578
+  },
579
+];
580
+
581
+const fullIndicatorReportGridOptions: VxeGridProps = {
582
+  columns: fullIndicatorReportColumns,
583
+  size: 'medium',
584
+  height: '500px',
585
+  useSearchForm: false,
586
+  proxyConfig: {
587
+    enabled: true,
588
+    autoLoad: true,
589
+    ajax: {
590
+      query: async () => {
591
+        return {
592
+          items: FULL_INDICATOR_MOCK_DATA,
593
+          total: FULL_INDICATOR_MOCK_DATA.length,
594
+        };
595
+      },
596
+    },
597
+  },
598
+  rowConfig: { keyField: 'id' },
599
+  toolbarConfig: {},
600
+  id: 'full-indicator-report-table',
601
+  scrollX: true,
602
+  scrollY: true,
603
+};
604
+
605
+// 创建表格实例
606
+const [TaskReportTable] = useVbenVxeGrid({
607
+  gridOptions: taskReportGridOptions,
608
+});
609
+const [FullIndicatorReportTable] = useVbenVxeGrid({
610
+  gridOptions: fullIndicatorReportGridOptions,
611
+});
612
+
613
+// 事件处理函数
614
+// 查询按钮点击事件
615
+const handleQuery = () => {
616
+  console.log('查询条件:', {
617
+    reportType: reportType.value,
618
+    periodType: periodType.value,
619
+    period: currentPeriod.value,
620
+    name: selectedName.value,
621
+    position: selectedPosition.value,
622
+  });
623
+  // TODO: 这里可以添加实际的查询逻辑,调用API获取真实数据
624
+};
625
+
626
+// 重置按钮点击事件
627
+const handleReset = () => {
628
+  resetSearch();
629
+  console.log('重置搜索条件');
630
+};
631
+
632
+// 导出按钮点击事件
633
+const handleExport = () => {
634
+  console.log('导出数据');
635
+  // TODO: 这里可以添加导出逻辑
636
+};
637
+
638
+// 生命周期钩子和监听
639
+// 监听时间类型变化 - 更新当前时段显示
640
+watch(periodType, (newType) => {
641
+  updateTimeRange(newType);
642
+});
643
+
644
+// 组件初始化 - 设置默认时间范围
645
+onMounted(() => {
646
+  updateTimeRange(periodType.value);
647
+});
3 648
 </script>
649
+
4 650
 <template>
5
-<Page>
6
-<div class="wrap">
7
-         空空如也
8
-</div>
9
-</Page>
651
+  <Page :auto-content-height="true">
652
+    <div class="task-report-container">
653
+      <!-- 报表类型切换 -->
654
+      <div class="report-type-container">
655
+        <ElRadioGroup v-model="reportType" size="large">
656
+          <ElRadioButton
657
+            v-for="option in reportTypeOptions"
658
+            :key="option.value"
659
+            :label="option.value"
660
+          >
661
+            {{ option.label }}
662
+          </ElRadioButton>
663
+        </ElRadioGroup>
664
+      </div>
665
+
666
+      <!-- 搜索区域 -->
667
+      <div class="search-container">
668
+        <ElSpace>
669
+          <div class="search-item">
670
+            <label style="width: 80px">姓名:</label>
671
+            <ElSelect
672
+              v-model="selectedName"
673
+              placeholder="请选择姓名"
674
+              clearable
675
+              filterable
676
+              :options="nameOptions"
677
+            />
678
+          </div>
679
+          <div class="search-item">
680
+            <label style="width: 80px">岗位:</label>
681
+            <ElSelect
682
+              v-model="selectedPosition"
683
+              placeholder="请选择岗位"
684
+              clearable
685
+              filterable
686
+              :options="positionOptions"
687
+            />
688
+          </div>
689
+          <div class="search-item">
690
+            <ElRadioGroup v-model="periodType" size="large">
691
+              <ElRadioButton
692
+                v-for="option in periodTypeOptions"
693
+                :key="option.value"
694
+                :label="option.value"
695
+              >
696
+                {{ option.label }}
697
+              </ElRadioButton>
698
+            </ElRadioGroup>
699
+          </div>
700
+          <div class="search-item">
701
+            <span>{{ currentPeriod }}</span>
702
+          </div>
703
+        </ElSpace>
704
+      </div>
705
+
706
+      <!-- 操作按钮区域 -->
707
+      <div class="button-container">
708
+        <ElSpace>
709
+          <ElButton type="primary" @click="handleQuery">查询</ElButton>
710
+          <ElButton @click="handleReset">重置</ElButton>
711
+          <ElButton @click="handleExport">导出</ElButton>
712
+        </ElSpace>
713
+      </div>
714
+
715
+      <!-- 报表提示语 -->
716
+      <div class="notice-container">
717
+        <p>数据周期:次周周三早9点自动生成,按周切片,次周日早9点自动生成。</p>
718
+      </div>
719
+
720
+      <!-- 报表数据表格 -->
721
+      <div class="table-container">
722
+        <TaskReportTable v-if="reportType === 'evaluation'" />
723
+        <FullIndicatorReportTable v-else />
724
+      </div>
725
+    </div>
726
+  </Page>
10 727
 </template>
11
-<style lang="scss" scoped>
12
-.wrap {
13
-padding: 16px;
14
-background-color: #fff;
15
-border-radius: 6px;
728
+
729
+<style scoped lang="scss">
730
+.task-report-container {
731
+  min-height: calc(100vh - 120px);
732
+  padding: 16px;
733
+  background-color: #fff;
734
+
735
+  .report-type-container {
736
+    margin-bottom: 16px;
737
+  }
738
+
739
+  .search-container {
740
+    display: flex;
741
+    align-items: center;
742
+    padding: 16px;
743
+    margin-bottom: 16px;
744
+    border-radius: 6px;
745
+
746
+    .search-item {
747
+      display: flex;
748
+      align-items: center;
749
+
750
+      label {
751
+        margin-right: 8px;
752
+        font-weight: 500;
753
+      }
754
+    }
755
+  }
756
+
757
+  .button-container {
758
+    margin-bottom: 16px;
759
+  }
760
+
761
+  .notice-container {
762
+    padding: 12px 16px;
763
+    margin-bottom: 16px;
764
+    font-size: 14px;
765
+    color: #606266;
766
+    background-color: #f0f5ff;
767
+    border-left: 4px solid #409eff;
768
+    border-radius: 4px;
769
+
770
+    p {
771
+      margin: 0;
772
+    }
773
+  }
774
+
775
+  .table-container {
776
+    width: 100%;
777
+  }
16 778
 }
17 779
 </style>