调整样式

This commit is contained in:
yumaojun03 2025-08-09 22:23:24 +08:00
parent cfef51c6d1
commit 531888be09
8 changed files with 787 additions and 57 deletions

View File

@ -21,6 +21,7 @@
"eslint": "^9.31.0", "eslint": "^9.31.0",
"eslint-plugin-vue": "~10.3.0", "eslint-plugin-vue": "~10.3.0",
"globals": "^16.3.0", "globals": "^16.3.0",
"less": "^4.4.0",
"prettier": "3.6.2", "prettier": "3.6.2",
"vite": "^7.0.6", "vite": "^7.0.6",
"vite-plugin-vue-devtools": "^8.0.0" "vite-plugin-vue-devtools": "^8.0.0"
@ -2406,6 +2407,20 @@
"url": "https://github.com/fb55/entities?sponsor=1" "url": "https://github.com/fb55/entities?sponsor=1"
} }
}, },
"node_modules/errno": {
"version": "0.1.8",
"resolved": "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz",
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"prr": "~1.0.1"
},
"bin": {
"errno": "cli.js"
}
},
"node_modules/error-stack-parser-es": { "node_modules/error-stack-parser-es": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmmirror.com/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", "resolved": "https://registry.npmmirror.com/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz",
@ -3061,6 +3076,14 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true,
"license": "ISC",
"optional": true
},
"node_modules/has-flag": { "node_modules/has-flag": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz",
@ -3127,6 +3150,20 @@
"node": ">=18.18.0" "node": ">=18.18.0"
} }
}, },
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz",
@ -3137,6 +3174,20 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/image-size": {
"version": "0.5.5",
"resolved": "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz",
"integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==",
"dev": true,
"license": "MIT",
"optional": true,
"bin": {
"image-size": "bin/image-size.js"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/import-fresh": { "node_modules/import-fresh": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.1.tgz", "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.1.tgz",
@ -3388,6 +3439,53 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/less": {
"version": "4.4.0",
"resolved": "https://registry.npmmirror.com/less/-/less-4.4.0.tgz",
"integrity": "sha512-kdTwsyRuncDfjEs0DlRILWNvxhDG/Zij4YLO4TMJgDLW+8OzpfkdPnRgrsRuY1o+oaxJGWsps5f/RVBgGmmN0w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"copy-anything": "^2.0.1",
"parse-node-version": "^1.0.1",
"tslib": "^2.3.0"
},
"bin": {
"lessc": "bin/lessc"
},
"engines": {
"node": ">=14"
},
"optionalDependencies": {
"errno": "^0.1.1",
"graceful-fs": "^4.1.2",
"image-size": "~0.5.0",
"make-dir": "^2.1.0",
"mime": "^1.4.1",
"needle": "^3.1.0",
"source-map": "~0.6.0"
}
},
"node_modules/less/node_modules/copy-anything": {
"version": "2.0.6",
"resolved": "https://registry.npmmirror.com/copy-anything/-/copy-anything-2.0.6.tgz",
"integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-what": "^3.14.1"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/less/node_modules/is-what": {
"version": "3.14.1",
"resolved": "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz",
"integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==",
"dev": true,
"license": "MIT"
},
"node_modules/levn": { "node_modules/levn": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz", "resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz",
@ -3444,6 +3542,32 @@
"@jridgewell/sourcemap-codec": "^1.5.0" "@jridgewell/sourcemap-codec": "^1.5.0"
} }
}, },
"node_modules/make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz",
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"pify": "^4.0.1",
"semver": "^5.6.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"license": "ISC",
"optional": true,
"bin": {
"semver": "bin/semver"
}
},
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -3453,6 +3577,20 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true,
"license": "MIT",
"optional": true,
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
@ -3536,6 +3674,24 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/needle": {
"version": "3.3.1",
"resolved": "https://registry.npmmirror.com/needle/-/needle-3.3.1.tgz",
"integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"iconv-lite": "^0.6.3",
"sax": "^1.2.4"
},
"bin": {
"needle": "bin/needle"
},
"engines": {
"node": ">= 4.4.x"
}
},
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.19", "version": "2.0.19",
"resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz", "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz",
@ -3695,6 +3851,16 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/parse-node-version": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz",
"integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/path-exists": { "node_modules/path-exists": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz",
@ -3748,6 +3914,17 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/pify": {
"version": "4.0.1",
"resolved": "https://registry.npmmirror.com/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true,
"license": "MIT",
"optional": true,
"engines": {
"node": ">=6"
}
},
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.5.6", "version": "8.5.6",
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz", "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz",
@ -3851,6 +4028,14 @@
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/prr": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz",
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
"dev": true,
"license": "MIT",
"optional": true
},
"node_modules/punycode": { "node_modules/punycode": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz",
@ -3938,6 +4123,22 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"license": "MIT",
"optional": true
},
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
"dev": true,
"license": "ISC",
"optional": true
},
"node_modules/scroll-into-view-if-needed": { "node_modules/scroll-into-view-if-needed": {
"version": "2.2.31", "version": "2.2.31",
"resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz", "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
@ -4022,6 +4223,17 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"optional": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
@ -4136,6 +4348,13 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
"license": "0BSD"
},
"node_modules/type-check": { "node_modules/type-check": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz",

View File

@ -27,6 +27,7 @@
"eslint": "^9.31.0", "eslint": "^9.31.0",
"eslint-plugin-vue": "~10.3.0", "eslint-plugin-vue": "~10.3.0",
"globals": "^16.3.0", "globals": "^16.3.0",
"less": "^4.4.0",
"prettier": "3.6.2", "prettier": "3.6.2",
"vite": "^7.0.6", "vite": "^7.0.6",
"vite-plugin-vue-devtools": "^8.0.0" "vite-plugin-vue-devtools": "^8.0.0"

View File

@ -0,0 +1,10 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- 方框 -->
<rect x="4" y="4" width="16" height="16" rx="2" stroke="#165DFF" stroke-width="1.5" fill="none"/>
<!-- 终端提示符 > -->
<path d="M8 12L11 9V15L8 12Z" fill="#12D2AC"/>
<!-- 下划线光标 _ -->
<rect x="13" y="14" width="6" height="1.5" fill="#0057FE"/>
</svg>

After

Width:  |  Height:  |  Size: 395 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 120" preserveAspectRatio="none">
<path d="M0,0V46.29c47.79,22.2,103.59,32.17,158,28,70.36-5.37,136.33-33.31,206.8-37.5C438.64,32.43,512.34,53.67,583,72.05c69.27,18,138.3,24.88,209.4,13.08,36.15-6,69.85-17.84,104.45-29.34C989.49,25,1113-14.29,1200,52.47V0Z" opacity=".25" fill="#1890ff"></path>
<path d="M0,0V15.81C13,36.92,27.64,56.86,47.69,72.05,99.41,111.27,165,111,224.58,91.58c31.15-10.15,60.09-26.07,89.67-39.8,40.92-19,84.73-46,130.83-49.67,36.26-2.85,70.9,9.42,98.6,31.56,31.77,25.39,62.32,62,103.63,73,40.44,10.79,81.35-6.69,119.13-24.28s75.16-39,116.92-43.05c59.73-5.85,113.28,22.88,168.9,38.84,30.2,8.66,59,6.17,87.09-7.5,22.43-10.89,48-26.93,60.65-49.24V0Z" opacity=".5" fill="#1890ff"></path>
<path d="M0,0V5.63C149.93,59,314.09,71.32,475.83,42.57c43-7.64,84.23-20.12,127.61-26.46,59-8.63,112.48,12.24,165.56,35.4C827.93,77.22,886,95.24,951.2,90c86.53-7,172.46-45.71,248.8-84.81V0Z" fill="#1890ff"></path>
</svg>

After

Width:  |  Height:  |  Size: 988 B

View File

@ -1,11 +1,366 @@
<template> <template>
<div> <div class="layout-container">
后台布局页面 <!-- 背景装饰元素 -->
<div class="decoration-circle circle-1"></div>
<div class="decoration-circle circle-2"></div>
<div class="decoration-wave"></div>
<!-- 固定顶部导航栏 -->
<div class="fixed-header">
<div class="header-content">
<div class="logo-section">
<h1 class="platform-name">研发交付平台</h1>
</div>
<div class="main-nav-section">
<a-menu mode="horizontal" :default-selected-keys="['1']">
<a-menu-item key="1">工作台</a-menu-item>
<a-menu-item key="2">项目管理</a-menu-item>
<a-menu-item key="3">研发交付</a-menu-item>
<a-menu-item key="4">制品库</a-menu-item>
<a-menu-item key="5">测试中心</a-menu-item>
<a-menu-item key="6">运维中心</a-menu-item>
</a-menu>
</div>
<div class="user-section">
<a-dropdown position="bottom">
<a-avatar :size="32" class="user-avatar">
<icon-user />
</a-avatar>
<template #content>
<a-doption>个人中心</a-doption>
<a-doption>系统设置</a-doption>
<a-doption>退出登录</a-doption>
</template>
</a-dropdown>
</div>
</div>
</div>
<!-- 主内容区 -->
<div class="main-content-wrapper">
<!-- 可收缩侧边栏 -->
<div class="fixed-sidebar" :class="{ 'collapsed': isSidebarCollapsed }">
<!-- 使用原生a-menu确保折叠效果 -->
<a-menu :theme="light" :default-selected-keys="['1']" :collapsed="isSidebarCollapsed" :collapsed-width="64"
:style="{ width: '100%', height: '100%' }">
<a-menu-item key="1">
<template #icon><icon-dashboard /></template>
<span class="menu-title">流水线列表</span>
</a-menu-item>
<a-menu-item key="2">
<template #icon><icon-branch /></template>
<span class="menu-title">分支管理</span>
</a-menu-item>
<a-menu-item key="3">
<template #icon><icon-history /></template>
<span class="menu-title">执行历史</span>
</a-menu-item>
<a-menu-item key="4">
<template #icon><icon-settings /></template>
<span class="menu-title">流水线模板</span>
</a-menu-item>
<a-menu-item key="5">
<template #icon><icon-monitor /></template>
<span class="menu-title">监控中心</span>
</a-menu-item>
</a-menu>
<!-- 自定义收缩按钮 -->
<div class="collapse-btn-wrapper">
<a-button class="collapse-btn" @click="toggleSidebar">
<template #icon>
<icon-left v-if="!isSidebarCollapsed" />
<icon-right v-else />
</template>
</a-button>
</div>
</div>
<!-- 内容滚动区域关键修改 -->
<div class="scrollable-content" :class="{ 'expanded': isSidebarCollapsed }">
<div class="content-scroll-wrapper">
<!-- 面包屑会随内容滚动 -->
<div class="breadcrumb">
<a-breadcrumb>
<a-breadcrumb-item>首页</a-breadcrumb-item>
<a-breadcrumb-item>流水线系统</a-breadcrumb-item>
<a-breadcrumb-item>流水线列表</a-breadcrumb-item>
</a-breadcrumb>
</div>
<!-- 主内容区 -->
<main class="router-view-wrapper">
<router-view />
</main>
<!-- 页脚会随内容滚动 -->
<footer class="layout-footer">
<p>© 2025 研发交付平台 · 让软件交付更高效</p>
</footer>
</div>
</div>
</div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref } from 'vue';
const isSidebarCollapsed = ref(false);
const toggleSidebar = () => {
isSidebarCollapsed.value = !isSidebarCollapsed.value;
};
</script> </script>
<style lang="css" scoped></style> <style lang="less" scoped>
/* 基础布局 */
.layout-container {
min-height: 100vh;
background-color: #f5f7fa;
position: relative;
overflow: hidden;
.decoration-circle {
position: fixed;
border-radius: 50%;
background: linear-gradient(135deg, rgba(24, 144, 255, 0.1) 0%, rgba(24, 144, 255, 0.05) 100%);
z-index: 0;
&.circle-1 {
width: 600px;
height: 600px;
top: -200px;
left: -200px;
}
&.circle-2 {
width: 400px;
height: 400px;
bottom: -100px;
right: -100px;
}
}
.decoration-wave {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 70px;
background: url('@/assets/svg/wave.svg') repeat-x;
background-size: 1000px 100px;
opacity: 0.1;
}
}
/* 顶部导航 */
.fixed-header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 60px;
background-color: #fff;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
z-index: 100;
.header-content {
max-width: 100%;
height: 100%;
padding: 0 24px;
margin: 0 auto;
display: flex;
align-items: center;
.logo-section {
.platform-name {
color: var(--color-text-1);
font-size: 18px;
font-weight: 600;
margin: 0;
white-space: nowrap;
}
}
.main-nav-section {
flex: 1;
margin: 0 40px;
overflow-x: auto;
overflow-y: hidden;
:deep(.arco-menu-horizontal) {
height: 60px;
background: transparent;
border-bottom: none;
}
}
.user-avatar {
background-color: var(--color-primary-light-3);
color: var(--color-primary);
cursor: pointer;
transition: all 0.2s;
&:hover {
background-color: var(--color-primary-light-2);
}
}
}
}
/* 主内容区 */
.main-content-wrapper {
display: flex;
padding-top: 60px;
height: calc(100vh - 60px);
}
/* 侧边栏 */
.fixed-sidebar {
position: fixed;
left: 0;
top: 60px;
padding: 12px 8px;
bottom: 0;
width: 220px;
background-color: var(--color-bg-2);
z-index: 90;
transition: width 0.3s ease;
&.collapsed {
width: 64px;
}
.sidebar-header {
padding: 16px;
background-color: var(--color-primary-light-1);
height: 60px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
h3 {
color: var(--color-text-1);
font-size: 16px;
font-weight: 500;
margin: 0;
white-space: nowrap;
}
}
/* 强制修正折叠菜单样式 */
:deep(.arco-menu) {
height: 100%;
border-right: none;
&.arco-menu-collapsed {
.arco-menu-item {
justify-content: center !important;
padding: 0 12px !important;
.arco-menu-icon {
margin: 0 auto !important;
}
.arco-menu-title {
display: inline-block;
width: 0;
overflow: hidden;
}
}
}
}
}
/* 自定义收缩按钮 */
.collapse-btn-wrapper {
position: absolute;
right: -12px;
top: 50%;
transform: translateY(-50%);
z-index: 110;
width: 24px;
height: 32px;
.collapse-btn {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
border: 1px solid var(--color-border-2);
border-radius: 4px;
padding: 0;
transition: all 0.2s;
cursor: pointer;
// &:hover {
// background: var(--color-fill-2);
// border-color: var(--color-border-3);
// box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
// }
&> :deep(svg) {
font-size: 14px;
color: var(--color-text-2);
}
}
}
/* 内容滚动区域(关键修改) */
.scrollable-content {
flex: 1;
margin-left: 220px;
height: 100%;
overflow-y: scroll;
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE/Edge */
transition: margin-left 0.3s ease;
&::-webkit-scrollbar {
display: none;
/* Chrome/Safari */
}
&.expanded {
margin-left: 64px;
}
.content-scroll-wrapper {
min-height: 100%;
display: flex;
flex-direction: column;
}
}
/* 面包屑 */
.breadcrumb {
padding: 16px 24px 8px;
flex-shrink: 0;
}
/* 路由视图容器 */
.router-view-wrapper {
flex: 1;
padding: 0 24px;
min-height: calc(100vh - 180px);
/* 动态计算最小高度 */
}
/* 页脚 */
.layout-footer {
padding: 16px 24px;
margin-top: auto;
/* 关键:使页脚始终在底部 */
text-align: center;
color: var(--color-text-3);
font-size: 12px;
border-top: 1px solid var(--color-border-2);
background: var(--color-bg-2);
}
</style>

View File

@ -1,39 +1,74 @@
<template> <template>
<div class="login"> <div class="login-container">
<!-- form登录表单 --> <!-- 背景装饰元素 -->
<div :style="{ width: '480px', height: '400px' }"> <div class="decoration-circle circle-1"></div>
<div style="display: flex; height: 40px;justify-content: center;align-items:center;margin-bottom: 12px;"> <div class="decoration-circle circle-2"></div>
<h2>欢迎登录</h2> <div class="decoration-wave"></div>
<!-- 登录卡片 -->
<div class="login-card">
<!-- 平台Logo和标题 -->
<div class="login-header">
<h2 class="platform-name">研发交付平台</h2>
<p class="welcome-text">持续集成 · 持续交付 · 高效协作</p>
</div> </div>
<a-form :model="form" size="large" @submit="handleSubmit">
<a-form-item hide-label field="parameter.username" :rules="{ <!-- 登录表单 -->
required: true, <a-form class="login-form" :model="form" size="large" @submit="handleSubmit">
message: '请输入用户名' <a-form-item hide-label field="parameter.username" :rules="{ required: true, message: '请输入用户名' }">
}"> <a-input v-model="form.parameter.username" placeholder="请输入用户名" allow-clear>
<a-input v-model="form.parameter.username" placeholder="请输入用户名">
<template #prefix> <template #prefix>
<icon-user /> <icon-user style="color: var(--color-text-3)" />
</template> </template>
</a-input> </a-input>
</a-form-item> </a-form-item>
<a-form-item hide-label field="parameter.password" required :rules="{
required: true, <a-form-item hide-label field="parameter.password" :rules="{ required: true, message: '请输入密码' }">
message: '请输入密码'
}">
<a-input-password :invisible-button="false" v-model="form.parameter.password" placeholder="请输入密码" allow-clear> <a-input-password :invisible-button="false" v-model="form.parameter.password" placeholder="请输入密码" allow-clear>
<template #prefix> <template #prefix>
<icon-lock /> <icon-lock style="color: var(--color-text-3)" />
</template> </template>
</a-input-password> </a-input-password>
</a-form-item> </a-form-item>
<a-form-item hide-label field="remember">
<a-checkbox v-model="form.remember"> 记住 </a-checkbox> <div class="form-actions">
</a-form-item> <a-form-item hide-label field="remember">
<a-checkbox v-model="form.remember">记住我</a-checkbox>
</a-form-item>
<a-link style="width: 80px;">忘记密码?</a-link>
</div>
<a-form-item hide-label> <a-form-item hide-label>
<a-button type="primary" :style="{ width: '100%' }" html-type="submit">登录</a-button> <a-button type="primary" long html-type="submit" class="login-btn"> </a-button>
</a-form-item> </a-form-item>
<div class="other-login-methods">
<a-divider>其他登录方式</a-divider>
<div class="oauth-icons">
<a-tooltip content="GitLab登录">
<a-button shape="circle" class="oauth-btn">
<icon-gitlab />
</a-button>
</a-tooltip>
<a-tooltip content="GitHub登录">
<a-button shape="circle" class="oauth-btn">
<icon-github />
</a-button>
</a-tooltip>
<a-tooltip content="LDAP登录">
<a-button shape="circle" class="oauth-btn">
<icon-user-group />
</a-button>
</a-tooltip>
</div>
</div>
</a-form> </a-form>
</div> </div>
<!-- 页脚 -->
<div class="login-footer">
<p>© 2025 研发交付平台 · 让软件交付更高效</p>
</div>
</div> </div>
</template> </template>
@ -43,7 +78,6 @@ import mcenter from '@/api/mcenter'
import token from '@/storage/token' import token from '@/storage/token'
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
//
const form = ref({ const form = ref({
issuer: 'password', issuer: 'password',
parameter: { parameter: {
@ -51,44 +85,139 @@ const form = ref({
password: '' password: ''
}, },
remember: false, remember: false,
}) });
// router const router = useRouter();
const router = useRouter()
//
const handleSubmit = async (data) => { const handleSubmit = async (data) => {
//
if (data.errors == null) { if (data.errors == null) {
// HttpClient const resp = await mcenter.Login(data.values);
const resp = await mcenter.Login(data.values) token.value = resp;
router.push({ name: 'HomePage' });
// 1. cookie, session storage, localstorage
// localStorage.setItem('token', JSON.stringify(resp))
// localStorage.getItem('token')
// localStorage
// https://cn.vuejs.org/guide/reusability/composables.html
token.value = resp
//
// location.assign('/users/eduardo')
// vue router,
//
// router.push('/users/eduardo')
//
router.push({ name: 'HomePage' })
} }
} };
</script> </script>
<style lang="css" scoped> <style lang="less" scoped>
.login { .login-container {
display: flex; display: flex;
justify-content: center; justify-content: center;
flex-direction: column;
align-items: center; align-items: center;
height: 100%; min-height: 100vh;
width: 100%; width: 100%;
background-color: #f5f7fa;
position: relative;
overflow: hidden;
.decoration-circle {
position: absolute;
border-radius: 50%;
background: linear-gradient(135deg, rgba(24, 144, 255, 0.1) 0%, rgba(24, 144, 255, 0.05) 100%);
z-index: 0;
&.circle-1 {
width: 600px;
height: 600px;
top: -200px;
left: -200px;
}
&.circle-2 {
width: 400px;
height: 400px;
bottom: -100px;
right: -100px;
}
}
.decoration-wave {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100px;
background: url('@/assets/svg/wave.svg') repeat-x;
background-size: 1000px 100px;
opacity: 0.1;
}
.login-card {
width: 420px;
padding: 40px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
position: relative;
z-index: 1;
.login-header {
text-align: center;
margin-bottom: 30px;
.logo {
width: 60px;
height: 60px;
margin-bottom: 16px;
}
.platform-name {
color: var(--color-text-1);
margin-bottom: 8px;
font-weight: 600;
}
.welcome-text {
color: var(--color-text-3);
font-size: 14px;
margin: 0;
}
}
.login-form {
.form-actions {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.login-btn {
height: 44px;
font-size: 16px;
border-radius: 4px;
margin-top: 8px;
}
.other-login-methods {
margin-top: 24px;
.oauth-icons {
display: flex;
justify-content: center;
gap: 16px;
margin-top: 16px;
.oauth-btn {
color: var(--color-text-2);
background-color: var(--color-fill-2);
border: none;
&:hover {
background-color: var(--color-fill-3);
}
}
}
}
}
}
.login-footer {
position: absolute;
bottom: 20px;
width: 100%;
text-align: center;
color: var(--color-text-3);
font-size: 12px;
}
} }
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div style="height: 900px;">
测试使用
</div> </div>
</template> </template>

View File

@ -1,6 +1,6 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import HomePage from '@/pages/HomePage.vue' import BackendLayout from '@/layout/BackendLayout.vue'
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
@ -8,7 +8,7 @@ const router = createRouter({
{ {
path: '/', path: '/',
name: 'HomePage', name: 'HomePage',
component: HomePage, component: BackendLayout,
}, },
{ {
path: '/login', path: '/login',
@ -18,6 +18,17 @@ const router = createRouter({
// which is lazy-loaded when the route is visited. // which is lazy-loaded when the route is visited.
component: () => import('../pages/LoginPage.vue'), component: () => import('../pages/LoginPage.vue'),
}, },
{
path: '/cmdb',
component: () => import('@/layout/BackendLayout.vue'),
children: [
{
path: 'secret',
name: 'SecretPage',
component: () => import('@/pages/cmdb/SecretPage.vue'),
},
],
},
], ],
}) })