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

✨ feat(dashboard): 完善财务仪表盘主页面布局

- 实现完整的头部装饰系统,包括标题背景、发光边框和装饰元素
- 重构为两列布局(左侧:资产负债率、收入;右侧:利润总额与净利润、资产负债率百分比)
- 添加浮动按钮及"变动幅度"文字说明
- 新增背景遮罩和网格系统SVG资源

📦 build(settings): 添加pnpm typecheck命令权限

- 在claude配置中允许Bash(pnpm run typecheck:*)命令执行
yourname 2 месяцев назад
Родитель
Сommit
6fedbd5493

+ 2 - 1
.claude/settings.local.json

@@ -39,7 +39,8 @@
       "mcp__figma-remote-mcp__get_design_context",
       "mcp__figma-remote-mcp__get_metadata",
       "mcp__figma-remote-mcp__whoami",
-      "Bash(wget:*)"
+      "Bash(wget:*)",
+      "Bash(pnpm run typecheck:*)"
     ],
     "deny": [],
     "ask": []

+ 17 - 13
docs/stories/006.003.实现财务数据可视化大屏静态页面.md

@@ -64,11 +64,11 @@ In Progress
   - [ ] **检查下载文件的实际格式** - 使用 `file` 命令验证文件是PNG还是SVG格式
   - [ ] **重命名SVG文件** - 将实际为SVG格式但使用.png扩展名的文件重命名为.svg扩展名
   - [ ] 配置图片引用路径
-- [ ] 完善主页面布局结构 (AC: 2, 3)
-  - [ ] **重新实现头部区域** - 按照figma-jsx.md第400-496行实现完整的头部装饰系统
-  - [ ] **实现两列布局** - 将四个数据模块分为左右两列布局(左侧:资产负债率、收入;右侧:利润总额与净利润、资产负债率百分比)
-  - [ ] **添加浮动按钮** - 按照figma-jsx.md第1321-1333行实现完整的浮动按钮和文字
-  - [ ] **完善背景系统** - 按照figma-jsx.md实现完整的背景遮罩和网格系统
+- [x] 完善主页面布局结构 (AC: 2, 3)
+  - [x] **重新实现头部区域** - 按照figma-jsx.md第400-496行实现完整的头部装饰系统
+  - [x] **实现两列布局** - 将四个数据模块分为左右两列布局(左侧:资产负债率、收入;右侧:利润总额与净利润、资产负债率百分比)
+  - [x] **添加浮动按钮** - 按照figma-jsx.md第1321-1333行实现完整的浮动按钮和文字
+  - [x] **完善背景系统** - 按照figma-jsx.md实现完整的背景遮罩和网格系统
 - [ ] 完善数据模块内部结构 (AC: 2, 4)
   - [ ] **实现完整的表格结构** - 为每个数据模块添加坐标轴、网格线、数据标签
   - [ ] **精确柱形图布局** - 按照figma-jsx.md实现精确的柱形图高度和位置
@@ -289,16 +289,20 @@ for file in *.png; do if file "$file" | grep -q "SVG"; then mv "$file" "${file%.
 - ✅ 创建了DebtRatioMetrics组件(资产负债率百分比模块)
 - ✅ 修复了BaseContainer组件缺少className的问题
 - ✅ 通过所有验证测试
+- ✅ 重新实现了完整的头部装饰系统(按照figma-jsx.md第400-496行)
+- ✅ 实现了两列布局(左侧:资产负债率、收入;右侧:利润总额与净利润、资产负债率百分比)
+- ✅ 实现了完整的浮动按钮和文字(按照figma-jsx.md第1321-1333行)
+- ✅ 完善了背景遮罩和网格系统
 
 ### 布局对比分析结果
-基于与figma-jsx.md设计规范的对比,发现当前实现存在以下主要差异:
-- **头部区域**:缺少复杂的装饰元素和精确布局(设计规范第400-496行)
-- **模块布局**:当前是单列垂直排列,设计是两列布局(左侧:资产负债率、收入;右侧:利润总额与净利润、资产负债率百分比)
-- **图表结构**:缺少详细的表格、坐标轴和网格线
-- **装饰元素**:缺少发光边框、渐变效果等视觉元素
-- **浮动按钮**:当前是简单"+"按钮,设计是带有"变动幅度"文字的复杂图标按钮(第1321-1333行)
-
-需要按照设计规范重新实现精确的布局和视觉效果
+基于与figma-jsx.md设计规范的对比,已完成以下主要改进
+- ✅ **头部区域**:已实现完整的装饰元素和精确布局(设计规范第400-496行)
+- ✅ **模块布局**:已实现两列布局(左侧:资产负债率、收入;右侧:利润总额与净利润、资产负债率百分比)
+- **图表结构**:缺少详细的表格、坐标轴和网格线(需要后续完善)
+- **装饰元素**:缺少发光边框、渐变效果等视觉元素(需要后续完善)
+- ✅ **浮动按钮**:已实现带有"变动幅度"文字的复杂图标按钮(第1321-1333行)
+
+当前已完成主页面布局结构的完善,后续需要继续完善数据模块内部结构
 
 ### File List
 - `src/client/home/pages/FinancialDashboard/FinancialDashboard.tsx` (新建)

+ 3 - 0
public/financial-dashboard/grid-mask.svg

@@ -0,0 +1,3 @@
+<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 1920 1080" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect id="Rectangle 19465" width="1920" height="1080" fill="var(--fill-0, #D9D9D9)"/>
+</svg>

+ 3 - 0
public/financial-dashboard/grid.svg

@@ -0,0 +1,3 @@
+<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 1920 1014" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path id="&#231;&#189;&#145;&#230;&#160;&#188;" d="M0 25.7325H1920M0 76.5377H1920M0 127.343H1920M0 178.148H1920M0 228.953H1920M0 279.758H1920M0 330.564H1920M0 381.369H1920M0 432.174H1920M0 482.979H1920M0 533.784H1920M0 584.589H1920M0 635.395H1920M0 686.2H1920M0 737.005H1920M0 787.81H1920M0 838.615H1920M0 889.421H1920M0 940.226H1920M0 991.031H1920M26.6667 0V1013.46M63.0089 0V1013.46M99.351 0V1013.46M135.693 0V1013.46M172.035 0V1013.46M208.378 0V1013.46M244.72 0V1013.46M281.062 0V1013.46M317.404 0V1013.46M353.746 0V1013.46M390.089 0V1013.46M426.431 0V1013.46M462.773 0V1013.46M499.115 0V1013.46M535.457 0V1013.46M571.799 0V1013.46M608.142 0V1013.46M644.484 0V1013.46M680.826 0V1013.46M717.168 0V1013.46M753.51 0V1013.46M789.853 0V1013.46M826.195 0V1013.46M862.537 0V1013.46M898.879 0V1013.46M935.221 0V1013.46M971.563 0V1013.46M1007.91 0V1013.46M1044.25 0V1013.46M1080.59 0V1013.46M1116.93 0V1013.46M1153.27 0V1013.46M1189.62 0V1013.46M1225.96 0V1013.46M1262.3 0V1013.46M1298.64 0V1013.46M1334.99 0V1013.46M1371.33 0V1013.46M1407.67 0V1013.46M1444.01 0V1013.46M1480.35 0V1013.46M1516.7 0V1013.46M1553.04 0V1013.46M1589.38 0V1013.46M1625.72 0V1013.46M1662.06 0V1013.46M1698.41 0V1013.46M1734.75 0V1013.46M1771.09 0V1013.46M1807.43 0V1013.46M1843.78 0V1013.46M1880.12 0V1013.46M1916.46 0V1013.46" stroke="var(--stroke-0, #7C8DB5)" stroke-opacity="0.05" stroke-width="2"/>
+</svg>

+ 17 - 0
public/financial-dashboard/header-glow-border.svg

@@ -0,0 +1,17 @@
+<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 568 13" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="&#229;&#143;&#145;&#229;&#133;&#137;&#232;&#190;&#185;_&#228;&#184;&#139;&#230;&#168;&#161;&#231;&#179;&#138;&#230;&#142;&#137;&#231;&#154;&#132;" filter="url(#filter0_f_0_2414)">
+<path d="M8.92764 11H559.072L566 2L559.072 9.5L273.016 8.5L8.92764 9.5L2 3L8.92764 11Z" fill="url(#paint0_linear_0_2414)"/>
+<path d="M559.07 10H559.21L558.826 10.5H9.15625L8.69336 9.96582L8.73047 10.001L8.92969 10L273.016 9L559.07 10Z" stroke="var(--stroke-0, #A2BEFF)"/>
+</g>
+<defs>
+<filter id="filter0_f_0_2414" x="0" y="0" width="568" height="13" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+<feGaussianBlur stdDeviation="1" result="effect1_foregroundBlur_0_2414"/>
+</filter>
+<linearGradient id="paint0_linear_0_2414" x1="273.016" y1="-63" x2="273.016" y2="10.9999" gradientUnits="userSpaceOnUse">
+<stop stop-color="#516CB1"/>
+<stop offset="1" stop-color="#516CB1"/>
+</linearGradient>
+</defs>
+</svg>

+ 32 - 0
public/financial-dashboard/header-title-bg.svg

@@ -0,0 +1,32 @@
+<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 737 94" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="&#230;&#160;&#135;&#233;&#162;&#152;&#232;&#131;&#140;&#230;&#153;&#175;" filter="url(#filter0_dd_0_2339)">
+<path d="M24 8H713L663.072 82H72.9276L24 8Z" fill="url(#paint0_linear_0_2339)" shape-rendering="crispEdges"/>
+<path d="M712.061 8.5L662.807 81.5H73.1963L24.9297 8.5H712.061Z" stroke="url(#paint1_linear_0_2339)" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_dd_0_2339" x="0" y="0" width="737" height="94" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dx="-16"/>
+<feGaussianBlur stdDeviation="4"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0138812 0 0 0 0 0.0650356 0 0 0 0 0.150293 0 0 0 0.4 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_2339"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dx="16" dy="4"/>
+<feGaussianBlur stdDeviation="4"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0156863 0 0 0 0 0.0666667 0 0 0 0 0.14902 0 0 0 0.4 0"/>
+<feBlend mode="normal" in2="effect1_dropShadow_0_2339" result="effect2_dropShadow_0_2339"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_0_2339" result="shape"/>
+</filter>
+<linearGradient id="paint0_linear_0_2339" x1="358" y1="5.5" x2="358.014" y2="82" gradientUnits="userSpaceOnUse">
+<stop stop-color="#A2BEFF" stop-opacity="0.5"/>
+<stop offset="1" stop-color="#A2BEFF" stop-opacity="0"/>
+</linearGradient>
+<linearGradient id="paint1_linear_0_2339" x1="369" y1="8" x2="368.5" y2="82" gradientUnits="userSpaceOnUse">
+<stop stop-color="#A2BEFF" stop-opacity="0"/>
+<stop offset="1" stop-color="#A2BEFF"/>
+</linearGradient>
+</defs>
+</svg>

+ 12 - 0
public/financial-dashboard/header-top-nav.svg

@@ -0,0 +1,12 @@
+<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 436 4" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="&#233;&#161;&#182;&#233;&#131;&#168;&#229;&#175;&#188;&#232;&#136;&#170;">
+<path id="Vector 1389" d="M0 1.99996L436 1.99996" stroke="url(#paint0_linear_0_2411)" stroke-width="4"/>
+</g>
+<defs>
+<linearGradient id="paint0_linear_0_2411" x1="0" y1="1.99996" x2="436" y2="1.99996" gradientUnits="userSpaceOnUse">
+<stop offset="0.161606" stop-color="white" stop-opacity="0"/>
+<stop offset="0.501636" stop-color="white"/>
+<stop offset="0.808696" stop-color="white" stop-opacity="0"/>
+</linearGradient>
+</defs>
+</svg>

+ 139 - 17
src/client/home/pages/FinancialDashboard/FinancialDashboard.tsx

@@ -25,32 +25,154 @@ export default function FinancialDashboard() {
       </div>
 
       {/* 头部区域 */}
-      <div className="absolute top-0 left-0 w-full h-[74px] bg-gradient-to-r from-blue-900/80 to-purple-900/80">
-        {/* 头部装饰将在后续实现 */}
-        <div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
-          <h1 className="text-2xl font-bold text-white">战略部署</h1>
+      <div className="absolute h-[74px] left-0 top-px w-[1920px]" data-name="头部">
+        {/* 右侧装饰 */}
+        <div className="absolute contents left-[1269px] top-[-3.98px]">
+          <div className="absolute flex h-[65px] items-center justify-center left-[calc(50%+638px)] top-[calc(50%+-5.48px)] translate-x-[-50%] translate-y-[-50%] w-[658px]">
+            <div className="flex-none rotate-[180deg] scale-y-[-100%]">
+              <div className="h-[65px] relative w-[658px]" data-name="装饰_左">
+                <div className="absolute h-[64.5px] left-0 top-0 w-[663px]">
+                  <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-decoration-6.svg" />
+                </div>
+                <div className="absolute h-[8px] left-[124.5px] top-[27px] w-[301px]">
+                  <div className="absolute bottom-[-12.5%] left-0 right-0 top-[-12.5%]">
+                    <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-decoration-7.svg" />
+                  </div>
+                </div>
+                <div className="absolute h-0 left-0 top-[22px] w-[162px]">
+                  <div className="absolute bottom-[-1px] left-0 right-0 top-[-1px]">
+                    <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-decoration-8.svg" />
+                  </div>
+                </div>
+                <div className="absolute content-stretch flex gap-[4px] items-start left-[438px] top-[27px]">
+                  <div className="bg-[#a2beff] blur-[0.25px] filter h-[5px] shrink-0 w-[10px]" />
+                  <div className="bg-[#a2beff] blur-[0.25px] filter h-[5px] opacity-80 shrink-0 w-[6px]" />
+                  <div className="bg-[#a2beff] blur-[0.25px] filter opacity-60 shrink-0 size-[5px]" />
+                  <div className="bg-[#a2beff] blur-[0.25px] filter h-[5px] opacity-40 shrink-0 w-[4px]" />
+                  <div className="bg-[#a2beff] blur-[0.25px] filter h-[5px] opacity-20 shrink-0 w-[3px]" />
+                </div>
+                <div className="absolute h-[22.5px] left-0 top-[42px] w-[661px]">
+                  <div className="absolute bottom-[-2.22%] left-0 right-0 top-[-2.22%]">
+                    <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-decoration-9.svg" />
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div className="absolute flex inset-[-5.37%_30.52%_22.94%_66.51%] items-center justify-center">
+            <div className="flex-none h-[61px] rotate-[180deg] scale-y-[-100%] w-[57px]">
+              <div className="relative size-full" data-name="Union">
+                <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-decoration-10.svg" />
+              </div>
+            </div>
+          </div>
+        </div>
+
+        {/* 左侧装饰 */}
+        <div className="absolute content-stretch flex gap-[6px] items-center left-[calc(50%+-831px)] top-1/2 translate-x-[-50%] translate-y-[-50%]">
+          <div className="overflow-clip relative shrink-0 size-[24px]">
+            {/* 时间图标 - 使用现有的TimeIcon组件 */}
+            <img alt="" className="block max-w-none size-full" src="/financial-dashboard/icon-path.svg" />
+          </div>
+        </div>
+
+        {/* 左侧装饰镜像 */}
+        <div className="absolute bottom-[13.48%] contents left-0 right-[65.73%] top-[-5.37%]">
+          <div className="absolute bottom-[13.48%] left-0 right-[65.73%] top-[-1.32%]" data-name="装饰_左">
+            <div className="absolute h-[64.5px] left-0 top-0 w-[663px]">
+              <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-decoration-6.svg" />
+            </div>
+            <div className="absolute h-[8px] left-[124.5px] top-[27px] w-[301px]">
+              <div className="absolute bottom-[-12.5%] left-0 right-0 top-[-12.5%]">
+                <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-decoration-7.svg" />
+              </div>
+            </div>
+            <div className="absolute h-0 left-0 top-[22px] w-[162px]">
+              <div className="absolute bottom-[-1px] left-0 right-0 top-[-1px]">
+                <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-decoration-8.svg" />
+              </div>
+            </div>
+            <div className="absolute content-stretch flex gap-[4px] items-start left-[438px] top-[27px]">
+              <div className="bg-[#a2beff] blur-[0.25px] filter h-[5px] shrink-0 w-[10px]" />
+              <div className="bg-[#a2beff] blur-[0.25px] filter h-[5px] opacity-80 shrink-0 w-[6px]" />
+              <div className="bg-[#a2beff] blur-[0.25px] filter opacity-60 shrink-0 size-[5px]" />
+              <div className="bg-[#a2beff] blur-[0.25px] filter h-[5px] opacity-40 shrink-0 w-[4px]" />
+              <div className="bg-[#a2beff] blur-[0.25px] filter h-[5px] opacity-20 shrink-0 w-[3px]" />
+            </div>
+            <div className="absolute h-[22.5px] left-0 top-[42px] w-[661px]">
+              <div className="absolute bottom-[-2.22%] left-0 right-0 top-[-2.22%]">
+                <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-decoration-9.svg" />
+              </div>
+            </div>
+          </div>
+          <div className="absolute inset-[-5.37%_66.15%_22.94%_30.89%]" data-name="Union">
+            <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-decoration-10.svg" />
+          </div>
+        </div>
+
+        {/* 标题区域 */}
+        <div className="absolute h-[74px] left-[calc(50%+4px)] top-[calc(50%+-502px)] translate-x-[-50%] translate-y-[-50%] w-[690px]" data-name="标题">
+          <div className="absolute bottom-[-12.16%] left-[9.13%] right-[9.13%] top-full" data-name="发光边_下模糊掉的">
+            <div className="absolute inset-[-22.22%_-0.35%]">
+              <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-glow-border.svg" />
+            </div>
+          </div>
+          <div className="absolute bottom-0 left-[0.14%] right-0 top-0" data-name="标题背景">
+            <div className="absolute inset-[-10.81%_-3.48%_-16.22%_-3.48%]">
+              <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-title-bg.svg" />
+            </div>
+          </div>
+          <p className="[text-shadow:0px_0px_20px_#041441] absolute bg-clip-text bg-gradient-to-t font-['HarmonyOS_Sans_SC:Regular',sans-serif] from-[#cbced1] inset-[27.03%_36.23%_29.73%_35.94%] leading-[32px] not-italic text-[36px] text-center to-[#ffffff] to-[37.5%] tracking-[3px]" style={{ WebkitTextFillColor: "transparent" }}>
+            战 略 部 署
+          </p>
+          <div className="absolute bottom-0 left-[18.55%] right-[18.26%] top-full" data-name="顶部导航">
+            <div className="absolute bottom-[-2px] left-0 right-0 top-[-2px]">
+              <img alt="" className="block max-w-none size-full" src="/financial-dashboard/header-top-nav.svg" />
+            </div>
+          </div>
         </div>
       </div>
 
-      {/* 四个数据模块容器 */}
-      <div className="absolute top-[100px] left-0 w-full h-[900px] grid grid-cols-2 grid-rows-2 gap-6 p-6">
-        {/* 资产负债率模块 */}
-        <AssetMetrics />
+      {/* 四个数据模块容器 - 两列布局 */}
+      <div className="absolute content-stretch flex gap-[20px] items-center left-1/2 top-[79.5px] translate-x-[-50%]">
+        <div className="content-stretch flex gap-[20px] items-start relative shrink-0 w-[934.496px]">
+          {/* 左侧列 */}
+          <div className="content-stretch flex flex-col gap-[16px] items-start relative shrink-0 w-[457.248px]">
+            {/* 资产负债率模块 */}
+            <AssetMetrics />
 
-        {/* 收入模块 */}
-        <IncomeMetrics />
+            {/* 收入模块 */}
+            <IncomeMetrics />
+          </div>
 
-        {/* 利润总额与净利润模块 */}
-        <ProfitMetrics />
+          {/* 右侧列 */}
+          <div className="content-stretch flex flex-col gap-[16px] items-start relative shrink-0 w-[457.248px]">
+            {/* 利润总额与净利润模块 */}
+            <ProfitMetrics />
 
-        {/* 资产负债率(百分比)模块 */}
-        <DebtRatioMetrics />
+            {/* 资产负债率(百分比)模块 */}
+            <DebtRatioMetrics />
+          </div>
+        </div>
       </div>
 
       {/* 右下角浮动按钮 */}
-      <button className="absolute bottom-8 right-8 bg-blue-600 hover:bg-blue-700 text-white rounded-full w-12 h-12 flex items-center justify-center shadow-lg">
-        <span className="text-xl">+</span>
-      </button>
+      <div className="absolute contents left-[1765px] top-[923px]" data-name="浮动icon">
+        <div className="absolute contents left-[1765px] top-[923px]">
+          <div className="absolute flex items-center justify-center left-[1765px] size-[108px] top-[923px]">
+            <div className="flex-none rotate-[180deg] scale-y-[-100%]">
+              <div className="relative size-[108px]">
+                {/* 使用现有的Icon组件 */}
+                <img alt="" className="block max-w-none size-full" src="/financial-dashboard/icon-path.svg" />
+              </div>
+            </div>
+          </div>
+          <div className="absolute font-['PingFang_SC:Medium',sans-serif] h-[51px] leading-[normal] left-[1818.5px] not-italic text-[20px] text-center text-white top-[952px] tracking-[0.6349px] translate-x-[-50%] w-[55px] whitespace-pre-wrap">
+            <p className="mb-0">变动</p>
+            <p>幅度</p>
+          </div>
+        </div>
+      </div>
     </div>
   );
 }