This commit is contained in:
Your Name
2026-06-15 09:12:15 +08:00
parent 8ae5b4eead
commit 4ba75e5a94
304 changed files with 382 additions and 510 deletions
+2 -2
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>后台管理系统</title>
<title>中医问诊管理后台</title>
<style>
* {
margin: 0;
@@ -29,7 +29,7 @@
stroke-dasharray: 90, 150;
stroke-dashoffset: 0;
stroke-width: 2;
stroke: #4073fa;
stroke: #0EA5E9;
stroke-linecap: round;
}
+15 -12
View File
@@ -1,28 +1,31 @@
const defaultSetting = {
showCrumb: true, // 是否显示面包屑
showLogo: false, // 是否显示logo
showLogo: true, // 是否显示logo
isUniqueOpened: true, //只展开一个一级菜单
sideWidth: 183, //侧边栏宽度
sideTheme: 'dark', //侧边栏主题
sideDarkColor: '#1d2124', //侧边栏深色主题颜色
sideWidth: 200, //侧边栏宽度
sideTheme: 'light', //侧边栏主题
sideDarkColor: '#0369A1', //侧边栏深色主题颜色(深天蓝)
openMultipleTabs: true, // 是否开启多标签tab栏
theme: '#4A5DFF', //主题色
successTheme: '#67c23a', //成功主题色
warningTheme: '#e6a23c', //警告主题色
dangerTheme: '#f56c6c', //危险主题色
errorTheme: '#f56c6c', //错误主题色
infoTheme: '#909399' //信息主题色
theme: '#0EA5E9', //主题色(天蓝)
successTheme: '#16A34A', //成功主题色
warningTheme: '#D97706', //警告主题色
dangerTheme: '#DC2626', //危险主题色
errorTheme: '#DC2626', //错误主题色
infoTheme: '#64748B' //信息主题色
}
/** 本地 setting 缓存结构版本。提升后仅对低于该版本的老缓存执行 SETTING_SCHEMA_MIGRATIONS */
export const SETTING_SCHEMA_VERSION = 1
export const SETTING_SCHEMA_VERSION = 4
/**
* 按版本写入 defaultSetting 中的键(老用户 localStorage 会长期盖住 config 默认值)。
* 以后若要再推一批新默认值:把 SETTING_SCHEMA_VERSION +1,并为本版本追加一条迁移键列表。
*/
export const SETTING_SCHEMA_MIGRATIONS: Record<number, (keyof typeof defaultSetting)[]> = {
1: ['sideTheme', 'sideDarkColor']
1: ['sideTheme', 'sideDarkColor'],
2: ['theme', 'successTheme', 'warningTheme', 'dangerTheme', 'errorTheme', 'infoTheme', 'sideTheme', 'sideDarkColor', 'showLogo', 'sideWidth'],
3: ['theme', 'sideTheme', 'sideDarkColor', 'sideWidth'],
4: ['theme', 'sideDarkColor']
}
export default defaultSetting
@@ -26,17 +26,19 @@ useWatchRoute((route) => {
.app-breadcrumb {
:deep(.el-breadcrumb__item) {
.el-breadcrumb__inner {
color: #303133;
color: var(--el-text-color-regular);
font-weight: 400;
transition: color 0.2s ease;
}
&:last-child .el-breadcrumb__inner {
color: var(--health-primary-dark, var(--el-color-primary));
font-weight: 500;
}
&:last-child .el-breadcrumb__inner {
color: #303133;
}
}
:deep(.el-breadcrumb__separator) {
color: #606266;
color: var(--el-text-color-secondary);
}
}
</style>
@@ -1,8 +1,14 @@
<template>
<header class="header">
<div class="navbar">
<div class="flex-1 flex">
<div class="navbar-item">
<div class="navbar-left flex-1 flex items-center min-w-0">
<side-logo
v-if="settingStore.showLogo"
class="navbar-logo shrink-0"
:show-title="!isCollapsed || isMobile"
theme="light"
/>
<div class="navbar-item shrink-0">
<el-tooltip
class="box-item"
effect="dark"
@@ -12,16 +18,19 @@
<fold />
</el-tooltip>
</div>
<div class="navbar-item">
<div class="navbar-item shrink-0">
<el-tooltip class="box-item" effect="dark" content="刷新" placement="bottom">
<refresh />
</el-tooltip>
</div>
<div class="flex items-center px-2" v-if="!isMobile && settingStore.showCrumb">
<div
class="flex items-center px-2 min-w-0"
v-if="!isMobile && settingStore.showCrumb"
>
<breadcrumb />
</div>
</div>
<div class="flex">
<div class="navbar-right flex shrink-0">
<div class="navbar-item" v-if="!isMobile">
<el-tooltip
class="box-item"
@@ -47,7 +56,6 @@
</div>
</div>
</div>
<multiple-tabs v-if="settingStore.openMultipleTabs" />
</header>
</template>
@@ -57,11 +65,11 @@ import { useFullscreen } from '@vueuse/core'
import useAppStore from '@/stores/modules/app'
import useSettingStore from '@/stores/modules/setting'
import SideLogo from '../sidebar/logo.vue'
import Setting from '../setting/index.vue'
import Breadcrumb from './breadcrumb.vue'
import Fold from './fold.vue'
import FullScreen from './full-screen.vue'
import MultipleTabs from './multiple-tabs.vue'
import Refresh from './refresh.vue'
import UserDropDown from './user-drop-down.vue'
@@ -73,11 +81,31 @@ const { isFullscreen } = useFullscreen()
</script>
<style lang="scss">
.header {
background: var(--el-bg-color);
border-bottom: 1px solid var(--health-border, var(--el-border-color-lighter));
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.03);
}
.navbar {
height: var(--navbar-height);
@apply flex px-2 bg-body;
@apply flex px-4;
.navbar-logo {
margin-right: 4px;
border-bottom: none !important;
padding-right: 8px !important;
}
.navbar-item {
@apply h-full flex justify-center items-center hover:bg-page;
@apply h-10 flex justify-center items-center cursor-pointer;
min-width: 40px;
border-radius: 8px;
transition: background-color 0.2s ease;
&:hover {
background-color: var(--el-fill-color);
}
}
}
</style>
@@ -1,5 +1,5 @@
<template>
<div class="app-tabs pl-4 flex bg-body">
<div class="app-tabs flex bg-body">
<div class="flex-1 min-w-0">
<el-tabs
:model-value="currentTab"
@@ -13,7 +13,7 @@
</el-tabs>
</div>
<el-dropdown @command="handleCommand">
<span class="flex items-center px-3">
<span class="flex items-center px-3 cursor-pointer tab-dropdown">
<icon :size="16" name="el-icon-arrow-down" />
</span>
<template #dropdown>
@@ -58,9 +58,22 @@ const handleCommand = (command: any) => {
}
}
</script>
<style lang="scss" scoped>
.app-tabs {
@apply border-t border-br;
padding: 0 16px;
background: var(--el-bg-color);
border-bottom: 1px solid var(--health-border, var(--el-border-color-lighter));
.tab-dropdown {
height: 40px;
border-radius: 6px;
transition: background-color 0.2s ease;
&:hover {
background-color: var(--el-fill-color);
}
}
:deep(.el-tabs) {
height: 40px;
.el-tabs {
@@ -80,35 +93,19 @@ const handleCommand = (command: any) => {
}
&__item {
font-weight: normal;
padding: 0 15px !important;
padding: 0 16px !important;
box-sizing: border-box;
color: var(--el-text-color-secondary);
transition: color 0.2s ease;
&.is-active {
color: var(--el-text-color-primary);
background-color: var(--el-color-primary-light-9);
&::before {
content: '';
display: inline-block;
width: 6px;
height: 6px;
background-color: var(--el-color-primary);
margin-right: 6px;
border-radius: 50%;
vertical-align: 2px;
}
&::after {
position: absolute;
content: '';
display: block;
top: 0;
height: 2px;
left: 0;
width: 100%;
background-color: var(--el-color-primary);
}
color: var(--health-primary-dark, var(--el-color-primary));
font-weight: 500;
}
.is-icon-close {
color: var(--el-text-color-regular);
color: var(--el-text-color-secondary);
vertical-align: -2px;
border-radius: 50%;
transition: all 0.2s ease;
&:hover {
color: var(--color-white);
background-color: var(--el-color-danger);
@@ -116,7 +113,9 @@ const handleCommand = (command: any) => {
}
}
&__active-bar {
display: none;
height: 2px;
border-radius: 2px;
background-color: var(--health-primary, var(--el-color-primary));
}
}
}
+13 -3
View File
@@ -1,7 +1,7 @@
<template>
<main class="main-wrap h-full bg-page">
<main class="main-wrap h-full">
<el-scrollbar>
<div class="px-2 py-4">
<div class="main-content">
<router-view v-if="isRouteShow" v-slot="{ Component, route }">
<keep-alive :include="includeList" :max="20">
<component :is="Component" :key="route.fullPath" />
@@ -24,4 +24,14 @@ const isRouteShow = computed(() => appStore.isRouteShow)
const includeList = computed(() => (settingStore.openMultipleTabs ? tabsStore.getCacheTabList : []))
</script>
<style></style>
<style lang="scss" scoped>
.main-wrap {
height: 100%;
background: var(--el-bg-color);
}
.main-content {
padding: 16px 20px 24px;
min-height: 100%;
}
</style>
@@ -100,7 +100,7 @@ import theme_light from '@/assets/images/theme_white.png'
import useSettingStore from '@/stores/modules/setting'
const settingStore = useSettingStore()
const predefineColors = ref(['#409EFF', '#28C76F', '#EA5455', '#FF9F43', '#01CFE8', '#4A5DFF'])
const predefineColors = ref(['#0EA5E9', '#38BDF8', '#0284C7', '#16A34A', '#DC2626', '#0369A1'])
const sideThemeList = [
{
type: 'dark',
@@ -44,11 +44,13 @@ const handleClick = () => {
overflow: hidden;
cursor: pointer;
user-select: none;
@apply flex items-center p-2 relative;
@apply flex items-center px-3 relative;
.logo-title {
width: 70%;
position: absolute;
@apply text-xl;
@apply text-base font-medium;
color: var(--el-text-color-primary);
}
.title-width-enter-active {
@@ -67,33 +67,53 @@ const themeClass = computed(() => `theme-${props.theme}`)
&.theme-dark {
.el-menu {
:deep(.el-menu-item) {
margin: 2px 10px;
border-radius: 6px;
&.is-active {
@apply bg-primary border-primary;
background-color: rgba(255, 255, 255, 0.12);
color: #fff;
font-weight: 500;
}
}
:deep(.el-sub-menu__title) {
margin: 2px 10px;
border-radius: 6px;
}
}
:deep(.el-menu--collapse) {
.el-sub-menu.is-active .el-sub-menu__title {
@apply bg-primary #{!important};
background-color: rgba(255, 255, 255, 0.12) !important;
}
}
}
&.theme-light {
:deep(.el-menu) {
.el-menu-item {
border-color: transparent;
margin: 2px 10px;
border-radius: 6px;
color: var(--el-text-color-regular);
&.is-active {
@apply bg-primary-light-9 border-r-2 border-primary;
background-color: var(--health-primary-light, var(--el-color-primary-light-9));
color: var(--health-primary-dark, var(--el-color-primary));
font-weight: 500;
}
}
.el-sub-menu__title {
margin: 2px 10px;
border-radius: 6px;
color: var(--el-text-color-regular);
}
.el-menu-item:hover,
.el-sub-menu__title:hover {
color: var(--el-color-primary);
background-color: var(--el-fill-color);
color: var(--el-text-color-primary);
}
}
}
.el-menu {
border-right: none;
background: transparent;
padding: 10px 0;
&:not(.el-menu--collapse) {
width: var(--aside-width);
}
@@ -1,6 +1,10 @@
<template>
<div class="side" :style="sideStyle">
<side-logo v-if="settingStore.showLogo" :show-title="!isCollapsed" :theme="sideTheme" />
<side-logo
v-if="settingStore.showLogo && appStore.isMobile"
:show-title="!isCollapsed"
:theme="sideTheme"
/>
<side-menu
:routes="routes"
:is-collapsed="isCollapsed"
@@ -45,9 +49,9 @@ const sideStyle = computed(() => {
})
const menuProp = computed(() => {
return {
backgroundColor: sideTheme.value == 'dark' ? settingStore.sideDarkColor : '',
textColor: sideTheme.value == 'dark' ? 'var(--el-color-white)' : '',
activeTextColor: sideTheme.value == 'dark' ? 'var(--el-color-white)' : ''
backgroundColor: sideTheme.value == 'dark' ? settingStore.sideDarkColor : 'transparent',
textColor: sideTheme.value == 'dark' ? 'rgba(255,255,255,0.85)' : '',
activeTextColor: sideTheme.value == 'dark' ? '#ffffff' : ''
}
})
const handleSelect = () => {
@@ -60,8 +64,8 @@ const handleSelect = () => {
<style lang="scss" scoped>
.side {
position: relative;
z-index: 999;
@apply border-r border-br-light h-full flex flex-col;
background-color: var(--side-dark-color, var(--el-bg-color));
z-index: 10;
@apply h-full flex flex-col;
background-color: var(--side-dark-color, var(--health-bg-sidebar, var(--el-bg-color)));
}
</style>
+28 -9
View File
@@ -1,23 +1,42 @@
<template>
<div class="layout-default flex h-screen w-full">
<!-- shrink-0避免主内容区宽表格/图表把侧栏压缩到折叠宽度 -->
<div class="app-aside shrink-0">
<layout-sidebar />
<div class="layout-default flex flex-col h-screen w-full bg-page">
<div class="app-header shrink-0">
<layout-header />
</div>
<div class="flex-1 flex flex-col min-w-0">
<div class="app-header">
<layout-header />
<div class="layout-body flex flex-1 min-h-0">
<div class="app-aside shrink-0">
<layout-sidebar />
</div>
<div class="app-main flex-1 min-h-0">
<layout-main />
<div class="app-content flex flex-1 flex-col min-w-0 bg-body">
<multiple-tabs v-if="settingStore.openMultipleTabs" />
<div class="app-main flex-1 min-h-0">
<layout-main />
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import useSettingStore from '@/stores/modules/setting'
import LayoutHeader from './components/header/index.vue'
import MultipleTabs from './components/header/multiple-tabs.vue'
import LayoutMain from './components/main.vue'
import LayoutSidebar from './components/sidebar/index.vue'
const settingStore = useSettingStore()
</script>
<style lang="scss" scoped>
.layout-body {
flex: 1;
min-height: 0;
}
.app-content {
border-left: 1px solid var(--health-border, var(--el-border-color-lighter));
}
</style>
+34 -31
View File
@@ -1,43 +1,46 @@
:root.dark {
color-scheme: dark;
--table-header-bg-color: var(--el-bg-color);
--el-bg-color-page: #0a0a0a;
--el-bg-color: #1d2124;
--el-bg-color-overlay: #1d1e1f;
--el-text-color-primary: #e5eaf3;
--el-text-color-regular: #cfd3dc;
--el-text-color-secondary: #a3a6ad;
--el-text-color-placeholder: #8d9095;
--el-text-color-disabled: #6c6e72;
--el-border-color-darker: #636466;
--el-border-color-dark: #58585b;
--el-border-color: #4c4d4f;
--el-border-color-light: #414243;
--el-border-color-lighter: #363637;
--el-border-color-extra-light: #2b2b2c;
--el-fill-color-darker: #424243;
--el-fill-color-dark: #39393a;
--el-fill-color: #303030;
--el-fill-color-light: #262727;
--el-fill-color-lighter: #1d1d1d;
--el-fill-color-extra-light: #191919;
--table-header-bg-color: #1E293B;
--health-bg-page: #0F1419;
--health-bg-sidebar: #151B23;
--health-text-primary: #F1F5F9;
--health-text-secondary: #94A3B8;
--health-border: #334155;
--health-border-light: #1E293B;
--health-primary-light: rgba(14, 165, 233, 0.15);
--el-bg-color-page: var(--health-bg-page);
--el-bg-color: #151B23;
--el-bg-color-overlay: #1E293B;
--el-text-color-primary: var(--health-text-primary);
--el-text-color-regular: #CBD5E1;
--el-text-color-secondary: #94A3B8;
--el-text-color-placeholder: #64748B;
--el-text-color-disabled: #475569;
--el-border-color-darker: #475569;
--el-border-color-dark: #334155;
--el-border-color: #334155;
--el-border-color-light: #334155;
--el-border-color-lighter: #1E293B;
--el-border-color-extra-light: #151B23;
--el-fill-color-darker: #334155;
--el-fill-color-dark: #1E293B;
--el-fill-color: #1E293B;
--el-fill-color-light: #151B23;
--el-fill-color-lighter: #0F1419;
--el-fill-color-extra-light: #1E293B;
--el-fill-color-blank: var(--el-bg-color);
--el-mask-color: rgba(0, 0, 0, 0.8);
--el-mask-color-extra-light: rgba(0, 0, 0, 0.3);
--el-box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, 0.36), 0px 8px 20px rgba(0, 0, 0, 0.72);
--el-box-shadow-light: 0px 0px 12px rgba(0, 0, 0, 0.72);
--el-box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, 0.72);
--el-box-shadow-dark: 0px 16px 48px 16px rgba(0, 0, 0, 0.72), 0px 12px 32px #000000,
0px 8px 16px -8px #000000 !important;
/* wangeditor主题 */
--el-mask-color: rgba(0, 0, 0, 0.72);
--el-mask-color-extra-light: rgba(0, 0, 0, 0.36);
--el-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
--el-box-shadow-light: 0 1px 4px rgba(0, 0, 0, 0.25);
--el-box-shadow-lighter: 0 1px 2px rgba(0, 0, 0, 0.2);
--el-box-shadow-dark: 0 4px 16px rgba(0, 0, 0, 0.4);
--w-e-textarea-bg-color: var(--el-bg-color);
--w-e-textarea-color: var(--el-text-color-primary);
--w-e-textarea-border-color: var(--el-border-color);
--w-e-textarea-slight-border-color: var(--el-border-color-light);
--w-e-textarea-slight-color: var(--el-border-color);
--w-e-textarea-slight-bg-color: var(--el-bg-color-page);
/* --w-e-textarea-selected-border-color: #b4d5ff;
--w-e-textarea-handler-bg-color: #4290f7; */
--w-e-toolbar-color: var(--el-text-color-primary);
--w-e-toolbar-bg-color: var(--el-bg-color);
--w-e-toolbar-active-color: var(--el-text-color-primary);
+30 -6
View File
@@ -23,7 +23,7 @@
flex: none;
display: flex;
flex-direction: column;
border-radius: 5px;
border-radius: 8px;
&.body-padding .el-dialog__body {
padding: 0;
@@ -56,17 +56,27 @@
}
.el-table {
--el-table-header-text-color: var(--el-text-color-primary);
--el-table-header-text-color: var(--el-text-color-regular);
--el-table-header-bg-color: var(--table-header-bg-color);
--el-table-border-color: var(--health-border, var(--el-border-color-lighter));
--el-table-row-hover-bg-color: var(--el-fill-color-light);
font-size: var(--el-font-size-base);
border-radius: 8px;
overflow: hidden;
thead {
th {
font-weight: 400;
font-weight: 500;
}
}
}
.el-card {
border-radius: 8px;
border-color: var(--health-border, var(--el-border-color-lighter));
box-shadow: none;
}
.el-input-group__prepend {
background-color: var(--el-fill-color-blank);
}
@@ -78,22 +88,30 @@
.el-menu--popup-container {
&.theme-light {
.el-menu {
border-radius: 8px;
padding: 4px;
.el-menu-item {
border-radius: 6px;
&.is-active {
@apply bg-primary-light-9 border-primary border-r-2;
background-color: var(--health-primary-light, var(--el-color-primary-light-9));
color: var(--health-primary-dark, var(--el-color-primary));
font-weight: 500;
}
}
.el-menu-item:hover,
.el-sub-menu__title:hover {
color: var(--el-color-primary);
background-color: var(--el-fill-color-light);
}
}
}
&.theme-dark {
.el-menu {
border-radius: 8px;
padding: 4px;
.el-menu-item {
border-radius: 6px;
&.is-active {
@apply bg-primary;
background-color: rgba(255, 255, 255, 0.12);
}
}
}
@@ -110,6 +128,12 @@
}
}
.el-button {
border-radius: 6px;
font-weight: 500;
transition: all 0.2s ease;
}
.el-button--primary {
--el-button-hover-link-text-color: var(--el-color-primary-light-3);
}
+11
View File
@@ -1,6 +1,12 @@
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap');
body {
@apply text-base text-tx-primary overflow-hidden min-w-[375px];
font-feature-settings: 'tnum' 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.form-tips {
@apply text-tx-secondary text-xs leading-6 mt-1;
}
@@ -15,4 +21,9 @@ body {
/* NProgress */
#nprogress .bar {
@apply bg-primary #{!important};
height: 3px !important;
}
#nprogress .peg {
box-shadow: 0 0 8px var(--el-color-primary), 0 0 4px var(--el-color-primary) !important;
}
+40 -31
View File
@@ -1,49 +1,58 @@
:root {
--el-font-family: theme(fontFamily.sans);
--el-font-weight-primary: 400;
--el-menu-item-height: 46px;
--el-menu-item-height: 42px;
--el-menu-sub-item-height: var(--el-menu-item-height);
--el-menu-icon-width: 18px;
--aside-width: 200px;
--navbar-height: 50px;
--navbar-height: 52px;
--color-white: #ffffff;
--table-header-bg-color: #f8f8f8;
--table-header-bg-color: #F8FAFC;
--el-font-size-extra-large: 18px;
--el-menu-base-level-padding: 16px;
--el-menu-level-padding: 26px;
--el-menu-base-level-padding: 14px;
--el-menu-level-padding: 24px;
--el-font-size-large: 16px;
--el-font-size-medium: 15px;
--el-font-size-base: 14px;
--el-font-size-small: 13px;
--el-font-size-extra-small: 12px;
/* 天蓝点缀 + 中性底色(天蓝仅用于主色/激活态,不铺满全局) */
--health-primary: #0EA5E9;
--health-primary-light: #E0F2FE;
--health-primary-dark: #0284C7;
--health-bg-page: #F1F5F9;
--health-bg-sidebar: #FFFFFF;
--health-text-primary: #1E293B;
--health-text-secondary: #64748B;
--health-border: #E2E8F0;
--health-border-light: #EEF2F6;
--el-bg-color: var(--color-white);
--el-bg-color-page: #f6f6f6;
--el-bg-color-page: var(--health-bg-page);
--el-bg-color-overlay: #ffffff;
--el-text-color-primary: #333333;
--el-text-color-regular: #666666;
--el-text-color-secondary: #999999;
--el-text-color-placeholder: #a8abb2;
--el-text-color-disabled: #c0c4cc;
--el-border-color: #dcdfe6;
--el-border-color-light: #e4e7ed;
--el-border-color-lighter: #ebeef5;
--el-border-color-extra-light: #f2f2f2;
--el-border-color-dark: #d4d7de;
--el-border-color-darker: #cdd0d6;
--el-fill-color: #f0f2f5;
--el-fill-color-light: #f8f8f8;
--el-fill-color-lighter: #fafafa;
--el-fill-color-extra-light: #fafcff;
--el-fill-color-dark: #ebedf0;
--el-fill-color-darker: #e6e8eb;
--el-text-color-primary: var(--health-text-primary);
--el-text-color-regular: var(--health-text-secondary);
--el-text-color-secondary: #94A3B8;
--el-text-color-placeholder: #94A3B8;
--el-text-color-disabled: #CBD5E1;
--el-border-color: var(--health-border);
--el-border-color-light: var(--health-border);
--el-border-color-lighter: var(--health-border-light);
--el-border-color-extra-light: #F8FAFC;
--el-border-color-dark: #CBD5E1;
--el-border-color-darker: #94A3B8;
--el-fill-color: #F1F5F9;
--el-fill-color-light: #F8FAFC;
--el-fill-color-lighter: #FAFBFC;
--el-fill-color-extra-light: #F8FAFC;
--el-fill-color-dark: #E2E8F0;
--el-fill-color-darker: #CBD5E1;
--el-fill-color-blank: #ffffff;
/* 过亮会盖住抽屉/弹窗下的内容;Element Loading 与部分蒙层共用此变量 */
--el-mask-color: rgba(255, 255, 255, 0.5);
--el-mask-color-extra-light: rgba(255, 255, 255, 0.22);
-el-box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, 0.04), 0px 8px 20px rgba(0, 0, 0, 0.08);
--el-box-shadow-light: 0px 0px 12px rgba(0, 0, 0, 0.12);
--el-box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, 0.12);
--el-box-shadow-dark: 0px 16px 48px 16px rgba(0, 0, 0, 0.08), 0px 12px 32px rgba(0, 0, 0, 0.12),
0px 8px 16px -8px rgba(0, 0, 0, 0.16);
--el-mask-color: rgba(255, 255, 255, 0.65);
--el-mask-color-extra-light: rgba(255, 255, 255, 0.28);
--el-box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
--el-box-shadow-light: 0 1px 3px rgba(15, 23, 42, 0.06);
--el-box-shadow-lighter: 0 1px 2px rgba(15, 23, 42, 0.04);
--el-box-shadow-dark: 0 4px 12px rgba(15, 23, 42, 0.08);
}
+78 -8
View File
@@ -1,14 +1,27 @@
<template>
<div class="login flex flex-col">
<div class="flex-1 flex items-center justify-center">
<div class="login-card flex rounded-md overflow-hidden">
<div class="flex-1 h-full hidden md:inline-block">
<image-contain :src="config.login_image" :width="400" height="100%" />
<div class="login-bg-decoration"></div>
<div class="flex-1 flex items-center justify-center relative z-10">
<div class="login-card flex rounded-xl overflow-hidden shadow-lg">
<div class="login-visual hidden md:flex flex-col justify-center items-center relative">
<div class="login-visual-content">
<div class="login-visual-icon">
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="20" y="8" width="8" height="32" rx="2" fill="currentColor" opacity="0.9"/>
<rect x="8" y="20" width="32" height="8" rx="2" fill="currentColor" opacity="0.9"/>
</svg>
</div>
<h2 class="login-visual-title">中医在线问诊平台</h2>
<p class="login-visual-desc">专业 · 安全 · 可信赖的医疗管理系统</p>
</div>
</div>
<div
class="login-form bg-body flex flex-col justify-center px-10 py-10 md:w-[420px] w-[380px] flex-none mx-auto"
>
<div class="text-center text-3xl font-medium mb-8">{{ config.web_name }}</div>
<div class="text-center mb-8">
<div class="login-form-badge">管理后台</div>
<div class="text-2xl font-semibold text-tx-primary mt-3">{{ config.web_name }}</div>
</div>
<!-- 企业微信自动授权中 -->
<div v-if="wxWorkAutoLogin" class="text-center py-10">
@@ -287,11 +300,68 @@ onMounted(async () => {
<style lang="scss" scoped>
.login {
background-image: url('./images/login_bg.png');
@apply min-h-screen bg-no-repeat bg-center bg-cover;
position: relative;
@apply min-h-screen overflow-hidden;
background: var(--health-bg-page, #F1F5F9);
.login-bg-decoration {
display: none;
}
.login-card {
height: auto;
min-height: 400px;
min-height: 440px;
border: 1px solid var(--health-border, var(--el-border-color-lighter));
box-shadow: var(--el-box-shadow-light);
background: var(--el-bg-color);
}
.login-visual {
width: 400px;
background: var(--el-bg-color);
color: var(--el-text-color-primary);
padding: 48px 40px;
border-right: 1px solid var(--health-border, var(--el-border-color-lighter));
.login-visual-icon {
width: 56px;
height: 56px;
border-radius: 14px;
background: var(--el-color-primary-light-9);
color: var(--el-color-primary);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 24px;
svg {
width: 28px;
height: 28px;
}
}
.login-visual-title {
font-size: 20px;
font-weight: 600;
margin-bottom: 10px;
color: var(--el-text-color-primary);
}
.login-visual-desc {
font-size: 14px;
color: var(--el-text-color-secondary);
line-height: 1.7;
}
}
.login-form-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
color: var(--el-color-primary);
background: var(--el-color-primary-light-9);
}
}
+8 -1
View File
@@ -77,7 +77,14 @@ module.exports = {
mask: 'var(--el-mask-color)'
},
fontFamily: {
sans: ['PingFang SC', 'Arial', 'Hiragino Sans GB', 'Microsoft YaHei', 'sans-serif']
sans: [
'Noto Sans SC',
'PingFang SC',
'Microsoft YaHei',
'Hiragino Sans GB',
'Arial',
'sans-serif'
]
},
boxShadow: {
DEFAULT: 'var(--el-box-shadow)',