From 308e2cc3b78e6f8351e4f3fb0ad1ca191ae0db48 Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期二, 02 六月 2026 17:45:13 +0800
Subject: [PATCH] fix: 更新入库的源单号不显示问题
---
src/views/systemArchitecture/index.vue | 1034 +++++++++++++++++++++-----------------------------------
1 files changed, 393 insertions(+), 641 deletions(-)
diff --git a/src/views/systemArchitecture/index.vue b/src/views/systemArchitecture/index.vue
index c3c6c49..6ed31f6 100644
--- a/src/views/systemArchitecture/index.vue
+++ b/src/views/systemArchitecture/index.vue
@@ -1,658 +1,410 @@
<template>
- <div class="architecture-page">
- <div class="page-header">
- <span class="header-line"></span>
- <h1 class="page-title">绯荤粺鏋舵瀯鍥�</h1>
- </div>
-
- <section ref="canvasRef" class="canvas">
- <svg
- v-if="svgSize.width && svgSize.height"
- class="link-overlay"
- :width="svgSize.width"
- :height="svgSize.height"
- aria-hidden="true"
- >
- <defs>
- <marker
- id="erp-link-arrow"
- markerWidth="10"
- markerHeight="10"
- refX="7"
- refY="4.5"
- orient="auto"
- markerUnits="strokeWidth"
- >
- <path d="M0,0 L0,7 L7,3.5 z" fill="#a7bdda" />
- </marker>
- </defs>
-
- <path
- v-for="path in aiPaths"
- :key="path.key"
- :d="path.d"
- class="link-overlay__path link-overlay__path--ai"
- />
-
- <path
- v-if="flowPath"
- :d="flowPath"
- class="link-overlay__path"
- marker-end="url(#erp-link-arrow)"
- />
- </svg>
-
- <section
- v-for="row in architectureRows"
- :key="row.key"
- class="lane"
- >
- <aside class="lane__aside">
- <div class="lane__aside-card" :class="`lane__aside-card--${row.key}`">
- <div class="lane__aside-icon">
- <svg-icon :icon-class="row.icon" class="lane__icon" />
- </div>
- <div class="lane__aside-content">
- <h2>{{ row.label }}</h2>
+ <div class="scale-container">
+ <div class="scroll-content"
+ :style="{
+ height: `${designHeight * scaleRatio}px`,
+ width: `${designWidth * scaleRatio}px`
+ }">
+ <div class="architecture-scaling-container"
+ :style="{ transform: `scale(${scaleRatio})` }">
+ <div class="architecture-container">
+ <div class="header">
+ <span class="title-bar"></span>
+ <h1 class="title-text">绯荤粺鏋舵瀯鍥�</h1>
+ </div>
+ <div class="image-wrapper">
+ <div class="hotspot-container">
+ <img :src="architectureImg"
+ alt="绯荤粺鏋舵瀯鍥�"
+ class="architecture-img" />
+ <!-- 鐑偣鍖哄煙 -->
+ <div v-for="spot in hotspots"
+ :key="spot.id"
+ class="hotspot"
+ :style="{ top: spot.top, left: spot.left, width: spot.width, height: spot.height }"
+ @click="handleSpotClick(spot)"
+ :title="'璺宠浆鑷�: ' + spot.name">
+ </div>
</div>
</div>
- </aside>
-
- <div class="lane__flow" :class="`lane__flow--${row.key}`">
- <template v-for="(item, index) in row.items" :key="item.name">
- <div
- class="node-wrap"
- :class="{ 'node-wrap--spacer': item.spacer }"
- >
- <template v-if="item.isCore">
- <article ref="coreRef" class="ai-core">
- <div class="ai-core__halo"></div>
- <div class="ai-core__brain">
- <img :src="aiHead" alt="AI 鏍稿績" class="ai-core__head-image" />
- </div>
- </article>
- </template>
-
- <template v-else>
- <article
- class="node"
- :class="{ 'node--accent': item.accent, 'node--small-gap': item.compact }"
- :ref="setNodeRef(item)"
- >
- <div class="node__icon-wrapper">
- <svg-icon :icon-class="item.icon" class="node__icon" />
- </div>
- <h3>{{ item.name }}</h3>
- </article>
- </template>
-
- <span
- v-if="index < row.items.length - 1"
- class="flow-arrow"
- :class="{ 'flow-arrow--hidden': item.hideArrowAfter }"
- ></span>
- </div>
- </template>
</div>
- </section>
- </section>
+ </div>
+ </div>
</div>
</template>
<script setup>
-import { nextTick, onBeforeUnmount, onMounted, onUpdated, ref } from 'vue'
-import aiHead from '@/assets/images/head.svg'
+ import { ref, onMounted, onBeforeUnmount, nextTick } from "vue";
+ import { useRouter } from "vue-router";
+ import architectureImg from "@/assets/images/xitongjiagou.svg";
-const architectureRows = [
- {
- key: 'basic',
- label: '鍩虹閰嶇疆',
- description: '绯荤粺鍩虹淇℃伅绠$悊',
- icon: 'system',
- items: [
- { name: '瑙掕壊鐢ㄦ埛绠$悊', icon: 'user' },
- { name: '浜у搧缁存姢', icon: 'monitor' },
- { name: '瀹℃壒绠$悊', icon: 'tree', accent: true }
- ]
- },
- {
- key: 'sale',
- label: '閿�鍞厤缃�',
- description: '瀹㈡埛涓庨攢鍞鐞�',
- icon: 'chart',
- items: [
- { name: '瀹㈡埛妗f', icon: 'peoples' },
- { name: '閿�鍞姤浠�', icon: 'form' },
- { name: '閿�鍞姤浠�', icon: 'chart' },
- { name: '閿�鍞彴璐�', icon: 'table' },
- { name: '鍙戣揣鍙拌处', icon: 'clipboard', accent: true, linkSource: true, aiLink: true },
- { name: '閿�鍞��璐�', icon: 'nested', accent: true, aiLink: true },
- { name: '瀹㈡埛寰�鏉�', icon: 'money' },
- { name: '鎸囨爣缁熻', icon: 'pie-chart' }
- ]
- },
- {
- key: 'purchase',
- label: '閲囪喘閰嶇疆',
- description: '閲囪喘涓庝緵搴斿晢绠$悊',
- icon: 'shopping',
- items: [
- { name: '渚涘簲鍟嗘。妗�', icon: 'people' },
- { name: '閲囪喘鍙拌处', icon: 'table' },
- { name: '閲囪喘閫�璐�', icon: 'nested', accent: true, aiLink: true },
- { isCore: true, hideArrowAfter: true },
- { name: '渚涘簲鍟嗗線鏉�', icon: 'money' },
- { name: '閲囪喘鎶ヨ〃', icon: 'chart' }
- ]
- },
- {
- key: 'produce',
- label: '鐢熶骇閰嶇疆',
- description: '鐢熶骇杩囩▼绠$悊',
- icon: 'build',
- items: [
- { name: '宸ュ簭', icon: 'tree' },
- { name: 'BOM', icon: 'list' },
- { name: '宸ヨ壓璺嚎', icon: 'guide', accent: true },
- { name: '鐢熶骇璁㈠崟', icon: 'peoples', aiLink: true },
- { name: '鐢熶骇鎺掍骇', icon: 'date' },
- { name: '鐢熶骇鎶ュ伐', icon: 'edit' },
- { name: '鎶ュ伐鍙拌处', icon: 'clipboard' },
- { name: '鐢熶骇鏍哥畻', icon: 'money', accent: true }
- ]
- },
- {
- key: 'store',
- label: '浠撳偍鐗╂祦',
- description: '搴撳瓨涓庡嚭鍏ュ簱绠$悊',
- icon: 'redis',
- items: [
- { name: '鍏ュ簱绠$悊', icon: 'download' },
- { name: '鍑哄簱绠$悊', icon: 'upload', linkTarget: true },
- { name: '搴撳瓨绠$悊', icon: 'redis-list' }
- ]
+ const router = useRouter();
+
+ // 鐑偣鍖哄煙瀹氫箟
+ const hotspots = ref([
+ {
+ id: 1,
+ name: "瑙掕壊绠$悊",
+ top: "3%",
+ left: "19%",
+ width: "9%",
+ height: "11%",
+ path: "/system/role",
+ },
+ {
+ id: 2,
+ name: "鑱屼笟绠$悊",
+ top: "1.6%",
+ left: "36.5%",
+ width: "9%",
+ height: "11%",
+ path: "/system/user",
+ },
+ {
+ id: 3,
+ name: "宀椾綅绠$悊",
+ top: "1.6%",
+ left: "56%",
+ width: "9%",
+ height: "11%",
+ path: "/system/post",
+ },
+ {
+ id: 4,
+ name: "閮ㄩ棬绠$悊",
+ top: "3%",
+ left: "73%",
+ width: "9%",
+ height: "11%",
+ path: "/system/dept",
+ },
+ {
+ id: 5,
+ name: "瀹㈡埛妗f",
+ top: "42%",
+ left: "17%",
+ width: "9%",
+ height: "3%",
+ path: "/salesManagement/customerFileOpenSea",
+ },
+ {
+ id: 6,
+ name: "閿�鍞姤浠�",
+ top: "46%",
+ left: "17%",
+ width: "9%",
+ height: "3%",
+ path: "/salesManagement/salesQuotation",
+ },
+ {
+ id: 7,
+ name: "閿�鍞彴璐�",
+ top: "51%",
+ left: "17%",
+ width: "9%",
+ height: "3%",
+ path: "/salesManagement/salesLedger",
+ },
+ {
+ id: 8,
+ name: "鍙戣揣鍙拌处",
+ top: "55%",
+ left: "17%",
+ width: "9%",
+ height: "3%",
+ path: "/salesManagement/deliveryLedger",
+ },
+ {
+ id: 9,
+ name: "閿�鍞��璐�",
+ top: "59%",
+ left: "17%",
+ width: "9%",
+ height: "3%",
+ path: "/salesManagement/returnOrder",
+ },
+ {
+ id: 10,
+ name: "渚涘簲鍟嗘。妗�",
+ top: "42%",
+ left: "75%",
+ width: "9%",
+ height: "3%",
+ path: "/salesManagement/customerFileOpenSea",
+ },
+ {
+ id: 11,
+ name: "閲囪喘鍙拌处",
+ top: "47%",
+ left: "75%",
+ width: "9%",
+ height: "3%",
+ path: "/procurementManagement/procurementLedger",
+ },
+ {
+ id: 12,
+ name: "閲囪喘閫�璐�",
+ top: "51%",
+ left: "75%",
+ width: "9%",
+ height: "3%",
+ path: "/procurementManagement/purchaseReturnOrder",
+ },
+ {
+ id: 13,
+ name: "渚涘簲鍟嗗線鏉�",
+ top: "56%",
+ left: "75%",
+ width: "9%",
+ height: "3%",
+ path: "/procurementManagement/paymentLedger",
+ },
+ {
+ id: 14,
+ name: "閲囪喘鎶ヨ〃",
+ top: "60%",
+ left: "75%",
+ width: "9%",
+ height: "3%",
+ path: "/procurementManagement/procurementReport",
+ },
+ {
+ id: 15,
+ name: "鐢熶骇鎺掍骇",
+ top: "77%",
+ left: "19%",
+ width: "15%",
+ height: "3%",
+ path: "/productionManagement/productionManagement/workOrderEdit/index",
+ },
+ {
+ id: 16,
+ name: "鐢熶骇璁㈠崟",
+ top: "76%",
+ left: "43%",
+ width: "15%",
+ height: "3%",
+ path: "/productionManagement/productionOrder",
+ },
+ {
+ id: 17,
+ name: "bom",
+ top: "77%",
+ left: "70%",
+ width: "15%",
+ height: "3%",
+ path: "/processDesign/productionManagement/productStructure/index",
+ },
+ {
+ id: 18,
+ name: "鐢熶骇璁㈠崟",
+ top: "82%",
+ left: "32%",
+ width: "15%",
+ height: "3%",
+ path: "/productionManagement/productionOrder",
+ },
+ {
+ id: 19,
+ name: "宸ヨ壓璺嚎",
+ top: "82%",
+ left: "57%",
+ width: "15%",
+ height: "3%",
+ path: "/processDesign/processRoute",
+ },
+ {
+ id: 20,
+ name: "宸ュ簭",
+ top: "87%",
+ left: "17%",
+ width: "9%",
+ height: "4%",
+ path: "/processDesign/productionManagement/productionProcess/index",
+ },
+ {
+ id: 21,
+ name: "鐢熶骇鎶ュ伐",
+ top: "89%",
+ left: "32%",
+ width: "17%",
+ height: "4%",
+ path: "/productionManagement/workOrderManagement",
+ },
+ {
+ id: 22,
+ name: "鐢熶骇鏍哥畻",
+ top: "89%",
+ left: "56%",
+ width: "19%",
+ height: "4%",
+ path: "/productionManagement/productionCosting",
+ },
+ ]);
+
+ const handleSpotClick = spot => {
+ if (spot.path) {
+ router.push(spot.path);
+ }
+ };
+
+ // 缂╂斁姣斾緥
+ const scaleRatio = ref(1);
+ // 璁捐灏哄锛堝熀鍑嗗昂瀵革級
+ const designWidth = 1920;
+ const designHeight = 980;
+
+ // 璁$畻缂╂斁姣斾緥
+ const calculateScale = () => {
+ const container = document.querySelector(".scale-container");
+ if (!container) return;
+
+ // 鑾峰彇瀹瑰櫒鐨勫疄闄呭昂瀵�
+ const containerWidth = container.clientWidth;
+ const containerHeight = container.clientHeight;
+
+ if (containerWidth === 0 || containerHeight === 0) {
+ // 濡傛灉杩樻病娓叉煋鍑烘潵锛屽欢杩熶竴涓嬪啀璁$畻
+ setTimeout(calculateScale, 100);
+ return;
+ }
+
+ // 璁$畻缂╂斁姣斾緥锛屽彇瀹介珮姣斾緥涓殑杈冨ぇ鍊硷紝纭繚濮嬬粓鎾戞弧鏁翠釜瀹瑰櫒
+ const scaleX = containerWidth / designWidth;
+ const scaleY = containerHeight / designHeight;
+ scaleRatio.value = Math.max(scaleX, scaleY);
+ };
+
+ // 绐楀彛澶у皬鍙樺寲澶勭悊
+ const handleResize = () => {
+ calculateScale();
+ };
+
+ // 鐢熷懡鍛ㄦ湡
+ let resizeObserver = null;
+ onMounted(() => {
+ // 璁$畻鍒濆缂╂斁姣斾緥
+ nextTick(() => {
+ calculateScale();
+ });
+
+ // 鐩戝惉绐楀彛澶у皬鍙樺寲
+ window.addEventListener("resize", handleResize);
+
+ // 浣跨敤 ResizeObserver 鐩戝惉瀹瑰櫒灏哄鍙樺寲锛堣В鍐充晶杈规爮鍒囨崲闂锛�
+ const container = document.querySelector(".scale-container");
+ if (container && window.ResizeObserver) {
+ resizeObserver = new ResizeObserver(() => {
+ calculateScale();
+ });
+ resizeObserver.observe(container);
+ }
+ });
+
+ onBeforeUnmount(() => {
+ window.removeEventListener("resize", handleResize);
+ if (resizeObserver) {
+ resizeObserver.disconnect();
+ }
+ });
+</script>
+
+<style scoped lang="scss">
+ .scale-container {
+ position: relative;
+ width: 100%;
+ height: calc(100vh - 84px);
+ background-color: #f5f7fa;
+ overflow: auto;
+ display: flex;
+ justify-content: center;
+ align-items: flex-start;
}
-]
-const canvasRef = ref(null)
-const coreRef = ref(null)
-const sourceNodeRef = ref(null)
-const targetNodeRef = ref(null)
-const svgSize = ref({ width: 0, height: 0 })
-const flowPath = ref('')
-const aiPaths = ref([])
-const aiNodeRefs = []
-let resizeObserver = null
+ .scroll-content {
+ position: relative;
+ flex-shrink: 0;
+ }
-function setNodeRef(item) {
- return (el) => {
- if (item.linkSource) sourceNodeRef.value = el
- if (item.linkTarget) targetNodeRef.value = el
+ .architecture-scaling-container {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 1920px;
+ height: 980px;
+ transform-origin: left top;
+ background-color: #f5f7fa;
+ transition: transform 0.3s;
+ }
- if (item.aiLink) {
- if (el && !aiNodeRefs.some((entry) => entry.key === item.name && entry.el === el)) {
- aiNodeRefs.push({ key: item.name, el })
+ .architecture-container {
+ padding: 20px;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+
+ .header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+ padding: 10px 20px;
+ background: #fff;
+ border-radius: 8px;
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
+
+ .title-bar {
+ width: 4px;
+ height: 20px;
+ background-color: #409eff;
+ margin-right: 12px;
+ border-radius: 2px;
+ }
+
+ .title-text {
+ margin: 0;
+ font-size: 20px;
+ font-weight: 600;
+ color: #303133;
+ }
+ }
+
+ .image-wrapper {
+ flex: 1;
+ background: #fff;
+ border-radius: 8px;
+ padding: 20px 40px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ overflow: hidden;
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
+
+ .hotspot-container {
+ position: relative;
+ display: inline-block;
+ max-width: 100%;
+ max-height: 100%;
+
+ .architecture-img {
+ display: block;
+ max-width: 100%;
+ max-height: 100%;
+ object-fit: contain;
+ }
+
+ .hotspot {
+ position: absolute;
+ cursor: pointer;
+ background: rgba(64, 158, 255, 0);
+ transition: background 0.3s;
+ border-radius: 4px;
+
+ // &:hover {
+ // background: rgba(64, 158, 255, 0.15);
+ // box-shadow: 0 0 10px rgba(64, 158, 255, 0.3);
+ // }
+ }
}
}
}
-}
-
-function resetLines() {
- flowPath.value = ''
- aiPaths.value = []
-}
-
-function getCenter(rect) {
- return {
- x: rect.left + rect.width / 2,
- y: rect.top + rect.height / 2
- }
-}
-
-function getEdgePoint(sourceRect, targetRect) {
- const sourceCenter = getCenter(sourceRect)
- const targetCenter = getCenter(targetRect)
- const deltaX = targetCenter.x - sourceCenter.x
- const deltaY = targetCenter.y - sourceCenter.y
-
- if (Math.abs(deltaX) > Math.abs(deltaY)) {
- return {
- x: deltaX > 0 ? sourceRect.right : sourceRect.left,
- y: sourceCenter.y
- }
- }
-
- return {
- x: sourceCenter.x,
- y: deltaY > 0 ? sourceRect.bottom : sourceRect.top
- }
-}
-
-function updateLinkLines() {
- if (!canvasRef.value) {
- resetLines()
- return
- }
-
- svgSize.value = {
- width: Math.ceil(canvasRef.value.scrollWidth),
- height: Math.ceil(canvasRef.value.scrollHeight)
- }
-
- if (window.innerWidth <= 1200 || !coreRef.value) {
- resetLines()
- return
- }
-
- const canvasRect = canvasRef.value.getBoundingClientRect()
- const coreRect = coreRef.value.getBoundingClientRect()
- const validAiNodes = aiNodeRefs.filter((entry) => entry.el?.isConnected)
-
- aiPaths.value = validAiNodes.map((entry) => {
- const nodeRect = entry.el.getBoundingClientRect()
- const corePoint = getEdgePoint(coreRect, nodeRect)
- const nodePoint = getEdgePoint(nodeRect, coreRect)
- const startX = nodePoint.x - canvasRect.left
- const startY = nodePoint.y - canvasRect.top
- const endX = corePoint.x - canvasRect.left
- const endY = corePoint.y - canvasRect.top
- const controlY = startY < endY ? startY + (endY - startY) * 0.45 : startY - (startY - endY) * 0.45
- const controlX = (startX + endX) / 2
-
- return {
- key: entry.key,
- d: `M ${startX} ${startY} C ${controlX} ${controlY}, ${controlX} ${controlY}, ${endX} ${endY}`
- }
- })
-
- if (!sourceNodeRef.value || !targetNodeRef.value) {
- flowPath.value = ''
- return
- }
-
- const sourceRect = sourceNodeRef.value.getBoundingClientRect()
- const targetRect = targetNodeRef.value.getBoundingClientRect()
- const startX = sourceRect.left + sourceRect.width / 2 - canvasRect.left
- const startY = sourceRect.bottom - canvasRect.top + 2
- const endX = targetRect.left + targetRect.width / 2 - canvasRect.left
- const endY = targetRect.top - canvasRect.top - 4
- const middleY = startY + (endY - startY) / 2
-
- flowPath.value = `M ${startX} ${startY} C ${startX} ${middleY}, ${endX} ${middleY}, ${endX} ${endY}`
-}
-
-function handleResize() {
- requestAnimationFrame(() => {
- requestAnimationFrame(updateLinkLines)
- })
-}
-
-onMounted(async () => {
- await nextTick()
- handleResize()
- window.addEventListener('resize', handleResize)
- if (window.ResizeObserver && canvasRef.value) {
- resizeObserver = new ResizeObserver(handleResize)
- resizeObserver.observe(canvasRef.value)
- }
-})
-
-onUpdated(() => {
- nextTick(handleResize)
-})
-
-onBeforeUnmount(() => {
- window.removeEventListener('resize', handleResize)
- if (resizeObserver) resizeObserver.disconnect()
-})
-</script>
-
-<style scoped>
-.architecture-page {
- min-height: calc(100vh - 84px);
- padding: 24px;
- background: #f0f4fb;
-}
-
-.page-header {
- display: flex;
- align-items: center;
- gap: 12px;
- margin-bottom: 24px;
-}
-
-.header-line {
- width: 4px;
- height: 20px;
- background: #2563eb;
- border-radius: 2px;
-}
-
-.page-title {
- margin: 0;
- font-size: 18px;
- font-weight: 700;
- color: #1f2937;
-}
-
-.canvas {
- position: relative;
- display: flex;
- flex-direction: column;
- gap: 20px;
- padding: 28px 24px;
- background: #fff;
- border: 1px solid rgba(219, 234, 254, 0.9);
- border-radius: 18px;
- box-shadow: 0 10px 30px rgba(30, 64, 175, 0.06);
-}
-
-.lane {
- display: grid;
- grid-template-columns: 190px 1fr;
- gap: 18px;
- align-items: stretch;
-}
-
-.lane__aside-card {
- height: 100%;
- min-height: 138px;
- padding: 22px 20px;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- gap: 14px;
- background: linear-gradient(180deg, #f8fbff 0%, #eef5ff 100%);
- border: 1px solid rgba(219, 234, 254, 0.95);
- border-radius: 18px;
- box-shadow: inset 0 1px 8px rgba(255, 255, 255, 0.9);
-}
-
-.lane__aside-card--sale .lane__aside-icon {
- background: linear-gradient(180deg, #f3e8ff 0%, #e9d5ff 100%);
- color: #9333ea;
-}
-
-.lane__aside-card--purchase .lane__aside-icon {
- background: linear-gradient(180deg, #e0f2fe 0%, #bae6fd 100%);
- color: #0284c7;
-}
-
-.lane__aside-card--produce .lane__aside-icon {
- background: linear-gradient(180deg, #ecfdf5 0%, #d1fae5 100%);
- color: #16a34a;
-}
-
-.lane__aside-card--store .lane__aside-icon {
- background: linear-gradient(180deg, #eef2ff 0%, #dbeafe 100%);
- color: #2563eb;
-}
-
-.lane__aside-icon {
- width: 44px;
- height: 44px;
- flex-shrink: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 14px;
- background: linear-gradient(180deg, #e0ecff 0%, #dbeafe 100%);
- color: #2563eb;
- box-shadow: 0 8px 18px rgba(37, 99, 235, 0.12);
-}
-
-.lane__icon {
- font-size: 24px;
-}
-
-.lane__aside-content h2 {
- margin: 0;
- font-size: 18px;
- font-weight: 700;
- color: #1d4ed8;
- line-height: 1.2;
- text-align: center;
-}
-
-.lane__aside-content p {
- margin: 0;
- font-size: 13px;
- color: #7c8aa5;
-}
-
-.lane__flow {
- position: relative;
- z-index: 2;
- display: flex;
- align-items: center;
- gap: 12px;
- min-height: 138px;
- padding: 18px 22px;
- background: linear-gradient(180deg, #ffffff 0%, #fbfdff 100%);
- border: 1px solid rgba(219, 234, 254, 0.9);
- border-radius: 18px;
- box-shadow: inset 0 1px 10px rgba(255, 255, 255, 0.92);
-}
-
-.lane__flow--purchase,
-.lane__flow--produce {
- padding-left: 28px;
- padding-right: 28px;
-}
-
-.node-wrap {
- display: flex;
- align-items: center;
- gap: 12px;
- flex-shrink: 0;
-}
-
-.node {
- width: 96px;
- min-height: 86px;
- padding: 8px 6px;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- gap: 8px;
- background: transparent;
-}
-
-.node__icon-wrapper {
- width: 58px;
- height: 58px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 16px;
- background: linear-gradient(180deg, #ffffff 0%, #f2f7ff 100%);
- border: 1px solid rgba(191, 219, 254, 0.95);
- box-shadow:
- 0 8px 18px rgba(37, 99, 235, 0.08),
- inset 0 1px 8px rgba(255, 255, 255, 0.95);
-}
-
-.node__icon {
- font-size: 26px;
- color: #2563eb;
-}
-
-.node--accent .node__icon-wrapper {
- background: linear-gradient(180deg, #ffffff 0%, #eef4ff 100%);
-}
-
-.node h3 {
- margin: 0;
- font-size: 12px;
- line-height: 1.35;
- font-weight: 600;
- color: #334155;
- text-align: center;
-}
-
-.flow-arrow {
- width: 36px;
- height: 1px;
- position: relative;
- background: repeating-linear-gradient(
- to right,
- #bfd7ff 0,
- #bfd7ff 4px,
- transparent 4px,
- transparent 8px
- );
-}
-
-.flow-arrow::after {
- content: '';
- position: absolute;
- top: 50%;
- right: -1px;
- width: 6px;
- height: 6px;
- border-top: 1px solid #9ec5ff;
- border-right: 1px solid #9ec5ff;
- transform: translateY(-50%) rotate(45deg);
-}
-
-.flow-arrow--hidden {
- visibility: hidden;
-}
-
-.ai-core {
- position: relative;
- width: 252px;
- height: 176px;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.ai-core__halo {
- position: absolute;
- inset: 14px 28px 32px;
- border-radius: 50%;
- background: radial-gradient(circle, rgba(96, 165, 250, 0.12) 0%, rgba(96, 165, 250, 0) 72%);
- transform: scale(1.08);
-}
-
-.ai-core__brain {
- position: absolute;
- inset: 6px 0 0;
- left: 50%;
- width: 232px;
- height: 156px;
- transform: translateX(-50%);
- display: flex;
- align-items: center;
- justify-content: center;
- filter: drop-shadow(0 10px 18px rgba(96, 165, 250, 0.18));
-}
-
-.ai-core__head-image {
- width: 100%;
- height: 100%;
- object-fit: contain;
-}
-
-.link-overlay {
- position: absolute;
- inset: 0;
- z-index: 3;
- pointer-events: none;
-}
-
-.link-overlay__path {
- fill: none;
- stroke: #bfd2ea;
- stroke-width: 1.2;
- stroke-dasharray: 4 5;
- stroke-linecap: round;
- stroke-linejoin: round;
-}
-
-.link-overlay__path--ai {
- stroke: #bfd7ff;
- stroke-width: 1.4;
-}
-
-@media (max-width: 1200px) {
- .architecture-page {
- padding: 16px;
- }
-
- .lane {
- grid-template-columns: 1fr;
- }
-
- .lane__aside-card,
- .lane__flow {
- min-height: auto;
- }
-
- .lane__flow {
- flex-wrap: wrap;
- }
-
- .ai-core {
- order: 99;
- width: 100%;
- max-width: 268px;
- margin: 0 auto;
- }
-
- .link-overlay {
- display: none;
- }
-}
-
-@media (max-width: 768px) {
- .canvas {
- padding: 16px;
- gap: 16px;
- }
-
- .lane__aside-card {
- min-height: auto;
- padding: 18px 16px;
- }
-
- .lane__flow {
- padding: 16px;
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(88px, 1fr));
- gap: 12px;
- }
-
- .node-wrap {
- flex-direction: column;
- gap: 8px;
- }
-
- .node {
- width: 100%;
- }
-
- .flow-arrow {
- width: 1px;
- height: 16px;
- margin: 0 auto;
- background: repeating-linear-gradient(
- to bottom,
- #bfd7ff 0,
- #bfd7ff 4px,
- transparent 4px,
- transparent 8px
- );
- }
-
- .flow-arrow::after {
- top: auto;
- right: 50%;
- bottom: -1px;
- transform: translateX(50%) rotate(135deg);
- }
-}
</style>
--
Gitblit v1.9.3