From 3df460667d74868d0a54fce12d5e881bbd6c0c1a Mon Sep 17 00:00:00 2001
From: WXL <wl_5969728@163.com>
Date: 星期四, 17 九月 2026 17:11:18 +0800
Subject: [PATCH] 青岛维护统计

---
 src/views/statistics/organ.vue |  239 ++++++++++++++++++++++++++++-------------------------------
 1 files changed, 113 insertions(+), 126 deletions(-)

diff --git a/src/views/statistics/organ.vue b/src/views/statistics/organ.vue
index bff9883..9c420ae 100644
--- a/src/views/statistics/organ.vue
+++ b/src/views/statistics/organ.vue
@@ -81,20 +81,20 @@
         border
         stripe
       >
-        <el-table-column label="骞翠唤" prop="year" align="center"  />
-        <el-table-column label="鍣ㄥ畼鍚嶇О" prop="organName" align="center"  />
-        <el-table-column label="鑾峰彇鏁伴噺" prop="acquisitionCount" align="center"  />
-        <el-table-column label="绉绘鏁伴噺" prop="transplantCount" align="center"  />
-        <el-table-column label="绉绘鐜�" prop="transplantRate" align="center" >
+        <el-table-column label="骞翠唤" prop="year" align="center" />
+        <el-table-column label="鍣ㄥ畼鍚嶇О" prop="organName" align="center" />
+        <el-table-column label="鑾峰彇鏁伴噺" prop="acquisitionCount" align="center" />
+        <el-table-column label="绉绘鏁伴噺" prop="transplantCount" align="center" />
+        <el-table-column label="绉绘鐜�" prop="transplantRate" align="center">
           <template slot-scope="{ row }">
             <el-tag :type="getRateTag(row.transplantRate)" size="small">
               {{ row.transplantRate }}%
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column label="寮冪敤鏁伴噺" prop="abandonCount" align="center"  />
-        <el-table-column label="鍦板尯" prop="region" align="center"  />
-        <el-table-column label="鎿嶄綔" align="center"  fixed="right">
+        <el-table-column label="寮冪敤鏁伴噺" prop="abandonCount" align="center" />
+        <el-table-column label="鍦板尯" prop="region" align="center" />
+        <el-table-column label="鎿嶄綔" align="center" fixed="right">
           <template slot-scope="{ row }">
             <el-button
               type="text"
@@ -139,6 +139,10 @@
 import FilterPanel from '@/components/charts/FilterPanel.vue';
 import EChartsWrapper from '@/components/charts/EChartsWrapper.vue';
 import OrganDetail from './components/OrganDetail.vue';
+import { organ, organMoon, organType } from '@/api/businessApi';
+import { toTotalsList, toMonth, toNum } from '@/utils/totals';
+import statisticsMode from '@/utils/statisticsMode';
+import { COLORS, PALETTE, axisTooltip, grid, xAxis, yAxis, legend, barSeries } from '@/utils/chartStyle';
 
 export default {
   name: 'OrganStatistics',
@@ -166,13 +170,13 @@
           type: 'select',
           multiple: true,
           options: [
-            { label: '闈掑矝鍦板尯', value: 'qingdao' },
-            { label: '鏃ョ収鍦板尯', value: 'rizhao' },
-            { label: '娴庡崡鍦板尯', value: 'jinan' },
-            { label: '鐑熷彴鍦板尯', value: 'yantai' },
-            { label: '濞佹捣鍦板尯', value: 'weihai' },
-            { label: '娼嶅潑鍦板尯', value: 'weifang' },
-            { label: '涓存矀鍦板尯', value: 'linyi' }
+            { label: '闈掑矝鍦板尯', value: '闈掑矝鍦板尯' },
+            { label: '鏃ョ収鍦板尯', value: '鏃ョ収鍦板尯' },
+            { label: '娴庡崡鍦板尯', value: '娴庡崡鍦板尯' },
+            { label: '鐑熷彴鍦板尯', value: '鐑熷彴鍦板尯' },
+            { label: '濞佹捣鍦板尯', value: '濞佹捣鍦板尯' },
+            { label: '娼嶅潑鍦板尯', value: '娼嶅潑鍦板尯' },
+            { label: '涓存矀鍦板尯', value: '涓存矀鍦板尯' }
           ],
           width: '300px'
         },
@@ -191,12 +195,12 @@
           prop: 'organType',
           type: 'select',
           options: [
-            { label: '鍏ㄨ倽', value: 'liver' },
-            { label: '鑲捐剰', value: 'kidney' },
-            { label: '蹇冭剰', value: 'heart' },
-            { label: '鑲�', value: 'lung' },
-            { label: '鑳拌吅', value: 'pancreas' },
-            { label: '鐪艰鑶�', value: 'cornea' }
+            { label: '鍏ㄨ倽', value: '鍏ㄨ倽' },
+            { label: '鑲捐剰', value: '鑲捐剰' },
+            { label: '蹇冭剰', value: '蹇冭剰' },
+            { label: '鑲�', value: '鑲�' },
+            { label: '鑳拌吅', value: '鑳拌吅' },
+            { label: '鐪艰鑶�', value: '鐪艰鑶�' }
           ],
           width: '200px'
         }
@@ -211,93 +215,97 @@
 
       // 姒傝鏁版嵁
       overviewData: [
-        { title: '鎬昏幏鍙栨暟閲�', value: 0, desc: '缁熻鍛ㄦ湡鍐�', icon: 'el-icon-s-claim', color: '#409EFF' },
-        { title: '鎬荤Щ妞嶆暟閲�', value: 0, desc: '缁熻鍛ㄦ湡鍐�', icon: 'el-icon-success', color: '#67C23A' },
-        { title: '鎬荤Щ妞嶇巼', value: '0%', desc: '缁熻鍛ㄦ湡鍐�', icon: 'el-icon-s-data', color: '#E6A23C' },
-        { title: '鎬诲純鐢ㄦ暟閲�', value: 0, desc: '缁熻鍛ㄦ湡鍐�', icon: 'el-icon-warning', color: '#F56C6C' }
+        { title: '鎬昏幏鍙栨暟閲�', value: 0, desc: '缁熻鍛ㄦ湡鍐�', icon: 'el-icon-s-claim', color: '#5B8FF9' },
+        { title: '鎬荤Щ妞嶆暟閲�', value: 0, desc: '缁熻鍛ㄦ湡鍐�', icon: 'el-icon-success', color: '#5AD8A6' },
+        { title: '鎬荤Щ妞嶇巼', value: '0%', desc: '缁熻鍛ㄦ湡鍐�', icon: 'el-icon-s-data', color: '#F6BD16' },
+        { title: '鎬诲純鐢ㄦ暟閲�', value: 0, desc: '缁熻鍛ㄦ湡鍐�', icon: 'el-icon-warning', color: '#E8684A' }
       ],
 
       // 鍥捐〃閰嶇疆
       trendChartOptions: {},
       distributionChartOptions: {},
 
+      // 鍥捐〃鏁版嵁
+      chartData: {
+        trend: [],
+        distribution: []
+      },
+
       // 寮圭獥鎺у埗
       showOrganDetail: false,
-      detailQuery: {},
-
-      // 妯℃嫙鏁版嵁
-      mockData: {
-        table: [
-          { id: 1, year: '2024', organName: '鍏ㄨ倽', acquisitionCount: 15, transplantCount: 12, transplantRate: 80.0, abandonCount: 3, region: '闈掑矝鍦板尯' },
-          { id: 2, year: '2024', organName: '鑲捐剰', acquisitionCount: 20, transplantCount: 18, transplantRate: 90.0, abandonCount: 2, region: '闈掑矝鍦板尯' },
-          { id: 3, year: '2024', organName: '鍏ㄨ倽', acquisitionCount: 8, transplantCount: 6, transplantRate: 75.0, abandonCount: 2, region: '鏃ョ収鍦板尯' },
-          { id: 4, year: '2024', organName: '蹇冭剰', acquisitionCount: 5, transplantCount: 4, transplantRate: 80.0, abandonCount: 1, region: '闈掑矝鍦板尯' },
-          { id: 5, year: '2023', organName: '鍏ㄨ倽', acquisitionCount: 12, transplantCount: 10, transplantRate: 83.3, abandonCount: 2, region: '闈掑矝鍦板尯' },
-          { id: 6, year: '2023', organName: '鐪艰鑶�', acquisitionCount: 25, transplantCount: 22, transplantRate: 88.0, abandonCount: 3, region: '娴庡崡鍦板尯' }
-        ],
-        trend: [
-          { year: '2020', acquisition: 120, transplant: 100 },
-          { year: '2021', acquisition: 150, transplant: 130 },
-          { year: '2022', acquisition: 180, transplant: 160 },
-          { year: '2023', acquisition: 220, transplant: 200 },
-          { year: '2024', acquisition: 250, transplant: 230 }
-        ],
-        distribution: [
-          { name: '鍏ㄨ倽', value: 85 },
-          { name: '鑲捐剰', value: 120 },
-          { name: '蹇冭剰', value: 45 },
-          { name: '鑲�', value: 60 },
-          { name: '鑳拌吅', value: 30 },
-          { name: '鐪艰鑶�', value: 200 }
-        ]
-      }
+      detailQuery: {}
     };
   },
   created() {
     this.loadData();
+    // 鏁版嵁婧�(mock/鐪熷疄鎺ュ彛)鍒囨崲鏃堕噸鏂板姞杞�
+    this.$watch(() => statisticsMode.useMock, () => this.loadData());
   },
   methods: {
+    // 缁勮鏌ヨ鏉′欢
+    buildQuery() {
+      const q = {};
+      if (this.query.region && this.query.region.length) {
+        q.area = this.query.region.join(',');
+      }
+      if (this.query.yearRange && this.query.yearRange.length === 2) {
+        q.startTime = this.query.yearRange[0];
+        q.endTime = this.query.yearRange[1];
+      }
+      if (this.query.organType) {
+        q.organName = this.query.organType;
+      }
+      return q;
+    },
+
     // 鍔犺浇鏁版嵁
     async loadData() {
       this.loading = true;
       try {
-        await new Promise(resolve => setTimeout(resolve, 500));
+        const q = this.buildQuery();
+        const [moonRes, typeRes, organRes] = await Promise.all([
+          organMoon(q),
+          organType(q),
+          organ(q)
+        ]);
 
-        // 澶勭悊琛ㄦ牸鏁版嵁
-        let filteredData = [...this.mockData.table];
+        // 鑾峰彇/绉绘瓒嬪娍
+        this.chartData.trend = toTotalsList(moonRes).map(item => ({
+          time: toMonth(item.donateTime) || toMonth(item.month),
+          acquisition: toNum(item.getCount),
+          transplant: toNum(item.useCount)
+        }));
 
-        if (this.query.region.length > 0) {
-          filteredData = filteredData.filter(item =>
-            this.query.region.includes(item.region.replace('鍦板尯', '').toLowerCase())
-          );
-        }
+        // 鍣ㄥ畼绫诲瀷鍒嗗竷
+        this.chartData.distribution = toTotalsList(typeRes).map(item => ({
+          name: item.organName || '',
+          value: toNum(item.getCount)
+        }));
 
-        if (this.query.yearRange && this.query.yearRange.length === 2) {
-          const [start, end] = this.query.yearRange;
-          filteredData = filteredData.filter(item =>
-            parseInt(item.year) >= parseInt(start) && parseInt(item.year) <= parseInt(end)
-          );
-        }
-
-        if (this.query.organType) {
-          const organMap = { liver: '鑲�', kidney: '鑲�', heart: '蹇冭剰', lung: '鑲�', pancreas: '鑳拌吅', cornea: '鐪艰鑶�' };
-          const organName = organMap[this.query.organType];
-          if (organName) {
-            filteredData = filteredData.filter(item => item.organName.includes(organName));
-          }
-        }
-
-        // 鍒嗛〉
+        // 鏄庣粏琛�
+        const all = toTotalsList(organRes).map(item => {
+          const get = toNum(item.getCount);
+          const use = toNum(item.useCount);
+          const rate = get > 0 ? Number(((use / get) * 100).toFixed(1)) : 0;
+          return {
+            year: String(item.donateTime || item.year || '').slice(0, 4),
+            organName: item.organName || '',
+            acquisitionCount: get,
+            transplantCount: use,
+            transplantRate: rate,
+            abandonCount: get - use,
+            region: item.area || item.region || ''
+          };
+        });
+        this.total = all.length;
         const start = (this.query.page - 1) * this.query.limit;
-        this.tableData = filteredData.slice(start, start + this.query.limit);
-        this.total = filteredData.length;
+        this.tableData = all.slice(start, start + this.query.limit);
 
-        // 鏇存柊姒傝鏁版嵁
-        this.updateOverviewData(filteredData);
+        // 鏇存柊姒傝
+        this.updateOverviewData(all);
 
         // 鏇存柊鍥捐〃
         this.updateCharts();
-
       } catch (error) {
         console.error('鍔犺浇鏁版嵁澶辫触:', error);
         this.$message.error('鏁版嵁鍔犺浇澶辫触');
@@ -308,12 +316,10 @@
 
     // 鏇存柊姒傝鏁版嵁
     updateOverviewData(data) {
-      if (data.length === 0) return;
-
-      const totalAcquisition = data.reduce((sum, item) => sum + item.acquisitionCount, 0);
-      const totalTransplant = data.reduce((sum, item) => sum + item.transplantCount, 0);
-      const totalAbandon = data.reduce((sum, item) => sum + item.abandonCount, 0);
-      const transplantRate = totalAcquisition > 0 ? (totalTransplant / totalAcquisition * 100).toFixed(1) : 0;
+      const totalAcquisition = data.reduce((sum, item) => sum + toNum(item.acquisitionCount), 0);
+      const totalTransplant = data.reduce((sum, item) => sum + toNum(item.transplantCount), 0);
+      const totalAbandon = data.reduce((sum, item) => sum + toNum(item.abandonCount), 0);
+      const transplantRate = totalAcquisition > 0 ? ((totalTransplant / totalAcquisition) * 100).toFixed(1) : 0;
 
       this.overviewData[0].value = totalAcquisition;
       this.overviewData[1].value = totalTransplant;
@@ -325,47 +331,20 @@
     updateCharts() {
       // 瓒嬪娍鍥�
       this.trendChartOptions = {
-        tooltip: {
-          trigger: 'axis',
-          axisPointer: {
-            type: 'shadow'
-          }
-        },
-        legend: {
-          data: ['鑾峰彇鏁伴噺', '绉绘鏁伴噺']
-        },
-        grid: {
-          left: '3%',
-          right: '4%',
-          bottom: '3%',
-          containLabel: true
-        },
-        xAxis: {
-          type: 'category',
-          data: this.mockData.trend.map(item => item.year + '骞�')
-        },
-        yAxis: {
-          type: 'value',
-          name: '鏁伴噺(涓�)'
-        },
+        tooltip: axisTooltip(),
+        legend: legend(['鑾峰彇鏁伴噺', '绉绘鏁伴噺']),
+        grid: grid(),
+        xAxis: xAxis(this.chartData.trend.map(item => item.time)),
+        yAxis: yAxis(),
         series: [
-          {
-            name: '鑾峰彇鏁伴噺',
-            type: 'bar',
-            data: this.mockData.trend.map(item => item.acquisition),
-            itemStyle: { color: '#409EFF' }
-          },
-          {
-            name: '绉绘鏁伴噺',
-            type: 'bar',
-            data: this.mockData.trend.map(item => item.transplant),
-            itemStyle: { color: '#67C23A' }
-          }
+          barSeries('鑾峰彇鏁伴噺', this.chartData.trend.map(item => item.acquisition), COLORS.blue),
+          barSeries('绉绘鏁伴噺', this.chartData.trend.map(item => item.transplant), COLORS.green)
         ]
       };
 
       // 鍒嗗竷鍥�
       this.distributionChartOptions = {
+        color: PALETTE,
         tooltip: {
           trigger: 'item',
           formatter: '{a} <br/>{b} : {c} ({d}%)'
@@ -373,15 +352,23 @@
         legend: {
           orient: 'vertical',
           left: 'left',
-          data: this.mockData.distribution.map(item => item.name)
+          top: 'middle',
+          itemWidth: 10,
+          itemHeight: 10,
+          itemGap: 16,
+          textStyle: { fontSize: 14, color: '#606266' },
+          data: this.chartData.distribution.map(item => item.name)
         },
         series: [
           {
             name: '鍣ㄥ畼鍒嗗竷',
             type: 'pie',
             radius: '55%',
-            center: ['50%', '60%'],
-            data: this.mockData.distribution,
+            center: ['55%', '50%'],
+            itemStyle: { borderColor: '#fff', borderWidth: 2 },
+            label: { fontSize: 14, color: '#606266', formatter: '{b} {d}%' },
+            labelLine: { lineStyle: { color: '#c0c4cc' } },
+            data: this.chartData.distribution,
             emphasis: {
               itemStyle: {
                 shadowBlur: 10,

--
Gitblit v1.9.3