Commit 74bd42914d2058420c33d0b11861929b4c6d1a4f
1 parent
b59f2fb2
Refactor: Replace hardcoded RGBA colors with global CSS variables for consistent…
… theming and maintainability.
Showing
5 changed files
with
134 additions
and
59 deletions
src/layouts/MainLayout.vue
| ... | ... | @@ -17,6 +17,7 @@ |
| 17 | 17 | <div class="menu-scroll"> |
| 18 | 18 | <a-menu |
| 19 | 19 | v-model:selectedKeys="selectedKeys" |
| 20 | + :theme="app.isDarkMode ? 'dark' : 'light'" | |
| 20 | 21 | mode="inline" |
| 21 | 22 | :inline-collapsed="collapsed" |
| 22 | 23 | @click="onMenuClick" |
| ... | ... | @@ -82,17 +83,18 @@ |
| 82 | 83 | <menu-unfold-outlined /> |
| 83 | 84 | </button> |
| 84 | 85 | <div class="topbar-header-info"> |
| 85 | - <a-breadcrumb separator="/"> | |
| 86 | - <a-breadcrumb-item key="home"> | |
| 87 | - <router-link to="/"> | |
| 88 | - <home-outlined /> | |
| 89 | - </router-link> | |
| 90 | - </a-breadcrumb-item> | |
| 91 | - <a-breadcrumb-item v-for="bc in breadcrumbs" :key="bc.path"> | |
| 92 | - {{ bc.title }} | |
| 93 | - </a-breadcrumb-item> | |
| 94 | - </a-breadcrumb> | |
| 95 | - <h1>{{ currentTitle }}</h1> | |
| 86 | + <transition name="breadcrumb-fade" mode="out-in"> | |
| 87 | + <a-breadcrumb :key="route.path" class="custom-breadcrumb"> | |
| 88 | + <template #separator> | |
| 89 | + <span class="bc-separator"><right-outlined /></span> | |
| 90 | + </template> | |
| 91 | + <a-breadcrumb-item v-for="(bc, idx) in breadcrumbs" :key="idx"> | |
| 92 | + <span :class="idx === breadcrumbs.length - 1 ? 'bc-last' : 'bc-parent'"> | |
| 93 | + {{ bc.title }} | |
| 94 | + </span> | |
| 95 | + </a-breadcrumb-item> | |
| 96 | + </a-breadcrumb> | |
| 97 | + </transition> | |
| 96 | 98 | </div> |
| 97 | 99 | </div> |
| 98 | 100 | <div class="topbar-actions"> |
| ... | ... | @@ -142,7 +144,11 @@ |
| 142 | 144 | </header> |
| 143 | 145 | |
| 144 | 146 | <div class="soft-page-shell"> |
| 145 | - <router-view /> | |
| 147 | + <router-view v-slot="{ Component }"> | |
| 148 | + <transition name="fade-slide" mode="out-in"> | |
| 149 | + <component :is="Component" /> | |
| 150 | + </transition> | |
| 151 | + </router-view> | |
| 146 | 152 | </div> |
| 147 | 153 | </main> |
| 148 | 154 | |
| ... | ... | @@ -159,6 +165,7 @@ |
| 159 | 165 | </div> |
| 160 | 166 | <a-menu |
| 161 | 167 | v-model:selectedKeys="selectedKeys" |
| 168 | + :theme="app.isDarkMode ? 'dark' : 'light'" | |
| 162 | 169 | mode="inline" |
| 163 | 170 | @click="onMenuClick(); collapsed = true" |
| 164 | 171 | > |
| ... | ... | @@ -223,7 +230,7 @@ import { |
| 223 | 230 | UserOutlined, UnorderedListOutlined, ApiOutlined, DownOutlined, StarOutlined, |
| 224 | 231 | CalendarOutlined, MenuFoldOutlined, MenuUnfoldOutlined, HomeOutlined, ControlOutlined, |
| 225 | 232 | FullscreenOutlined, FullscreenExitOutlined, BellOutlined, |
| 226 | - BulbOutlined, BulbFilled | |
| 233 | + BulbOutlined, BulbFilled, RightOutlined | |
| 227 | 234 | } from '@ant-design/icons-vue' |
| 228 | 235 | |
| 229 | 236 | const router = useRouter() |
| ... | ... | @@ -248,16 +255,30 @@ onUnmounted(() => { |
| 248 | 255 | watch(() => route.path, (p) => { selectedKeys.value = [p] }) |
| 249 | 256 | |
| 250 | 257 | const isAdmin = computed(() => auth.userInfo?.role === 'admin') |
| 251 | -const currentTitle = computed(() => (route.meta.title as string) || '外卖管理') | |
| 252 | 258 | |
| 253 | 259 | // Breadcrumbs logic |
| 260 | +const menuParents: Record<string, string> = { | |
| 261 | + '/merchant/enter': '商家管理', | |
| 262 | + '/merchant/store': '商家管理', | |
| 263 | + '/order': '订单管理', | |
| 264 | + '/refund': '订单管理', | |
| 265 | + '/delivery/order': '订单管理', | |
| 266 | + '/config/fee-plan': '配置中心', | |
| 267 | + '/dispatch/rule': '配置中心', | |
| 268 | + '/open': '开放平台', | |
| 269 | + '/open/mock-delivery': '开放平台', | |
| 270 | +} | |
| 271 | + | |
| 254 | 272 | const breadcrumbs = computed(() => { |
| 255 | - return route.matched | |
| 256 | - .filter(r => r.meta && r.meta.title) | |
| 257 | - .map(r => ({ | |
| 258 | - title: r.meta.title, | |
| 259 | - path: r.path || '/', | |
| 260 | - })) | |
| 273 | + const list = [] | |
| 274 | + const parentTitle = menuParents[route.path] | |
| 275 | + if (parentTitle) { | |
| 276 | + list.push({ title: parentTitle, path: '' }) | |
| 277 | + } | |
| 278 | + if (route.meta && route.meta.title) { | |
| 279 | + list.push({ title: route.meta.title as string, path: route.path }) | |
| 280 | + } | |
| 281 | + return list | |
| 261 | 282 | }) |
| 262 | 283 | |
| 263 | 284 | const isFullscreen = ref(false) |
| ... | ... | @@ -297,6 +318,7 @@ function handleLogout() { |
| 297 | 318 | grid-template-columns: 280px minmax(0, 1fr); |
| 298 | 319 | gap: 16px; |
| 299 | 320 | padding: 16px; |
| 321 | + transition: grid-template-columns 0.35s cubic-bezier(0.25, 0.8, 0.25, 1); | |
| 300 | 322 | } |
| 301 | 323 | |
| 302 | 324 | .layout-shell.collapsed { |
| ... | ... | @@ -320,6 +342,7 @@ function handleLogout() { |
| 320 | 342 | display: flex; |
| 321 | 343 | flex-direction: column; |
| 322 | 344 | overflow: hidden; |
| 345 | + transition: all 0.35s cubic-bezier(0.25, 0.8, 0.25, 1); | |
| 323 | 346 | } |
| 324 | 347 | |
| 325 | 348 | .menu-scroll { |
| ... | ... | @@ -355,7 +378,7 @@ function handleLogout() { |
| 355 | 378 | border-radius: 12px; |
| 356 | 379 | border: none; |
| 357 | 380 | background: var(--line-strong); |
| 358 | - color: var(--soft-primary); | |
| 381 | + color: var(--brand); | |
| 359 | 382 | cursor: pointer; |
| 360 | 383 | margin-bottom: 12px; |
| 361 | 384 | } |
| ... | ... | @@ -576,9 +599,54 @@ h1 { |
| 576 | 599 | gap: 16px; |
| 577 | 600 | } |
| 578 | 601 | |
| 579 | -.topbar-header-info h1 { | |
| 580 | - margin: 2px 0 0; | |
| 581 | - font-size: 20px; | |
| 602 | +.topbar-header-info { | |
| 603 | + display: flex; | |
| 604 | + align-items: center; | |
| 605 | + height: 40px; | |
| 606 | +} | |
| 607 | + | |
| 608 | +:deep(.custom-breadcrumb) { | |
| 609 | + display: flex; | |
| 610 | + align-items: center; | |
| 611 | + margin-bottom: 0; | |
| 612 | +} | |
| 613 | + | |
| 614 | +:deep(.custom-breadcrumb li) { | |
| 615 | + display: inline-flex; | |
| 616 | + align-items: center; | |
| 617 | +} | |
| 618 | + | |
| 619 | +.bc-separator { | |
| 620 | + font-size: 11px; | |
| 621 | + opacity: 0.6; | |
| 622 | + color: var(--text-soft); | |
| 623 | + margin: 0 4px; | |
| 624 | +} | |
| 625 | + | |
| 626 | +.bc-parent { | |
| 627 | + color: var(--text-soft) !important; | |
| 628 | + font-size: 14px; | |
| 629 | +} | |
| 630 | + | |
| 631 | +.bc-last { | |
| 632 | + font-size: 18px; | |
| 633 | + font-weight: 600; | |
| 634 | + color: var(--text-main) !important; | |
| 635 | + letter-spacing: 0.5px; | |
| 636 | +} | |
| 637 | + | |
| 638 | +/* Breadcrumb transition */ | |
| 639 | +.breadcrumb-fade-enter-active, | |
| 640 | +.breadcrumb-fade-leave-active { | |
| 641 | + transition: all 0.25s cubic-bezier(0.25, 0.8, 0.25, 1); | |
| 642 | +} | |
| 643 | +.breadcrumb-fade-enter-from { | |
| 644 | + opacity: 0; | |
| 645 | + transform: translateX(10px); | |
| 646 | +} | |
| 647 | +.breadcrumb-fade-leave-to { | |
| 648 | + opacity: 0; | |
| 649 | + transform: translateX(-10px); | |
| 582 | 650 | } |
| 583 | 651 | |
| 584 | 652 | .header-action-group { |
| ... | ... | @@ -609,12 +677,18 @@ h1 { |
| 609 | 677 | padding: 12px 16px 24px; |
| 610 | 678 | } |
| 611 | 679 | |
| 612 | -:deep(.ant-breadcrumb) { | |
| 613 | - font-size: 11px; | |
| 614 | -} | |
| 615 | 680 | |
| 616 | -:deep(.ant-breadcrumb-link), :deep(.ant-breadcrumb-separator) { | |
| 617 | - color: var(--soft-subtext) !important; | |
| 681 | +.fade-slide-enter-active, | |
| 682 | +.fade-slide-leave-active { | |
| 683 | + transition: all 0.25s cubic-bezier(0.25, 0.8, 0.25, 1); | |
| 684 | +} | |
| 685 | +.fade-slide-enter-from { | |
| 686 | + opacity: 0; | |
| 687 | + transform: translateY(10px); | |
| 688 | +} | |
| 689 | +.fade-slide-leave-to { | |
| 690 | + opacity: 0; | |
| 691 | + transform: translateY(-10px); | |
| 618 | 692 | } |
| 619 | 693 | |
| 620 | 694 | @media (max-width: 960px) { | ... | ... |
src/style.css
| ... | ... | @@ -143,7 +143,7 @@ a { |
| 143 | 143 | |
| 144 | 144 | .ant-table-wrapper .ant-table-container { |
| 145 | 145 | border-radius: var(--radius-md); |
| 146 | - border: 1px solid rgba(194, 185, 239, 0.22); | |
| 146 | + border: 1px solid var(--line); | |
| 147 | 147 | overflow: hidden; |
| 148 | 148 | } |
| 149 | 149 | |
| ... | ... | @@ -338,6 +338,7 @@ a { |
| 338 | 338 | margin-block: 4px !important; |
| 339 | 339 | width: calc(100% - 16px) !important; |
| 340 | 340 | font-size: var(--font-size-md) !important; |
| 341 | + color: var(--text-main); | |
| 341 | 342 | } |
| 342 | 343 | |
| 343 | 344 | .ant-form-item { |
| ... | ... | @@ -351,11 +352,10 @@ a { |
| 351 | 352 | font-size: var(--font-size-md); |
| 352 | 353 | } |
| 353 | 354 | |
| 354 | -.ant-menu-light .ant-menu-item-selected, | |
| 355 | -.ant-menu-light > .ant-menu .ant-menu-item-selected, | |
| 356 | -.ant-menu-light .ant-menu-submenu-selected > .ant-menu-submenu-title { | |
| 357 | - background: linear-gradient(135deg, rgba(140, 124, 240, 0.18), rgba(255, 212, 235, 0.3)) !important; | |
| 358 | - color: var(--brand-deep) !important; | |
| 355 | +.ant-menu-item-selected, | |
| 356 | +.ant-menu-submenu-selected > .ant-menu-submenu-title { | |
| 357 | + background: var(--panel-tint) !important; | |
| 358 | + color: var(--brand) !important; | |
| 359 | 359 | } |
| 360 | 360 | |
| 361 | 361 | .ant-menu-submenu-popup .ant-menu { |
| ... | ... | @@ -384,15 +384,15 @@ a { |
| 384 | 384 | |
| 385 | 385 | .ant-menu-item:hover, |
| 386 | 386 | .ant-menu-submenu-title:hover { |
| 387 | - color: var(--brand-deep) !important; | |
| 387 | + color: var(--brand) !important; | |
| 388 | 388 | background: var(--line) !important; |
| 389 | 389 | } |
| 390 | 390 | |
| 391 | 391 | .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) { |
| 392 | - color: var(--brand-deep); | |
| 392 | + color: var(--brand); | |
| 393 | 393 | background: var(--panel-strong); |
| 394 | - border-color: rgba(140, 124, 240, 0.45); | |
| 395 | - box-shadow: 0 8px 18px rgba(140, 124, 240, 0.12); | |
| 394 | + border-color: var(--brand); | |
| 395 | + box-shadow: var(--shadow-sm); | |
| 396 | 396 | } |
| 397 | 397 | |
| 398 | 398 | .ant-empty { | ... | ... |
src/views/config/FeePlanList.vue
| ... | ... | @@ -913,8 +913,8 @@ onMounted(loadCities) |
| 913 | 913 | min-height: 36px; |
| 914 | 914 | padding: 0 14px; |
| 915 | 915 | border-radius: 999px; |
| 916 | - border: 1px solid rgba(194, 185, 239, 0.28); | |
| 917 | - background: rgba(246, 242, 255, 0.84); | |
| 916 | + border: 1px solid var(--line); | |
| 917 | + background: var(--panel-strong); | |
| 918 | 918 | } |
| 919 | 919 | |
| 920 | 920 | .plan-list { |
| ... | ... | @@ -985,7 +985,7 @@ onMounted(loadCities) |
| 985 | 985 | border: none; |
| 986 | 986 | border-radius: 12px; |
| 987 | 987 | background: linear-gradient(135deg, #8c7cf0, #a98ff7 55%, #e5b5dc); |
| 988 | - box-shadow: 0 8px 18px rgba(140, 124, 240, 0.18); | |
| 988 | + box-shadow: var(--shadow-sm); | |
| 989 | 989 | } |
| 990 | 990 | |
| 991 | 991 | .plan-save-button:hover, |
| ... | ... | @@ -1018,9 +1018,9 @@ onMounted(loadCities) |
| 1018 | 1018 | min-height: 26px; |
| 1019 | 1019 | padding: 0 12px; |
| 1020 | 1020 | border-radius: 999px; |
| 1021 | - background: rgba(246, 242, 255, 0.95); | |
| 1022 | - border: 1px solid rgba(140, 124, 240, 0.18); | |
| 1023 | - color: #7f6de5; | |
| 1021 | + background: var(--panel-strong); | |
| 1022 | + border: 1px solid var(--line-strong); | |
| 1023 | + color: var(--brand); | |
| 1024 | 1024 | font-size: 12px; |
| 1025 | 1025 | font-weight: 700; |
| 1026 | 1026 | } |
| ... | ... | @@ -1049,7 +1049,8 @@ onMounted(loadCities) |
| 1049 | 1049 | |
| 1050 | 1050 | .preview-card { |
| 1051 | 1051 | border-radius: 16px; |
| 1052 | - background: #fafbff; | |
| 1052 | + background: var(--panel-strong); | |
| 1053 | + border: 1px solid var(--line); | |
| 1053 | 1054 | } |
| 1054 | 1055 | |
| 1055 | 1056 | .preview-subtitle { | ... | ... |
src/views/dispatch/DispatchRuleList.vue
| ... | ... | @@ -672,7 +672,7 @@ onMounted(loadCities) |
| 672 | 672 | border: none; |
| 673 | 673 | border-radius: 12px; |
| 674 | 674 | background: linear-gradient(135deg, #8c7cf0, #a98ff7 55%, #e5b5dc); |
| 675 | - box-shadow: 0 8px 18px rgba(140, 124, 240, 0.18); | |
| 675 | + box-shadow: var(--shadow-sm); | |
| 676 | 676 | } |
| 677 | 677 | |
| 678 | 678 | .plan-save-button:hover, |
| ... | ... | @@ -701,9 +701,9 @@ onMounted(loadCities) |
| 701 | 701 | min-height: 26px; |
| 702 | 702 | padding: 0 12px; |
| 703 | 703 | border-radius: 999px; |
| 704 | - background: rgba(246, 242, 255, 0.95); | |
| 705 | - border: 1px solid rgba(140, 124, 240, 0.18); | |
| 706 | - color: #7f6de5; | |
| 704 | + background: var(--panel-strong); | |
| 705 | + border: 1px solid var(--line-strong); | |
| 706 | + color: var(--brand); | |
| 707 | 707 | font-size: 12px; |
| 708 | 708 | font-weight: 700; |
| 709 | 709 | } |
| ... | ... | @@ -796,13 +796,13 @@ onMounted(loadCities) |
| 796 | 796 | |
| 797 | 797 | :deep(.grab-scope-option-checked .grab-scope-card), |
| 798 | 798 | :deep(.grab-scope-option.ant-radio-wrapper-checked .grab-scope-card) { |
| 799 | - border-color: rgba(140, 124, 240, 0.5); | |
| 800 | - background: rgba(246, 242, 255, 0.96); | |
| 801 | - box-shadow: 0 10px 24px rgba(140, 124, 240, 0.12); | |
| 799 | + border-color: var(--brand); | |
| 800 | + background: var(--panel-tint); | |
| 801 | + box-shadow: var(--shadow-sm); | |
| 802 | 802 | } |
| 803 | 803 | |
| 804 | 804 | :deep(.grab-scope-option:hover .grab-scope-card) { |
| 805 | - border-color: rgba(140, 124, 240, 0.34); | |
| 805 | + border-color: var(--brand); | |
| 806 | 806 | } |
| 807 | 807 | |
| 808 | 808 | .dispatch-condition-list { |
| ... | ... | @@ -835,9 +835,9 @@ onMounted(loadCities) |
| 835 | 835 | font-family: var(--font-display); |
| 836 | 836 | font-size: 18px; |
| 837 | 837 | font-weight: 700; |
| 838 | - color: #7f6de5; | |
| 839 | - background: rgba(246, 242, 255, 0.92); | |
| 840 | - border: 1px solid rgba(140, 124, 240, 0.18); | |
| 838 | + color: var(--brand); | |
| 839 | + background: var(--panel-strong); | |
| 840 | + border: 1px solid var(--line-strong); | |
| 841 | 841 | } |
| 842 | 842 | |
| 843 | 843 | .dispatch-condition-content { |
| ... | ... | @@ -871,7 +871,7 @@ onMounted(loadCities) |
| 871 | 871 | .dispatch-condition-body { |
| 872 | 872 | margin-top: 14px; |
| 873 | 873 | padding-top: 14px; |
| 874 | - border-top: 1px dashed rgba(194, 185, 239, 0.36); | |
| 874 | + border-top: 1px dashed var(--line); | |
| 875 | 875 | } |
| 876 | 876 | |
| 877 | 877 | .dispatch-condition-input { | ... | ... |
src/views/open/OpenMockDelivery.vue