From e2c104fdff2df9b35c267652c4849571e5a4b2ca Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期三, 09 九月 2026 01:18:30 +0800
Subject: [PATCH] 完善首页统计与待办负责人权限

---
 src/views/Dashboard.vue |   78 ++++++++++++++++++++++++--------------
 1 files changed, 49 insertions(+), 29 deletions(-)

diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue
index 4a86a63..b78d367 100644
--- a/src/views/Dashboard.vue
+++ b/src/views/Dashboard.vue
@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { computed, ref } from 'vue'
+import { computed, onMounted, ref } from 'vue'
 import { useRouter } from 'vue-router'
 import { use } from 'echarts/core'
 import { CanvasRenderer } from 'echarts/renderers'
@@ -7,6 +7,9 @@
 import { GridComponent, TooltipComponent } from 'echarts/components'
 import VChart from 'vue-echarts'
 import { useTests, type TestRecord } from '@/stores/tests'
+import { useTodos } from '@/stores/todos'
+import { getTestList } from '@/api/tests'
+import { getBatteryGroupList } from '@/api/batteryGroups'
 
 use([CanvasRenderer, BarChart, GridComponent, TooltipComponent])
 
@@ -14,6 +17,21 @@
 const chartPeriod = ref('week')
 const router = useRouter()
 const { records } = useTests()
+const { records: todoRecords } = useTodos()
+onMounted(async () => {
+  try {
+    const [tests, groups] = await Promise.all([
+      getTestList({ pageNum: 1, pageSize: 1000 }),
+      getBatteryGroupList({ pageNum: 1, pageSize: 1000 }),
+    ])
+    records.value = tests.rows
+    // 首页的电池组总数来自后端列表,避免用页面种子推断业务事实。
+    batteryGroupCount.value = groups.total
+  } catch {
+    // 页面保留当前已加载数据,错误提示由全局请求层处理。
+  }
+})
+const batteryGroupCount = ref(0)
 const testFilterVisible = ref(false)
 const testType = ref('全部')
 const testTypeDraft = ref('全部')
@@ -49,31 +67,33 @@
 const runningTestCount = computed(() => records.value.filter(item => item.status === '检测中').length)
 const pendingTestCount = computed(() => records.value.filter(item => item.status === '待测试').length)
 
-const cabinetStatusSummary = [
-  { label: '在线', value: 18, color: '#23865e' },
-  { label: '离线', value: 18, color: '#8795a3' },
-  { label: '待测试', value: 8, color: '#b77a24' },
-  { label: '进行中', value: 12, color: '#2188f5' },
-  { label: '暂停', value: 0, color: '#b34f4f' },
-]
+const cabinetStatusSummary = computed(() => [
+  { label: '在线', value: cabinets.filter(item => item.status === '在线').length, color: '#23865e' },
+  { label: '离线', value: cabinets.filter(item => item.status === '离线').length, color: '#8795a3' },
+  { label: '待测试', value: records.value.filter(item => item.status === '待测试').length, color: '#b77a24' },
+  { label: '进行中', value: records.value.filter(item => item.status === '检测中').length, color: '#2188f5' },
+  { label: '暂停', value: records.value.filter(item => item.status === '暂停').length, color: '#b34f4f' },
+])
 
-const todoList = [
-  { title: '高温循环测试', time: '09:14 · 待处理', priority: 'P1' },
-  { title: '电芯容量测试', time: '10:18 · 待处理', priority: 'P2' },
-  { title: '低温充放电测试', time: '11:06 · 待处理', priority: 'P1' },
-  { title: 'A-03 设备校准', time: '12:00 · 待处理', priority: 'P2' },
-  { title: '数据修订复核', time: '14:05 · 待处理', priority: 'P1' },
-  { title: '异常记录确认', time: '14:28 · 待处理', priority: 'P1' },
-]
+const todoList = computed(() => todoRecords.value.filter(item => item.status === '待处理').slice(0, 6))
 
-const periodData = {
-  week: { labels: ['07/04', '07/05', '07/06', '07/07', '07/08', '07/09', '07/10'], values: [312, 348, 320, 401, 376, 428, 392] },
-  month: { labels: ['第 1 周', '第 2 周', '第 3 周', '第 4 周'], values: [1460, 1580, 1720, 1640] },
-  year: { labels: ['1月', '3月', '5月', '7月', '9月', '11月'], values: [5200, 6480, 7320, 8874, 9120, 9840] },
-}
+const periodData = computed(() => {
+  const now = new Date()
+  const dayKey = (date: Date) => `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
+  const count = (key: string) => records.value.filter(item => item.createdAt.slice(0, key.length) === key).length
+  const weekLabels: string[] = []; const weekValues: number[] = []
+  for (let index = 6; index >= 0; index -= 1) { const date = new Date(now); date.setDate(now.getDate() - index); const key = dayKey(date); weekLabels.push(`${date.getMonth() + 1}/${date.getDate()}`); weekValues.push(count(key)) }
+  const monthKey = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
+  const monthDays = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate(); const monthLabels: string[] = []; const monthValues: number[] = []
+  for (let day = 1; day <= Math.min(now.getDate(), monthDays); day += 1) { const key = `${monthKey}-${String(day).padStart(2, '0')}`; monthLabels.push(`${day}日`); monthValues.push(count(key)) }
+  const yearLabels: string[] = []; const yearValues: number[] = []
+  for (let month = 1; month <= now.getMonth() + 1; month += 1) { const key = `${now.getFullYear()}-${String(month).padStart(2, '0')}`; yearLabels.push(`${month}月`); yearValues.push(count(key)) }
+  return { week: { labels: weekLabels, values: weekValues }, month: { labels: monthLabels, values: monthValues }, year: { labels: yearLabels, values: yearValues } }
+})
 
 const chartOption = computed(() => {
-  const data = periodData[chartPeriod.value as keyof typeof periodData]
+  const data = periodData.value[chartPeriod.value as keyof typeof periodData.value]
+  const values = data.values
   return {
     tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
     grid: { left: 8, right: 10, bottom: 4, top: 22, containLabel: true },
@@ -88,7 +108,7 @@
     },
     series: [{
       type: 'bar', barMaxWidth: 28,
-      data: data.values.map((value, index) => ({ value, itemStyle: { color: index === data.values.length - 1 ? '#2188f5' : '#b9d8f8' } })),
+      data: values.map((value, index) => ({ value, itemStyle: { color: index === values.length - 1 ? '#2188f5' : '#b9d8f8' } })),
       itemStyle: { borderRadius: 0 },
     }],
   }
@@ -154,10 +174,10 @@
         </section>
 
         <div class="metrics">
-          <article><span>总测试数</span><small>+12.4%</small><strong>373</strong></article>
-          <article><span>总电池组数</span><small>+4.2%</small><strong>368</strong></article>
-          <article><span>日新增测试</span><small>+18.7%</small><strong>8,874</strong></article>
-          <article><span>月新增测试</span><small>+9.6%</small><strong>8,874</strong></article>
+          <article><span>总测试数</span><strong>{{ records.length }}</strong></article>
+          <article><span>总电池组数</span><strong>{{ batteryGroupCount }}</strong></article>
+          <article><span>日新增测试</span><strong>{{ records.filter(item => item.createdAt.slice(0, 10) === new Date().toISOString().slice(0, 10)).length }}</strong></article>
+          <article><span>月新增测试</span><strong>{{ records.filter(item => item.createdAt.slice(0, 7) === new Date().toISOString().slice(0, 7)).length }}</strong></article>
         </div>
 
         <section class="panel chart-panel">
@@ -183,8 +203,8 @@
         </section>
 
         <section class="panel todo-panel">
-          <header class="panel-header"><div class="panel-title"><i></i><h3>待办 (18)</h3></div><button class="text-action" type="button" @click="router.push('/todo-list')">全部</button></header>
-          <div class="todo-list"><div v-for="item in todoList" :key="item.title"><span><strong>{{ item.title }}</strong><small>{{ item.time }}</small></span><b :class="item.priority.toLowerCase()">{{ item.priority }}</b></div></div>
+          <header class="panel-header"><div class="panel-title"><i></i><h3>待办 ({{ todoRecords.filter(item => item.status === '待处理').length }})</h3></div><button class="text-action" type="button" @click="router.push('/todo-list')">全部</button></header>
+          <div class="todo-list"><div v-for="item in todoList" :key="item.id"><span><strong>{{ item.content }}</strong><small>{{ item.operatedAt }} · 待处理</small></span><b class="pending">待处理</b></div></div>
         </section>
       </aside>
     </div>

--
Gitblit v1.7.1