From 464386efe001aa2cea9b952d6226a88c0016c097 Mon Sep 17 00:00:00 2001 From: peanut_hzm Date: Sat, 27 Dec 2025 16:45:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E5=8F=B0=E7=AE=A1=E7=90=86=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web-admin/src/App.vue | 7 +- .../src/components/AiConfigQuickActions.vue | 15 +- web-admin/src/layouts/Layout.vue | 38 +- web-admin/src/main.ts | 5 + web-admin/src/styles/life-script-theme.scss | 393 ++++++++++++++++++ web-admin/src/views/Dashboard.vue | 10 +- web-admin/src/views/Login.vue | 32 +- web-admin/src/views/NotFound.vue | 6 +- web-admin/src/views/admin/AdminList.vue | 2 +- web-admin/src/views/aiconfig/AiConfigList.vue | 15 +- .../src/views/dictionary/DictionaryForm.vue | 42 +- .../src/views/dictionary/DictionaryList.vue | 22 +- web-admin/src/views/tools/ApiTester.vue | 10 +- web-admin/src/views/user/UserList.vue | 2 +- 14 files changed, 542 insertions(+), 57 deletions(-) create mode 100644 web-admin/src/styles/life-script-theme.scss diff --git a/web-admin/src/App.vue b/web-admin/src/App.vue index 0a00084..aa83cc9 100644 --- a/web-admin/src/App.vue +++ b/web-admin/src/App.vue @@ -6,6 +6,11 @@ diff --git a/web-admin/src/components/AiConfigQuickActions.vue b/web-admin/src/components/AiConfigQuickActions.vue index d823b53..4790ae3 100644 --- a/web-admin/src/components/AiConfigQuickActions.vue +++ b/web-admin/src/components/AiConfigQuickActions.vue @@ -143,18 +143,19 @@ onMounted(() => { align-items: center; gap: 12px; padding: 12px; - border: 1px solid #e4e7ed; - border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: var(--ls-radius-md); + background: rgba(255, 255, 255, 0.02); transition: all 0.3s; &:hover { - border-color: #409eff; - background-color: #f0f9ff; + border-color: rgba(255, 171, 145, 0.28); + background: rgba(255, 171, 145, 0.06); } .action-icon { font-size: 24px; - color: #409eff; + color: var(--ls-accent-orange); } .action-content { @@ -163,13 +164,13 @@ onMounted(() => { .action-title { font-size: 14px; font-weight: 500; - color: #333; + color: rgba(226, 232, 240, 0.92); margin-bottom: 4px; } .action-desc { font-size: 12px; - color: #999; + color: rgba(226, 232, 240, 0.6); } } } diff --git a/web-admin/src/layouts/Layout.vue b/web-admin/src/layouts/Layout.vue index 2ac3a53..e736a67 100644 --- a/web-admin/src/layouts/Layout.vue +++ b/web-admin/src/layouts/Layout.vue @@ -115,10 +115,14 @@ onMounted(() => { diff --git a/web-admin/src/main.ts b/web-admin/src/main.ts index 05dcea8..4898550 100644 --- a/web-admin/src/main.ts +++ b/web-admin/src/main.ts @@ -1,6 +1,11 @@ import { createApp } from 'vue' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' +/** + * 全局主题样式: + * - 仅覆盖样式,确保 web-admin 视觉风格与 life-script 对齐 + */ +import './styles/life-script-theme.scss' import * as ElementPlusIconsVue from '@element-plus/icons-vue' import App from './App.vue' import router from './router' diff --git a/web-admin/src/styles/life-script-theme.scss b/web-admin/src/styles/life-script-theme.scss new file mode 100644 index 0000000..9d747bb --- /dev/null +++ b/web-admin/src/styles/life-script-theme.scss @@ -0,0 +1,393 @@ +/** + * web-admin 全局主题(对齐 life-script 视觉风格) + * + * 目标: + * - 深色基底 + 玻璃拟态(glassmorphism) + * - 橙/蓝点缀色(accent) + * - 更大的圆角、更柔和的阴影、更一致的 hover/active 反馈 + * + * 说明: + * - 仅做样式覆盖,不涉及任何业务逻辑与交互行为变更 + * - 通过 CSS Variables 覆盖 Element Plus 主题变量,并对常用 el-* 组件做全局外观微调 + */ + +/* 使用国内镜像加载字体,避免 Google Fonts 访问超时(与 life-script 保持一致) */ +@import url('https://fonts.loli.net/css2?family=Noto+Serif+SC:wght@300;600&family=Noto+Sans+SC:wght@300;400;500&display=swap'); + +:root { + /* ====== life-script tokens ====== */ + --ls-bg: #0a0c10; + --ls-text: #e2e8f0; + --ls-text-muted: rgba(226, 232, 240, 0.7); + + --ls-glass-bg: rgba(15, 17, 26, 0.4); + --ls-glass-bg-strong: rgba(15, 17, 26, 0.55); + --ls-glass-border: rgba(255, 255, 255, 0.08); + --ls-glass-border-strong: rgba(255, 255, 255, 0.14); + --ls-shadow: 0 20px 50px -12px rgba(0, 0, 0, 0.5); + + --ls-accent-orange: #ffab91; + --ls-accent-blue: #81d4fa; + + --ls-radius-xl: 32px; + --ls-radius-lg: 20px; + --ls-radius-md: 16px; + + /* ====== Element Plus theme overrides(尽量使用官方变量名)====== */ + --el-color-primary: var(--ls-accent-orange); + --el-color-success: #67c23a; + --el-color-warning: #e6a23c; + --el-color-danger: #f56c6c; + --el-color-info: var(--ls-accent-blue); + + --el-bg-color: var(--ls-bg); + --el-bg-color-overlay: var(--ls-glass-bg-strong); + /** + * Element Plus 填充色: + * - 避免“白底控件”的观感,统一使用偏黑的玻璃面 + */ + --el-fill-color-blank: rgba(15, 17, 26, 0.28); + --el-fill-color-light: rgba(15, 17, 26, 0.34); + --el-fill-color: rgba(15, 17, 26, 0.40); + --el-fill-color-dark: rgba(15, 17, 26, 0.46); + + --el-text-color-primary: var(--ls-text); + --el-text-color-regular: rgba(226, 232, 240, 0.85); + --el-text-color-secondary: rgba(226, 232, 240, 0.7); + --el-text-color-placeholder: rgba(226, 232, 240, 0.45); + --el-border-color: var(--ls-glass-border); + --el-border-color-light: rgba(255, 255, 255, 0.06); + --el-border-color-lighter: rgba(255, 255, 255, 0.05); + --el-border-color-extra-light: rgba(255, 255, 255, 0.04); + + --el-border-radius-base: var(--ls-radius-md); + --el-border-radius-round: 999px; + --el-box-shadow-light: var(--ls-shadow); +} + +* { + box-sizing: border-box; +} + +html, +body, +#app { + height: 100%; +} + +body { + margin: 0; + padding: 0; + overflow-x: hidden; + font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + -webkit-font-smoothing: antialiased; + color: var(--ls-text); + background-color: var(--ls-bg); +} + +.font-serif { + font-family: 'Noto Serif SC', serif; +} + +/* ====== 背景层(给整个后台一个 life-script 风格的氛围底)====== */ +#app { + background: + radial-gradient(1200px 800px at 10% 20%, rgba(255, 171, 145, 0.12), transparent 55%), + radial-gradient(900px 700px at 90% 10%, rgba(129, 212, 250, 0.10), transparent 50%), + radial-gradient(900px 700px at 70% 90%, rgba(255, 171, 145, 0.08), transparent 50%), + var(--ls-bg); +} + +/* ====== 通用 glass 外观(与 life-script 对齐)====== */ +.glass-card, +.el-card, +.el-dialog, +.el-message-box, +.el-drawer { + background: var(--ls-glass-bg) !important; + border: 1px solid var(--ls-glass-border) !important; + border-radius: var(--ls-radius-xl) !important; + box-shadow: var(--ls-shadow) !important; + backdrop-filter: blur(25px) saturate(180%); + -webkit-backdrop-filter: blur(25px) saturate(180%); +} + +.el-card__header { + border-bottom: 1px solid rgba(255, 255, 255, 0.06) !important; +} + +/* ====== 按钮(玻璃按钮/强调按钮)====== */ +.glass-btn, +.el-button { + background: rgba(15, 17, 26, 0.35); + border: 1px solid rgba(255, 255, 255, 0.08); + color: var(--ls-text); + transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1); +} + +.el-button:hover, +.glass-btn:hover { + background: rgba(15, 17, 26, 0.25); + border-color: rgba(255, 255, 255, 0.18); + transform: translateY(-2px); +} + +.el-button:active, +.glass-btn:active { + transform: scale(0.98); +} + +.el-button.is-disabled, +.el-button.is-disabled:hover { + opacity: 0.5; + transform: none; +} + +/* primary:用 life-script 的橙色作为主强调 */ +.el-button--primary { + background: rgba(255, 171, 145, 0.14) !important; + border-color: rgba(255, 171, 145, 0.35) !important; + color: var(--ls-accent-orange) !important; +} +.el-button--primary:hover { + background: var(--ls-accent-orange) !important; + color: #000 !important; + border-color: var(--ls-accent-orange) !important; +} + +/* link 按钮在深色底上更清晰 */ +.el-button.is-link { + background: transparent !important; + border-color: transparent !important; +} +.el-button.is-link:hover { + background: rgba(255, 171, 145, 0.08) !important; + border-color: rgba(255, 171, 145, 0.12) !important; +} + +/* ====== 输入框(glass-input 风格)====== */ +.glass-input, +.el-input__wrapper, +.el-textarea__inner { + background: rgba(0, 0, 0, 0.2) !important; + border: 1px solid rgba(255, 255, 255, 0.06) !important; + border-radius: var(--ls-radius-md) !important; + color: var(--ls-text) !important; + box-shadow: none !important; +} + +.el-input__wrapper.is-focus, +.el-textarea__inner:focus { + border-color: rgba(255, 171, 145, 0.55) !important; + box-shadow: 0 0 20px rgba(255, 171, 145, 0.10) !important; +} + +.el-input__inner::placeholder, +.el-textarea__inner::placeholder { + color: rgba(255, 255, 255, 0.35) !important; +} + +/** + * 浏览器自动填充(尤其登录页)可能将输入框渲染为浅色/白底: + * - 强制覆盖为深色玻璃背景,避免出现白底 + */ +input:-webkit-autofill, +input:-webkit-autofill:hover, +input:-webkit-autofill:focus, +textarea:-webkit-autofill, +textarea:-webkit-autofill:hover, +textarea:-webkit-autofill:focus, +select:-webkit-autofill, +select:-webkit-autofill:hover, +select:-webkit-autofill:focus { + -webkit-text-fill-color: var(--ls-text) !important; + box-shadow: 0 0 0 1000px rgba(0, 0, 0, 0.25) inset !important; + -webkit-box-shadow: 0 0 0 1000px rgba(0, 0, 0, 0.25) inset !important; + transition: background-color 9999s ease-out 0s; +} + +/* ====== Tabs(border-card 默认面板偏白,统一改为深色玻璃)====== */ +.el-tabs--border-card { + background: var(--ls-glass-bg) !important; + border: 1px solid rgba(255, 255, 255, 0.06) !important; + border-radius: var(--ls-radius-xl) !important; + overflow: hidden; +} + +.el-tabs--border-card > .el-tabs__header { + background: rgba(15, 17, 26, 0.35) !important; + border-bottom: 1px solid rgba(255, 255, 255, 0.06) !important; +} + +.el-tabs--border-card > .el-tabs__header .el-tabs__item { + color: rgba(226, 232, 240, 0.75) !important; +} + +.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active { + color: var(--ls-accent-orange) !important; +} + +.el-tabs__nav-wrap::after { + background-color: rgba(255, 255, 255, 0.06) !important; +} + +.el-tabs__content { + background: transparent !important; +} + +/* ====== Popper/Dropdown/Select/DatePicker 面板(避免白底)====== */ +.el-popper, +.el-popper.is-light, +.el-select__popper, +.el-dropdown__popper, +.el-autocomplete__popper, +.el-tooltip__popper, +.el-picker__popper { + background: rgba(15, 17, 26, 0.72) !important; + border: 1px solid rgba(255, 255, 255, 0.10) !important; + backdrop-filter: blur(25px) saturate(180%); + -webkit-backdrop-filter: blur(25px) saturate(180%); +} + +.el-select-dropdown__item, +.el-dropdown-menu__item { + color: rgba(226, 232, 240, 0.85) !important; +} + +.el-select-dropdown__item.hover, +.el-select-dropdown__item:hover, +.el-dropdown-menu__item:hover { + background: rgba(255, 171, 145, 0.10) !important; +} + +.el-select-dropdown__item.selected { + color: var(--ls-accent-orange) !important; +} + +/* ====== 表格/分页(深色玻璃)====== */ +.el-table { + background: transparent !important; + color: var(--ls-text) !important; +} +.el-table th.el-table__cell { + background: rgba(255, 255, 255, 0.03) !important; + color: rgba(226, 232, 240, 0.85) !important; + border-bottom: 1px solid rgba(255, 255, 255, 0.06) !important; +} +.el-table td.el-table__cell { + background: transparent !important; + border-bottom: 1px solid rgba(255, 255, 255, 0.04) !important; +} +.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell { + background: rgba(255, 255, 255, 0.02) !important; +} +.el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell { + background: rgba(255, 171, 145, 0.06) !important; +} + +.el-pagination { + color: rgba(226, 232, 240, 0.85) !important; +} + +/* ====== 弹窗(对话框/MessageBox)====== */ +.el-dialog__header { + margin-right: 0 !important; + border-bottom: 1px solid rgba(255, 255, 255, 0.06); +} +.el-dialog__title { + color: var(--ls-text) !important; +} + +/* ====== Tag/Statistic 等小组件可读性 ====== */ +.el-tag { + /** + * Tag 在深色玻璃主题下默认背景会偏亮,导致“白底字段”观感: + * - 统一改为深色玻璃底 + * - 不同 type 使用对应色系做文字/边框强调 + */ + background: rgba(15, 17, 26, 0.38) !important; + border: 1px solid rgba(255, 255, 255, 0.10) !important; + color: rgba(226, 232, 240, 0.85) !important; +} + +/* Tag 颜色语义:保持可读性与 life-script 点缀风格一致 */ +.el-tag--primary { + background: rgba(255, 171, 145, 0.12) !important; + border-color: rgba(255, 171, 145, 0.28) !important; + color: var(--ls-accent-orange) !important; +} + +.el-tag--success { + background: rgba(103, 194, 58, 0.12) !important; + border-color: rgba(103, 194, 58, 0.28) !important; + color: rgba(199, 255, 176, 0.95) !important; +} + +.el-tag--warning { + background: rgba(230, 162, 60, 0.12) !important; + border-color: rgba(230, 162, 60, 0.28) !important; + color: rgba(255, 220, 160, 0.95) !important; +} + +.el-tag--danger { + background: rgba(245, 108, 108, 0.12) !important; + border-color: rgba(245, 108, 108, 0.30) !important; + color: rgba(255, 190, 190, 0.95) !important; +} + +.el-tag--info { + background: rgba(129, 212, 250, 0.10) !important; + border-color: rgba(129, 212, 250, 0.26) !important; + color: var(--ls-accent-blue) !important; +} + +/* plain 模式也避免浅底 */ +.el-tag.is-plain { + background: rgba(15, 17, 26, 0.28) !important; +} + +/* ====== Descriptions(详情展示默认也可能偏白)====== */ +.el-descriptions, +.el-descriptions__body, +.el-descriptions__table { + background: transparent !important; + color: var(--ls-text) !important; +} + +.el-descriptions__cell { + background: rgba(15, 17, 26, 0.24) !important; + border-color: rgba(255, 255, 255, 0.06) !important; + color: rgba(226, 232, 240, 0.85) !important; +} + +.el-descriptions__label { + color: rgba(226, 232, 240, 0.65) !important; +} + +.el-descriptions__content { + color: rgba(226, 232, 240, 0.90) !important; +} +.el-statistic__head { + color: rgba(226, 232, 240, 0.7) !important; +} +.el-statistic__content { + color: var(--ls-text) !important; +} + +/* ====== 滚动条(与 life-script 接近)====== */ +*::-webkit-scrollbar { + width: 4px; + height: 4px; +} +*::-webkit-scrollbar-track { + background: transparent; +} +*::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.08); + border-radius: 10px; +} +*::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.15); +} + + diff --git a/web-admin/src/views/Dashboard.vue b/web-admin/src/views/Dashboard.vue index 754bd91..42baa20 100644 --- a/web-admin/src/views/Dashboard.vue +++ b/web-admin/src/views/Dashboard.vue @@ -498,7 +498,7 @@ const updateUserChart = () => { .page-title { margin: 0; font-size: 24px; - color: #333; + color: var(--ls-text); } .dashboard-actions { @@ -535,13 +535,13 @@ const updateUserChart = () => { .stat-value { font-size: 28px; font-weight: bold; - color: #333; + color: var(--ls-text); margin-bottom: 5px; } .stat-label { font-size: 14px; - color: #999; + color: rgba(226, 232, 240, 0.65); } } } @@ -563,7 +563,7 @@ const updateUserChart = () => { .nickname { font-size: 14px; font-weight: 500; - color: #333; + color: rgba(226, 232, 240, 0.9); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -571,7 +571,7 @@ const updateUserChart = () => { .username { font-size: 12px; - color: #999; + color: rgba(226, 232, 240, 0.6); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; diff --git a/web-admin/src/views/Login.vue b/web-admin/src/views/Login.vue index e5d8a4d..410ff50 100644 --- a/web-admin/src/views/Login.vue +++ b/web-admin/src/views/Login.vue @@ -93,15 +93,33 @@ const handleLogin = async () => { justify-content: center; align-items: center; min-height: 100vh; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + background: var(--ls-bg); + position: relative; + overflow: hidden; +} + +.login-container::before { + content: ''; + position: absolute; + inset: -20%; + background: + radial-gradient(700px 500px at 20% 30%, rgba(255, 171, 145, 0.18), transparent 55%), + radial-gradient(650px 500px at 80% 20%, rgba(129, 212, 250, 0.14), transparent 55%), + radial-gradient(800px 600px at 60% 80%, rgba(255, 171, 145, 0.10), transparent 55%); + filter: blur(0px); + pointer-events: none; } .login-box { width: 400px; padding: 40px; - background: #fff; - border-radius: 10px; - box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1); + background: var(--ls-glass-bg); + border: 1px solid var(--ls-glass-border); + border-radius: var(--ls-radius-xl); + box-shadow: var(--ls-shadow); + backdrop-filter: blur(25px) saturate(180%); + -webkit-backdrop-filter: blur(25px) saturate(180%); + position: relative; } .login-header { @@ -110,13 +128,13 @@ const handleLogin = async () => { h2 { font-size: 24px; - color: #333; + color: var(--ls-text); margin-bottom: 10px; } p { font-size: 14px; - color: #999; + color: rgba(226, 232, 240, 0.7); } } @@ -132,7 +150,7 @@ const handleLogin = async () => { p { font-size: 12px; - color: #999; + color: rgba(226, 232, 240, 0.6); } } diff --git a/web-admin/src/views/NotFound.vue b/web-admin/src/views/NotFound.vue index 057574d..053f943 100644 --- a/web-admin/src/views/NotFound.vue +++ b/web-admin/src/views/NotFound.vue @@ -24,20 +24,20 @@ const goHome = () => { justify-content: center; align-items: center; min-height: 100vh; - background-color: #f0f2f5; + background-color: var(--ls-bg); .content { text-align: center; h1 { font-size: 120px; - color: #409eff; + color: var(--ls-accent-orange); margin-bottom: 20px; } p { font-size: 24px; - color: #666; + color: rgba(226, 232, 240, 0.75); margin-bottom: 30px; } } diff --git a/web-admin/src/views/admin/AdminList.vue b/web-admin/src/views/admin/AdminList.vue index c374c24..e97dfed 100644 --- a/web-admin/src/views/admin/AdminList.vue +++ b/web-admin/src/views/admin/AdminList.vue @@ -296,7 +296,7 @@ onMounted(() => { .page-title { margin-bottom: 20px; font-size: 24px; - color: #333; + color: var(--ls-text); } .search-card { diff --git a/web-admin/src/views/aiconfig/AiConfigList.vue b/web-admin/src/views/aiconfig/AiConfigList.vue index 3506eee..402fecc 100644 --- a/web-admin/src/views/aiconfig/AiConfigList.vue +++ b/web-admin/src/views/aiconfig/AiConfigList.vue @@ -1581,7 +1581,7 @@ onMounted(() => { .page-title { margin-bottom: 20px; font-size: 24px; - color: #333; + color: var(--ls-text); } .search-card { @@ -1614,8 +1614,9 @@ onMounted(() => { .stats-row { margin-bottom: 20px; padding: 20px; - background: #f8f9fa; - border-radius: 8px; + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: var(--ls-radius-lg); } .pagination { @@ -1627,7 +1628,7 @@ onMounted(() => { .form-tip { margin-left: 10px; font-size: 12px; - color: #999; + color: rgba(226, 232, 240, 0.6); } } @@ -1635,8 +1636,8 @@ onMounted(() => { .test-section { h4 { margin-bottom: 20px; - color: #333; - border-bottom: 2px solid #409eff; + color: var(--ls-text); + border-bottom: 2px solid rgba(255, 171, 145, 0.6); padding-bottom: 8px; } @@ -1646,7 +1647,7 @@ onMounted(() => { gap: 8px; .info-icon { - color: #909399; + color: rgba(226, 232, 240, 0.6); cursor: help; } } diff --git a/web-admin/src/views/dictionary/DictionaryForm.vue b/web-admin/src/views/dictionary/DictionaryForm.vue index 24ffa05..2c5e791 100644 --- a/web-admin/src/views/dictionary/DictionaryForm.vue +++ b/web-admin/src/views/dictionary/DictionaryForm.vue @@ -69,7 +69,7 @@ diff --git a/web-admin/src/views/user/UserList.vue b/web-admin/src/views/user/UserList.vue index 128e165..450f2e0 100644 --- a/web-admin/src/views/user/UserList.vue +++ b/web-admin/src/views/user/UserList.vue @@ -190,7 +190,7 @@ onMounted(() => { .page-title { margin-bottom: 20px; font-size: 24px; - color: #333; + color: var(--ls-text); } .search-card {