From 564fc88fc8ed4121736d159274c537878ef0f7a9 Mon Sep 17 00:00:00 2001 From: g1307092382 <1307092382@qq.com> Date: Fri, 11 Sep 2026 17:02:42 +0800 Subject: [PATCH] feat: establish admin visual foundation --- admin-web/src/layouts/MainLayout.vue | 530 +++++++++++++++++++++++--- admin-web/src/theme/index.css | 32 +- ui-tests/admin-redesign-contracts.mjs | 32 ++ 3 files changed, 537 insertions(+), 57 deletions(-) create mode 100644 ui-tests/admin-redesign-contracts.mjs diff --git a/admin-web/src/layouts/MainLayout.vue b/admin-web/src/layouts/MainLayout.vue index 4f49c5a..ad9e71e 100644 --- a/admin-web/src/layouts/MainLayout.vue +++ b/admin-web/src/layouts/MainLayout.vue @@ -2,67 +2,495 @@
-
缘
-
善缘丹阳公益婚恋运营平台
+ +
+ 善缘丹阳 + 公益婚恋运营平台 +
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + +
+ -
善缘丹阳 · 公益服务
工作台{{currentTitle}}
-
服务正常
+
+
善缘丹阳 · 公益服务
+ + 工作台 + {{ currentTitle }} + +
+ +
+ + + + + + + + +
- + + + + + +
+ + \ No newline at end of file +.main-layout { + width: 100%; + height: 100vh; +} + +.sidebar { + display: flex; + flex-direction: column; + overflow: hidden; + color: var(--admin-sidebar-text); + background: var(--admin-sidebar-bg); + border-right: 1px solid rgba(255, 255, 255, 0.06); + transition: width 0.2s ease; +} + +.brand { + display: flex; + align-items: center; + gap: 12px; + height: 92px; + padding: 20px 18px; + border-bottom: 1px solid rgba(255, 255, 255, 0.08); +} + +.brand.compact { + justify-content: center; + padding: 18px 10px; +} + +.brand-mark { + width: 44px; + height: 44px; + flex: none; + object-fit: contain; +} + +.brand-copy { + display: flex; + flex-direction: column; + white-space: nowrap; +} + +.brand-copy strong { + color: #FFFFFF; + font-size: 18px; + letter-spacing: 1px; +} + +.brand-copy span { + margin-top: 4px; + color: var(--admin-sidebar-muted); + font-size: 11px; +} + +.menu-scroll { + flex: 1; +} + +.sidebar-menu { + padding: 12px 10px; + border: 0; + background: transparent; +} + +.sidebar-menu :deep(.el-menu-item) { + height: 42px; + margin: 3px 0; + color: var(--admin-sidebar-text); + border-radius: 9px; +} + +.sidebar-menu :deep(.el-menu-item:hover) { + color: #FFFFFF; + background: var(--admin-sidebar-surface); +} + +.sidebar-menu :deep(.el-menu-item.is-active) { + color: #FFFFFF; + font-weight: 600; + background: var(--admin-primary); +} + +.sidebar-menu :deep(.el-menu-item-group__title) { + padding: 18px 12px 5px !important; + overflow: hidden; + color: var(--admin-sidebar-muted); + font-size: 11px; + letter-spacing: 0.5px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.collapse-control { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + height: 52px; + margin: 10px; + color: var(--admin-sidebar-muted); + cursor: pointer; + background: transparent; + border: 0; + border-top: 1px solid rgba(255, 255, 255, 0.08); +} + +.collapse-control:hover { + color: #FFFFFF; +} + +.workspace { + min-width: 0; +} + +.header { + display: flex; + align-items: center; + justify-content: space-between; + height: var(--header-height); + padding: 0 24px; + background: var(--admin-header-bg); + border-bottom: 1px solid var(--color-border-light); +} + +.page-context { + min-width: 180px; +} + +.context-kicker { + margin-bottom: 4px; + color: var(--admin-primary); + font-size: 10px; + letter-spacing: 1px; +} + +.header-tools, +.user-info { + display: flex; + align-items: center; +} + +.header-tools { + gap: 16px; +} + +.global-search { + width: 260px; +} + +.global-search :deep(.el-input__wrapper) { + background: #F5F6F7; + border-radius: 10px; + box-shadow: inset 0 0 0 1px #E8EAED; +} + +.notification-button { + position: relative; + display: grid; + width: 38px; + height: 38px; + color: var(--color-text-secondary); + cursor: pointer; + background: #FFFFFF; + border: 1px solid var(--color-border-light); + border-radius: 10px; + place-items: center; +} + +.notification-dot { + position: absolute; + top: 8px; + right: 8px; + width: 7px; + height: 7px; + background: var(--admin-primary); + border: 2px solid #FFFFFF; + border-radius: 50%; +} + +.user-info { + gap: 9px; + cursor: pointer; +} + +.user-info .el-avatar { + color: #FFFFFF; + background: var(--admin-primary); +} + +.user-copy { + display: flex; + flex-direction: column; +} + +.user-copy strong { + font-size: 13px; +} + +.user-copy small { + margin-top: 2px; + color: var(--color-text-tertiary); + font-size: 11px; +} + +.main-content { + padding: 0; + overflow: auto; + background: var(--admin-page-bg); +} + +@media (max-width: 1000px) { + .sidebar { + width: 72px !important; + } + + .brand-copy, + .collapse-control span, + .sidebar-menu :deep(.el-menu-item-group__title) { + display: none; + } + + .brand { + justify-content: center; + } +} + +@media (max-width: 760px) { + .header { + padding: 0 14px; + } + + .page-context, + .global-search, + .user-copy { + display: none; + } +} + diff --git a/admin-web/src/theme/index.css b/admin-web/src/theme/index.css index 510632b..5b35439 100644 --- a/admin-web/src/theme/index.css +++ b/admin-web/src/theme/index.css @@ -1,6 +1,19 @@ :root { - --color-primary: #E96B6B; - --color-primary-hover: #D95F5F; + --admin-sidebar-bg: #172733; + --admin-sidebar-surface: #213542; + --admin-sidebar-text: #D9E1E6; + --admin-sidebar-muted: #8FA1AC; + --admin-page-bg: #F7F7F5; + --admin-primary: #EE666B; + --admin-primary-hover: #D9545A; + --admin-card-radius: 14px; + --admin-header-bg: #FFFFFF; + --admin-soft-pink: #FFF0F1; + --admin-soft-blue: #EEF5FF; + --admin-soft-green: #EDF8F1; + --admin-soft-purple: #F4EFFF; + --color-primary: var(--admin-primary); + --color-primary-hover: var(--admin-primary-hover); --color-primary-light: #FFF3F2; --color-primary-lighter: #FFF8F7; --color-success: #2E9B68; @@ -12,13 +25,13 @@ --color-text-tertiary: #888888; --color-bg-primary: #FFFFFF; --color-bg-secondary: #FFF8F7; - --color-bg-page: #FAFAF8; + --color-bg-page: var(--admin-page-bg); --color-border: #E8E5E2; --color-border-light: #F0EDE9; --sidebar-width: 220px; --header-height: 64px; --border-radius-sm: 8px; - --border-radius-md: 12px; + --border-radius-md: var(--admin-card-radius); --border-radius-lg: 16px; --shadow-card: 0 8px 24px rgba(75, 55, 46, 0.06); --el-color-primary: var(--color-primary); @@ -34,6 +47,13 @@ html, body, #app { background-color: var(--color-bg-page); } body { min-width: 1100px; } +button:focus-visible, +a:focus-visible, +input:focus-visible, +[tabindex]:focus-visible { + outline: 3px solid rgba(238, 102, 107, 0.32); + outline-offset: 2px; +} .el-button--primary { --el-button-bg-color: var(--color-primary); --el-button-border-color: var(--color-primary); @@ -45,7 +65,7 @@ body { min-width: 1100px; } border-color: var(--color-primary); } .el-card { --el-card-border-radius: var(--border-radius-md); --el-card-border-color: var(--color-border-light); } -.el-table { --el-table-header-bg-color: #FCFAF8; --el-table-border-color: var(--color-border-light); } +.el-table { --el-table-header-bg-color: #FBFAF8; --el-table-border-color: var(--color-border-light); } .el-tag { border-radius: 999px; } .page-container { padding: 24px; } .page-shell { max-width: 1440px; margin: 0 auto; } @@ -64,4 +84,4 @@ body { min-width: 1100px; } .mb-lg { margin-bottom: 24px; } .flex-center { display: flex; align-items: center; justify-content: center; } @media (max-width: 1200px) { body { min-width: 0; } } -@media (max-width: 900px) { .page-container { padding: 16px; } .page-heading { align-items: flex-start; flex-direction: column; } } \ No newline at end of file +@media (max-width: 900px) { .page-container { padding: 16px; } .page-heading { align-items: flex-start; flex-direction: column; } } diff --git a/ui-tests/admin-redesign-contracts.mjs b/ui-tests/admin-redesign-contracts.mjs new file mode 100644 index 0000000..414c139 --- /dev/null +++ b/ui-tests/admin-redesign-contracts.mjs @@ -0,0 +1,32 @@ +import assert from 'node:assert/strict' +import { readFileSync } from 'node:fs' +import { resolve } from 'node:path' + +const root = resolve(import.meta.dirname, '..') +const read = (file) => readFileSync(resolve(root, file), 'utf8') +const theme = read('admin-web/src/theme/index.css') +const layout = read('admin-web/src/layouts/MainLayout.vue') + +for (const token of ['--admin-sidebar-bg', '--admin-page-bg', '--admin-primary', '--admin-card-radius']) { + assert.ok(theme.includes(token), `缺少管理端令牌 ${token}`) +} + +for (const group of [ + '工作台', + '用户与资料审核', + '匹配与活动服务', + '公益咨询与转介', + '服务站、预约与专项服务', + 'Banner 与内容运营', + '举报、申诉与审计', + '组织、人员与权限', + '数据统计', +]) { + assert.ok(layout.includes(group), `缺少菜单组 ${group}`) +} + +assert.ok(layout.includes('/brand/logo-mark.png'), '管理端未使用正式品牌标志') +assert.ok(layout.includes('globalSearch'), '管理端顶部搜索没有可操作状态') +assert.ok(layout.includes('showNotifications'), '管理端通知入口没有可操作反馈') + +console.log('Admin redesign contracts passed')