Sfoglia il codice sorgente

feat(assistant): 新增使用报表功能及优化绩效分析

添加使用报表功能模块,包括API接口、页面组件及导出功能
优化绩效分析模块的日期选择逻辑和图表显示配置
调整主界面布局以支持新功能入口
huoyi 4 settimane fa
parent
commit
f048dbd08d

+ 9 - 0
src/api/assistant/assistant.js

@@ -106,4 +106,13 @@ export function getCalculateByTimeList(data) {
106 106
     method: 'post',
107 107
     data: data
108 108
   })
109
+}
110
+
111
+//使用报告
112
+export function getUsageReport(query) {
113
+  return request({
114
+    url: '/system/usageReport/report',
115
+    method: 'get',
116
+    params: query
117
+  })
109 118
 }

+ 23 - 6
src/views/assistant/components/performanceAnalysis.vue

@@ -297,6 +297,15 @@ const disabledStartMonth = (date) => {
297 297
     return true
298 298
   }
299 299
 
300
+  // 如果已经选择了结束月份,开始月份不能晚于或等于结束月份
301
+  if (queryForm.value.endMonth) {
302
+    const endDate = new Date(queryForm.value.endMonth)
303
+    if (date.getFullYear() > endDate.getFullYear() ||
304
+      (date.getFullYear() === endDate.getFullYear() && date.getMonth() >= endDate.getMonth())) {
305
+      return true
306
+    }
307
+  }
308
+
300 309
   return false
301 310
 }
302 311
 
@@ -316,11 +325,11 @@ const disabledEndMonth = (date) => {
316 325
     return true
317 326
   }
318 327
 
319
-  // 如果已经选择了开始月份,结束月份不能早于开始月份
328
+  // 如果已经选择了开始月份,结束月份不能早于或等于开始月份
320 329
   if (queryForm.value.startMonth) {
321 330
     const startDate = new Date(queryForm.value.startMonth)
322 331
     if (date.getFullYear() < startDate.getFullYear() ||
323
-      (date.getFullYear() === startDate.getFullYear() && date.getMonth() < startDate.getMonth())) {
332
+      (date.getFullYear() === startDate.getFullYear() && date.getMonth() <= startDate.getMonth())) {
324 333
       return true
325 334
     }
326 335
   }
@@ -409,7 +418,9 @@ const brigadeChartOptions = {
409 418
   },
410 419
   yAxis: {
411 420
     type: 'value',
412
-    name: '得分'
421
+    name: '得分',
422
+    min: 80,
423
+    interval: 5
413 424
   },
414 425
   series: [
415 426
 
@@ -438,7 +449,9 @@ const departmentChartOptions = {
438 449
   },
439 450
   yAxis: {
440 451
     type: 'value',
441
-    name: '得分'
452
+    name: '得分',
453
+    min: 80,
454
+    interval: 5
442 455
   },
443 456
   series: [
444 457
 
@@ -467,7 +480,9 @@ const teamListChartOptions = {
467 480
   },
468 481
   yAxis: {
469 482
     type: 'value',
470
-    name: '得分'
483
+    name: '得分',
484
+    min: 80,
485
+    interval: 5
471 486
   },
472 487
   series: []
473 488
 }
@@ -494,7 +509,9 @@ const personalChartOptions = {
494 509
   },
495 510
   yAxis: {
496 511
     type: 'value',
497
-    name: '得分'
512
+    name: '得分',
513
+    min: 80,
514
+    interval: 5
498 515
   },
499 516
   series: []
500 517
 }

File diff suppressed because it is too large
+ 680 - 0
src/views/assistant/components/useReports.vue


+ 32 - 40
src/views/assistant/index.vue

@@ -1,6 +1,6 @@
1 1
 <template>
2 2
   <div class="ai-assist-wrapper">
3
-    <div class="ai-assist-container" v-if="!showDataBoard && !showPerformanceAnalysis">
3
+    <div class="ai-assist-container" v-if="!showDataBoard && !showPerformanceAnalysis && !showUseReports">
4 4
 
5 5
       <!-- 消息区域 -->
6 6
       <div class="messages-area" ref="messagesRef">
@@ -20,10 +20,12 @@
20 20
                 <div v-for="step in msg.steps" :key="step.step" :class="['step-item', step.status]">
21 21
                   <span class="step-icon">
22 22
                     <svg v-if="step.status === 'running'" class="spin-icon" viewBox="0 0 24 24" fill="none">
23
-                      <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" stroke-dasharray="32" stroke-dashoffset="10"/>
23
+                      <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" stroke-dasharray="32"
24
+                        stroke-dashoffset="10" />
24 25
                     </svg>
25 26
                     <svg v-else viewBox="0 0 24 24" fill="none">
26
-                      <path d="M5 13l4 4L19 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
27
+                      <path d="M5 13l4 4L19 7" stroke="currentColor" stroke-width="2" stroke-linecap="round"
28
+                        stroke-linejoin="round" />
27 29
                     </svg>
28 30
                   </span>
29 31
                   <span class="step-name">{{ step.name }}</span>
@@ -52,21 +54,10 @@
52 54
                     <div class="answer-text">{{ msg.result.answer }}</div>
53 55
                   </div>
54 56
                   <div class="result-summary">{{ msg.result.message }}</div>
55
-                  <el-table
56
-                    v-if="msg.result.rows && msg.result.rows.length"
57
-                    :data="msg.result.rows"
58
-                    border
59
-                    size="small"
60
-                    max-height="360"
61
-                    class="result-table"
62
-                  >
63
-                    <el-table-column
64
-                      v-for="col in msg.result.columns"
65
-                      :key="col"
66
-                      :prop="col"
67
-                      :label="col"
68
-                      min-width="100"
69
-                    />
57
+                  <el-table v-if="msg.result.rows && msg.result.rows.length" :data="msg.result.rows" border size="small"
58
+                    max-height="360" class="result-table">
59
+                    <el-table-column v-for="col in msg.result.columns" :key="col" :prop="col" :label="col"
60
+                      min-width="100" />
70 61
                   </el-table>
71 62
                   <div v-else-if="msg.result.rows" class="no-data">暂无数据</div>
72 63
                 </div>
@@ -80,8 +71,8 @@
80 71
               <!-- 错误 -->
81 72
               <div v-if="msg.status === 'error'" class="error-message">
82 73
                 <svg viewBox="0 0 24 24" fill="none" width="16" height="16">
83
-                  <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
84
-                  <path d="M12 8v4m0 4h.01" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
74
+                  <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" />
75
+                  <path d="M12 8v4m0 4h.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
85 76
                 </svg>
86 77
                 {{ msg.errorText }}
87 78
               </div>
@@ -95,24 +86,14 @@
95 86
         <div class="quick-action">
96 87
           <el-button class="report-btn" @click="handleReportClick">质控分析报告</el-button>
97 88
           <el-button class="report-btn" @click="handlePerformanceClick">绩效分析报告</el-button>
89
+          <el-button class="report-btn" @click="handleUseReportClick">使用报表</el-button>
98 90
         </div>
99 91
         <div class="input-container">
100
-          <el-input
101
-            v-model="inputMessage"
102
-            type="textarea"
103
-            :rows="3"
104
-            placeholder="请输入您的问题,按 Enter 发送..."
105
-            class="chat-input"
106
-            @keydown.enter.exact.prevent="handleSend"
107
-          />
108
-          <el-button
109
-            :disabled="!inputMessage.trim() || isLoading"
110
-            circle
111
-            class="send-btn"
112
-            @click="handleSend"
113
-          >
92
+          <el-input v-model="inputMessage" type="textarea" :rows="3" placeholder="请输入您的问题,按 Enter 发送..."
93
+            class="chat-input" @keydown.enter.exact.prevent="handleSend" />
94
+          <el-button :disabled="!inputMessage.trim() || isLoading" circle class="send-btn" @click="handleSend">
114 95
             <svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18">
115
-              <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
96
+              <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
116 97
             </svg>
117 98
           </el-button>
118 99
         </div>
@@ -121,6 +102,7 @@
121 102
 
122 103
     <DataBoard v-if="showDataBoard" @back="handleBack" />
123 104
     <PerformanceAnalysis v-if="showPerformanceAnalysis" @back="handleBack" />
105
+    <UseReports v-if="showUseReports" @back="handleBack" />
124 106
   </div>
125 107
 </template>
126 108
 
@@ -129,7 +111,7 @@ import { ref, nextTick, onMounted, onActivated, onDeactivated } from 'vue'
129 111
 import DataBoard from './components/dataBoard.vue'
130 112
 import PerformanceAnalysis from './components/performanceAnalysis.vue'
131 113
 import useUserStore from '@/store/modules/user'
132
-
114
+import UseReports from './components/useReports.vue'
133 115
 const userStore = useUserStore()
134 116
 const AI_SERVICE_URL = import.meta.env.VITE_AI_SERVICE_URL || 'http://localhost:8000'
135 117
 
@@ -139,6 +121,7 @@ const messages = ref([])
139 121
 const messagesRef = ref(null)
140 122
 const showDataBoard = ref(false)
141 123
 const showPerformanceAnalysis = ref(false)
124
+const showUseReports = ref(false)
142 125
 
143 126
 onMounted(() => resetState())
144 127
 onActivated(() => resetState())
@@ -149,6 +132,7 @@ const resetState = () => {
149 132
   showPerformanceAnalysis.value = false
150 133
   inputMessage.value = ''
151 134
   messages.value = []
135
+  showUseReports.value = false
152 136
   isLoading.value = false
153 137
 }
154 138
 
@@ -270,9 +254,11 @@ const handleSend = async () => {
270 254
 
271 255
 const handleReportClick = () => { showDataBoard.value = true }
272 256
 const handlePerformanceClick = () => { showPerformanceAnalysis.value = true }
257
+const handleUseReportClick = () => { showUseReports.value = true }
273 258
 const handleBack = () => {
274 259
   showDataBoard.value = false
275 260
   showPerformanceAnalysis.value = false
261
+  showUseReports.value = false
276 262
 }
277 263
 </script>
278 264
 
@@ -349,7 +335,7 @@ const handleBack = () => {
349 335
   background: #fff;
350 336
   padding: 14px 16px;
351 337
   border-radius: 18px 18px 18px 4px;
352
-  box-shadow: 0 2px 8px rgba(0,0,0,0.08);
338
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
353 339
   font-size: 14px;
354 340
   line-height: 1.6;
355 341
 }
@@ -392,8 +378,13 @@ const handleBack = () => {
392 378
 }
393 379
 
394 380
 @keyframes spin {
395
-  from { transform: rotate(0deg); }
396
-  to { transform: rotate(360deg); }
381
+  from {
382
+    transform: rotate(0deg);
383
+  }
384
+
385
+  to {
386
+    transform: rotate(360deg);
387
+  }
397 388
 }
398 389
 
399 390
 .step-detail {
@@ -536,7 +527,8 @@ const handleBack = () => {
536 527
     font-size: 24px;
537 528
   }
538 529
 
539
-  .user-bubble, .assistant-bubble {
530
+  .user-bubble,
531
+  .assistant-bubble {
540 532
     max-width: 95%;
541 533
   }
542 534
 }