feat(system): 新增系统配置页面和登录页切换,快捷菜单抽屉功能
- 新增系统配置页面,可设置系统名称、备案号、登录页类型等 - 实现登录页类型切换,支持多种登录页面样式- 添加主题类和登录页类型的选择功能 - 优化导航栏,增加抽屉菜单按钮 - 调整布局样式,支持新的主题类,登录页选择
This commit is contained in:
parent
6d3e42d9c1
commit
ab709310c4
|
@ -0,0 +1,143 @@
|
||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
:visible.sync="visible"
|
||||||
|
direction="btt"
|
||||||
|
size="95%"
|
||||||
|
custom-class="drawer-menu"
|
||||||
|
:with-header="false"
|
||||||
|
@close="$emit('update:visible', false)"
|
||||||
|
>
|
||||||
|
<div class="drawer-menu-content">
|
||||||
|
<div class="drawer-menu-title">快捷菜单</div>
|
||||||
|
<div v-for="group in filteredMenuGroups" :key="group.path" class="drawer-menu-group">
|
||||||
|
<div class="drawer-menu-group-title">{{ group.meta && group.meta.title }}</div>
|
||||||
|
<div class="drawer-menu-grid">
|
||||||
|
<div
|
||||||
|
v-for="item in group.children"
|
||||||
|
:key="item.path"
|
||||||
|
class="drawer-menu-item"
|
||||||
|
@click="handleMenuClick(item, group.path)"
|
||||||
|
>
|
||||||
|
<div class="drawer-menu-icon">
|
||||||
|
<svg-icon :icon-class="item.meta && item.meta.icon"/>
|
||||||
|
<!-- <i v-if="item.meta && item.meta.icon" :class="['iconfont', item.meta.icon]" /> -->
|
||||||
|
</div>
|
||||||
|
<div class="drawer-menu-label">{{ item.meta && item.meta.title }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
function isExternal(path) {
|
||||||
|
return /^(https?:|mailto:|tel:)/.test(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DrawerMenu',
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['sidebarRouters']),
|
||||||
|
filteredMenuGroups() {
|
||||||
|
// 递归过滤hidden
|
||||||
|
function filterMenu(list) {
|
||||||
|
return (list || []).filter(item => !item.hidden).map(item => {
|
||||||
|
const newItem = { ...item };
|
||||||
|
if (item.children) {
|
||||||
|
newItem.children = filterMenu(item.children);
|
||||||
|
}
|
||||||
|
return newItem;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 一级菜单只保留有可见子项的分组
|
||||||
|
return filterMenu(this.sidebarRouters).filter(group => group.children && group.children.length > 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleMenuClick(item, parentPath = '') {
|
||||||
|
// 拼接父级和子级path
|
||||||
|
let fullPath = '';
|
||||||
|
if (item.path) {
|
||||||
|
if (item.path.startsWith('http') || item.path.startsWith('https') || item.path.startsWith('mailto') || item.path.startsWith('tel')) {
|
||||||
|
fullPath = item.path;
|
||||||
|
} else {
|
||||||
|
if (item.path.startsWith('/')) {
|
||||||
|
fullPath = item.path;
|
||||||
|
} else {
|
||||||
|
fullPath = parentPath ? (parentPath.endsWith('/') ? parentPath + item.path : parentPath + '/' + item.path) : item.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fullPath) return;
|
||||||
|
if (isExternal(fullPath)) {
|
||||||
|
window.open(fullPath, '_blank');
|
||||||
|
} else {
|
||||||
|
this.$router.push(fullPath);
|
||||||
|
}
|
||||||
|
this.$emit('update:visible', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.drawer-menu {
|
||||||
|
border-radius: 16px 16px 0 0;
|
||||||
|
background: #19294a;
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
.drawer-menu-content {
|
||||||
|
padding: 24px 16px 32px 16px;
|
||||||
|
}
|
||||||
|
.drawer-menu-title {
|
||||||
|
color: #000;
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 26px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.drawer-menu-group-title {
|
||||||
|
color: #000;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 26px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.drawer-menu-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px 10px;
|
||||||
|
}
|
||||||
|
.drawer-menu-item {
|
||||||
|
width: 100px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.drawer-menu-icon {
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
margin: 0 auto 5px auto;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #00A9AB;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 32px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.drawer-menu-label {
|
||||||
|
color: #000;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,8 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="navbar">
|
<div class="navbar">
|
||||||
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
|
<!-- <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> -->
|
||||||
|
<!-- <i class="el-icon-menu" @click="drawerMenuVisible = true">
|
||||||
|
<i class="el-icon-menu" />
|
||||||
|
</i> -->
|
||||||
|
<el-tooltip class="item" effect="dark" content="快捷菜单" placement="bottom">
|
||||||
|
<i class="el-icon-menu drawer-menu-btn" @click="drawerMenuVisible = true"></i>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" />
|
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" />
|
||||||
|
|
||||||
|
|
||||||
<div class="right-menu">
|
<div class="right-menu">
|
||||||
<template v-if="device!=='mobile'">
|
<template v-if="device!=='mobile'">
|
||||||
|
@ -41,6 +48,7 @@
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
|
<drawer-menu :visible.sync="drawerMenuVisible" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -54,9 +62,15 @@ import SizeSelect from '@/components/SizeSelect'
|
||||||
import Search from '@/components/HeaderSearch'
|
import Search from '@/components/HeaderSearch'
|
||||||
import RuoYiGit from '@/components/SmartPower/Git'
|
import RuoYiGit from '@/components/SmartPower/Git'
|
||||||
import RuoYiDoc from '@/components/SmartPower/Doc'
|
import RuoYiDoc from '@/components/SmartPower/Doc'
|
||||||
|
import DrawerMenu from '@/components/DrawerMenu'
|
||||||
import { getIotFileUrl } from "@/utils/hciot"
|
import { getIotFileUrl } from "@/utils/hciot"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
drawerMenuVisible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
Breadcrumb,
|
Breadcrumb,
|
||||||
Hamburger,
|
Hamburger,
|
||||||
|
@ -64,7 +78,8 @@ export default {
|
||||||
SizeSelect,
|
SizeSelect,
|
||||||
Search,
|
Search,
|
||||||
RuoYiGit,
|
RuoYiGit,
|
||||||
RuoYiDoc
|
RuoYiDoc,
|
||||||
|
DrawerMenu
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters([
|
...mapGetters([
|
||||||
|
@ -127,6 +142,20 @@ export default {
|
||||||
background: rgba(0, 0, 0, .025)
|
background: rgba(0, 0, 0, .025)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.drawer-menu-btn{
|
||||||
|
padding: 0 10px;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 50px;
|
||||||
|
height: 100%;
|
||||||
|
float: left;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background .3s;
|
||||||
|
-webkit-tap-highlight-color:transparent;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 0, 0, .025)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.breadcrumb-container {
|
.breadcrumb-container {
|
||||||
float: left;
|
float: left;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="setting-drawer-title">
|
<div class="setting-drawer-title">
|
||||||
<h3 class="drawer-title">主题风格设置</h3>
|
<h3 class="drawer-title">主题风格设置</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-drawer-block-checbox">
|
<!-- <div class="setting-drawer-block-checbox">
|
||||||
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
|
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
|
||||||
<img src="@/assets/images/dark.svg" alt="dark">
|
<img src="@/assets/images/dark.svg" alt="dark">
|
||||||
<div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
|
<div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')">
|
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')">
|
||||||
<img src="@/assets/images/light.svg" alt="light">
|
<img src="@/assets/images/light.svg" alt="light">
|
||||||
<div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
|
<div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
|
||||||
<i aria-label="图标: check" class="anticon anticon-check">
|
<i aria-label="图标: check" class="anticon anticon-check">
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
</svg>
|
</svg>
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div>
|
||||||
|
|
||||||
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-N1')">
|
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-N1')">
|
||||||
<img src="@/assets/images/light.svg" alt="N1">
|
<img src="@/assets/images/light.svg" alt="N1">
|
||||||
|
@ -43,12 +43,36 @@
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<div class="drawer-item">
|
<div class="drawer-item">
|
||||||
<span>主题颜色</span>
|
<span>主题颜色</span>
|
||||||
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
|
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-item">
|
||||||
|
<span>主题类</span>
|
||||||
|
<el-select v-model="themeClass" size="mini" placeholder="请选择主题类" style="float: right; width: 160px" popper-class="settings-select-popper" @change="handleThemeClassChange">
|
||||||
|
<el-option
|
||||||
|
v-for="item in themeClassOptions"
|
||||||
|
:key="item.dictCode"
|
||||||
|
:label="item.dictLabel"
|
||||||
|
:value="item.dictValue"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-item">
|
||||||
|
<span>登录页</span>
|
||||||
|
<el-select v-model="loginPageType" size="mini" placeholder="请选择登录页" style="float: right; width: 160px" popper-class="settings-select-popper" @change="handleLoginPageTypeChange">
|
||||||
|
<el-option
|
||||||
|
v-for="item in loginPageOptions"
|
||||||
|
:key="item.dictCode"
|
||||||
|
:label="item.dictLabel"
|
||||||
|
:value="item.dictValue"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-divider/>
|
<el-divider/>
|
||||||
|
@ -76,11 +100,16 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ThemePicker from '@/components/ThemePicker'
|
import ThemePicker from '@/components/ThemePicker'
|
||||||
|
import { getDicts } from "@/api/system/dict/data";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { ThemePicker },
|
components: { ThemePicker },
|
||||||
data() {
|
data() {
|
||||||
return {}
|
return {
|
||||||
|
themeClassOptions: [],
|
||||||
|
loginPageOptions: [],
|
||||||
|
loginPageType: ''
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
theme() {
|
theme() {
|
||||||
|
@ -122,6 +151,30 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
themeClass: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.settings.themeClass
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.dispatch('settings/changeSetting', {
|
||||||
|
key: 'themeClass',
|
||||||
|
value: val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 获取主题类字典
|
||||||
|
getDicts('sys_skin_name').then((response) => {
|
||||||
|
this.themeClassOptions = response.data || [];
|
||||||
|
});
|
||||||
|
// 获取登录页字典
|
||||||
|
getDicts('sys_login_page').then((response) => {
|
||||||
|
this.loginPageOptions = response.data || [];
|
||||||
|
// 初始化loginPageType
|
||||||
|
const cache = localStorage.getItem('loginPageType');
|
||||||
|
this.loginPageType = cache || (process.env.VUE_APP_LOGIN_PAGE || '');
|
||||||
|
});
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
themeChange(val) {
|
themeChange(val) {
|
||||||
|
@ -135,6 +188,15 @@ export default {
|
||||||
key: 'sideTheme',
|
key: 'sideTheme',
|
||||||
value: val
|
value: val
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
handleThemeClassChange(val) {
|
||||||
|
// 保存到localStorage
|
||||||
|
localStorage.setItem('themeClass', val);
|
||||||
|
// 已通过v-model同步到Vuex
|
||||||
|
},
|
||||||
|
handleLoginPageTypeChange(val) {
|
||||||
|
// 保存到localStorage
|
||||||
|
localStorage.setItem('loginPageType', val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,6 +260,9 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.drawer-item {
|
.drawer-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
color: rgba(0, 0, 0, .65);
|
color: rgba(0, 0, 0, .65);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
|
@ -208,3 +273,8 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<style>
|
||||||
|
.settings-select-popper {
|
||||||
|
z-index: 41000 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="[classObj,themeClass1]" :style="{'--current-color': theme}" class="app-wrapper">
|
<div :class="[classObj,themeClass]" :style="{'--current-color': theme}" class="app-wrapper">
|
||||||
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
|
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
|
||||||
<sidebar class="sidebar-container" />
|
<sidebar class="sidebar-container" />
|
||||||
<div :class="{hasTagsView:needTagsView}" class="main-container">
|
<div :class="{hasTagsView:needTagsView}" class="main-container">
|
||||||
|
@ -36,6 +36,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
theme: state => state.settings.theme,
|
theme: state => state.settings.theme,
|
||||||
|
themeClass: state => state.settings.themeClass,
|
||||||
sideTheme: state => state.settings.sideTheme,
|
sideTheme: state => state.settings.sideTheme,
|
||||||
sidebar: state => state.app.sidebar,
|
sidebar: state => state.app.sidebar,
|
||||||
device: state => state.app.device,
|
device: state => state.app.device,
|
||||||
|
|
|
@ -5,8 +5,8 @@ import Cookies from 'js-cookie'
|
||||||
import Element from 'element-ui'
|
import Element from 'element-ui'
|
||||||
import './assets/styles/element-variables.scss'
|
import './assets/styles/element-variables.scss'
|
||||||
|
|
||||||
import '@/assets/styles/index.scss'
|
|
||||||
import '@/assets/styles/ruoyi.scss'
|
import '@/assets/styles/ruoyi.scss'
|
||||||
|
import '@/assets/styles/index.scss'
|
||||||
import App from './App'
|
import App from './App'
|
||||||
import store from './store'
|
import store from './store'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
|
|
|
@ -32,11 +32,11 @@ import ParentView from '@/components/ParentView';
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// 根据环境变量动态导入组件
|
// // 根据环境变量动态导入组件
|
||||||
function dynamicImportLoginPage(resolve) {
|
// function dynamicImportLoginPage(resolve) {
|
||||||
const loginPagePath = process.env.VUE_APP_LOGIN_PAGE;
|
// const loginPagePath = process.env.VUE_APP_LOGIN_PAGE;
|
||||||
require([`@/views/${loginPagePath}`], resolve);
|
// require([`@/views/${loginPagePath}`], resolve);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 公共路由
|
// 公共路由
|
||||||
export const constantRoutes = [
|
export const constantRoutes = [
|
||||||
|
@ -53,7 +53,8 @@ export const constantRoutes = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
component: (resolve) => dynamicImportLoginPage(resolve),
|
// component: (resolve) => dynamicImportLoginPage(resolve),
|
||||||
|
component: (resolve) => require(['@/views/LoginWrapper'], resolve),
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -76,6 +77,12 @@ export const constantRoutes = [
|
||||||
component: (resolve) => require(['@/views/error/401'], resolve),
|
component: (resolve) => require(['@/views/error/401'], resolve),
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/bigScreen',
|
||||||
|
component: () => import('@/views/bigScreenIframe/index'),
|
||||||
|
hidden: true,
|
||||||
|
meta: { bigScreen: true }
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
|
@ -92,6 +99,17 @@ export const constantRoutes = [
|
||||||
showNav: false
|
showNav: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// path: '/index',
|
||||||
|
// component: (resolve) => require(['@/views/index'], resolve),
|
||||||
|
// name: 'BigScreen',
|
||||||
|
// meta: {
|
||||||
|
// title: '监控大屏', icon: 'dashboard', noCache: true, affix: true
|
||||||
|
// },
|
||||||
|
// params: {
|
||||||
|
// showNav: false
|
||||||
|
// }
|
||||||
|
// },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,10 +3,12 @@ import defaultSettings from '@/settings'
|
||||||
|
|
||||||
const { theme, themeClass, sideTheme, showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
|
const { theme, themeClass, sideTheme, showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
|
||||||
|
|
||||||
|
const storageThemeClass = localStorage.getItem('themeClass') || ''
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
theme: theme,
|
theme: theme,
|
||||||
sideTheme: sideTheme,
|
sideTheme: sideTheme,
|
||||||
themeClass: themeClass,
|
themeClass: storageThemeClass || themeClass,
|
||||||
showSettings: showSettings,
|
showSettings: showSettings,
|
||||||
tagsView: tagsView,
|
tagsView: tagsView,
|
||||||
fixedHeader: fixedHeader,
|
fixedHeader: fixedHeader,
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
<template>
|
||||||
|
<component v-if="currentLoginComponent" :is="currentLoginComponent" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'LoginWrapper',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentLoginComponent: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
// 读取缓存条件
|
||||||
|
let type = localStorage.getItem('loginPageType')
|
||||||
|
if (!type) {
|
||||||
|
// 无缓存时用环境变量
|
||||||
|
type = process.env.VUE_APP_LOGIN_PAGE || 'login-green'
|
||||||
|
}
|
||||||
|
// 动态import
|
||||||
|
if (type === 'login-blue-black') {
|
||||||
|
this.currentLoginComponent = (await import('@/views/login-blue-black')).default
|
||||||
|
} else if (type === 'login-blue-white') {
|
||||||
|
this.currentLoginComponent = (await import('@/views/login-blue-white')).default
|
||||||
|
} else if (type === 'login-green') {
|
||||||
|
this.currentLoginComponent = (await import('@/views/login-green')).default
|
||||||
|
} else {
|
||||||
|
// 兜底:尝试import指定路径
|
||||||
|
try {
|
||||||
|
this.currentLoginComponent = (await import(`@/views/${type}`)).default
|
||||||
|
} catch (e) {
|
||||||
|
this.currentLoginComponent = (await import('@/views/login-green')).default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,128 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<div class="main-content-card">
|
||||||
|
<el-form :model="form" :rules="rules" ref="form" label-width="160px" label-position="top">
|
||||||
|
<el-form-item label="系统名称" prop="systemName">
|
||||||
|
<el-input v-model="form.systemName" placeholder="请输入系统名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备案号" prop="icp">
|
||||||
|
<el-input v-model="form.icp" placeholder="请输入备案号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="登录页" prop="loginPageType">
|
||||||
|
<el-select v-model="form.loginPageType" placeholder="请选择登录页">
|
||||||
|
<el-option v-for="item in loginPageOptions" :key="item.dictCode" :label="item.dictLabel" :value="item.dictValue" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="主题配色" prop="themeClass">
|
||||||
|
<el-select v-model="form.themeClass" placeholder="请选择主题配色">
|
||||||
|
<el-option v-for="item in themeClassOptions" :key="item.dictCode" :label="item.dictLabel" :value="item.dictValue" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="大屏地址" prop="bigScreenUrl">
|
||||||
|
<el-input v-model="form.bigScreenUrl" placeholder="请输入大屏地址" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="登录页logo(200x200px)" prop="loginLogo">
|
||||||
|
<ImageUpload v-model="form.loginLogo" :limit="1" tip="建议尺寸:200x200px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="登录页背景图(1920x1080)" prop="loginBg">
|
||||||
|
<ImageUpload v-model="form.loginBg" :limit="1" tip="建议尺寸:1920x1080px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="ico图标(16x16px)" prop="ico">
|
||||||
|
<ImageUpload v-model="form.ico" :limit="1" tip="建议尺寸:16x16px,格式:.ico/.png" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="菜单页logo(168x168px)" prop="menuLogo">
|
||||||
|
<ImageUpload v-model="form.menuLogo" :limit="1" tip="建议尺寸:168x168px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="公众号二维码(258x258px)" prop="wechatQrcode">
|
||||||
|
<ImageUpload v-model="form.wechatQrcode" :limit="1" tip="建议尺寸:258x258px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="小程序二维码(258x258px)" prop="miniQrcode">
|
||||||
|
<ImageUpload v-model="form.miniQrcode" :limit="1" tip="建议尺寸:258x258px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||||
|
<el-button @click="onReset">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getDicts } from "@/api/system/dict/data";
|
||||||
|
import ImageUpload from '@/components/ImageUpload'
|
||||||
|
// 假设有API getConfigInfo, saveConfigInfo
|
||||||
|
import { getConfigInfo, saveConfigInfo } from '@/api/system/config'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ConfigPage',
|
||||||
|
components: { ImageUpload },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
form: {
|
||||||
|
systemName: '',
|
||||||
|
icp: '',
|
||||||
|
loginPageType: '',
|
||||||
|
themeClass: '',
|
||||||
|
bigScreenUrl: '',
|
||||||
|
loginLogo: '',
|
||||||
|
loginBg: '',
|
||||||
|
ico: '',
|
||||||
|
menuLogo: '',
|
||||||
|
wechatQrcode: '',
|
||||||
|
miniQrcode: ''
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
systemName: [{ required: true, message: '请输入系统名称', trigger: 'blur' }],
|
||||||
|
loginPageType: [{ required: true, message: '请选择登录页', trigger: 'change' }],
|
||||||
|
themeClass: [{ required: true, message: '请选择主题配色', trigger: 'change' }]
|
||||||
|
},
|
||||||
|
loginPageOptions: [],
|
||||||
|
themeClassOptions: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 获取字典
|
||||||
|
getDicts('sys_login_page').then(res => {
|
||||||
|
this.loginPageOptions = res.data || [];
|
||||||
|
});
|
||||||
|
getDicts('sys_skin_name').then(res => {
|
||||||
|
this.themeClassOptions = res.data || [];
|
||||||
|
});
|
||||||
|
// 获取配置信息
|
||||||
|
getConfigInfo().then(res => {
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
this.form = Object.assign(this.form, res.data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSubmit() {
|
||||||
|
this.$refs.form.validate(valid => {
|
||||||
|
if (!valid) return;
|
||||||
|
saveConfigInfo(this.form).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.$message.success('保存成功')
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg || '保存失败')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onReset() {
|
||||||
|
this.$refs.form.resetFields();
|
||||||
|
// 重新拉取后端数据
|
||||||
|
getConfigInfo().then(res => {
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
this.form = Object.assign(this.form, res.data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.system-config-page {
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue