| | |
| | | # 页面标题 |
| | | VITE_APP_TITLE = 若依管理系统 |
| | | VITE_APP_TITLE = Hugray |
| | | |
| | | # 开发环境配置 |
| | | VITE_APP_ENV = 'development' |
| | |
| | | # 页面标题 |
| | | VITE_APP_TITLE = 若依管理系统 |
| | | VITE_APP_TITLE = Hugray |
| | | |
| | | # 生产环境配置 |
| | | VITE_APP_ENV = 'production' |
| | |
| | | # 页面标题 |
| | | VITE_APP_TITLE = 若依管理系统 |
| | | VITE_APP_TITLE = Hugray |
| | | |
| | | # 生产环境配置 |
| | | VITE_APP_ENV = 'staging' |
| | |
| | | <svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path fill="#5a5e66" d="M0 54.857h54.796v18.286H36.531V128H18.265V73.143H0V54.857zm127.857-36.571H91.935V128H72.456V18.286H36.534V0h91.326l-.003 18.286z"/></svg> |
| | | <svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h54.796v18.286H36.531V128H18.265V73.143H0V54.857zm127.857-36.571H91.935V128H72.456V18.286H36.534V0h91.326l-.003 18.286z"/></svg> |
| | |
| | | } |
| | | } |
| | | |
| | | //main-container全局样式 |
| | | //main-container全局样式(内容区浅灰底上的白色圆角卡片) |
| | | .app-container { |
| | | padding: 20px; |
| | | margin: 16px; |
| | | background-color: #ffffff; |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | // 暗色模式下卡片改用 EP 的浮层底色,否则白底 + 暗色文字规则会让内容不可读 |
| | | html.dark .app-container { |
| | | background-color: var(--el-bg-color-overlay); |
| | | } |
| | | |
| | | .components-container { |
| | |
| | | .el-table__header-wrapper, .el-table__fixed-header-wrapper { |
| | | th { |
| | | word-break: break-word; |
| | | background-color: #f8f8f9 !important; |
| | | color: #515a6e; |
| | | background-color: #F2F3F5 !important; |
| | | color: #303133; |
| | | height: 40px !important; |
| | | font-size: 13px; |
| | | } |
| | |
| | | /** 表格更多操作下拉样式 */ |
| | | .el-table .el-dropdown-link { |
| | | cursor: pointer; |
| | | color: #409EFF; |
| | | color: #0F5291; |
| | | margin-left: 10px; |
| | | } |
| | | |
| | |
| | | .top-right-btn { |
| | | margin-left: auto; |
| | | } |
| | | |
| | | /* ===== 换肤:设计稿配色(深蓝 chrome + 绿色主色) ===== */ |
| | | /* 以下浅色配色均为设计稿专用,限定 html:not(.dark):暗色模式沿用 EP 默认深色体系, |
| | | 避免出现浅灰填充/深蓝字落在深色面板上不可读 */ |
| | | |
| | | html:not(.dark) { |
| | | |
| | | /* 行内操作链接:设计稿为深蓝,不跟随主题色(主题色是绿色) */ |
| | | .el-table .el-button--primary.is-link { |
| | | --el-button-text-color: #0F5291; |
| | | --el-button-hover-text-color: #1667B3; |
| | | --el-button-active-text-color: #0B4A85; |
| | | } |
| | | |
| | | /* 表格单元格内的文字链接(与上面的操作链接同色系) */ |
| | | .el-table .link-type, |
| | | .el-table .link-type:focus { |
| | | color: #0F5291; |
| | | |
| | | &:hover { |
| | | color: #1667B3; |
| | | } |
| | | } |
| | | |
| | | /* 分页当前页:设计稿为浅蓝底 + 深蓝字,而非 primary 实心块 */ |
| | | .el-pagination.is-background .el-pager li.is-active { |
| | | background-color: #E8F4FF; |
| | | color: #0F5291; |
| | | } |
| | | |
| | | /* 默认按钮:设计稿为浅灰填充、无边框(走 EP 变量,保留 1px 边框宽度以免尺寸变化)。 |
| | | 用 :not(带类型按钮) 而非 .el-button--default——后者只在全局 size=default 时存在, |
| | | SizeSelect 切到"较大/稍小"会整站静默失效 */ |
| | | .el-button:not(.el-button--primary):not(.el-button--success):not(.el-button--warning):not(.el-button--danger):not(.el-button--info) { |
| | | --el-button-bg-color: #F7F8FA; |
| | | --el-button-border-color: transparent; |
| | | --el-button-text-color: #4E5969; |
| | | --el-button-hover-bg-color: #EEF0F2; |
| | | --el-button-hover-border-color: transparent; |
| | | --el-button-hover-text-color: #303133; |
| | | --el-button-active-bg-color: #E5E8EC; |
| | | --el-button-active-border-color: transparent; |
| | | --el-button-disabled-bg-color: #F7F8FA; |
| | | --el-button-disabled-border-color: transparent; |
| | | --el-button-disabled-text-color: #A8ABB2; |
| | | } |
| | | |
| | | /* 列表页查询表单:设计稿为浅灰填充、无边框输入框(弹窗内表单保持 EP 默认样式) */ |
| | | .app-container .el-form--inline { |
| | | |
| | | .el-input__wrapper, |
| | | .el-select__wrapper { |
| | | background-color: #F7F8FA; |
| | | box-shadow: none; |
| | | |
| | | &.is-focus, |
| | | &.is-focused { |
| | | box-shadow: 0 0 0 1px var(--el-color-primary) inset; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | transition: margin-left .28s; |
| | | margin-left: vars.$base-sidebar-width; |
| | | position: relative; |
| | | /* 内容区浅灰底,白色卡片(.app-container)浮于其上 */ |
| | | background-color: #F7F8FA; |
| | | } |
| | | |
| | | /* 暗色模式沿用 EP 深色底,否则内容区留白会变成浅灰 */ |
| | | html.dark & .main-container { |
| | | background-color: var(--el-bg-color); |
| | | } |
| | | |
| | | .sidebarHide { |
| | |
| | | } |
| | | |
| | | .el-sub-menu.is-active > .el-sub-menu__title { |
| | | color: var(--current-color, #409eff) !important; |
| | | color: var(--menu-active-text, #ffffff) !important; |
| | | } |
| | | |
| | | .el-menu-item:not(.is-active), |
| | |
| | | $yellow: #FEC171; |
| | | $panGreen: #30B08F; |
| | | |
| | | // 默认主题变量 |
| | | $menuText: #bfcbd9; |
| | | $menuActiveText: #409eff; |
| | | $menuBg: #1a1f2e; |
| | | $menuHover: #263445; |
| | | // 默认主题变量(品牌深蓝底 + 白字) |
| | | $menuText: rgba(255, 255, 255, 0.82); |
| | | $menuActiveText: #ffffff; |
| | | $menuBg: #0B3F6F; |
| | | $menuHover: rgba(255, 255, 255, 0.12); |
| | | |
| | | // 浅色主题theme-light |
| | | $menuLightBg: #ffffff; |
| | |
| | | $sideBarWidth: 200px; |
| | | |
| | | // 菜单暗色变量 |
| | | $base-menu-color: rgba(255,255,255,.65); |
| | | $base-menu-color: rgba(255,255,255,.82); |
| | | $base-menu-color-active: #ffffff; |
| | | $base-menu-background: #1a1f2e; |
| | | $base-sub-menu-background: #141824; |
| | | $base-sub-menu-hover: rgba(255,255,255,.06); |
| | | $base-menu-background: #0B3F6F; |
| | | $base-sub-menu-background: #0A3660; |
| | | $base-sub-menu-hover: rgba(255,255,255,.10); |
| | | |
| | | // 组件变量 |
| | | $--color-primary: #409EFF; |
| | | $--color-primary: #80BF40; |
| | | $--color-success: #67C23A; |
| | | $--color-warning: #E6A23C; |
| | | $--color-danger: #F56C6C; |
| | |
| | | --sidebar-bg: #{$menuBg}; |
| | | --sidebar-text: #{$menuText}; |
| | | --menu-hover: #{$menuHover}; |
| | | /* 深色侧栏选中项文字色(此前只在 html.dark 里定义,浅色下会回落到兜底色) */ |
| | | --menu-active-text: #{$menuActiveText}; |
| | | |
| | | --navbar-bg: #ffffff; |
| | | --navbar-text: #303133; |
| | | --navbar-bg: #0B3F6F; |
| | | --navbar-text: #ffffff; |
| | | |
| | | /* splitpanes default-theme 变量 */ |
| | | --splitpanes-default-bg: #ffffff; |
| | |
| | | <style lang="scss" scoped> |
| | | .notice-trigger { |
| | | position: relative; |
| | | transform: translateX(-6px); |
| | | .svg-icon { width: 1.2em; height: 1.2em; vertical-align: -0.2em; } |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | /* 顶栏图标在 30px 圆形按钮内居中,行高需归零(否则继承 .right-menu 的 50px 使盒子溢出圆形) */ |
| | | line-height: 1; |
| | | .svg-icon { width: 1.2em; height: 1.2em; } |
| | | .notice-badge { |
| | | position: absolute; |
| | | top: 7px; |
| | | right: -3px; |
| | | top: -6px; |
| | | right: -8px; |
| | | background: #f56c6c; |
| | | color: #fff; |
| | | border-radius: 10px; |
| | |
| | | |
| | | <div class="right-menu"> |
| | | <template v-if="appStore.device !== 'mobile'"> |
| | | <header-search id="header-search" class="right-menu-item" /> |
| | | |
| | | <el-tooltip content="源码地址" effect="dark" placement="bottom"> |
| | | <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" /> |
| | | </el-tooltip> |
| | | |
| | | <el-tooltip content="文档地址" effect="dark" placement="bottom"> |
| | | <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" /> |
| | | </el-tooltip> |
| | | <header-search id="header-search" class="right-menu-item hover-effect" /> |
| | | |
| | | <screenfull id="screenfull" class="right-menu-item hover-effect" /> |
| | | |
| | |
| | | |
| | | <el-dropdown @command="handleCommand" class="avatar-container right-menu-item hover-effect" trigger="hover"> |
| | | <div class="avatar-wrapper"> |
| | | <img :src="userStore.avatar" class="user-avatar" /> |
| | | <span class="user-nickname"> {{ userStore.nickName }} </span> |
| | | <div class="avatar-initial">{{ avatarLetter }}</div> |
| | | </div> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | |
| | | import Screenfull from '@/components/Screenfull' |
| | | import SizeSelect from '@/components/SizeSelect' |
| | | import HeaderSearch from '@/components/HeaderSearch' |
| | | import RuoYiGit from '@/components/RuoYi/Git' |
| | | import RuoYiDoc from '@/components/RuoYi/Doc' |
| | | import useAppStore from '@/store/modules/app' |
| | | import useUserStore from '@/store/modules/user' |
| | | import useLockStore from '@/store/modules/lock' |
| | |
| | | const userStore = useUserStore() |
| | | const lockStore = useLockStore() |
| | | const settingsStore = useSettingsStore() |
| | | |
| | | // 顶栏头像为设计稿的绿色首字母圆,取昵称首字母(无昵称时兜底 A) |
| | | const avatarLetter = computed(() => (userStore.nickName || 'A').charAt(0).toUpperCase()) |
| | | |
| | | function toggleSideBar() { |
| | | appStore.toggleSideBar() |
| | |
| | | align-items: center; |
| | | // padding: 0 8px; |
| | | box-sizing: border-box; |
| | | /* 品牌深蓝顶栏:hamburger 等用 fill="currentColor" 的图标继承白字 */ |
| | | color: #ffffff; |
| | | |
| | | .hamburger-container { |
| | | line-height: 46px; |
| | |
| | | margin-right: 8px; |
| | | |
| | | &:hover { |
| | | background: rgba(0, 0, 0, 0.025); |
| | | background: rgba(255, 255, 255, 0.12); |
| | | } |
| | | } |
| | | |
| | | .breadcrumb-container { |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | /* 面包屑在深蓝底上改白系(#breadcrumb-container 提权以盖过 Breadcrumb 组件内 .no-redirect 的灰字) */ |
| | | #breadcrumb-container { |
| | | :deep(.el-breadcrumb__inner), |
| | | :deep(.el-breadcrumb__separator) { |
| | | color: rgba(255, 255, 255, 0.85); |
| | | } |
| | | |
| | | :deep(.el-breadcrumb__inner.is-link:hover) { |
| | | color: #ffffff; |
| | | } |
| | | } |
| | | |
| | | .topmenu-container { |
| | |
| | | outline: none; |
| | | } |
| | | |
| | | /* 设计稿顶栏右侧为一排白色描边的圆形图标按钮 */ |
| | | .right-menu-item { |
| | | display: inline-block; |
| | | padding: 0 8px; |
| | | height: 100%; |
| | | font-size: 18px; |
| | | color: #5a5e66; |
| | | vertical-align: text-bottom; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 30px; |
| | | height: 30px; |
| | | padding: 0; |
| | | margin: 0 5px; |
| | | font-size: 15px; |
| | | color: #ffffff; |
| | | border: 1px solid rgba(255, 255, 255, 0.35); |
| | | border-radius: 50%; |
| | | flex-shrink: 0; |
| | | |
| | | &.hover-effect { |
| | | cursor: pointer; |
| | | transition: background 0.3s; |
| | | transition: background 0.3s, border-color 0.3s; |
| | | |
| | | &:hover { |
| | | background: rgba(0, 0, 0, 0.025); |
| | | background: rgba(255, 255, 255, 0.12); |
| | | border-color: rgba(255, 255, 255, 0.6); |
| | | } |
| | | } |
| | | |
| | | /* 子组件自带的行高/内边距会在圆形按钮里偏心,归零让图标居中 */ |
| | | :deep(.size-icon--style) { |
| | | line-height: 1; |
| | | padding-right: 0; |
| | | } |
| | | |
| | | :deep(.size-icon), |
| | | :deep(.search-icon) { |
| | | font-size: 15px; |
| | | } |
| | | |
| | | &.theme-switch-wrapper { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | svg { |
| | | transition: transform 0.3s; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | .avatar-container { |
| | | margin-right: 0px; |
| | | padding-right: 0px; |
| | | /* 头像容器不参与描边圆按钮:内层是设计稿的绿色首字母实心圆 */ |
| | | .avatar-container, |
| | | .avatar-container.hover-effect:hover { |
| | | border: none; |
| | | background: transparent; |
| | | |
| | | .avatar-wrapper { |
| | | margin-top: 10px; |
| | | right: 8px; |
| | | position: relative; |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | .user-avatar { |
| | | cursor: pointer; |
| | | .avatar-initial { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 30px; |
| | | height: 30px; |
| | | margin-right: 8px; |
| | | border-radius: 50%; |
| | | } |
| | | |
| | | .user-nickname{ |
| | | position: relative; |
| | | left: 0px; |
| | | bottom: 10px; |
| | | background-color: #80BF40; |
| | | color: #ffffff; |
| | | font-size: 14px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | i { |
| | | font-weight: 600; |
| | | cursor: pointer; |
| | | position: absolute; |
| | | right: -20px; |
| | | top: 25px; |
| | | font-size: 12px; |
| | | user-select: none; |
| | | } |
| | | } |
| | | } |
| | |
| | | const sideTheme = ref(settingsStore.sideTheme) |
| | | const tagsViewPersist = ref(settingsStore.tagsViewPersist) |
| | | const storeSettings = computed(() => settingsStore) |
| | | const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]) |
| | | const predefineColors = ref(["#80BF40", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]) |
| | | |
| | | /** 是否需要dynamicTitle */ |
| | | function dynamicTitleChange() { |
| | |
| | | "sideTheme": storeSettings.value.sideTheme, |
| | | "theme": storeSettings.value.theme |
| | | } |
| | | localStorage.setItem("layout-setting", JSON.stringify(layoutSetting)) |
| | | localStorage.setItem("layout-setting-v2", JSON.stringify(layoutSetting)) |
| | | setTimeout(proxy.$modal.closeLoading(), 1000) |
| | | } |
| | | |
| | | function resetSetting() { |
| | | proxy.$cache.local.remove('tags-view-visited') |
| | | proxy.$modal.loading("正在清除设置缓存并刷新,请稍候...") |
| | | localStorage.removeItem("layout-setting") |
| | | localStorage.removeItem("layout-setting-v2") |
| | | setTimeout("window.location.reload()", 1000) |
| | | } |
| | | |
| | |
| | | return 'var(--sidebar-bg)' |
| | | } |
| | | if (settingsStore.navType == 3) { |
| | | return variables.menuLightBg |
| | | // 顶部菜单模式下 Logo 位于品牌深蓝顶栏内,底色跟顶栏一致(原先取白色,在深蓝顶栏上会露出白块) |
| | | return 'var(--navbar-bg)' |
| | | } |
| | | return sideTheme.value === 'theme-dark' ? variables.menuBg : variables.menuLightBg |
| | | }) |
| | |
| | | return 'var(--sidebar-logo-text)' |
| | | } |
| | | if (settingsStore.navType == 3) { |
| | | return variables.menuLightText |
| | | return '#ffffff' |
| | | } |
| | | return sideTheme.value === 'theme-dark' ? '#fff' : variables.menuLightText |
| | | }) |
| | |
| | | :background-color="getMenuBackground" |
| | | :text-color="getMenuTextColor" |
| | | :unique-opened="true" |
| | | :active-text-color="theme" |
| | | :active-text-color="getMenuActiveTextColor" |
| | | :collapse-transition="false" |
| | | mode="vertical" |
| | | :class="sideTheme" |
| | |
| | | return sideTheme.value === 'theme-dark' ? variables.menuText : variables.menuLightText |
| | | }) |
| | | |
| | | // 获取菜单选中项文字颜色 |
| | | // 设计稿的深蓝侧栏中选中项为白字:主题色(绿)若渗进侧栏会与深蓝 chrome 冲突, |
| | | // 暗色模式与 theme-light 仍跟随主题色,保持原有行为 |
| | | const getMenuActiveTextColor = computed(() => { |
| | | if (!settingsStore.isDark && sideTheme.value === 'theme-dark') { |
| | | return variables.menuActiveText |
| | | } |
| | | return theme.value |
| | | }) |
| | | |
| | | const activeMenu = computed(() => { |
| | | const { meta, path } = route |
| | | if (meta.activeMenu) { |
| | |
| | | float: left; |
| | | height: 50px !important; |
| | | line-height: 50px !important; |
| | | color: #303133 !important; |
| | | /* 顶栏为品牌深蓝底,菜单文字用白系 */ |
| | | color: #ffffff !important; |
| | | padding: 0 5px !important; |
| | | margin: 0 10px !important; |
| | | } |
| | |
| | | .topbar-menu.el-menu--horizontal > .el-sub-menu .el-sub-menu__title { |
| | | float: left; |
| | | line-height: 50px !important; |
| | | color: #303133 !important; |
| | | color: #ffffff !important; |
| | | margin: 0 15px -3px!important; |
| | | } |
| | | |
| | |
| | | float: left; |
| | | height: 50px !important; |
| | | line-height: 50px !important; |
| | | color: #303133 !important; |
| | | /* 顶栏为品牌深蓝底,菜单文字用白系 */ |
| | | color: #ffffff !important; |
| | | padding: 0 5px !important; |
| | | margin: 0 10px !important; |
| | | } |
| | | |
| | | .topmenu-container.el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title { |
| | | border-bottom: 2px solid #{'var(--theme)'} !important; |
| | | color: #303133; |
| | | color: #ffffff; |
| | | } |
| | | |
| | | /* sub-menu item */ |
| | |
| | | float: left; |
| | | height: 50px !important; |
| | | line-height: 50px !important; |
| | | color: #303133 !important; |
| | | color: #ffffff !important; |
| | | padding: 0 5px !important; |
| | | margin: 0 10px !important; |
| | | } |
| | | |
| | | /* 背景色隐藏 */ |
| | | .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .topmenu-container.el-menu--horizontal>.el-submenu .el-submenu__title:hover { |
| | | background-color: #ffffff; |
| | | background-color: rgba(255, 255, 255, 0.12); |
| | | } |
| | | |
| | | /* 图标右间距 */ |
| | |
| | | <template> |
| | | <div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme, '--current-color-light': theme + '1a', '--current-color-dark-bg': theme + '33' }"> |
| | | <!-- --current-color* 跟随主题色(页签栏选中项等);深色侧栏是固定的品牌深蓝,其选中/悬停覆盖层用固定白色,避免被主题色染成彩色块 --> |
| | | <div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme, '--current-color-light': theme + '1a', '--current-color-dark-bg': 'rgba(255, 255, 255, 0.12)' }"> |
| | | <div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside"/> |
| | | <sidebar v-if="!sidebar.hide" class="sidebar-container" /> |
| | | <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container"> |
| | |
| | | /** |
| | | * 底部版权文本内容 |
| | | */ |
| | | footerContent: 'Copyright © 2018-2026 RuoYi. All Rights Reserved.' |
| | | footerContent: 'Copyright © 2018-2026 Hugray. All Rights Reserved.' |
| | | } |
| | | |
| | |
| | | |
| | | const { sideTheme, showSettings, navType, tagsView, tagsViewPersist, tagsIcon, tagsViewStyle, fixedHeader, sidebarLogo, dynamicTitle, footerVisible, footerContent } = defaultSettings |
| | | |
| | | const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || '' |
| | | // v2:换肤后主题默认色由 #409EFF 改为 #80BF40,升级键名避免浏览器里的旧主题色覆盖新默认值 |
| | | const storageSetting = JSON.parse(localStorage.getItem('layout-setting-v2')) || '' |
| | | |
| | | const useSettingsStore = defineStore( |
| | | 'settings', |
| | | { |
| | | state: () => ({ |
| | | title: '', |
| | | theme: storageSetting.theme || '#409EFF', |
| | | theme: storageSetting.theme || '#80BF40', |
| | | sideTheme: storageSetting.sideTheme || sideTheme, |
| | | showSettings: showSettings, |
| | | navType: storageSetting.navType === undefined ? navType : storageSetting.navType, |
| | |
| | | <template> |
| | | <div class="login"> |
| | | <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form"> |
| | | <h3 class="title">{{ title }}</h3> |
| | | <el-form-item prop="username"> |
| | | <!-- 左侧品牌区:直接使用设计稿切图(含 Logo 与标语),图片底色 #0B3F6F 与面板底色一致,缩放后无缝 --> |
| | | <div class="login-brand"></div> |
| | | <!-- 右侧表单区 --> |
| | | <div class="login-panel"> |
| | | <el-form |
| | | ref="loginRef" |
| | | :model="loginForm" |
| | | :rules="loginRules" |
| | | label-position="top" |
| | | hide-required-asterisk |
| | | class="login-form" |
| | | > |
| | | <h3 class="title">登录</h3> |
| | | <el-form-item label="账号" prop="username"> |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | type="text" |
| | | size="large" |
| | | auto-complete="off" |
| | | placeholder="账号" |
| | | > |
| | | <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template> |
| | | </el-input> |
| | | placeholder="请输入" |
| | | @keyup.enter="handleLogin" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item prop="password"> |
| | | <el-form-item label="密码" prop="password"> |
| | | <el-input |
| | | v-model="loginForm.password" |
| | | type="password" |
| | | size="large" |
| | | auto-complete="off" |
| | | placeholder="密码" |
| | | placeholder="请输入" |
| | | @keyup.enter="handleLogin" |
| | | > |
| | | <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template> |
| | | </el-input> |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item prop="code" v-if="captchaEnabled"> |
| | | <div class="login-options"> |
| | | <el-checkbox v-model="loginForm.rememberMe" class="remember">记住我</el-checkbox> |
| | | <el-form-item prop="code" class="login-code" v-if="captchaEnabled"> |
| | | <el-input |
| | | v-model="loginForm.code" |
| | | size="large" |
| | | auto-complete="off" |
| | | placeholder="验证码" |
| | | style="width: 63%" |
| | | @keyup.enter="handleLogin" |
| | | > |
| | | <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template> |
| | | </el-input> |
| | | <div class="login-code"> |
| | | <img :src="codeUrl" @click="getCode" class="login-code-img"/> |
| | | </div> |
| | | /> |
| | | <img :src="codeUrl" class="login-code-img" alt="验证码" @click="getCode" /> |
| | | </el-form-item> |
| | | <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox> |
| | | <el-form-item style="width:100%;"> |
| | | <el-button |
| | | :loading="loading" |
| | | size="large" |
| | | type="primary" |
| | | style="width:100%;" |
| | | @click.prevent="handleLogin" |
| | | > |
| | | </div> |
| | | <div class="login-submit"> |
| | | <el-button :loading="loading" class="login-button" @click.prevent="handleLogin"> |
| | | <span v-if="!loading">登 录</span> |
| | | <span v-else>登 录 中...</span> |
| | | </el-button> |
| | | <div style="float: right;" v-if="register"> |
| | | </div> |
| | | <div class="login-register" v-if="register"> |
| | | <router-link class="link-type" :to="'/register'">立即注册</router-link> |
| | | </div> |
| | | </el-form-item> |
| | | </el-form> |
| | | <!-- 底部 --> |
| | | <div class="el-login-footer"> |
| | | <div class="el-login-footer" v-if="footerVisible"> |
| | | <span>{{ footerContent }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | |
| | | import useUserStore from '@/store/modules/user' |
| | | import defaultSettings from '@/settings' |
| | | |
| | | const title = import.meta.env.VITE_APP_TITLE |
| | | const footerVisible = defaultSettings.footerVisible |
| | | const footerContent = defaultSettings.footerContent |
| | | const userStore = useUserStore() |
| | | const route = useRoute() |
| | |
| | | <style lang='scss' scoped> |
| | | .login { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | height: 100%; |
| | | background-image: url("../assets/images/login-background.jpg"); |
| | | background-size: cover; |
| | | } |
| | | .title { |
| | | margin: 0px auto 30px auto; |
| | | text-align: center; |
| | | color: #707070; |
| | | |
| | | /* 左侧品牌区:设计稿切图按高度等比铺满,左右留白由同色底填充 */ |
| | | .login-brand { |
| | | flex: 0 0 61.5%; |
| | | background-color: #0B3F6F; |
| | | background-image: url("../assets/images/login-left.png"); |
| | | background-repeat: no-repeat; |
| | | background-position: center; |
| | | background-size: contain; |
| | | } |
| | | |
| | | /* 右侧表单区 */ |
| | | .login-panel { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: #80BF40; |
| | | } |
| | | |
| | | .login-form { |
| | | width: 360px; |
| | | max-width: calc(100% - 32px); |
| | | padding: 22px 52px 40px; |
| | | background-color: #ffffff; |
| | | border-radius: 6px; |
| | | background: #ffffff; |
| | | width: 400px; |
| | | padding: 25px 25px 5px 25px; |
| | | z-index: 1; |
| | | .el-input { |
| | | height: 40px; |
| | | input { |
| | | height: 40px; |
| | | } |
| | | } |
| | | .input-icon { |
| | | height: 39px; |
| | | width: 14px; |
| | | margin-left: 0px; |
| | | } |
| | | } |
| | | .login-tip { |
| | | font-size: 13px; |
| | | box-shadow: 0 4px 18px rgba(0, 0, 0, 0.12); |
| | | |
| | | .title { |
| | | margin: 0 0 18px; |
| | | text-align: center; |
| | | color: #bfbfbf; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #0B3F6F; |
| | | } |
| | | |
| | | :deep(.el-form-item) { |
| | | margin-bottom: 18px; |
| | | } |
| | | |
| | | :deep(.el-form-item__label) { |
| | | height: auto; |
| | | padding: 0 0 8px; |
| | | line-height: 1.2; |
| | | font-size: 13px; |
| | | color: #436596; |
| | | } |
| | | |
| | | /* 输入框颜色与尺寸全部写死,避免暗色主题的 CSS 变量把白底黑字改掉 */ |
| | | :deep(.el-input__wrapper) { |
| | | padding: 0 12px; |
| | | border-radius: 4px; |
| | | background-color: #ffffff; |
| | | box-shadow: 0 0 0 1px #D2D2D2 inset; |
| | | &:hover { |
| | | box-shadow: 0 0 0 1px #C0C4CC inset; |
| | | } |
| | | &.is-focus { |
| | | box-shadow: 0 0 0 1px #0B3F6F inset; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-input__inner) { |
| | | height: 36px; |
| | | font-size: 13px; |
| | | color: #333333; |
| | | &::placeholder { |
| | | color: #9DA6B3; |
| | | } |
| | | } |
| | | |
| | | .login-options { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .remember { |
| | | --el-checkbox-checked-bg-color: #1684FC; |
| | | --el-checkbox-checked-input-border-color: #1684FC; |
| | | --el-checkbox-checked-icon-color: #ffffff; |
| | | --el-checkbox-input-border-color-hover: #1684FC; |
| | | :deep(.el-checkbox__label) { |
| | | font-size: 13px; |
| | | color: #333333; |
| | | } |
| | | } |
| | | |
| | | /* 验证码输入框与图片同排,去掉表单项自身的下边距以与「记住我」垂直居中 */ |
| | | .login-code { |
| | | width: 33%; |
| | | height: 40px; |
| | | float: right; |
| | | img { |
| | | cursor: pointer; |
| | | flex: 0 1 auto; |
| | | min-width: 0; |
| | | margin-bottom: 0; |
| | | :deep(.el-form-item__content) { |
| | | flex-wrap: nowrap; |
| | | gap: 8px; |
| | | } |
| | | :deep(.el-input) { |
| | | flex: 0 1 88px; |
| | | width: 88px; |
| | | min-width: 56px; |
| | | } |
| | | } |
| | | |
| | | .login-code-img { |
| | | flex: 0 0 auto; |
| | | height: 36px; |
| | | border-radius: 4px; |
| | | vertical-align: middle; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .login-submit { |
| | | margin-top: 34px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .login-button { |
| | | width: 140px; |
| | | height: 36px; |
| | | font-size: 14px; |
| | | letter-spacing: 1px; |
| | | color: #ffffff; |
| | | background-color: #0B3F6F; |
| | | border-color: #0B3F6F; |
| | | border-radius: 4px; |
| | | &:hover, |
| | | &:focus { |
| | | color: #ffffff; |
| | | background-color: #0A3660; |
| | | border-color: #0A3660; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .login-register { |
| | | margin-top: 12px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .el-login-footer { |
| | | height: 40px; |
| | | line-height: 40px; |
| | | position: fixed; |
| | | bottom: 0; |
| | | width: 100%; |
| | | height: 40px; |
| | | line-height: 40px; |
| | | text-align: center; |
| | | color: #fff; |
| | | font-family: Arial; |
| | | font-size: 12px; |
| | | letter-spacing: 1px; |
| | | } |
| | | .login-code-img { |
| | | height: 40px; |
| | | padding-left: 12px; |
| | | color: rgba(11, 63, 111, 0.65); |
| | | } |
| | | |
| | | html.dark .login { |
| | | background-image: linear-gradient(rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0.55)), url("../assets/images/login-background.jpg"); |
| | | .login-form { |
| | | background: var(--el-bg-color-overlay) !important; |
| | | box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); |
| | | /* 窄屏收起品牌区,保证表单可用 */ |
| | | @media (max-width: 960px) { |
| | | .login-brand { |
| | | display: none; |
| | | } |
| | | } |
| | | </style> |