Răsfoiți Sursa

✨ feat(supply-chain): 新增多图展示组件和优化供应链图标

- 新增单图、双图、多图展示组件,支持不同图片数量的展示模式
- 优化供应链图标设计,更新水产、生鲜、水果、畜牧、盐业、种业等图标样式
- 重构弹窗组件,支持根据图片数量自动选择展示模式
- 添加图片轮播功能和自定义滚动条交互
- 更新文档说明多图展示功能
yourname 2 luni în urmă
părinte
comite
5ab185a754

+ 202 - 0
docs/figma-jsx/供应链-弹出层-多图.md

@@ -0,0 +1,202 @@
+<div data-layer="操控屏-1-粮食•油脂-油脂首页-基地弹出数据" className="1 w-[1920px] h-[1080px] relative bg-neutral-800/60 overflow-hidden">
+    <div data-layer="遮罩层" className="w-[1920px] h-[1080px] left-[-0.50px] top-[0.13px] absolute bg-stone-800/50 backdrop-blur-[5px]" />
+    <div data-layer="弹出框样式1" className="1 w-[1600px] h-[900px] left-[160px] top-[83.72px] absolute">
+        <div data-layer="Rectangle" className="Rectangle w-[1600px] h-[900px] left-0 top-0 absolute bg-stone-800/40" />
+        <div data-svg-wrapper data-layer="Union" className="Union left-[21.96px] top-[29.88px] absolute">
+            <svg width="1557" height="841" viewBox="0 0 1557 841" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <g opacity="0.5">
+            <path d="M10.9804 837.02H1545.1V496.309H1548.24V840.238H7.84314V496.309H10.9804V837.02Z" fill="#F6B02E"/>
+            <path d="M18.8235 485.721L0 497.91V281.743L18.8235 269.696V485.721Z" fill="#F6B02E"/>
+            <path d="M1556.08 281.884V497.91L1537.25 485.863V269.696L1556.08 281.884Z" fill="#F6B02E"/>
+            <path d="M428.474 19.2889H395.637L399.084 9.58322H10.9804V269.94H7.84314V6.36579H400.227L402.488 0H436.422L428.474 19.2889Z" fill="#F6B02E"/>
+            <path d="M1157.82 6.36579H1548.24V269.94H1545.1V9.58322H1156.49L1152.49 19.2889H1119.66L1126.51 0H1160.44L1157.82 6.36579Z" fill="#F6B02E"/>
+            </g>
+            </svg>
+        </div>
+    </div>
+    <div data-svg-wrapper data-layer="删除icon" className="Icon left-[1731px] top-[80px] absolute">
+        <svg width="41" height="41" viewBox="0 0 41 41" fill="none" xmlns="http://www.w3.org/2000/svg">
+        <g filter="url(#filter0_i_2124_5636)">
+        <circle cx="20.0476" cy="20.0476" r="19.0476" fill="#C9DDFF" fill-opacity="0.09"/>
+        </g>
+        <circle cx="20.0476" cy="20.0476" r="19.5476" stroke="#C9DDFF"/>
+        <g filter="url(#filter1_d_2124_5636)">
+        <path d="M14.2929 12.5145C14.151 12.5097 14.0129 12.5614 13.9092 12.6582L13.1261 13.3864C12.9107 13.5876 12.8993 13.9245 13.1005 14.1397L18.6218 20.0479L13.1005 25.9552C13.0036 26.0587 12.9515 26.1964 12.9564 26.3379C12.9612 26.4795 13.0223 26.6133 13.1261 26.71L13.9092 27.4377C14.013 27.5343 14.1514 27.586 14.2933 27.581C14.4351 27.5759 14.5691 27.5148 14.6658 27.4112L20.0485 21.6523L25.4308 27.4112C25.5275 27.5148 25.6615 27.5759 25.8033 27.581C25.9452 27.586 26.0835 27.5343 26.1874 27.4377L26.9705 26.71C27.0743 26.6133 27.1354 26.4795 27.1402 26.3379C27.1451 26.1964 27.093 26.0587 26.9961 25.9552L21.4743 20.0479L26.9961 14.1397C27.1973 13.9245 27.1858 13.5876 26.9705 13.3864L26.1874 12.6582C26.0837 12.5615 25.9456 12.5097 25.8037 12.5145C25.6619 12.5193 25.5277 12.5803 25.4308 12.6837L20.0485 18.4413L14.6658 12.6837C14.5689 12.5802 14.4347 12.5193 14.2929 12.5145Z" fill="#C9DDFF"/>
+        </g>
+        <defs>
+        <filter id="filter0_i_2124_5636" x="0" y="0" width="40.0957" height="40.0952" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+        <feFlood flood-opacity="0" result="BackgroundImageFix"/>
+        <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+        <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/>
+        <feGaussianBlur stdDeviation="6.5"/>
+        <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
+        <feColorMatrix type="matrix" values="0 0 0 0 0.788235 0 0 0 0 0.866667 0 0 0 0 1 0 0 0 0.5 0"/>
+        <feBlend mode="normal" in2="shape" result="effect1_innerShadow_2124_5636"/>
+        </filter>
+        <filter id="filter1_d_2124_5636" x="3.95605" y="3.51416" width="32.1846" height="33.0674" 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/>
+        <feGaussianBlur stdDeviation="4.5"/>
+        <feColorMatrix type="matrix" values="0 0 0 0 0.788235 0 0 0 0 0.866667 0 0 0 0 1 0 0 0 0.501961 0"/>
+        <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2124_5636"/>
+        <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2124_5636" result="shape"/>
+        </filter>
+        </defs>
+        </svg>
+    </div>
+    <div data-layer="图片样式1" className="1 w-[1357px] h-[640px] left-[281.50px] top-[269.15px] absolute rounded-[20px] overflow-hidden">
+        <div data-layer="Frame 1321316691" className="Frame1321316691 size- left-[-751px] top-0 absolute inline-flex justify-start items-center gap-5">
+            <div data-layer="图片1" className="1 w-[940px] h-[600px] relative rounded-[10px] overflow-hidden">
+                <img data-layer="省粮油集团粮食仓储加工基地" className="w-[1066.67px] h-[600px] left-[-126.67px] top-0 absolute" src="https://placehold.co/1067x600" />
+            </div>
+            <div data-layer="图片2" className="2 w-[940px] h-[640px] relative rounded-[10px] overflow-hidden">
+                <img data-layer="康宏公司张湖粮油基地示范片区 1" className="1 w-[992.50px] h-[640px] left-[-26.25px] top-0 absolute" src="https://placehold.co/992x640" />
+            </div>
+            <div data-layer="图片3" className="3 w-[940px] h-[600px] relative rounded-[10px] overflow-hidden">
+                <img data-layer="省粮油集团康宏粮油生产基地" className="w-[1066.67px] h-[600px] left-0 top-0 absolute" src="https://placehold.co/1067x600" />
+            </div>
+        </div>
+    </div>
+    <div data-layer="按钮" className="w-[1510px] left-[205px] top-[545.72px] absolute inline-flex justify-between items-center">
+        <div data-layer="原创-箭头right" className="Right size-20 relative origin-top-left rotate-180">
+            <div data-svg-wrapper data-layer="矩形" className="left-0 top-0 absolute">
+                <svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path fill-rule="evenodd" clip-rule="evenodd" d="M0 0V80H80V0H0Z" fill="black" fill-opacity="0.0117647"/>
+                </svg>
+            </div>
+            <div data-svg-wrapper data-layer="三角形" className="left-[15.47px] top-[16.70px] absolute">
+                <svg width="24" height="48" viewBox="0 0 24 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M22.8047 1.91602L19.9746 12.4355C17.9523 19.9527 17.9523 27.8715 19.9746 35.3887L22.8047 45.9092L0.808594 23.9121L22.8047 1.91602Z" fill="url(#paint0_linear_2124_5652)" stroke="url(#paint1_linear_2124_5652)" stroke-width="1.14286"/>
+                <defs>
+                <linearGradient id="paint0_linear_2124_5652" x1="0" y1="47.8244" x2="23.9123" y2="47.8244" gradientUnits="userSpaceOnUse">
+                <stop stop-color="#F6B02E"/>
+                <stop offset="1" stop-color="#7C5101"/>
+                </linearGradient>
+                <linearGradient id="paint1_linear_2124_5652" x1="0" y1="47.8244" x2="23.9123" y2="47.8244" gradientUnits="userSpaceOnUse">
+                <stop stop-color="#F6B02E"/>
+                <stop offset="1" stop-color="#7C5101"/>
+                </linearGradient>
+                </defs>
+                </svg>
+            </div>
+            <div data-svg-wrapper data-layer="三角形" className="left-[39.38px] top-[16.70px] absolute">
+                <svg width="24" height="48" viewBox="0 0 24 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M22.8047 1.91602L19.9746 12.4355C17.9523 19.9527 17.9523 27.8715 19.9746 35.3887L22.8047 45.9092L0.808594 23.9121L22.8047 1.91602Z" fill="#F6B02E" stroke="url(#paint0_linear_2124_5653)" stroke-width="1.14286"/>
+                <defs>
+                <linearGradient id="paint0_linear_2124_5653" x1="0" y1="47.8244" x2="23.9123" y2="47.8244" gradientUnits="userSpaceOnUse">
+                <stop stop-color="#F6B02E"/>
+                <stop offset="1" stop-color="#7C5101"/>
+                </linearGradient>
+                </defs>
+                </svg>
+            </div>
+        </div>
+        <div data-layer="原创-箭头right" className="Right size-20 relative">
+            <div data-svg-wrapper data-layer="矩形" className="left-0 top-0 absolute">
+                <svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path fill-rule="evenodd" clip-rule="evenodd" d="M80 0V80H0V0H80Z" fill="black" fill-opacity="0.0117647"/>
+                </svg>
+            </div>
+            <div data-svg-wrapper data-layer="三角形" className="left-[40.62px] top-[16.70px] absolute">
+                <svg width="24" height="48" viewBox="0 0 24 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M1.10742 1.91602L3.9375 12.4355C5.95979 19.9527 5.95979 27.8715 3.9375 35.3887L1.10742 45.9092L23.1035 23.9121L1.10742 1.91602Z" fill="url(#paint0_linear_2124_5656)" stroke="url(#paint1_linear_2124_5656)" stroke-width="1.14286"/>
+                <defs>
+                <linearGradient id="paint0_linear_2124_5656" x1="23.9121" y1="47.8244" x2="-0.000147684" y2="47.8244" gradientUnits="userSpaceOnUse">
+                <stop stop-color="#F6B02E"/>
+                <stop offset="1" stop-color="#7C5101"/>
+                </linearGradient>
+                <linearGradient id="paint1_linear_2124_5656" x1="23.9121" y1="47.8244" x2="-0.000147684" y2="47.8244" gradientUnits="userSpaceOnUse">
+                <stop stop-color="#F6B02E"/>
+                <stop offset="1" stop-color="#7C5101"/>
+                </linearGradient>
+                </defs>
+                </svg>
+            </div>
+            <div data-svg-wrapper data-layer="三角形" className="left-[16.70px] top-[16.70px] absolute">
+                <svg width="24" height="48" viewBox="0 0 24 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M1.10742 1.91602L3.9375 12.4355C5.95979 19.9527 5.95979 27.8715 3.9375 35.3887L1.10742 45.9092L23.1035 23.9121L1.10742 1.91602Z" fill="#F6B02E" stroke="url(#paint0_linear_2124_5657)" stroke-width="1.14286"/>
+                <defs>
+                <linearGradient id="paint0_linear_2124_5657" x1="23.9121" y1="47.8244" x2="-0.000145777" y2="47.8244" gradientUnits="userSpaceOnUse">
+                <stop stop-color="#F6B02E"/>
+                <stop offset="1" stop-color="#7C5101"/>
+                </linearGradient>
+                </defs>
+                </svg>
+            </div>
+        </div>
+    </div>
+    <div data-layer="标题" className="w-[1200px] h-32 left-[360px] top-[123.22px] absolute inline-flex justify-center items-center gap-7">
+        <div data-svg-wrapper data-layer="标题元素" data-property-1="光线左侧" className="relative">
+            <svg width="82" height="22" viewBox="0 0 82 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <g filter="url(#filter0_d_2124_5659)">
+            <path fill-rule="evenodd" clip-rule="evenodd" d="M9 11C9 11 69.8954 9 71 9C72.1046 9 73 9.89543 73 11C73 12.1046 72.1046 13 71 13C69.8954 13 9 11 9 11Z" fill="url(#paint0_linear_2124_5659)"/>
+            </g>
+            <defs>
+            <filter id="filter0_d_2124_5659" x="0" y="0" width="82" height="22" 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/>
+            <feGaussianBlur stdDeviation="4.5"/>
+            <feColorMatrix type="matrix" values="0 0 0 0 0.701923 0 0 0 0 0.494046 0 0 0 0 0.107988 0 0 0 1 0"/>
+            <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2124_5659"/>
+            <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2124_5659" result="shape"/>
+            </filter>
+            <linearGradient id="paint0_linear_2124_5659" x1="9" y1="13" x2="73" y2="13" gradientUnits="userSpaceOnUse">
+            <stop stop-color="#F6B02E" stop-opacity="0.01"/>
+            <stop offset="0.643405" stop-color="#C5FF6B" stop-opacity="0.01"/>
+            <stop offset="1" stop-color="#F6B02E"/>
+            </linearGradient>
+            </defs>
+            </svg>
+        </div>
+        <div data-layer="text" data-位置="居中对齐" data-字号="30px" data-字重="特粗" className="Text size- py-1 flex justify-center items-center gap-2.5">
+            <div data-layer="Text line-30px" className="TextLine30px text-center justify-center text-white text-4xl font-bold font-['HarmonyOS_Sans_SC'] leading-8 tracking-[8px]">湖北安陆的农发禾美佳淀粉糖项目</div>
+        </div>
+        <div data-svg-wrapper data-layer="标题元素" data-property-1="光线右侧" className="relative">
+            <svg width="82" height="22" viewBox="0 0 82 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <g filter="url(#filter0_d_2124_5663)">
+            <path fill-rule="evenodd" clip-rule="evenodd" d="M73 11C73 11 12.1046 9 11 9C9.89542 9 9 9.89543 9 11C9 12.1046 9.89542 13 11 13C12.1046 13 73 11 73 11Z" fill="url(#paint0_linear_2124_5663)"/>
+            </g>
+            <defs>
+            <filter id="filter0_d_2124_5663" x="0" y="0" width="82" height="22" 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/>
+            <feGaussianBlur stdDeviation="4.5"/>
+            <feColorMatrix type="matrix" values="0 0 0 0 0.701961 0 0 0 0 0.494118 0 0 0 0 0.109804 0 0 0 1 0"/>
+            <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2124_5663"/>
+            <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2124_5663" result="shape"/>
+            </filter>
+            <linearGradient id="paint0_linear_2124_5663" x1="73" y1="9" x2="9" y2="9" gradientUnits="userSpaceOnUse">
+            <stop stop-color="#F6B02E" stop-opacity="0.01"/>
+            <stop offset="0.643405" stop-color="#F6B02E" stop-opacity="0.372549"/>
+            <stop offset="1" stop-color="#F6B02E"/>
+            </linearGradient>
+            </defs>
+            </svg>
+        </div>
+    </div>
+    <div data-layer="返回icon" className="Icon size-24 left-[1860px] top-[990px] absolute origin-top-left rotate-180">
+        <div data-layer="Ellipse 4119" className="Ellipse4119 size-20 left-[87.86px] top-[87.86px] absolute origin-top-left rotate-180 bg-blue-200/10 rounded-full shadow-[inset_0px_0px_13px_0px_rgba(201,221,255,0.50)] outline outline-1 outline-blue-200" />
+        <div data-svg-wrapper data-layer="路径" className="left-[35.53px] top-[28.05px] absolute">
+            <svg width="37" height="52" viewBox="0 0 37 52" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <g filter="url(#filter0_d_2124_5667)">
+            <path fill-rule="evenodd" clip-rule="evenodd" d="M24.9389 42.9001C25.2582 42.9114 25.5689 42.7956 25.8025 42.5782L27.5649 40.9403C27.7984 40.7228 27.9357 40.4217 27.9466 40.1032C27.9574 39.7847 27.8409 39.475 27.6227 39.2422L15.199 25.9511L27.6227 12.6576C28.0755 12.1732 28.0496 11.4146 27.5649 10.962L25.8025 9.32397C25.5692 9.10633 25.2587 8.99009 24.9394 9.0009C24.6201 9.01171 24.3183 9.14867 24.1003 9.3816L10.1959 24.2555L9.38209 25.012C9.12173 25.2542 8.98239 25.599 9.00166 25.9535C8.98385 26.3064 9.12306 26.6492 9.38209 26.8902L10.2007 27.6467L24.1003 42.5182C24.3179 42.7515 24.6196 42.8889 24.9389 42.9001Z" fill="#C9DDFF"/>
+            </g>
+            <defs>
+            <filter id="filter0_d_2124_5667" x="0" y="0" width="36.9473" height="51.9009" 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/>
+            <feGaussianBlur stdDeviation="4.5"/>
+            <feColorMatrix type="matrix" values="0 0 0 0 0.788235 0 0 0 0 0.866667 0 0 0 0 1 0 0 0 0.501961 0"/>
+            <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2124_5667"/>
+            <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2124_5667" result="shape"/>
+            </filter>
+            </defs>
+            </svg>
+        </div>
+    </div>
+</div>

Fișier diff suprimat deoarece este prea mare
+ 8 - 9
public/supply-chain/BasePointIcon_aquatic.svg


Fișier diff suprimat deoarece este prea mare
+ 0 - 11
public/supply-chain/BasePointIcon_freshfood.svg


Fișier diff suprimat deoarece este prea mare
+ 8 - 9
public/supply-chain/BasePointIcon_fruit.svg


Fișier diff suprimat deoarece este prea mare
+ 4 - 10
public/supply-chain/BasePointIcon_livestock.svg


+ 22 - 17
public/supply-chain/BasePointIcon_salt.svg

@@ -1,16 +1,21 @@
 <svg width="42" height="50" viewBox="0 0 42 50" fill="none" xmlns="http://www.w3.org/2000/svg">
 <svg width="42" height="50" viewBox="0 0 42 50" fill="none" xmlns="http://www.w3.org/2000/svg">
-<g filter="url(#filter0_i_2019_11837)">
-<path d="M35.7472 22.6746C36.073 29.636 31.5656 35.599 25.2662 37.5417C23.7185 38.0274 22.388 38.9987 21.5191 40.3478L20.8403 41.4541L20.1343 40.3478C19.2926 39.0257 17.9892 38.0274 16.4958 37.5687C10.3593 35.7339 5.90625 30.0677 5.90625 23.3762C5.90625 14.9578 12.966 8.15835 21.5462 8.56308C29.2033 8.88686 35.3942 15.0657 35.7472 22.6746Z" fill="#151C3B"/>
-<path d="M35.7472 22.6746C36.073 29.636 31.5656 35.599 25.2662 37.5417C23.7185 38.0274 22.388 38.9987 21.5191 40.3478L20.8403 41.4541L20.1343 40.3478C19.2926 39.0257 17.9892 38.0274 16.4958 37.5687C10.3593 35.7339 5.90625 30.0677 5.90625 23.3762C5.90625 14.9578 12.966 8.15835 21.5462 8.56308C29.2033 8.88686 35.3942 15.0657 35.7472 22.6746Z" fill="url(#paint0_linear_2019_11837)" style="mix-blend-mode:overlay"/>
-<path d="M35.7472 22.6746C36.073 29.636 31.5656 35.599 25.2662 37.5417C23.7185 38.0274 22.388 38.9987 21.5191 40.3478L20.8403 41.4541L20.1343 40.3478C19.2926 39.0257 17.9892 38.0274 16.4958 37.5687C10.3593 35.7339 5.90625 30.0677 5.90625 23.3762C5.90625 14.9578 12.966 8.15835 21.5462 8.56308C29.2033 8.88686 35.3942 15.0657 35.7472 22.6746Z" fill="url(#paint1_linear_2019_11837)" style="mix-blend-mode:overlay"/>
+<g filter="url(#filter0_i_1918_216057)">
+<path d="M35.7457 22.6744C36.0715 29.6357 31.5642 35.5987 25.2647 37.5414C23.717 38.0271 22.3865 38.9985 21.5176 40.3476L20.8388 41.4538L20.1328 40.3476C19.2911 39.0254 17.9878 38.0271 16.4944 37.5684C10.3578 35.7336 5.90479 30.0674 5.90479 23.3759C5.90479 14.9576 12.9645 8.1581 21.5448 8.56283C29.2019 8.88662 35.3927 15.0655 35.7457 22.6744Z" fill="#151C3B"/>
+<path d="M35.7457 22.6744C36.0715 29.6357 31.5642 35.5987 25.2647 37.5414C23.717 38.0271 22.3865 38.9985 21.5176 40.3476L20.8388 41.4538L20.1328 40.3476C19.2911 39.0254 17.9878 38.0271 16.4944 37.5684C10.3578 35.7336 5.90479 30.0674 5.90479 23.3759C5.90479 14.9576 12.9645 8.1581 21.5448 8.56283C29.2019 8.88662 35.3927 15.0655 35.7457 22.6744Z" fill="url(#paint0_linear_1918_216057)" style="mix-blend-mode:overlay"/>
+<path d="M35.7457 22.6744C36.0715 29.6357 31.5642 35.5987 25.2647 37.5414C23.717 38.0271 22.3865 38.9985 21.5176 40.3476L20.8388 41.4538L20.1328 40.3476C19.2911 39.0254 17.9878 38.0271 16.4944 37.5684C10.3578 35.7336 5.90479 30.0674 5.90479 23.3759C5.90479 14.9576 12.9645 8.1581 21.5448 8.56283C29.2019 8.88662 35.3927 15.0655 35.7457 22.6744Z" fill="url(#paint1_linear_1918_216057)" style="mix-blend-mode:overlay"/>
 </g>
 </g>
-<path d="M6.15625 23.376C6.15635 15.101 13.0962 8.41465 21.5342 8.8125H21.5361C29.0638 9.13103 35.1501 15.2073 35.4971 22.6865C35.8173 29.5292 31.3874 35.3922 25.1924 37.3027H25.1914C23.5919 37.8047 22.2114 38.8112 21.3086 40.2129L21.3057 40.2168L20.835 40.9824L20.3447 40.2129H20.3438C19.4704 38.8418 18.1196 37.8063 16.5693 37.3301L16.5674 37.3291C10.5335 35.525 6.15625 29.9536 6.15625 23.376Z" stroke="url(#paint2_linear_2019_11837)" stroke-width="0.5" style="mix-blend-mode:overlay"/>
-<path d="M6.15625 23.376C6.15635 15.101 13.0962 8.41465 21.5342 8.8125H21.5361C29.0638 9.13103 35.1501 15.2073 35.4971 22.6865C35.8173 29.5292 31.3874 35.3922 25.1924 37.3027H25.1914C23.5919 37.8047 22.2114 38.8112 21.3086 40.2129L21.3057 40.2168L20.835 40.9824L20.3447 40.2129H20.3438C19.4704 38.8418 18.1196 37.8063 16.5693 37.3301L16.5674 37.3291C10.5335 35.525 6.15625 29.9536 6.15625 23.376Z" stroke="url(#paint3_linear_2019_11837)" stroke-width="0.5" style="mix-blend-mode:overlay"/>
-<path d="M4.10938 23.1494C4.10948 13.8491 12.0095 6.32054 21.6318 6.76855L21.6348 6.76953C30.2166 7.12798 37.1471 13.9677 37.542 22.374C37.9064 30.0649 32.8643 36.6625 25.8018 38.8135L25.7998 38.8145C23.9117 39.3996 22.2763 40.5733 21.2051 42.2158L21.1992 42.2256L20.832 42.8154L20.4463 42.2178H20.4453C19.41 40.6124 17.8099 39.4008 15.9736 38.8438L15.9697 38.8428L15.3301 38.6406C8.78478 36.4194 4.10938 30.3116 4.10938 23.1494Z" stroke="url(#paint4_linear_2019_11837)"/>
-<path d="M4.10938 23.1494C4.10948 13.8491 12.0095 6.32054 21.6318 6.76855L21.6348 6.76953C30.2166 7.12798 37.1471 13.9677 37.542 22.374C37.9064 30.0649 32.8643 36.6625 25.8018 38.8135L25.7998 38.8145C23.9117 39.3996 22.2763 40.5733 21.2051 42.2158L21.1992 42.2256L20.832 42.8154L20.4463 42.2178H20.4453C19.41 40.6124 17.8099 39.4008 15.9736 38.8438L15.9697 38.8428L15.3301 38.6406C8.78478 36.4194 4.10938 30.3116 4.10938 23.1494Z" stroke="url(#paint5_linear_2019_11837)"/>
-<path opacity="0.78" d="M22.2622 16.9459C22.2622 16.9459 21.7354 16.6533 20.8314 16.6761C19.9274 16.6533 19.4014 16.9459 19.4014 16.9459V18.0434H22.2622V16.9459L22.2622 16.9459ZM26.1839 31.8599C26.1839 31.8599 26.1839 22.5112 26.1839 21.9991C26.1839 21.487 25.8604 21.3162 25.8604 21.3162L22.276 18.4613H19.3876L15.8032 21.3162C15.8032 21.3162 15.4789 21.487 15.4789 21.9991C15.4789 22.5112 15.4789 31.8599 15.4789 31.8599C15.4789 31.8599 15.3537 33.3248 16.9503 33.3248H19.4014C20.8558 33.3248 22.2622 33.3248 22.2622 33.3248H24.7133C26.3091 33.3248 26.1839 31.8599 26.1839 31.8599ZM24.7125 28.3172C24.7125 28.4781 24.5775 28.6098 24.4117 28.6098H22.2208C22.0549 28.6098 21.9208 28.4781 21.9208 28.3172V23.4819C21.9208 23.3193 22.0549 23.1884 22.2208 23.1884H24.4117C24.5775 23.1884 24.7125 23.3193 24.7125 23.4819V28.3172L24.7125 28.3172Z" fill="white"/>
+<path d="M6.15479 23.3757C6.15489 15.1007 13.0947 8.4144 21.5327 8.81226H21.5347C29.0624 9.13079 35.1486 15.2071 35.4956 22.6863C35.8158 29.5289 31.3859 35.392 25.1909 37.3025H25.1899C23.5905 37.8044 22.2099 38.811 21.3071 40.2126L21.3042 40.2166L20.8335 40.9822L20.3433 40.2126H20.3423C19.469 38.8415 18.1182 37.8061 16.5679 37.3298L16.5659 37.3289C10.532 35.5247 6.15479 29.9534 6.15479 23.3757Z" stroke="url(#paint2_linear_1918_216057)" stroke-width="0.5" style="mix-blend-mode:overlay"/>
+<path d="M6.15479 23.3757C6.15489 15.1007 13.0947 8.4144 21.5327 8.81226H21.5347C29.0624 9.13079 35.1486 15.2071 35.4956 22.6863C35.8158 29.5289 31.3859 35.392 25.1909 37.3025H25.1899C23.5905 37.8044 22.2099 38.811 21.3071 40.2126L21.3042 40.2166L20.8335 40.9822L20.3433 40.2126H20.3423C19.469 38.8415 18.1182 37.8061 16.5679 37.3298L16.5659 37.3289C10.532 35.5247 6.15479 29.9534 6.15479 23.3757Z" stroke="url(#paint3_linear_1918_216057)" stroke-width="0.5" style="mix-blend-mode:overlay"/>
+<path d="M4.10791 23.1492C4.10802 13.8489 12.008 6.3203 21.6304 6.76831L21.6333 6.76929C30.2151 7.12773 37.1456 13.9674 37.5405 22.3738C37.9049 30.0647 32.8628 36.6622 25.8003 38.8132L25.7983 38.8142C23.9103 39.3994 22.2748 40.5731 21.2036 42.2156L21.1978 42.2253L20.8306 42.8152L20.4448 42.2175H20.4438C19.4085 40.6121 17.8084 39.4006 15.9722 38.8435L15.9683 38.8425L15.3286 38.6404C8.78332 36.4191 4.10791 30.3114 4.10791 23.1492Z" stroke="url(#paint4_linear_1918_216057)"/>
+<path d="M4.10791 23.1492C4.10802 13.8489 12.008 6.3203 21.6304 6.76831L21.6333 6.76929C30.2151 7.12773 37.1456 13.9674 37.5405 22.3738C37.9049 30.0647 32.8628 36.6622 25.8003 38.8132L25.7983 38.8142C23.9103 39.3994 22.2748 40.5731 21.2036 42.2156L21.1978 42.2253L20.8306 42.8152L20.4448 42.2175H20.4438C19.4085 40.6121 17.8084 39.4006 15.9722 38.8435L15.9683 38.8425L15.3286 38.6404C8.78332 36.4191 4.10791 30.3114 4.10791 23.1492Z" stroke="url(#paint5_linear_1918_216057)"/>
+<path d="M20.2911 29.0577H19.6834V28.1228H20.2911V29.0577Z" fill="white"/>
+<path d="M21.1231 29.0577H20.5061V28.1228H21.1231V29.0577Z" fill="white"/>
+<path d="M21.9646 29.0577H21.3382V28.1228H21.9646V29.0577Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M20.8334 23.9715C22.778 23.9715 24.3581 25.5516 24.3581 27.4963C24.3581 29.441 22.778 31.0211 20.8334 31.0211C18.8887 31.0211 17.3086 29.441 17.3086 27.4963C17.3086 25.5516 18.8887 23.9715 20.8334 23.9715ZM19.4683 29.0577H19.0195V29.254H22.619V29.0577H22.1798V27.9264H19.4683V29.0577ZM21.2261 27.7394H21.4411V26.6549C21.7403 26.8045 22.0955 27.0195 22.5256 27.3L22.6472 27.1223C22.2171 26.8605 21.8151 26.6361 21.4411 26.4492V25.7292H21.2261V27.7394ZM19.8797 26.4024H19.1972V26.6268H19.8704V27.4122C19.6927 27.4402 19.4402 27.4776 19.113 27.515L19.1692 27.7113C19.7862 27.6272 20.3472 27.5244 20.8521 27.4122V27.2064C20.5996 27.2625 20.3471 27.3186 20.0947 27.3654V26.6174H20.7773V26.4024H20.0947V25.7292H19.8797V26.4024Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M22.9483 21.693C27.6341 21.693 28.7849 30.899 28.7849 30.899C28.7849 32.1119 27.8103 33.3248 26.5974 33.3248H15.0693C13.8668 33.3248 12.8819 32.1119 12.8818 30.899C12.8818 30.899 14.0326 21.6931 18.7184 21.693H22.9483ZM20.8334 23.3621C18.5526 23.3621 16.6969 25.2178 16.6969 27.4985C16.6969 29.7793 18.5526 31.635 20.8334 31.635C23.1141 31.635 24.9698 29.7793 24.9698 27.4985C24.9698 25.2178 23.1141 23.3621 20.8334 23.3621Z" fill="white"/>
+<path d="M16.531 18.1579C16.531 17.3596 16.7384 16.5303 17.9928 16.6962C19.2368 16.8724 19.7448 17.6603 20.7608 17.6603C21.7456 17.6603 22.0774 16.6547 23.4562 16.6962C24.835 16.7376 24.918 17.3493 24.918 18.1579C24.9168 18.1613 23.9737 20.8533 22.7305 20.8533H18.7184C17.4752 20.8532 16.5323 18.1613 16.531 18.1579Z" fill="white"/>
 <defs>
 <defs>
-<filter id="filter0_i_2019_11837" x="5.90625" y="8.5459" width="29.8594" height="32.9082" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<filter id="filter0_i_1918_216057" x="5.90479" y="8.54565" width="29.8574" height="32.9082" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
 <feFlood flood-opacity="0" result="BackgroundImageFix"/>
 <feFlood flood-opacity="0" result="BackgroundImageFix"/>
 <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
 <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
 <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"/>
 <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"/>
@@ -18,29 +23,29 @@
 <feGaussianBlur stdDeviation="2.5"/>
 <feGaussianBlur stdDeviation="2.5"/>
 <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
 <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
 <feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
 <feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
-<feBlend mode="overlay" in2="shape" result="effect1_innerShadow_2019_11837"/>
+<feBlend mode="overlay" in2="shape" result="effect1_innerShadow_1918_216057"/>
 </filter>
 </filter>
-<linearGradient id="paint0_linear_2019_11837" x1="20.835" y1="8.5459" x2="20.835" y2="41.4541" gradientUnits="userSpaceOnUse">
+<linearGradient id="paint0_linear_1918_216057" x1="20.8335" y1="8.54565" x2="20.8335" y2="41.4538" gradientUnits="userSpaceOnUse">
 <stop stop-color="white" stop-opacity="0"/>
 <stop stop-color="white" stop-opacity="0"/>
 <stop offset="1" stop-color="white"/>
 <stop offset="1" stop-color="white"/>
 </linearGradient>
 </linearGradient>
-<linearGradient id="paint1_linear_2019_11837" x1="20.835" y1="8.5459" x2="20.835" y2="41.4541" gradientUnits="userSpaceOnUse">
+<linearGradient id="paint1_linear_1918_216057" x1="20.8335" y1="8.54565" x2="20.8335" y2="41.4538" gradientUnits="userSpaceOnUse">
 <stop stop-color="white" stop-opacity="0"/>
 <stop stop-color="white" stop-opacity="0"/>
 <stop offset="1" stop-color="white"/>
 <stop offset="1" stop-color="white"/>
 </linearGradient>
 </linearGradient>
-<linearGradient id="paint2_linear_2019_11837" x1="20.835" y1="8.5459" x2="20.835" y2="41.4541" gradientUnits="userSpaceOnUse">
+<linearGradient id="paint2_linear_1918_216057" x1="20.8335" y1="8.54565" x2="20.8335" y2="41.4538" gradientUnits="userSpaceOnUse">
 <stop stop-color="white" stop-opacity="0"/>
 <stop stop-color="white" stop-opacity="0"/>
 <stop offset="1" stop-color="white"/>
 <stop offset="1" stop-color="white"/>
 </linearGradient>
 </linearGradient>
-<linearGradient id="paint3_linear_2019_11837" x1="20.835" y1="33.9923" x2="20.835" y2="41.4541" gradientUnits="userSpaceOnUse">
+<linearGradient id="paint3_linear_1918_216057" x1="20.8335" y1="33.9921" x2="20.8335" y2="41.4538" gradientUnits="userSpaceOnUse">
 <stop stop-color="white" stop-opacity="0"/>
 <stop stop-color="white" stop-opacity="0"/>
 <stop offset="1" stop-color="white"/>
 <stop offset="1" stop-color="white"/>
 </linearGradient>
 </linearGradient>
-<linearGradient id="paint4_linear_2019_11837" x1="20.8349" y1="6.25" x2="20.8349" y2="43.75" gradientUnits="userSpaceOnUse">
+<linearGradient id="paint4_linear_1918_216057" x1="20.8334" y1="6.24976" x2="20.8334" y2="43.7498" gradientUnits="userSpaceOnUse">
 <stop stop-color="#151C3B" stop-opacity="0"/>
 <stop stop-color="#151C3B" stop-opacity="0"/>
 <stop offset="1" stop-color="#151C3B"/>
 <stop offset="1" stop-color="#151C3B"/>
 </linearGradient>
 </linearGradient>
-<linearGradient id="paint5_linear_2019_11837" x1="20.8349" y1="36.3281" x2="20.8349" y2="43.75" gradientUnits="userSpaceOnUse">
+<linearGradient id="paint5_linear_1918_216057" x1="20.8334" y1="36.3279" x2="20.8334" y2="43.7498" gradientUnits="userSpaceOnUse">
 <stop stop-color="white" stop-opacity="0"/>
 <stop stop-color="white" stop-opacity="0"/>
 <stop offset="1" stop-color="white"/>
 <stop offset="1" stop-color="white"/>
 </linearGradient>
 </linearGradient>

Fișier diff suprimat deoarece este prea mare
+ 4 - 10
public/supply-chain/BasePointIcon_seed.svg


Fișier diff suprimat deoarece este prea mare
+ 32 - 4
public/supply-chain/SupplyChainIcons_salt.svg


+ 165 - 0
src/client/home/pages/SupplyChainDashboards/components/DoubleImageDisplay.tsx

@@ -0,0 +1,165 @@
+import React, { useRef, useState, useEffect, useCallback } from 'react';
+
+interface DoubleImageDisplayProps {
+  imageUrls: string[];
+  title: string;
+  themeColor: string;
+}
+
+// 滚动条状态管理
+interface ScrollbarState {
+  isDragging: boolean;
+  scrollPosition: number;
+}
+
+// 滚动条交互工具函数
+const createScrollbarInteraction = (
+  containerRef: React.RefObject<HTMLDivElement | null>,
+  scrollState: ScrollbarState,
+  setScrollState: React.Dispatch<React.SetStateAction<ScrollbarState>>
+) => {
+  const handleScrollbarClick = (event: React.MouseEvent) => {
+    const rect = event.currentTarget.getBoundingClientRect();
+    const clickPosition = event.clientX - rect.left;
+    const scrollPercentage = clickPosition / rect.width;
+
+    if (containerRef.current) {
+      const scrollWidth = containerRef.current.scrollWidth - containerRef.current.clientWidth;
+      containerRef.current.scrollLeft = scrollWidth * scrollPercentage;
+    }
+  };
+
+  const handleScrollbarDragStart = (event: React.MouseEvent) => {
+    event.preventDefault();
+    setScrollState(prev => ({ ...prev, isDragging: true }));
+  };
+
+  const handleScrollbarDrag = (event: React.MouseEvent) => {
+    if (!scrollState.isDragging) return;
+
+    const rect = event.currentTarget.getBoundingClientRect();
+    const dragPosition = event.clientX - rect.left;
+    const scrollPercentage = Math.max(0, Math.min(1, dragPosition / rect.width));
+
+    if (containerRef.current) {
+      const scrollWidth = containerRef.current.scrollWidth - containerRef.current.clientWidth;
+      containerRef.current.scrollLeft = scrollWidth * scrollPercentage;
+    }
+  };
+
+  const handleScrollbarDragEnd = () => {
+    setScrollState(prev => ({ ...prev, isDragging: false }));
+  };
+
+  return {
+    handleScrollbarClick,
+    handleScrollbarDragStart,
+    handleScrollbarDrag,
+    handleScrollbarDragEnd
+  };
+};
+
+const DoubleImageDisplay: React.FC<DoubleImageDisplayProps> = ({ imageUrls, title, themeColor }) => {
+  const imageContainerRef = useRef<HTMLDivElement>(null);
+  const [scrollState, setScrollState] = useState<ScrollbarState>({
+    isDragging: false,
+    scrollPosition: 0
+  });
+
+  const {
+    handleScrollbarClick,
+    handleScrollbarDragStart,
+    handleScrollbarDrag,
+    handleScrollbarDragEnd
+  } = createScrollbarInteraction(imageContainerRef, scrollState, setScrollState);
+
+  const syncScrollbarPosition = useCallback(() => {
+    if (imageContainerRef.current) {
+      const scrollLeft = imageContainerRef.current.scrollLeft;
+      const scrollWidth = imageContainerRef.current.scrollWidth - imageContainerRef.current.clientWidth;
+      const scrollPercentage = scrollWidth > 0 ? scrollLeft / scrollWidth : 0;
+
+      setScrollState(prev => ({
+        ...prev,
+        scrollPosition: scrollPercentage
+      }));
+    }
+  }, []);
+
+  useEffect(() => {
+    const container = imageContainerRef.current;
+    if (!container) return;
+
+    const handleScroll = () => {
+      syncScrollbarPosition();
+    };
+
+    container.addEventListener('scroll', handleScroll);
+    return () => container.removeEventListener('scroll', handleScroll);
+  }, [syncScrollbarPosition]);
+
+  useEffect(() => {
+    if (imageContainerRef.current) {
+      syncScrollbarPosition();
+    }
+  }, [imageUrls, syncScrollbarPosition]);
+
+  return (
+    <>
+      <div
+        ref={imageContainerRef}
+        data-layer="双图滚动容器"
+        className="flex overflow-x-auto gap-[20px] h-full items-center"
+        style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }}
+      >
+        {/* 第一张图片 - 宽度853px */}
+        <div
+          data-layer="图片1"
+          className="h-[640px] overflow-clip relative rounded-[10px] shrink-0 w-[853px]"
+        >
+          <img
+            data-layer={`${title} 1`}
+            className="w-full h-full object-cover"
+            src={imageUrls[0]}
+            alt={`${title} 1`}
+          />
+        </div>
+        {/* 第二张图片 - 宽度940px */}
+        <div
+          data-layer="图片2"
+          className="h-[640px] overflow-clip relative rounded-[10px] shrink-0 w-[940px]"
+        >
+          <img
+            data-layer={`${title} 2`}
+            className="w-full h-full object-cover"
+            src={imageUrls[1]}
+            alt={`${title} 2`}
+          />
+        </div>
+      </div>
+
+      {/* 自定义滚动条 - 双图模式专用 */}
+      <div
+        data-layer="滚动条容器"
+        className="absolute bottom-[-40px] left-1/2 transform -translate-x-1/2 w-[60%] h-[8px] bg-stone-700/30 rounded-[4px] cursor-pointer"
+        onClick={handleScrollbarClick}
+        onMouseDown={handleScrollbarDragStart}
+        onMouseMove={scrollState.isDragging ? handleScrollbarDrag : undefined}
+        onMouseUp={handleScrollbarDragEnd}
+        onMouseLeave={handleScrollbarDragEnd}
+      >
+        <div
+          data-layer="滚动条滑块"
+          className="absolute h-full bg-stone-400 rounded-[4px] transition-all duration-200 hover:bg-stone-300 cursor-grab active:cursor-grabbing"
+          style={{
+            width: '20%',
+            left: `${scrollState.scrollPosition * 80}%`,
+            backgroundColor: themeColor
+          }}
+        />
+      </div>
+    </>
+  );
+};
+
+export default DoubleImageDisplay;

+ 133 - 0
src/client/home/pages/SupplyChainDashboards/components/MultipleImageDisplay.tsx

@@ -0,0 +1,133 @@
+import React, { useState } from 'react';
+
+interface MultipleImageDisplayProps {
+  imageUrls: string[];
+  title: string;
+  themeColor: string;
+}
+
+const MultipleImageDisplay: React.FC<MultipleImageDisplayProps> = ({ imageUrls, title, themeColor }) => {
+  const [currentIndex, setCurrentIndex] = useState(0);
+
+  const handlePrev = () => {
+    setCurrentIndex(prev => (prev === 0 ? imageUrls.length - 1 : prev - 1));
+  };
+
+  const handleNext = () => {
+    setCurrentIndex(prev => (prev === imageUrls.length - 1 ? 0 : prev + 1));
+  };
+
+  return (
+    <>
+      {/* 图片展示区域 */}
+      <div className="flex items-center justify-center h-full">
+        <div className="h-[640px] overflow-clip relative rounded-[10px] w-[940px]">
+          <img
+            data-layer={`${title} ${currentIndex + 1}`}
+            className="w-full h-full object-cover"
+            src={imageUrls[currentIndex]}
+            alt={`${title} ${currentIndex + 1}`}
+          />
+        </div>
+      </div>
+
+      {/* 左右箭头按钮 */}
+      <div
+        data-layer="按钮"
+        className="absolute w-[1510px] left-1/2 top-[545.72px] transform -translate-x-1/2 inline-flex justify-between items-center"
+      >
+        {/* 左箭头 */}
+        <button
+          data-layer="原创-箭头right"
+          className="size-20 relative origin-top-left rotate-180 cursor-pointer hover:opacity-80 transition-opacity"
+          onClick={handlePrev}
+        >
+          <div data-svg-wrapper data-layer="矩形" className="left-0 top-0 absolute">
+            <svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
+              <path fillRule="evenodd" clipRule="evenodd" d="M0 0V80H80V0H0Z" fill="black" fillOpacity="0.0117647" />
+            </svg>
+          </div>
+          <div data-svg-wrapper data-layer="三角形" className="left-[15.47px] top-[16.70px] absolute">
+            <svg width="24" height="48" viewBox="0 0 24 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+              <path d="M22.8047 1.91602L19.9746 12.4355C17.9523 19.9527 17.9523 27.8715 19.9746 35.3887L22.8047 45.9092L0.808594 23.9121L22.8047 1.91602Z" fill="url(#paint0_linear_2124_5652)" stroke="url(#paint1_linear_2124_5652)" strokeWidth="1.14286" />
+              <defs>
+                <linearGradient id="paint0_linear_2124_5652" x1="0" y1="47.8244" x2="23.9123" y2="47.8244" gradientUnits="userSpaceOnUse">
+                  <stop stopColor={themeColor} />
+                  <stop offset="1" stopColor="#7C5101" />
+                </linearGradient>
+                <linearGradient id="paint1_linear_2124_5652" x1="0" y1="47.8244" x2="23.9123" y2="47.8244" gradientUnits="userSpaceOnUse">
+                  <stop stopColor={themeColor} />
+                  <stop offset="1" stopColor="#7C5101" />
+                </linearGradient>
+              </defs>
+            </svg>
+          </div>
+          <div data-svg-wrapper data-layer="三角形" className="left-[39.38px] top-[16.70px] absolute">
+            <svg width="24" height="48" viewBox="0 0 24 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+              <path d="M22.8047 1.91602L19.9746 12.4355C17.9523 19.9527 17.9523 27.8715 19.9746 35.3887L22.8047 45.9092L0.808594 23.9121L22.8047 1.91602Z" fill={themeColor} stroke="url(#paint0_linear_2124_5653)" strokeWidth="1.14286" />
+              <defs>
+                <linearGradient id="paint0_linear_2124_5653" x1="0" y1="47.8244" x2="23.9123" y2="47.8244" gradientUnits="userSpaceOnUse">
+                  <stop stopColor={themeColor} />
+                  <stop offset="1" stopColor="#7C5101" />
+                </linearGradient>
+              </defs>
+            </svg>
+          </div>
+        </button>
+
+        {/* 右箭头 */}
+        <button
+          data-layer="原创-箭头right"
+          className="size-20 relative cursor-pointer hover:opacity-80 transition-opacity"
+          onClick={handleNext}
+        >
+          <div data-svg-wrapper data-layer="矩形" className="left-0 top-0 absolute">
+            <svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
+              <path fillRule="evenodd" clipRule="evenodd" d="M80 0V80H0V0H80Z" fill="black" fillOpacity="0.0117647" />
+            </svg>
+          </div>
+          <div data-svg-wrapper data-layer="三角形" className="left-[40.62px] top-[16.70px] absolute">
+            <svg width="24" height="48" viewBox="0 0 24 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+              <path d="M1.10742 1.91602L3.9375 12.4355C5.95979 19.9527 5.95979 27.8715 3.9375 35.3887L1.10742 45.9092L23.1035 23.9121L1.10742 1.91602Z" fill="url(#paint0_linear_2124_5656)" stroke="url(#paint1_linear_2124_5656)" strokeWidth="1.14286" />
+              <defs>
+                <linearGradient id="paint0_linear_2124_5656" x1="23.9121" y1="47.8244" x2="-0.000147684" y2="47.8244" gradientUnits="userSpaceOnUse">
+                  <stop stopColor={themeColor} />
+                  <stop offset="1" stopColor="#7C5101" />
+                </linearGradient>
+                <linearGradient id="paint1_linear_2124_5656" x1="23.9121" y1="47.8244" x2="-0.000147684" y2="47.8244" gradientUnits="userSpaceOnUse">
+                  <stop stopColor={themeColor} />
+                  <stop offset="1" stopColor="#7C5101" />
+                </linearGradient>
+              </defs>
+            </svg>
+          </div>
+          <div data-svg-wrapper data-layer="三角形" className="left-[16.70px] top-[16.70px] absolute">
+            <svg width="24" height="48" viewBox="0 0 24 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+              <path d="M1.10742 1.91602L3.9375 12.4355C5.95979 19.9527 5.95979 27.8715 3.9375 35.3887L1.10742 45.9092L23.1035 23.9121L1.10742 1.91602Z" fill={themeColor} stroke="url(#paint0_linear_2124_5657)" strokeWidth="1.14286" />
+              <defs>
+                <linearGradient id="paint0_linear_2124_5657" x1="23.9121" y1="47.8244" x2="-0.000145777" y2="47.8244" gradientUnits="userSpaceOnUse">
+                  <stop stopColor={themeColor} />
+                  <stop offset="1" stopColor="#7C5101" />
+                </linearGradient>
+              </defs>
+            </svg>
+          </div>
+        </button>
+      </div>
+
+      {/* 图片指示器 */}
+      <div className="absolute bottom-[-30px] left-1/2 transform -translate-x-1/2 flex gap-2">
+        {imageUrls.map((_, index) => (
+          <div
+            key={index}
+            className={`w-2 h-2 rounded-full transition-all duration-200 ${
+              index === currentIndex ? 'bg-white' : 'bg-white/30'
+            }`}
+          />
+        ))}
+      </div>
+    </>
+  );
+};
+
+export default MultipleImageDisplay;

+ 23 - 0
src/client/home/pages/SupplyChainDashboards/components/SingleImageDisplay.tsx

@@ -0,0 +1,23 @@
+import React from 'react';
+
+interface SingleImageDisplayProps {
+  imageUrl: string;
+  title: string;
+}
+
+const SingleImageDisplay: React.FC<SingleImageDisplayProps> = ({ imageUrl, title }) => {
+  return (
+    <div className="flex items-center justify-center h-full">
+      <div className="h-[640px] overflow-clip relative rounded-[10px] w-[960px]">
+        <img
+          data-layer="单图展示"
+          className="w-full h-full object-cover"
+          src={imageUrl}
+          alt={title}
+        />
+      </div>
+    </div>
+  );
+};
+
+export default SingleImageDisplay;

+ 18 - 169
src/client/home/pages/SupplyChainDashboards/components/SupplyChainModal.tsx

@@ -1,16 +1,11 @@
-import React, { useRef, useState, useEffect, useCallback } from 'react';
+import React, { useEffect } from 'react';
 import { useSupplyChain } from '../context/SupplyChainContext';
 import { useSupplyChain } from '../context/SupplyChainContext';
+import SingleImageDisplay from './SingleImageDisplay';
+import DoubleImageDisplay from './DoubleImageDisplay';
+import MultipleImageDisplay from './MultipleImageDisplay';
 
 
 // 图片展示模式类型
 // 图片展示模式类型
-type ImageDisplayMode = 'single' | 'multiple';
-
-// 滚动条状态管理
-interface ScrollbarState {
-  isDragging: boolean;
-  scrollPosition: number;
-  scrollbarWidth: number;
-  containerWidth: number;
-}
+type ImageDisplayMode = 'single' | 'double' | 'multiple';
 
 
 interface SupplyChainModalProps {
 interface SupplyChainModalProps {
   isOpen: boolean;
   isOpen: boolean;
@@ -20,57 +15,6 @@ interface SupplyChainModalProps {
   children?: React.ReactNode;
   children?: React.ReactNode;
 }
 }
 
 
-// 滚动条交互工具函数
-const createScrollbarInteraction = (
-  containerRef: React.RefObject<HTMLDivElement | null>,
-  scrollState: ScrollbarState,
-  setScrollState: React.Dispatch<React.SetStateAction<ScrollbarState>>
-) => {
-  // 处理滚动条点击
-  const handleScrollbarClick = (event: React.MouseEvent) => {
-    const rect = event.currentTarget.getBoundingClientRect();
-    const clickPosition = event.clientX - rect.left;
-    const scrollPercentage = clickPosition / rect.width;
-
-    if (containerRef.current) {
-      const scrollWidth = containerRef.current.scrollWidth - containerRef.current.clientWidth;
-      containerRef.current.scrollLeft = scrollWidth * scrollPercentage;
-    }
-  };
-
-  // 处理滚动条拖动开始
-  const handleScrollbarDragStart = (event: React.MouseEvent) => {
-    event.preventDefault();
-    setScrollState(prev => ({ ...prev, isDragging: true }));
-  };
-
-  // 处理滚动条拖动
-  const handleScrollbarDrag = (event: React.MouseEvent) => {
-    if (!scrollState.isDragging) return;
-
-    const rect = event.currentTarget.getBoundingClientRect();
-    const dragPosition = event.clientX - rect.left;
-    const scrollPercentage = Math.max(0, Math.min(1, dragPosition / rect.width));
-
-    if (containerRef.current) {
-      const scrollWidth = containerRef.current.scrollWidth - containerRef.current.clientWidth;
-      containerRef.current.scrollLeft = scrollWidth * scrollPercentage;
-    }
-  };
-
-  // 处理滚动条拖动结束
-  const handleScrollbarDragEnd = () => {
-    setScrollState(prev => ({ ...prev, isDragging: false }));
-  };
-
-  return {
-    handleScrollbarClick,
-    handleScrollbarDragStart,
-    handleScrollbarDrag,
-    handleScrollbarDragEnd
-  };
-};
-
 const SupplyChainModal: React.FC<SupplyChainModalProps> = ({
 const SupplyChainModal: React.FC<SupplyChainModalProps> = ({
   isOpen,
   isOpen,
   onClose,
   onClose,
@@ -78,40 +22,12 @@ const SupplyChainModal: React.FC<SupplyChainModalProps> = ({
   imageUrls = ["https://placehold.co/960x640"]
   imageUrls = ["https://placehold.co/960x640"]
 }) => {
 }) => {
   const { themeColor } = useSupplyChain();
   const { themeColor } = useSupplyChain();
-  const imageContainerRef = useRef<HTMLDivElement>(null);
-
-  // 滚动条状态管理
-  const [scrollState, setScrollState] = useState<ScrollbarState>({
-    isDragging: false,
-    scrollPosition: 0,
-    scrollbarWidth: 0,
-    containerWidth: 0
-  });
 
 
   // 根据图片数量确定展示模式
   // 根据图片数量确定展示模式
-  const displayMode: ImageDisplayMode = imageUrls.length <= 1 ? 'single' : 'multiple';
-
-  // 使用滚动条交互工具函数
-  const {
-    handleScrollbarClick,
-    handleScrollbarDragStart,
-    handleScrollbarDrag,
-    handleScrollbarDragEnd
-  } = createScrollbarInteraction(imageContainerRef, scrollState, setScrollState);
-
-  // 同步滚动条位置函数
-  const syncScrollbarPosition = useCallback(() => {
-    if (imageContainerRef.current) {
-      const scrollLeft = imageContainerRef.current.scrollLeft;
-      const scrollWidth = imageContainerRef.current.scrollWidth - imageContainerRef.current.clientWidth;
-      const scrollPercentage = scrollWidth > 0 ? scrollLeft / scrollWidth : 0;
-
-      setScrollState(prev => ({
-        ...prev,
-        scrollPosition: scrollPercentage
-      }));
-    }
-  }, []);
+  const displayMode: ImageDisplayMode =
+    imageUrls.length === 1 ? 'single' :
+    imageUrls.length === 2 ? 'double' :
+    'multiple';
 
 
   // ESC键关闭弹窗
   // ESC键关闭弹窗
   useEffect(() => {
   useEffect(() => {
@@ -127,26 +43,6 @@ const SupplyChainModal: React.FC<SupplyChainModalProps> = ({
     }
     }
   }, [isOpen, onClose]);
   }, [isOpen, onClose]);
 
 
-  // 监听图片容器滚动事件
-  useEffect(() => {
-    const container = imageContainerRef.current;
-    if (!container) return;
-
-    const handleScroll = () => {
-      syncScrollbarPosition();
-    };
-
-    container.addEventListener('scroll', handleScroll);
-    return () => container.removeEventListener('scroll', handleScroll);
-  }, [syncScrollbarPosition]);
-
-  // 初始化滚动条位置
-  useEffect(() => {
-    if (imageContainerRef.current) {
-      syncScrollbarPosition();
-    }
-  }, [imageUrls, syncScrollbarPosition]);
-
   if (!isOpen) return null;
   if (!isOpen) return null;
 
 
   return (
   return (
@@ -182,66 +78,19 @@ const SupplyChainModal: React.FC<SupplyChainModalProps> = ({
           data-layer="图片展示区域"
           data-layer="图片展示区域"
           className="absolute h-[640px] left-[calc(50%+-0.06px)] rounded-[20px] top-[calc(50%+48.26px)] translate-x-[-50%] translate-y-[-50%] w-[1357px]"
           className="absolute h-[640px] left-[calc(50%+-0.06px)] rounded-[20px] top-[calc(50%+48.26px)] translate-x-[-50%] translate-y-[-50%] w-[1357px]"
         >
         >
-          {/* 单图模式 - 图片居中显示 */}
+          {/* 单图模式 */}
           {displayMode === 'single' && (
           {displayMode === 'single' && (
-            <div className="flex items-center justify-center h-full">
-              <div className="h-[640px] overflow-clip relative rounded-[10px] w-[853px]">
-                <img
-                  data-layer="单图展示"
-                  className="w-full h-full object-cover"
-                  src={imageUrls[0]}
-                  alt={title}
-                />
-              </div>
-            </div>
+            <SingleImageDisplay imageUrl={imageUrls[0]} title={title} />
           )}
           )}
 
 
-          {/* 多图模式 - 横向滚动 */}
-          {displayMode === 'multiple' && (
-            <>
-              <div
-                ref={imageContainerRef}
-                data-layer="多图滚动容器"
-                className="flex overflow-x-auto gap-[20px] h-full items-center"
-                style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }}
-              >
-                {imageUrls.map((url, index) => (
-                  <div
-                    key={index}
-                    data-layer={`图片${index + 1}`}
-                    className="h-[640px] overflow-clip relative rounded-[10px] shrink-0 w-[853px]"
-                  >
-                    <img
-                      data-layer={`${title} ${index + 1}`}
-                      className="w-full h-full object-cover"
-                      src={url}
-                      alt={`${title} ${index + 1}`}
-                    />
-                  </div>
-                ))}
-              </div>
+          {/* 双图模式 */}
+          {displayMode === 'double' && (
+            <DoubleImageDisplay imageUrls={imageUrls} title={title} themeColor={themeColor} />
+          )}
 
 
-              {/* 自定义滚动条 */}
-              <div
-                data-layer="滚动条容器"
-                className="absolute bottom-[-40px] left-1/2 transform -translate-x-1/2 w-[60%] h-[8px] bg-stone-700/30 rounded-[4px] cursor-pointer"
-                onClick={handleScrollbarClick}
-                onMouseDown={handleScrollbarDragStart}
-                onMouseMove={scrollState.isDragging ? handleScrollbarDrag : undefined}
-                onMouseUp={handleScrollbarDragEnd}
-                onMouseLeave={handleScrollbarDragEnd}
-              >
-                <div
-                  data-layer="滚动条滑块"
-                  className="absolute h-full bg-stone-400 rounded-[4px] transition-all duration-200 hover:bg-stone-300 cursor-grab active:cursor-grabbing"
-                  style={{
-                    width: '20%',
-                    left: `${scrollState.scrollPosition * 80}%`,
-                    backgroundColor: themeColor
-                  }}
-                />
-              </div>
-            </>
+          {/* 多图模式 */}
+          {displayMode === 'multiple' && (
+            <MultipleImageDisplay imageUrls={imageUrls} title={title} themeColor={themeColor} />
           )}
           )}
         </div>
         </div>
 
 

+ 3 - 3
src/client/home/pages/SupplyChainDashboards/context/SupplyChainContext.tsx

@@ -198,7 +198,6 @@ const grainOilData: SupplyChainData = {
         industry: '粮食',
         industry: '粮食',
         imageUrls: [
         imageUrls: [
           "/supply-chain/images/康宏公司张湖粮油基地示范片区 1.png",
           "/supply-chain/images/康宏公司张湖粮油基地示范片区 1.png",
-          "/supply-chain/images/省储备粮咸宁库 1.png"
         ],
         ],
         metrics: [
         metrics: [
           { label: '种植面积:', value: '8', unit: '万亩' },
           { label: '种植面积:', value: '8', unit: '万亩' },
@@ -212,8 +211,8 @@ const grainOilData: SupplyChainData = {
         content: '优质小麦种植基地',
         content: '优质小麦种植基地',
         industry: '粮食',
         industry: '粮食',
         imageUrls: [
         imageUrls: [
+          "/supply-chain/images/省储备粮咸宁库 1.png",
           "/supply-chain/images/康宏公司张湖粮油基地示范片区 1.png",
           "/supply-chain/images/康宏公司张湖粮油基地示范片区 1.png",
-          "/supply-chain/images/省储备粮咸宁库 1.png"
         ],
         ],
         metrics: [
         metrics: [
           { label: '种植面积:', value: '6', unit: '万亩' },
           { label: '种植面积:', value: '6', unit: '万亩' },
@@ -228,7 +227,8 @@ const grainOilData: SupplyChainData = {
         industry: '粮食',
         industry: '粮食',
         imageUrls: [
         imageUrls: [
           "/supply-chain/images/康宏公司张湖粮油基地示范片区 1.png",
           "/supply-chain/images/康宏公司张湖粮油基地示范片区 1.png",
-          "/supply-chain/images/省储备粮咸宁库 1.png"
+          "/supply-chain/images/省储备粮咸宁库 1.png",
+          "/supply-chain/images/康宏公司张湖粮油基地示范片区 1.png",
         ],
         ],
         metrics: [
         metrics: [
           { label: '种植面积:', value: '7', unit: '万亩' },
           { label: '种植面积:', value: '7', unit: '万亩' },

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff