Просмотр исходного кода

♻️ refactor(dashboard): 重构关键指标展示组件

- 将数据卡片组件提取为独立的KeyMetrics组件,提高代码复用性
- 移除GrainOilDashboard中的内联DataCard定义,改为导入外部组件
- 为KeyMetrics组件添加默认指标数据和可自定义配置
- 添加数据来源说明区域,增强数据可信度
- 优化组件结构,使代码逻辑更清晰
yourname 2 месяцев назад
Родитель
Сommit
cb7c610ff7

+ 5 - 72
src/client/home/pages/SupplyChainDashboards/GrainOilDashboard.tsx

@@ -1,6 +1,7 @@
 import React, { useState } from 'react';
 import SupplyChainMap from './components/SupplyChainMap';
 import SupplyChainModel from './components/SupplyChainModel';
+import KeyMetrics from './components/KeyMetrics';
 
 // 定义组件接口
 interface GrainOilDashboardProps {
@@ -117,51 +118,11 @@ const Navigation: React.FC<{
   );
 };
 
-// 数据卡片组件
-const DataCard: React.FC<{
-  title: string;
-  value: string;
-  unit: string;
-  digits: string[];
-}> = ({ title, value, unit, digits }) => {
-  return (
-    <div className="box-border content-stretch flex flex-col gap-[20px] items-start px-0 py-[20px] relative shrink-0 w-[278px]">
-      <div className="box-border content-stretch flex gap-[10px] items-center px-0 py-[4px] relative shrink-0 w-full">
-        <div className="flex flex-col font-bold justify-center leading-[0] not-italic relative shrink-0 text-[40px] text-white whitespace-nowrap">
-          <p className="leading-[50px]">{title}</p>
-        </div>
-      </div>
-      <div className="content-stretch flex gap-[10px] h-[80px] items-end relative shrink-0 w-full">
-        <div className="content-stretch flex gap-[6px] items-center relative shrink-0">
-          {digits.map((digit, index) => (
-            <div key={index} className="h-[80px] relative shrink-0 w-[53.333px]">
-              <div className="absolute bg-gradient-to-b border-2 border-[#5e697e] border-solid from-[#474e60] inset-0 rounded-[6px] to-[#2b2f39]" />
-              <div className="absolute flex flex-col font-bold inset-[16.16%_13.74%] justify-center leading-[0] not-italic text-[#c5ff92] text-[60px] text-center tracking-[6px]">
-                <p className="leading-[normal] whitespace-pre-wrap">{digit}</p>
-              </div>
-            </div>
-          ))}
-        </div>
-        <div className="box-border content-stretch flex gap-[10px] items-center px-0 py-[4px] relative shrink-0">
-          <div className="flex flex-col font-bold justify-center leading-[0] not-italic relative shrink-0 text-[24px] text-white whitespace-nowrap">
-            <p className="leading-[32px]">{unit}</p>
-          </div>
-        </div>
-      </div>
-    </div>
-  );
-};
 
 // 主组件
 const GrainOilDashboard: React.FC<GrainOilDashboardProps> = () => {
   const [activeTab, setActiveTab] = useState<'grain' | 'oil'>('grain');
 
-  // 模拟数据
-  const grainData = {
-    processingCapacity: { value: '200', unit: '万吨/年', digits: ['2', '0', '0'] },
-    baseArea: { value: '15', unit: '万亩', digits: ['1', '5'] },
-    storageCapacity: { value: '?000', unit: '万吨', digits: ['?', '0', '0', '0'] }
-  };
 
   return (
     <div className="h-[1080px] w-[1920px] bg-[#0a1a3a] relative overflow-hidden">
@@ -236,38 +197,10 @@ const GrainOilDashboard: React.FC<GrainOilDashboardProps> = () => {
       <SupplyChainModel />
 
       {/* 左侧数据展示 */}
-      <div className="absolute content-stretch flex flex-col gap-[11px] items-start left-[199.88px] top-[calc(50%+4.02px)] translate-y-[-50%] w-[330px]">
-        <div className="box-border content-stretch flex gap-[10px] h-[80px] items-center px-[26px] py-[4px] relative shrink-0 w-full">
-          <div className="flex flex-col font-bold justify-center leading-[0] not-italic relative shrink-0 text-[0px] text-white whitespace-nowrap">
-            <p>
-              <span className="leading-[50px] text-[40px]">优质稻米</span>
-              <span className="leading-[32px] text-[28px]">产业链联合体</span>
-            </p>
-          </div>
-        </div>
-        <div className="grid-cols-[max-content] grid-rows-[max-content] inline-grid justify-items-start leading-[0] relative shrink-0">
-          <div className="box-border col-[1] content-stretch flex flex-col h-[700px] items-center justify-between ml-0 mt-0 px-0 py-[20px] relative row-[1] w-[330px]">
-            <DataCard
-              title="加工能力达"
-              value={grainData.processingCapacity.value}
-              unit={grainData.processingCapacity.unit}
-              digits={grainData.processingCapacity.digits}
-            />
-            <DataCard
-              title="自建优质水稻基地"
-              value={grainData.baseArea.value}
-              unit={grainData.baseArea.unit}
-              digits={grainData.baseArea.digits}
-            />
-            <DataCard
-              title="储备仓容"
-              value={grainData.storageCapacity.value}
-              unit={grainData.storageCapacity.unit}
-              digits={grainData.storageCapacity.digits}
-            />
-          </div>
-        </div>
-      </div>
+      <KeyMetrics
+        title="优质稻米"
+        subtitle="产业链联合体"
+      />
     </div>
   );
 };

+ 121 - 0
src/client/home/pages/SupplyChainDashboards/components/KeyMetrics.tsx

@@ -0,0 +1,121 @@
+import React from 'react';
+
+// 定义指标数据类型
+interface MetricData {
+  title: string;
+  value: string;
+  unit: string;
+  digits: string[];
+}
+
+interface KeyMetricsProps {
+  metrics?: MetricData[];
+  title?: string;
+  subtitle?: string;
+}
+
+// 数据卡片组件
+const DataCard: React.FC<{
+  title: string;
+  value: string;
+  unit: string;
+  digits: string[];
+}> = ({ title, value, unit, digits }) => {
+  return (
+    <div className="box-border content-stretch flex flex-col gap-[20px] items-start px-0 py-[20px] relative shrink-0 w-[278px]">
+      <div className="box-border content-stretch flex gap-[10px] items-center px-0 py-[4px] relative shrink-0 w-full">
+        <div className="flex flex-col font-bold justify-center leading-[0] not-italic relative shrink-0 text-[40px] text-white whitespace-nowrap">
+          <p className="leading-[50px]">{title}</p>
+        </div>
+      </div>
+      <div className="content-stretch flex gap-[10px] h-[80px] items-end relative shrink-0 w-full">
+        <div className="content-stretch flex gap-[6px] items-center relative shrink-0">
+          {digits.map((digit, index) => (
+            <div key={index} className="h-[80px] relative shrink-0 w-[53.333px]">
+              <div className="absolute bg-gradient-to-b border-2 border-[#5e697e] border-solid from-[#474e60] inset-0 rounded-[6px] to-[#2b2f39]" />
+              <div className="absolute flex flex-col font-bold inset-[16.16%_13.74%] justify-center leading-[0] not-italic text-[#c5ff92] text-[60px] text-center tracking-[6px]">
+                <p className="leading-[normal] whitespace-pre-wrap">{digit}</p>
+              </div>
+            </div>
+          ))}
+        </div>
+        <div className="box-border content-stretch flex gap-[10px] items-center px-0 py-[4px] relative shrink-0">
+          <div className="flex flex-col font-bold justify-center leading-[0] not-italic relative shrink-0 text-[24px] text-white whitespace-nowrap">
+            <p className="leading-[32px]">{unit}</p>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+const KeyMetrics: React.FC<KeyMetricsProps> = ({
+  metrics = [],
+  title = "优质稻米",
+  subtitle = "产业链联合体"
+}) => {
+  // 默认指标数据
+  const defaultMetrics: MetricData[] = [
+    {
+      title: "加工能力达",
+      value: "200",
+      unit: "万吨/年",
+      digits: ['2', '0', '0']
+    },
+    {
+      title: "自建优质水稻基地",
+      value: "15",
+      unit: "万亩",
+      digits: ['1', '5']
+    },
+    {
+      title: "储备仓容",
+      value: "?000",
+      unit: "万吨",
+      digits: ['?', '0', '0', '0']
+    }
+  ];
+
+  const displayMetrics = metrics.length > 0 ? metrics : defaultMetrics;
+
+  return (
+    <div className="absolute content-stretch flex flex-col gap-[11px] items-start left-[199.88px] top-[calc(50%+4.02px)] translate-y-[-50%] w-[330px]">
+      {/* 标题区域 */}
+      <div className="box-border content-stretch flex gap-[10px] h-[80px] items-center px-[26px] py-[4px] relative shrink-0 w-full">
+        <div className="flex flex-col font-bold justify-center leading-[0] not-italic relative shrink-0 text-[0px] text-white whitespace-nowrap">
+          <p>
+            <span className="leading-[50px] text-[40px]">{title}</span>
+            <span className="leading-[32px] text-[28px]">{subtitle}</span>
+          </p>
+        </div>
+      </div>
+
+      {/* 指标数据区域 */}
+      <div className="grid-cols-[max-content] grid-rows-[max-content] inline-grid justify-items-start leading-[0] relative shrink-0">
+        <div className="box-border col-[1] content-stretch flex flex-col h-[700px] items-center justify-between ml-0 mt-0 px-0 py-[20px] relative row-[1] w-[330px]">
+          {displayMetrics.map((metric, index) => (
+            <DataCard
+              key={index}
+              title={metric.title}
+              value={metric.value}
+              unit={metric.unit}
+              digits={metric.digits}
+            />
+          ))}
+        </div>
+      </div>
+
+      {/* 数据来源说明 */}
+      <div className="mt-4 text-center">
+        <p className="text-[rgba(255,255,255,0.5)] text-sm">
+          数据来源:省粮油集团统计年报
+        </p>
+        <p className="text-[rgba(255,255,255,0.5)] text-xs mt-1">
+          更新时间:2025年11月
+        </p>
+      </div>
+    </div>
+  );
+};
+
+export default KeyMetrics;