'admin-22.11.16:同步vue-next-admin-template分支v2.3.0版本'
This commit is contained in:
parent
d2e952e5cf
commit
22186136f5
14
CHANGELOG.md
14
CHANGELOG.md
|
|
@ -1,20 +1,26 @@
|
|||
# <a href="https://gitee.com/lyt-top/vue-next-admin" target="_blank">vue-next-admin-template-js(不带国际化) 更新日志</a>
|
||||
|
||||
🎉🎉🔥 `vue-next-admin-template-js` 基于 (vue-next-admin-template v0.2.2 版本) vue3.x 、vite、Element plus 等,适配手机、平板、pc 的后台开源免费模板库(vue2.x 请切换 vue-prev-admin 分支)
|
||||
🎉🎉🔥 `vue-next-admin-template-js` 基于 (vue-next-admin-template v2.3.0 版本) vue3.x 、vite、Element plus 等,适配手机、平板、pc 的后台开源免费模板库(vue2.x 请切换 vue-prev-admin 分支)
|
||||
|
||||
## 2.3.0
|
||||
|
||||
`2022.11.16`
|
||||
|
||||
- 🎉 同步 vue-next-admin-template 基础版本(不带国际化) 分支 v2.3.0 版本内容,具体查看 master 分支 CHANGELOG.md
|
||||
|
||||
## 2.2.0
|
||||
|
||||
`2022.07.11`
|
||||
|
||||
- 🎉 同步 [vue-next-admin-template-js](https://gitee.com/lyt-top/vue-next-admin/tree/vue-next-admin-template/) 分支 v2.2.0 版本内容,具体查看 [master CHANGELOG.md](https://gitee.com/lyt-top/vue-next-admin/blob/master/CHANGELOG.md)
|
||||
- 🎉 同步 vue-next-admin-template 基础版本(不带国际化) 分支 v2.2.0 版本内容,具体查看 master 分支 CHANGELOG.md
|
||||
|
||||
## 2.1.1
|
||||
|
||||
- 🎉 同步 [vue-next-admin-template-js](https://gitee.com/lyt-top/vue-next-admin/tree/vue-next-admin-template/) 分支 v2.1.1 版本内容,具体查看 [master CHANGELOG.md](https://gitee.com/lyt-top/vue-next-admin/blob/master/CHANGELOG.md)
|
||||
- 🎉 同步 vue-next-admin-template 基础版本(不带国际化) 分支 v2.1.1 版本内容,具体查看 master 分支 CHANGELOG.md
|
||||
|
||||
## 2.0.2
|
||||
|
||||
- 🎉 同步 vue-next-admin-template 基础版本(不带国际化) 分支 v2.0.2 版本内容,具体查看 master CHANGELOG.md
|
||||
- 🎉 同步 vue-next-admin-template 基础版本(不带国际化) 分支 v2.0.2 版本内容,具体查看 master 分支 CHANGELOG.md
|
||||
|
||||
## 0.1.0
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<p> </p>
|
||||
</div>
|
||||
|
||||
#### 🌈 介绍 基础版 js(不带国际化,基于 vue-next-admin-template V2.2.0 版)
|
||||
#### 🌈 介绍 基础版 js(不带国际化,基于 vue-next-admin-template V2.3.0 版,setup 语法糖)
|
||||
|
||||
基于 vue3.x + CompositionAPI + vite + element plus + vue-router-next,适配手机、平板、pc 的后台开源免费模板,希望减少工作量,帮助大家实现快速开发。
|
||||
|
||||
|
|
@ -71,9 +71,13 @@ cnpm run dev
|
|||
cnpm run build
|
||||
```
|
||||
|
||||
#### 📚 开发文档
|
||||
|
||||
- 查看开发文档:<a href="https://lyt-top.gitee.io/vue-next-admin-doc-preview" target="_blank">vue-next-admin-doc</a>
|
||||
|
||||
#### 💯 学习交流加 QQ 群
|
||||
|
||||
- 若加群了没同意(一般秒过),那就是群满了(500 人群),请换一个群试试。群会定期清理半年(6 个月)未发言的群友,资源有限,请谅解。建议勿加多群,可能会误伤!
|
||||
- 若加群了没同意(一般秒过),那就是群满了(500 人群),请换一个群试试。群会定期清理半年(6 个月)未发言的群友,资源有限,请谅解。建议勿加多群,可能会误伤!微信群由于只有 `7天有效` 就不放这里了。
|
||||
- 查看开发文档、<a href="https://lyt-top.gitee.io/vue-next-admin-preview/#/login" target="_blank">vue-next-admin</a> 开发文档正在编写中...
|
||||
- 群号码:
|
||||
1 群:<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi">665452019</a>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
36
package.json
36
package.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "vue-next-admin-template-js",
|
||||
"version": "2.2.0",
|
||||
"version": "2.3.0",
|
||||
"description": "vue3 vite next admin template js setup",
|
||||
"author": "lyt_20201208",
|
||||
"license": "MIT",
|
||||
|
|
@ -10,34 +10,34 @@
|
|||
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.6",
|
||||
"axios": "^0.27.2",
|
||||
"echarts": "^5.3.3",
|
||||
"element-plus": "^2.2.9",
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"axios": "^1.1.3",
|
||||
"echarts": "^5.4.0",
|
||||
"element-plus": "^2.2.21",
|
||||
"js-cookie": "^3.0.1",
|
||||
"mitt": "^3.0.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.0.16",
|
||||
"pinia": "^2.0.23",
|
||||
"qrcodejs2-fixes": "^0.0.2",
|
||||
"screenfull": "^6.0.2",
|
||||
"sortablejs": "^1.15.0",
|
||||
"vue": "^3.2.37",
|
||||
"vue": "^3.2.45",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-router": "^4.1.2"
|
||||
"vue-router": "^4.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^2.3.3",
|
||||
"@vue/compiler-sfc": "^3.2.37",
|
||||
"dotenv": "^16.0.1",
|
||||
"eslint": "^8.19.0",
|
||||
"eslint-plugin-vue": "^9.2.0",
|
||||
"@vitejs/plugin-vue": "^3.2.0",
|
||||
"@vue/compiler-sfc": "^3.2.45",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "^8.27.0",
|
||||
"eslint-plugin-vue": "^9.7.0",
|
||||
"prettier": "^2.7.1",
|
||||
"sass": "^1.53.0",
|
||||
"sass-loader": "^13.0.2",
|
||||
"unplugin-auto-import": "^0.9.3",
|
||||
"vite": "^2.9.14",
|
||||
"sass": "^1.56.1",
|
||||
"sass-loader": "^13.2.0",
|
||||
"unplugin-auto-import": "^0.11.4",
|
||||
"vite": "^3.2.4",
|
||||
"vite-plugin-vue-setup-extend": "^0.4.0",
|
||||
"vue-eslint-parser": "^9.0.3"
|
||||
"vue-eslint-parser": "^9.1.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
|
|
|
|||
19
src/App.vue
19
src/App.vue
|
|
@ -15,11 +15,12 @@ import { useThemeConfig } from '/@/stores/themeConfig';
|
|||
import other from '/@/utils/other';
|
||||
import { Local, Session } from '/@/utils/storage';
|
||||
import setIntroduction from '/@/utils/setIconfont';
|
||||
import LockScreen from '/@/layout/lockScreen/index.vue';
|
||||
import Setings from '/@/layout/navBars/breadcrumb/setings.vue';
|
||||
import CloseFull from '/@/layout/navBars/breadcrumb/closeFull.vue';
|
||||
import mittBus from './utils/mitt';
|
||||
|
||||
const LockScreen = defineAsyncComponent(() => import('/@/layout/lockScreen/index.vue'));
|
||||
const Setings = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/setings.vue'));
|
||||
const CloseFull = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/closeFull.vue'));
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const setingsRef = ref();
|
||||
const route = useRoute();
|
||||
const stores = useTagsViewRoutes();
|
||||
|
|
@ -29,10 +30,6 @@ const { themeConfig } = storeToRefs(storesThemeConfig);
|
|||
const getGlobalComponentSize = computed(() => {
|
||||
return other.globalComponentSize();
|
||||
});
|
||||
// 布局配置弹窗打开
|
||||
const openSetingsDrawer = () => {
|
||||
setingsRef.value.openDrawer();
|
||||
};
|
||||
// 设置初始化,防止刷新时恢复默认
|
||||
onBeforeMount(() => {
|
||||
// 设置批量第三方 icon 图标
|
||||
|
|
@ -44,8 +41,8 @@ onBeforeMount(() => {
|
|||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
// 监听布局配置弹窗点击打开
|
||||
proxy.mittBus.on('openSetingsDrawer', () => {
|
||||
openSetingsDrawer();
|
||||
mittBus.on('openSetingsDrawer', () => {
|
||||
setingsRef.value.openDrawer();
|
||||
});
|
||||
// 获取缓存中的布局配置
|
||||
if (Local.get('themeConfig')) {
|
||||
|
|
@ -60,7 +57,7 @@ onMounted(() => {
|
|||
});
|
||||
// 页面销毁时,关闭监听布局配置/i18n监听
|
||||
onUnmounted(() => {
|
||||
proxy.mittBus.off('openSetingsDrawer', () => {});
|
||||
mittBus.off('openSetingsDrawer', () => {});
|
||||
});
|
||||
// 监听路由的变化,设置网站标题
|
||||
watch(
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.4 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 36 KiB |
|
|
@ -62,7 +62,7 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import { ref, toRefs, reactive, onMounted, nextTick, computed, watch, defineComponent } from 'vue';
|
||||
import initIconfont from '/@/utils/getStyleSheets';
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<i v-else :class="getIconName" :style="setIconSvgStyle" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import { computed, defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@ import pinia from '/@/stores/index';
|
|||
import { useRoutesList } from '/@/stores/routesList';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||
import Logo from '/@/layout/logo/index.vue';
|
||||
import Vertical from '/@/layout/navMenu/vertical.vue';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const Logo = defineAsyncComponent(() => import('/@/layout/logo/index.vue'));
|
||||
const Vertical = defineAsyncComponent(() => import('/@/layout/navMenu/vertical.vue'));
|
||||
|
||||
const layoutAsideScrollbarRef = ref();
|
||||
const stores = useRoutesList();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||
|
|
@ -97,14 +99,13 @@ const initMenuFixed = (clientWidth) => {
|
|||
const onAsideEnterLeave = (bool) => {
|
||||
let { layout } = themeConfig.value;
|
||||
if (layout !== 'columns') return false;
|
||||
if (!bool) proxy.mittBus.emit('restoreDefault');
|
||||
if (!bool) mittBus.emit('restoreDefault');
|
||||
stores.setColumnsMenuHover(bool);
|
||||
};
|
||||
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
||||
watch(themeConfig.value, (val) => {
|
||||
if (val.isShowLogoChange !== val.isShowLogo) {
|
||||
if (!proxy.$refs.layoutAsideScrollbarRef) return false;
|
||||
proxy.$refs.layoutAsideScrollbarRef.update();
|
||||
if (layoutAsideScrollbarRef.value) layoutAsideScrollbarRef.value.update();
|
||||
}
|
||||
});
|
||||
// 监听vuex值的变化,动态赋值给菜单中
|
||||
|
|
@ -123,22 +124,22 @@ watch(
|
|||
onBeforeMount(() => {
|
||||
initMenuFixed(document.body.clientWidth);
|
||||
setFilterRoutes();
|
||||
// 此界面不需要取消监听(proxy.mittBus.off('setSendColumnsChildren))
|
||||
// 此界面不需要取消监听(mittBus.off('setSendColumnsChildren))
|
||||
// 因为切换布局时有的监听需要使用,取消了监听,某些操作将不生效
|
||||
proxy.mittBus.on('setSendColumnsChildren', (res) => {
|
||||
mittBus.on('setSendColumnsChildren', (res) => {
|
||||
state.menuList = res.children;
|
||||
});
|
||||
proxy.mittBus.on('setSendClassicChildren', (res) => {
|
||||
mittBus.on('setSendClassicChildren', (res) => {
|
||||
let { layout, isClassicSplitMenu } = themeConfig.value;
|
||||
if (layout === 'classic' && isClassicSplitMenu) {
|
||||
state.menuList = [];
|
||||
state.menuList = res.children;
|
||||
}
|
||||
});
|
||||
proxy.mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
|
||||
mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
|
||||
setFilterRoutes();
|
||||
});
|
||||
proxy.mittBus.on('layoutMobileResize', (res) => {
|
||||
mittBus.on('layoutMobileResize', (res) => {
|
||||
initMenuFixed(res.clientWidth);
|
||||
closeLayoutAsideMobileMode();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -50,10 +50,10 @@ import { storeToRefs } from 'pinia';
|
|||
import pinia from '/@/stores/index';
|
||||
import { useRoutesList } from '/@/stores/routesList';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
|
||||
const columnsAsideOffsetTopRefs = ref([]);
|
||||
const columnsAsideActiveRef = ref();
|
||||
const { proxy } = getCurrentInstance();
|
||||
const stores = useRoutesList();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { routesList, isColumnsMenuHover, isColumnsNavHover } = storeToRefs(stores);
|
||||
|
|
@ -83,11 +83,12 @@ const onColumnsAsideMenuClick = (v, k) => {
|
|||
};
|
||||
// 鼠标移入时,显示当前的子级菜单
|
||||
const onColumnsAsideMenuMouseenter = (v, k) => {
|
||||
if (!themeConfig.value.isColumnsMenuHoverPreload) return false;
|
||||
let { path } = v;
|
||||
state.liOldPath = path;
|
||||
state.liOldIndex = k;
|
||||
state.liHoverIndex = k;
|
||||
proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(path));
|
||||
mittBus.emit('setSendColumnsChildren', setSendChildren(path));
|
||||
stores.setColumnsMenuHover(false);
|
||||
stores.setColumnsNavHover(true);
|
||||
};
|
||||
|
|
@ -96,7 +97,7 @@ const onColumnsAsideMenuMouseleave = async () => {
|
|||
await stores.setColumnsNavHover(false);
|
||||
// 添加延时器,防止拿到的 store.state.routesList 值不是最新的
|
||||
setTimeout(() => {
|
||||
if (!isColumnsMenuHover && !isColumnsNavHover) proxy.mittBus.emit('restoreDefault');
|
||||
if (!isColumnsMenuHover && !isColumnsNavHover) mittBus.emit('restoreDefault');
|
||||
}, 100);
|
||||
};
|
||||
// 设置高亮动态位置
|
||||
|
|
@ -111,7 +112,7 @@ const setFilterRoutes = () => {
|
|||
const resData = setSendChildren(route.path);
|
||||
if (Object.keys(resData).length <= 0) return false;
|
||||
onColumnsAsideDown(resData.item[0].k);
|
||||
proxy.mittBus.emit('setSendColumnsChildren', resData);
|
||||
mittBus.emit('setSendColumnsChildren', resData);
|
||||
};
|
||||
// 传送当前子级数据到菜单中
|
||||
const setSendChildren = (path) => {
|
||||
|
|
@ -156,11 +157,11 @@ watch(
|
|||
val.themeConfig.themeConfig.columnsAsideStyle === 'columnsRound' ? (state.difference = 3) : (state.difference = 0);
|
||||
if (!val.routesList.isColumnsMenuHover && !val.routesList.isColumnsNavHover) {
|
||||
state.liHoverIndex = null;
|
||||
proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(route.path));
|
||||
mittBus.emit('setSendColumnsChildren', setSendChildren(route.path));
|
||||
} else {
|
||||
state.liHoverIndex = state.liOldIndex;
|
||||
if (!state.liOldPath) return false;
|
||||
proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(state.liOldPath));
|
||||
mittBus.emit('setSendColumnsChildren', setSendChildren(state.liOldPath));
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -171,19 +172,19 @@ watch(
|
|||
onMounted(() => {
|
||||
setFilterRoutes();
|
||||
// 销毁变量,防止鼠标再次移入时,保留了上次的记录
|
||||
proxy.mittBus.on('restoreDefault', () => {
|
||||
mittBus.on('restoreDefault', () => {
|
||||
state.liOldIndex = null;
|
||||
state.liOldPath = null;
|
||||
});
|
||||
});
|
||||
// 页面卸载时
|
||||
onUnmounted(() => {
|
||||
proxy.mittBus.off('restoreDefault', () => {});
|
||||
mittBus.off('restoreDefault', () => {});
|
||||
});
|
||||
// 路由更新时
|
||||
onBeforeRouteUpdate((to) => {
|
||||
setColumnsMenuHighlight(to.path);
|
||||
proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(to.path));
|
||||
mittBus.emit('setSendColumnsChildren', setSendChildren(to.path));
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
@ -194,6 +195,16 @@ onBeforeRouteUpdate((to) => {
|
|||
background: var(--next-bg-columnsMenuBar);
|
||||
ul {
|
||||
position: relative;
|
||||
.layout-columns-active {
|
||||
color: var(--next-bg-columnsMenuBarColor) !important;
|
||||
transition: 0.3s ease-in-out;
|
||||
}
|
||||
.layout-columns-hover {
|
||||
color: var(--el-color-primary);
|
||||
a {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
li {
|
||||
color: var(--next-bg-columnsMenuBarColor);
|
||||
width: 100%;
|
||||
|
|
@ -203,6 +214,9 @@ onBeforeRouteUpdate((to) => {
|
|||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
&:hover {
|
||||
@extend .layout-columns-hover;
|
||||
}
|
||||
.columns-vertical {
|
||||
margin: auto;
|
||||
.columns-vertical-title {
|
||||
|
|
@ -230,16 +244,6 @@ onBeforeRouteUpdate((to) => {
|
|||
color: var(--next-bg-columnsMenuBarColor);
|
||||
}
|
||||
}
|
||||
.layout-columns-active {
|
||||
color: var(--next-bg-columnsMenuBarColor) !important;
|
||||
transition: 0.3s ease-in-out;
|
||||
}
|
||||
.layout-columns-hover {
|
||||
color: var(--el-color-primary);
|
||||
a {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
.columns-round {
|
||||
background: var(--el-color-primary);
|
||||
color: var(--el-color-white);
|
||||
|
|
|
|||
|
|
@ -1,23 +1,15 @@
|
|||
<template>
|
||||
<el-header class="layout-header" :height="setHeaderHeight" v-show="!isTagsViewCurrenFull">
|
||||
<el-header class="layout-header" v-show="!isTagsViewCurrenFull">
|
||||
<NavBarsIndex />
|
||||
</el-header>
|
||||
</template>
|
||||
|
||||
<script setup name="layoutHeader">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||
import NavBarsIndex from '/@/layout/navBars/index.vue';
|
||||
|
||||
const NavBarsIndex = defineAsyncComponent(() => import('/@/layout/navBars/index.vue'));
|
||||
|
||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
||||
// 设置 header 的高度
|
||||
const setHeaderHeight = computed(() => {
|
||||
let { isTagsview, layout } = themeConfig.value;
|
||||
if (isTagsview && layout !== 'classic') return '84px';
|
||||
else return '50px';
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,82 +1,50 @@
|
|||
<template>
|
||||
<el-main class="layout-main">
|
||||
<el-scrollbar
|
||||
ref="layoutScrollbarRef"
|
||||
:class="{
|
||||
'layout-scrollbar':
|
||||
(!isClassicOrTransverse && !state.currentRouteMeta.isLink && !state.currentRouteMeta.isIframe) ||
|
||||
(!isClassicOrTransverse && currentRouteMeta.isLink && !state.currentRouteMeta.isIframe),
|
||||
}"
|
||||
>
|
||||
<LayoutParentView
|
||||
:style="{
|
||||
padding: !isClassicOrTransverse || (state.currentRouteMeta.isLink && state.currentRouteMeta.isIframe) ? '0' : '15px',
|
||||
transition: 'padding 0.3s ease-in-out',
|
||||
}"
|
||||
/>
|
||||
<Footer v-if="themeConfig.isFooter" />
|
||||
<el-main class="layout-main" :style="isFixedHeader ? `height: calc(100% - ${setMainHeight})` : `minHeight: calc(100% - ${setMainHeight})`">
|
||||
<el-scrollbar ref="layoutMainScrollbarRef" class="layout-main-scroll" wrap-class="layout-main-scroll" view-class="layout-main-scroll">
|
||||
<LayoutParentView />
|
||||
<LayoutFooter v-if="isFooter" />
|
||||
</el-scrollbar>
|
||||
<el-backtop target=".layout-backtop .el-scrollbar__wrap" />
|
||||
</el-main>
|
||||
</template>
|
||||
|
||||
<script setup name="layoutMain">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { NextLoading } from '/@/utils/loading';
|
||||
import LayoutParentView from '/@/layout/routerView/parent.vue';
|
||||
import Footer from '/@/layout/footer/index.vue';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const LayoutParentView = defineAsyncComponent(() => import('/@/layout/routerView/parent.vue'));
|
||||
const LayoutFooter = defineAsyncComponent(() => import('/@/layout/footer/index.vue'));
|
||||
|
||||
const layoutMainScrollbarRef = ref('');
|
||||
const route = useRoute();
|
||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const route = useRoute();
|
||||
const state = reactive({
|
||||
headerHeight: '',
|
||||
currentRouteMeta: {},
|
||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
||||
// 设置 footer 显示/隐藏
|
||||
const isFooter = computed(() => {
|
||||
return themeConfig.value.isFooter && !route.meta.isIframe;
|
||||
});
|
||||
// 判断布局
|
||||
const isClassicOrTransverse = computed(() => {
|
||||
const { layout } = themeConfig.value;
|
||||
return layout === 'classic' || layout === 'transverse';
|
||||
// 设置 header 固定
|
||||
const isFixedHeader = computed(() => {
|
||||
return themeConfig.value.isFixedHeader;
|
||||
});
|
||||
// 设置主内容区的高度
|
||||
const setMainHeight = computed(() => {
|
||||
if (isTagsViewCurrenFull.value) return '0px';
|
||||
const { isTagsview, layout } = themeConfig.value;
|
||||
if (isTagsview && layout !== 'classic') return '85px';
|
||||
else return '51px';
|
||||
});
|
||||
// 设置 main 的高度
|
||||
const initHeaderHeight = () => {
|
||||
const bool = state.currentRouteMeta.isLink && state.currentRouteMeta.isIframe;
|
||||
let { isTagsview } = themeConfig.value;
|
||||
if (isTagsview) return (state.headerHeight = bool ? `86px` : `115px`);
|
||||
else return (state.headerHeight = `80px`);
|
||||
};
|
||||
// 初始化获取当前路由 meta,用于设置 iframes padding
|
||||
const initGetMeta = () => {
|
||||
state.currentRouteMeta = route.meta;
|
||||
};
|
||||
// 页面加载时
|
||||
onMounted(async () => {
|
||||
await initGetMeta();
|
||||
initHeaderHeight();
|
||||
NextLoading.done();
|
||||
});
|
||||
// 监听路由变化
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
state.currentRouteMeta = route.meta;
|
||||
const bool = state.currentRouteMeta.isLink && state.currentRouteMeta.isIframe;
|
||||
state.headerHeight = bool ? `86px` : `115px`;
|
||||
proxy.$refs.layoutScrollbarRef.update();
|
||||
}
|
||||
);
|
||||
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
||||
watch(
|
||||
themeConfig,
|
||||
(val) => {
|
||||
state.currentRouteMeta = route.meta;
|
||||
const bool = state.currentRouteMeta.isLink && state.currentRouteMeta.isIframe;
|
||||
state.headerHeight = val.isTagsview ? (bool ? `86px` : `115px`) : '51px';
|
||||
proxy.$refs?.layoutScrollbarRef?.update();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
layoutMainScrollbarRef,
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="layout-footer mt15" v-show="state.isDelayFooter">
|
||||
<div class="layout-footer pb15">
|
||||
<div class="layout-footer-warp">
|
||||
<div>vue-next-admin,Made by lyt with ❤️</div>
|
||||
<div class="mt5">版权所有:深圳市xxx软件科技有限公司</div>
|
||||
|
|
@ -7,22 +7,7 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="layoutFooter">
|
||||
import { onBeforeRouteUpdate } from 'vue-router';
|
||||
|
||||
const state = reactive({
|
||||
isDelayFooter: true,
|
||||
});
|
||||
// 路由改变时,等主界面动画加载完毕再显示 footer
|
||||
onBeforeRouteUpdate(() => {
|
||||
setTimeout(() => {
|
||||
state.isDelayFooter = false;
|
||||
setTimeout(() => {
|
||||
state.isDelayFooter = true;
|
||||
}, 800);
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
<script setup name="layoutFooter"></script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.layout-footer {
|
||||
|
|
@ -32,7 +17,7 @@ onBeforeRouteUpdate(() => {
|
|||
margin: auto;
|
||||
color: var(--el-text-color-secondary);
|
||||
text-align: center;
|
||||
animation: logoAnimation 0.3s ease-in-out;
|
||||
animation: error-num 0.3s ease;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
<template>
|
||||
<Defaults v-if="themeConfig.layout === 'defaults'" />
|
||||
<Classic v-else-if="themeConfig.layout === 'classic'" />
|
||||
<Transverse v-else-if="themeConfig.layout === 'transverse'" />
|
||||
<Columns v-else-if="themeConfig.layout === 'columns'" />
|
||||
<component :is="layouts[themeConfig.layout]"></component>
|
||||
</template>
|
||||
|
||||
<script setup name="layout">
|
||||
|
|
@ -10,13 +7,15 @@ import { defineAsyncComponent } from 'vue';
|
|||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { Local } from '/@/utils/storage';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
|
||||
const Defaults = defineAsyncComponent(() => import('/@/layout/main/defaults.vue'));
|
||||
const Classic = defineAsyncComponent(() => import('/@/layout/main/classic.vue'));
|
||||
const Transverse = defineAsyncComponent(() => import('/@/layout/main/transverse.vue'));
|
||||
const Columns = defineAsyncComponent(() => import('/@/layout/main/columns.vue'));
|
||||
const layouts = {
|
||||
defaults: defineAsyncComponent(() => import('/@/layout/main/defaults.vue')),
|
||||
classic: defineAsyncComponent(() => import('/@/layout/main/classic.vue')),
|
||||
transverse: defineAsyncComponent(() => import('/@/layout/main/transverse.vue')),
|
||||
columns: defineAsyncComponent(() => import('/@/layout/main/columns.vue')),
|
||||
};
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
// 窗口大小改变时(适配移动端)
|
||||
|
|
@ -25,12 +24,12 @@ const onLayoutResize = () => {
|
|||
const clientWidth = document.body.clientWidth;
|
||||
if (clientWidth < 1000) {
|
||||
themeConfig.value.isCollapse = false;
|
||||
proxy.mittBus.emit('layoutMobileResize', {
|
||||
mittBus.emit('layoutMobileResize', {
|
||||
layout: 'defaults',
|
||||
clientWidth,
|
||||
});
|
||||
} else {
|
||||
proxy.mittBus.emit('layoutMobileResize', {
|
||||
mittBus.emit('layoutMobileResize', {
|
||||
layout: Local.get('oldLayout') ? Local.get('oldLayout') : themeConfig.value.layout,
|
||||
clientWidth,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ import { useThemeConfig } from '/@/stores/themeConfig';
|
|||
import { formatDate } from '/@/utils/formatTime';
|
||||
import { Local } from '/@/utils/storage';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const layoutLockScreenInputRef = ref();
|
||||
|
|
@ -127,7 +126,7 @@ const onEnd = () => {
|
|||
// 获取要拖拽的初始元素
|
||||
const initGetElement = () => {
|
||||
nextTick(() => {
|
||||
state.querySelectorEl = proxy.$refs.layoutLockScreenDateRef;
|
||||
state.querySelectorEl = layoutLockScreenDateRef.value;
|
||||
});
|
||||
};
|
||||
// 时间初始化
|
||||
|
|
|
|||
|
|
@ -1,25 +1,65 @@
|
|||
<template>
|
||||
<el-container class="layout-container flex-center">
|
||||
<Header />
|
||||
<LayoutHeader />
|
||||
<el-container class="layout-mian-height-50">
|
||||
<Aside />
|
||||
<LayoutAside />
|
||||
<div class="flex-center layout-backtop">
|
||||
<TagsView v-if="themeConfig.isTagsview" />
|
||||
<Main />
|
||||
<LayoutTagsView v-if="isTagsview" />
|
||||
<LayoutMain ref="layoutMainRef" />
|
||||
</div>
|
||||
</el-container>
|
||||
<el-backtop target=".layout-backtop .el-main .el-scrollbar__wrap"></el-backtop>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup name="layoutClassic">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import Aside from '/@/layout/component/aside.vue';
|
||||
import Header from '/@/layout/component/header.vue';
|
||||
import Main from '/@/layout/component/main.vue';
|
||||
import TagsView from '/@/layout/navBars/tagsView/tagsView.vue';
|
||||
|
||||
const LayoutAside = defineAsyncComponent(() => import('/@/layout/component/aside.vue'));
|
||||
const LayoutHeader = defineAsyncComponent(() => import('/@/layout/component/header.vue'));
|
||||
const LayoutMain = defineAsyncComponent(() => import('/@/layout/component/main.vue'));
|
||||
const LayoutTagsView = defineAsyncComponent(() => import('/@/layout/navBars/tagsView/tagsView.vue'));
|
||||
|
||||
const layoutMainRef = ref('');
|
||||
const route = useRoute();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
// 判断是否显示 tasgview
|
||||
const isTagsview = computed(() => {
|
||||
return themeConfig.value.isTagsview;
|
||||
});
|
||||
// 重置滚动条高度,更新子级 scrollbar
|
||||
const updateScrollbar = () => {
|
||||
layoutMainRef.value.layoutMainScrollbarRef.update();
|
||||
};
|
||||
// 重置滚动条高度,由于组件是异步引入的
|
||||
const initScrollBarHeight = () => {
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
updateScrollbar();
|
||||
layoutMainRef.value.layoutMainScrollbarRef.wrap$.scrollTop = 0;
|
||||
}, 500);
|
||||
});
|
||||
};
|
||||
// 监听路由的变化,切换界面时,滚动条置顶
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
initScrollBarHeight();
|
||||
}
|
||||
);
|
||||
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
||||
watch(
|
||||
themeConfig,
|
||||
() => {
|
||||
updateScrollbar();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
initScrollBarHeight();
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,32 +1,66 @@
|
|||
<template>
|
||||
<el-container class="layout-container">
|
||||
<ColumnsAside />
|
||||
<div class="layout-columns-warp">
|
||||
<Aside />
|
||||
<el-container class="flex-center layout-backtop" :class="{ 'layout-backtop': !isFixedHeader }">
|
||||
<Header v-if="isFixedHeader" />
|
||||
<el-scrollbar :class="{ 'layout-backtop': isFixedHeader }">
|
||||
<Header v-if="!isFixedHeader" />
|
||||
<Main />
|
||||
</el-scrollbar>
|
||||
</el-container>
|
||||
</div>
|
||||
<el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>
|
||||
<el-container class="layout-columns-warp layout-container-view h100">
|
||||
<LayoutAside />
|
||||
<el-scrollbar ref="layoutScrollbarRef" class="layout-backtop">
|
||||
<LayoutHeader />
|
||||
<LayoutMain ref="layoutMainRef" />
|
||||
</el-scrollbar>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup name="layoutColumns">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import Aside from '/@/layout/component/aside.vue';
|
||||
import Header from '/@/layout/component/header.vue';
|
||||
import Main from '/@/layout/component/main.vue';
|
||||
import ColumnsAside from '/@/layout/component/columnsAside.vue';
|
||||
|
||||
const LayoutAside = defineAsyncComponent(() => import('/@/layout/component/aside.vue'));
|
||||
const LayoutHeader = defineAsyncComponent(() => import('/@/layout/component/header.vue'));
|
||||
const LayoutMain = defineAsyncComponent(() => import('/@/layout/component/main.vue'));
|
||||
const ColumnsAside = defineAsyncComponent(() => import('/@/layout/component/columnsAside.vue'));
|
||||
|
||||
const layoutScrollbarRef = ref('');
|
||||
const layoutMainRef = ref('');
|
||||
const route = useRoute();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
// 是否固定顶栏
|
||||
const isFixedHeader = computed(() => {
|
||||
return themeConfig.value.isFixedHeader;
|
||||
// 重置滚动条高度
|
||||
const updateScrollbar = () => {
|
||||
// 更新父级 scrollbar
|
||||
layoutScrollbarRef.value.update();
|
||||
// 更新子级 scrollbar
|
||||
layoutMainRef.value.layoutMainScrollbarRef.update();
|
||||
};
|
||||
// 重置滚动条高度,由于组件是异步引入的
|
||||
const initScrollBarHeight = () => {
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
updateScrollbar();
|
||||
layoutScrollbarRef.value.wrap$.scrollTop = 0;
|
||||
layoutMainRef.value.layoutMainScrollbarRef.wrap$.scrollTop = 0;
|
||||
}, 500);
|
||||
});
|
||||
};
|
||||
// 监听路由的变化,切换界面时,滚动条置顶
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
initScrollBarHeight();
|
||||
}
|
||||
);
|
||||
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
||||
watch(
|
||||
themeConfig,
|
||||
() => {
|
||||
updateScrollbar();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
initScrollBarHeight();
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,37 +1,66 @@
|
|||
<template>
|
||||
<el-container class="layout-container">
|
||||
<Aside />
|
||||
<el-container class="flex-center" :class="{ 'layout-backtop': !isFixedHeader }">
|
||||
<Header v-if="isFixedHeader" />
|
||||
<el-scrollbar ref="layoutDefaultsScrollbarRef" :class="{ 'layout-backtop': isFixedHeader }">
|
||||
<Header v-if="!isFixedHeader" />
|
||||
<Main />
|
||||
<LayoutAside />
|
||||
<el-container class="layout-container-view h100">
|
||||
<el-scrollbar ref="layoutScrollbarRef" class="layout-backtop">
|
||||
<LayoutHeader />
|
||||
<LayoutMain ref="layoutMainRef" />
|
||||
</el-scrollbar>
|
||||
</el-container>
|
||||
<el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup name="layoutDefaults">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import Aside from '/@/layout/component/aside.vue';
|
||||
import Header from '/@/layout/component/header.vue';
|
||||
import Main from '/@/layout/component/main.vue';
|
||||
import { NextLoading } from '/@/utils/loading';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const LayoutAside = defineAsyncComponent(() => import('/@/layout/component/aside.vue'));
|
||||
const LayoutHeader = defineAsyncComponent(() => import('/@/layout/component/header.vue'));
|
||||
const LayoutMain = defineAsyncComponent(() => import('/@/layout/component/main.vue'));
|
||||
|
||||
const layoutScrollbarRef = ref('');
|
||||
const layoutMainRef = ref('');
|
||||
const route = useRoute();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
// 是否固定顶栏
|
||||
const isFixedHeader = computed(() => {
|
||||
return themeConfig.value.isFixedHeader;
|
||||
});
|
||||
// 监听路由的变化
|
||||
// 重置滚动条高度
|
||||
const updateScrollbar = () => {
|
||||
// 更新父级 scrollbar
|
||||
layoutScrollbarRef.value.update();
|
||||
// 更新子级 scrollbar
|
||||
layoutMainRef.value.layoutMainScrollbarRef.update();
|
||||
};
|
||||
// 重置滚动条高度,由于组件是异步引入的
|
||||
const initScrollBarHeight = () => {
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
updateScrollbar();
|
||||
layoutScrollbarRef.value.wrap$.scrollTop = 0;
|
||||
layoutMainRef.value.layoutMainScrollbarRef.wrap$.scrollTop = 0;
|
||||
}, 500);
|
||||
});
|
||||
};
|
||||
// 监听路由的变化,切换界面时,滚动条置顶
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
proxy.$refs.layoutDefaultsScrollbarRef.wrap$.scrollTop = 0;
|
||||
initScrollBarHeight();
|
||||
}
|
||||
);
|
||||
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
||||
watch(
|
||||
themeConfig,
|
||||
() => {
|
||||
updateScrollbar();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
initScrollBarHeight();
|
||||
NextLoading.done(600);
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,53 @@
|
|||
<template>
|
||||
<el-container class="layout-container flex-center layout-backtop">
|
||||
<Header />
|
||||
<Main />
|
||||
<el-backtop target=".layout-backtop .el-main .el-scrollbar__wrap"></el-backtop>
|
||||
<LayoutHeader />
|
||||
<LayoutMain ref="layoutMainRef" />
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup name="layoutTransverse">
|
||||
import Header from '/@/layout/component/header.vue';
|
||||
import Main from '/@/layout/component/main.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
|
||||
const LayoutHeader = defineAsyncComponent(() => import('/@/layout/component/header.vue'));
|
||||
const LayoutMain = defineAsyncComponent(() => import('/@/layout/component/main.vue'));
|
||||
|
||||
const layoutMainRef = ref('');
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const route = useRoute();
|
||||
// 重置滚动条高度,更新子级 scrollbar
|
||||
const updateScrollbar = () => {
|
||||
layoutMainRef.value.layoutMainScrollbarRef.update();
|
||||
};
|
||||
// 重置滚动条高度,由于组件是异步引入的
|
||||
const initScrollBarHeight = () => {
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
updateScrollbar();
|
||||
layoutMainRef.value.layoutMainScrollbarRef.wrap$.scrollTop = 0;
|
||||
}, 500);
|
||||
});
|
||||
};
|
||||
// 监听路由的变化,切换界面时,滚动条置顶
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
initScrollBarHeight();
|
||||
}
|
||||
);
|
||||
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
||||
watch(
|
||||
themeConfig,
|
||||
() => {
|
||||
updateScrollbar();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
initScrollBarHeight();
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -11,12 +11,13 @@
|
|||
import { storeToRefs } from 'pinia';
|
||||
import { useRoutesList } from '/@/stores/routesList';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import Breadcrumb from '/@/layout/navBars/breadcrumb/breadcrumb.vue';
|
||||
import User from '/@/layout/navBars/breadcrumb/user.vue';
|
||||
import Logo from '/@/layout/logo/index.vue';
|
||||
import Horizontal from '/@/layout/navMenu/horizontal.vue';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
|
||||
const Breadcrumb = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/breadcrumb.vue'));
|
||||
const User = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/user.vue'));
|
||||
const Logo = defineAsyncComponent(() => import('/@/layout/logo/index.vue'));
|
||||
const Horizontal = defineAsyncComponent(() => import('/@/layout/navMenu/horizontal.vue'));
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const stores = useRoutesList();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
|
|
@ -41,7 +42,7 @@ const setFilterRoutes = () => {
|
|||
if (layout === 'classic' && isClassicSplitMenu) {
|
||||
state.menuList = delClassicChildren(filterRoutesFun(routesList.value));
|
||||
const resData = setSendClassicChildren(route.path);
|
||||
proxy.mittBus.emit('setSendClassicChildren', resData);
|
||||
mittBus.emit('setSendClassicChildren', resData);
|
||||
} else {
|
||||
state.menuList = filterRoutesFun(routesList.value);
|
||||
}
|
||||
|
|
@ -80,13 +81,13 @@ const setSendClassicChildren = (path) => {
|
|||
// 页面加载时
|
||||
onMounted(() => {
|
||||
setFilterRoutes();
|
||||
proxy.mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
|
||||
mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
|
||||
setFilterRoutes();
|
||||
});
|
||||
});
|
||||
// 页面卸载时
|
||||
onUnmounted(() => {
|
||||
proxy.mittBus.off('getBreadcrumbIndexSetFilterRoutes', () => {});
|
||||
mittBus.off('getBreadcrumbIndexSetFilterRoutes', () => {});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,28 @@
|
|||
<template>
|
||||
<div class="layout-search-dialog">
|
||||
<el-dialog v-model="state.isShowSearch" width="300px" destroy-on-close :modal="false" fullscreen :show-close="false">
|
||||
<el-autocomplete
|
||||
v-model="state.menuQuery"
|
||||
:fetch-suggestions="menuSearch"
|
||||
placeholder="菜单搜索:支持中文、路由路径"
|
||||
ref="layoutMenuAutocompleteRef"
|
||||
@select="onHandleSelect"
|
||||
@blur="onSearchBlur"
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon class="el-input__icon">
|
||||
<ele-Search />
|
||||
</el-icon>
|
||||
</template>
|
||||
<template #default="{ item }">
|
||||
<div>
|
||||
<SvgIcon :name="item.meta.icon" class="mr5" />
|
||||
{{ item.meta.title }}
|
||||
</div>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
<el-dialog v-model="state.isShowSearch" destroy-on-close :show-close="false">
|
||||
<template #footer>
|
||||
<el-autocomplete
|
||||
v-model="state.menuQuery"
|
||||
:fetch-suggestions="menuSearch"
|
||||
placeholder="菜单搜索:支持中文、路由路径"
|
||||
ref="layoutMenuAutocompleteRef"
|
||||
@select="onHandleSelect"
|
||||
:fit-input-width="true"
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon class="el-input__icon">
|
||||
<ele-Search />
|
||||
</el-icon>
|
||||
</template>
|
||||
<template #default="{ item }">
|
||||
<div>
|
||||
<SvgIcon :name="item.meta.icon" class="mr5" />
|
||||
{{ item.meta.title }}
|
||||
</div>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -83,10 +85,6 @@ const onHandleSelect = (item) => {
|
|||
else router.push(path);
|
||||
closeSearch();
|
||||
};
|
||||
// input 失去焦点时
|
||||
const onSearchBlur = () => {
|
||||
closeSearch();
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
|
|
@ -97,14 +95,21 @@ defineExpose({
|
|||
<style scoped lang="scss">
|
||||
.layout-search-dialog {
|
||||
:deep(.el-dialog) {
|
||||
box-shadow: unset !important;
|
||||
border-radius: 0 !important;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
.el-dialog__header,
|
||||
.el-dialog__body {
|
||||
display: none;
|
||||
}
|
||||
.el-dialog__footer {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
top: -53vh;
|
||||
}
|
||||
}
|
||||
:deep(.el-autocomplete) {
|
||||
width: 560px;
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
top: 150px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,17 @@
|
|||
></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt14" :style="{ opacity: getThemeConfig.layout !== 'columns' ? 0.5 : 1 }">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">分栏菜单鼠标悬停预加载</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch
|
||||
v-model="getThemeConfig.isColumnsMenuHoverPreload"
|
||||
size="small"
|
||||
@change="onColumnsMenuHoverPreloadChange"
|
||||
:disabled="getThemeConfig.layout !== 'columns'"
|
||||
></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 界面设置 -->
|
||||
<el-divider content-position="left">界面设置</el-divider>
|
||||
|
|
@ -408,8 +419,8 @@ import { Local } from '/@/utils/storage';
|
|||
import Watermark from '/@/utils/wartermark';
|
||||
import commonFunction from '/@/utils/commonFunction';
|
||||
import other from '/@/utils/other';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const { copyText } = commonFunction();
|
||||
|
|
@ -466,6 +477,10 @@ const setGraduaFun = (el, bool, color) => {
|
|||
setLocalThemeConfig();
|
||||
}, 200);
|
||||
};
|
||||
// 2、分栏设置 ->
|
||||
const onColumnsMenuHoverPreloadChange = () => {
|
||||
setLocalThemeConfig();
|
||||
};
|
||||
// 3、界面设置 --> 菜单水平折叠
|
||||
const onThemeConfigChange = () => {
|
||||
setDispatchThemeConfig();
|
||||
|
|
@ -479,7 +494,7 @@ const onIsFixedHeaderChange = () => {
|
|||
const onClassicSplitMenuChange = () => {
|
||||
getThemeConfig.value.isBreadcrumb = false;
|
||||
setLocalThemeConfig();
|
||||
proxy.mittBus.emit('getBreadcrumbIndexSetFilterRoutes');
|
||||
mittBus.emit('getBreadcrumbIndexSetFilterRoutes');
|
||||
};
|
||||
// 4、界面显示 --> 侧边栏 Logo
|
||||
const onIsShowLogoChange = () => {
|
||||
|
|
@ -495,12 +510,12 @@ const onIsBreadcrumbChange = () => {
|
|||
};
|
||||
// 4、界面显示 --> 开启 TagsView 拖拽
|
||||
const onSortableTagsViewChange = () => {
|
||||
proxy.mittBus.emit('openOrCloseSortable');
|
||||
mittBus.emit('openOrCloseSortable');
|
||||
setLocalThemeConfig();
|
||||
};
|
||||
// 4、界面显示 --> 开启 TagsView 共用
|
||||
const onShareTagsViewChange = () => {
|
||||
proxy.mittBus.emit('openShareTagsView');
|
||||
mittBus.emit('openShareTagsView');
|
||||
setLocalThemeConfig();
|
||||
};
|
||||
// 4、界面显示 --> 灰色模式/色弱模式
|
||||
|
|
@ -551,7 +566,7 @@ const initLayoutChangeFun = () => {
|
|||
onBgColorPickerChange('columnsMenuBar');
|
||||
onBgColorPickerChange('columnsMenuBarColor');
|
||||
};
|
||||
// 关闭弹窗时,初始化变量。变量用于处理 proxy.$refs.layoutScrollbarRef.update()
|
||||
// 关闭弹窗时,初始化变量。变量用于处理 layoutScrollbarRef.value.update()
|
||||
const onDrawerClose = () => {
|
||||
getThemeConfig.value.isFixedHeaderChange = false;
|
||||
getThemeConfig.value.isShowLogoChange = false;
|
||||
|
|
@ -604,7 +619,7 @@ onMounted(() => {
|
|||
if (!Local.get('frequency')) initLayoutChangeFun();
|
||||
Local.set('frequency', 1);
|
||||
// 监听窗口大小改变,非默认布局,设置成默认布局(适配移动端)
|
||||
proxy.mittBus.on('layoutMobileResize', (res) => {
|
||||
mittBus.on('layoutMobileResize', (res) => {
|
||||
getThemeConfig.value.layout = res.layout;
|
||||
getThemeConfig.value.isDrawer = false;
|
||||
initLayoutChangeFun();
|
||||
|
|
@ -627,7 +642,7 @@ onMounted(() => {
|
|||
});
|
||||
});
|
||||
onUnmounted(() => {
|
||||
proxy.mittBus.off('layoutMobileResize', () => {});
|
||||
mittBus.off('layoutMobileResize', () => {});
|
||||
});
|
||||
|
||||
// 暴露变量
|
||||
|
|
|
|||
|
|
@ -70,10 +70,11 @@ import { Session, Local } from '/@/utils/storage';
|
|||
import { storeToRefs } from 'pinia';
|
||||
import { useUserInfo } from '/@/stores/userInfo';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import UserNews from '/@/layout/navBars/breadcrumb/userNews.vue';
|
||||
import Search from '/@/layout/navBars/breadcrumb/search.vue';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
|
||||
const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/userNews.vue'));
|
||||
const Search = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/search.vue'));
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const router = useRouter();
|
||||
const stores = useUserInfo();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
|
|
@ -108,7 +109,7 @@ const onScreenfullClick = () => {
|
|||
};
|
||||
// 布局配置 icon 点击时
|
||||
const onLayoutSetingClick = () => {
|
||||
proxy.mittBus.emit('openSetingsDrawer');
|
||||
mittBus.emit('openSetingsDrawer');
|
||||
};
|
||||
// 下拉菜单点击时
|
||||
const onHandleCommandClick = (path) => {
|
||||
|
|
@ -159,28 +160,18 @@ const onComponentSizeChange = (size) => {
|
|||
Local.remove('themeConfig');
|
||||
themeConfig.value.globalComponentSize = size;
|
||||
Local.set('themeConfig', themeConfig.value);
|
||||
initComponentSize();
|
||||
initI18nOrSize('globalComponentSize', 'disabledSize');
|
||||
window.location.reload();
|
||||
};
|
||||
// 初始化全局组件大小
|
||||
const initComponentSize = () => {
|
||||
switch (Local.get('themeConfig').globalComponentSize) {
|
||||
case 'large':
|
||||
state.disabledSize = 'large';
|
||||
break;
|
||||
case 'default':
|
||||
state.disabledSize = 'default';
|
||||
break;
|
||||
case 'small':
|
||||
state.disabledSize = 'small';
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
// 初始化组件大小/i18n
|
||||
const initI18nOrSize = (value, attr) => {
|
||||
state[attr] = Local.get('themeConfig')[value];
|
||||
};
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
if (Local.get('themeConfig')) {
|
||||
initComponentSize();
|
||||
initI18nOrSize('globalComponentSize', 'disabledSize');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@
|
|||
<script setup name="layoutNavBars">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import BreadcrumbIndex from '/@/layout/navBars/breadcrumb/index.vue';
|
||||
import TagsView from '/@/layout/navBars/tagsView/tagsView.vue';
|
||||
|
||||
const BreadcrumbIndex = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/index.vue'));
|
||||
const TagsView = defineAsyncComponent(() => import('/@/layout/navBars/tagsView/tagsView.vue'));
|
||||
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
:data-url="v.url"
|
||||
:class="{ 'is-active': isActive(v) }"
|
||||
@contextmenu.prevent="onContextmenu(v, $event)"
|
||||
@mousedown="onMousedownMenu(v, $event)"
|
||||
@click="onTagsClick(v, k)"
|
||||
:ref="
|
||||
(el) => {
|
||||
|
|
@ -57,9 +58,10 @@ import { useKeepALiveNames } from '/@/stores/keepAliveNames';
|
|||
import { Session } from '/@/utils/storage';
|
||||
import { isObjectValueEqual } from '/@/utils/arrayOperation';
|
||||
import other from '/@/utils/other';
|
||||
import Contextmenu from '/@/layout/navBars/tagsView/contextmenu.vue';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
|
||||
const Contextmenu = defineAsyncComponent(() => import('/@/layout/navBars/tagsView/contextmenu.vue'));
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const tagsRefs = ref([]);
|
||||
const scrollbarRef = ref();
|
||||
const contextmenuRef = ref();
|
||||
|
|
@ -188,13 +190,21 @@ const addTagsView = (path, to) => {
|
|||
// 动态路由(xxx/:id/:name"):参数不同,开启多个 tagsview
|
||||
if (!getThemeConfig.value.isShareTagsView) await solveAddTagsView(path, to);
|
||||
else await singleAddTagsView(path, to);
|
||||
if (state.tagsViewList.some((v) => v.path === to.meta.isDynamicPath)) return false;
|
||||
if (state.tagsViewList.some((v) => v.path === to.meta.isDynamicPath)) {
|
||||
// 防止首次进入界面时(登录进入) tagsViewList 不存浏览器中
|
||||
addBrowserSetSession(state.tagsViewList);
|
||||
return false;
|
||||
}
|
||||
item = state.tagsViewRoutesList.find((v) => v.path === to.meta.isDynamicPath);
|
||||
} else {
|
||||
// 普通路由:参数不同,开启多个 tagsview
|
||||
if (!getThemeConfig.value.isShareTagsView) await solveAddTagsView(path, to);
|
||||
else await singleAddTagsView(path, to);
|
||||
if (state.tagsViewList.some((v) => v.path === path)) return false;
|
||||
if (state.tagsViewList.some((v) => v.path === path)) {
|
||||
// 防止首次进入界面时(登录进入) tagsViewList 不存浏览器中
|
||||
addBrowserSetSession(state.tagsViewList);
|
||||
return false;
|
||||
}
|
||||
item = state.tagsViewRoutesList.find((v) => v.path === path);
|
||||
}
|
||||
if (!item || (item.meta.isLink && !item.meta.isIframe)) return false;
|
||||
|
|
@ -208,12 +218,20 @@ const addTagsView = (path, to) => {
|
|||
};
|
||||
// 2、刷新当前 tagsView:
|
||||
const refreshCurrentTagsView = async (fullPath) => {
|
||||
const item = state.tagsViewList.find((v) => (getThemeConfig.value.isShareTagsView ? v.path === fullPath : v.url === fullPath));
|
||||
if (item != null) {
|
||||
await storesKeepALiveNames.delCachedView(item);
|
||||
proxy.mittBus.emit('onTagsViewRefreshRouterView', fullPath);
|
||||
if (item.meta.isKeepAlive) storesKeepALiveNames.addCachedView(item);
|
||||
}
|
||||
const decodeURIPath = decodeURI(fullPath);
|
||||
let item = {};
|
||||
state.tagsViewList.forEach((v) => {
|
||||
v.transUrl = transUrlParams(v);
|
||||
if (v.transUrl) {
|
||||
if (v.transUrl === transUrlParams(v)) item = v;
|
||||
} else {
|
||||
if (v.path === decodeURIPath) item = v;
|
||||
}
|
||||
});
|
||||
if (!item) return false;
|
||||
await storesKeepALiveNames.delCachedView(item);
|
||||
mittBus.emit('onTagsViewRefreshRouterView', fullPath);
|
||||
if (item.meta.isKeepAlive) storesKeepALiveNames.addCachedView(item);
|
||||
};
|
||||
// 3、关闭当前 tagsView:如果是设置了固定的(isAffix),不可以关闭
|
||||
const closeCurrentTagsView = (path) => {
|
||||
|
|
@ -346,11 +364,31 @@ const onContextmenu = (v, e) => {
|
|||
state.dropdown.y = clientY;
|
||||
contextmenuRef.value.openContextmenu(v);
|
||||
};
|
||||
// 鼠标按下时,判断是鼠标中键就关闭当前 tasgview
|
||||
const onMousedownMenu = (v, e) => {
|
||||
if (!v.meta.isAffix && e.which === 2) {
|
||||
const item = Object.assign({}, { contextMenuClickId: 1, ...v });
|
||||
onCurrentContextmenuClick(item);
|
||||
}
|
||||
};
|
||||
// 当前的 tagsView 项点击时
|
||||
const onTagsClick = (v, k) => {
|
||||
state.tagsRefsIndex = k;
|
||||
router.push(v);
|
||||
};
|
||||
// 处理 url,地址栏链接有参数时,tagsview 右键菜单刷新功能失效问题
|
||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I5K3YO
|
||||
const transUrlParams = (v) => {
|
||||
let params = v.query && Object.keys(v.query).length > 0 ? v.query : v.params;
|
||||
if (!params) return '';
|
||||
let path = '';
|
||||
for (let [key, value] of Object.entries(params)) {
|
||||
if (v.meta.isDynamic) path += `/${value}`;
|
||||
else path += `&${key}=${value}`;
|
||||
}
|
||||
// 判断是否是动态路由(xxx/:id/:name")isDynamic
|
||||
return v.meta.isDynamic ? `${v.path.split(':')[0]}${path.replace(/^\//, '')}` : `${v.path}${path.replace(/^&/, '?')}`;
|
||||
};
|
||||
// 处理 tagsView 高亮(多标签详情时使用,单标签详情未使用)
|
||||
const setTagsViewHighlight = (v) => {
|
||||
let params = v.query && Object.keys(v.query).length > 0 ? v.query : v.params;
|
||||
|
|
@ -362,13 +400,9 @@ const setTagsViewHighlight = (v) => {
|
|||
// 判断是否是动态路由(xxx/:id/:name")
|
||||
return `${v.meta.isDynamic ? v.meta.isDynamicPath : v.path}-${path}`;
|
||||
};
|
||||
// 更新滚动条显示
|
||||
const updateScrollbar = () => {
|
||||
proxy.$refs.scrollbarRef.update();
|
||||
};
|
||||
// 鼠标滚轮滚动
|
||||
const onHandleScroll = (e) => {
|
||||
proxy.$refs.scrollbarRef.$refs.wrap$.scrollLeft += e.wheelDelta / 4;
|
||||
scrollbarRef.value.$refs.scrollbarRef.$refs.wrap$.scrollLeft += e.wheelDelta / 4;
|
||||
};
|
||||
// tagsView 横向滚动
|
||||
const tagsViewmoveToCurrentTag = () => {
|
||||
|
|
@ -385,7 +419,7 @@ const tagsViewmoveToCurrentTag = () => {
|
|||
// 最后 li
|
||||
let liLast = tagsRefs.value[tagsRefs.value.length - 1];
|
||||
// 当前滚动条的值
|
||||
let scrollRefs = proxy.$refs.scrollbarRef.$refs.wrap$;
|
||||
let scrollRefs = scrollbarRef.value.$refs.wrap$;
|
||||
// 当前滚动条滚动宽度
|
||||
let scrollS = scrollRefs.scrollWidth;
|
||||
// 当前滚动条偏移宽度
|
||||
|
|
@ -419,7 +453,7 @@ const tagsViewmoveToCurrentTag = () => {
|
|||
}
|
||||
}
|
||||
// 更新滚动条,防止不出现
|
||||
updateScrollbar();
|
||||
scrollbarRef.value.update();
|
||||
});
|
||||
};
|
||||
// 获取 tagsView 的下标:用于处理 tagsView 点击时的横向滚动
|
||||
|
|
@ -470,15 +504,15 @@ onBeforeMount(() => {
|
|||
// 拖动问题,https://gitee.com/lyt-top/vue-next-admin/issues/I3ZRRI
|
||||
window.addEventListener('resize', onSortableResize);
|
||||
// 监听非本页面调用 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部 4 当前页全屏
|
||||
proxy.mittBus.on('onCurrentContextmenuClick', (data) => {
|
||||
mittBus.on('onCurrentContextmenuClick', (data) => {
|
||||
onCurrentContextmenuClick(data);
|
||||
});
|
||||
// 监听布局配置界面开启/关闭拖拽
|
||||
proxy.mittBus.on('openOrCloseSortable', () => {
|
||||
mittBus.on('openOrCloseSortable', () => {
|
||||
initSortable();
|
||||
});
|
||||
// 监听布局配置开启 TagsView 共用,为了演示还原默认值
|
||||
proxy.mittBus.on('openShareTagsView', () => {
|
||||
mittBus.on('openShareTagsView', () => {
|
||||
if (getThemeConfig.value.isShareTagsView) {
|
||||
router.push('/home');
|
||||
state.tagsViewList = [];
|
||||
|
|
@ -494,11 +528,11 @@ onBeforeMount(() => {
|
|||
// 页面卸载时
|
||||
onUnmounted(() => {
|
||||
// 取消非本页面调用监听
|
||||
proxy.mittBus.off('onCurrentContextmenuClick', () => {});
|
||||
mittBus.off('onCurrentContextmenuClick', () => {});
|
||||
// 取消监听布局配置界面开启/关闭拖拽
|
||||
proxy.mittBus.off('openOrCloseSortable', () => {});
|
||||
mittBus.off('openOrCloseSortable', () => {});
|
||||
// 取消监听布局配置开启 TagsView 共用
|
||||
proxy.mittBus.off('openShareTagsView', () => {});
|
||||
mittBus.off('openShareTagsView', () => {});
|
||||
// 取消窗口 resize 监听
|
||||
window.removeEventListener('resize', onSortableResize);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
{{ val.meta.title }}
|
||||
</template>
|
||||
<template #title v-else>
|
||||
<a :href="val.meta.isLink" target="_blank" rel="opener" class="w100">
|
||||
<a class="w100" @click.prevent="onALinkClick(val)">
|
||||
<SvgIcon :name="val.meta.icon" />
|
||||
{{ val.meta.title }}
|
||||
</a>
|
||||
|
|
@ -35,7 +35,10 @@ import { storeToRefs } from 'pinia';
|
|||
import { useRoutesList } from '/@/stores/routesList';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { onBeforeRouteUpdate } from 'vue-router';
|
||||
import SubItem from '/@/layout/navMenu/subItem.vue';
|
||||
import { verifyUrl } from '/@/utils/toolsValidate';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
|
||||
const SubItem = defineAsyncComponent(() => import('/@/layout/navMenu/subItem.vue'));
|
||||
|
||||
const props = defineProps({
|
||||
menuList: {
|
||||
|
|
@ -43,12 +46,13 @@ const props = defineProps({
|
|||
default: () => [],
|
||||
},
|
||||
});
|
||||
const { proxy } = getCurrentInstance();
|
||||
const elMenuHorizontalScrollRef = ref();
|
||||
const stores = useRoutesList();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { routesList } = storeToRefs(stores);
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const state = reactive({
|
||||
defaultActive: null,
|
||||
});
|
||||
|
|
@ -59,14 +63,14 @@ const menuLists = computed(() => {
|
|||
// 设置横向滚动条可以鼠标滚轮滚动
|
||||
const onElMenuHorizontalScroll = (e) => {
|
||||
const eventDelta = e.wheelDelta || -e.deltaY * 40;
|
||||
proxy.$refs.elMenuHorizontalScrollRef.$refs.wrap$.scrollLeft = proxy.$refs.elMenuHorizontalScrollRef.$refs.wrap$.scrollLeft + eventDelta / 4;
|
||||
elMenuHorizontalScrollRef.value.$refs.wrap$.scrollLeft = elMenuHorizontalScrollRef.value.$refs.wrap$.scrollLeft + eventDelta / 4;
|
||||
};
|
||||
// 初始化数据,页面刷新时,滚动条滚动到对应位置
|
||||
const initElMenuOffsetLeft = () => {
|
||||
nextTick(() => {
|
||||
let els = document.querySelector('.el-menu.el-menu--horizontal li.is-active');
|
||||
if (!els) return false;
|
||||
proxy.$refs.elMenuHorizontalScrollRef.$refs.wrap$.scrollLeft = els.offsetLeft;
|
||||
elMenuHorizontalScrollRef.value.$refs.wrap$.scrollLeft = els.offsetLeft;
|
||||
});
|
||||
};
|
||||
// 路由过滤递归函数
|
||||
|
|
@ -104,6 +108,13 @@ const setCurrentRouterHighlight = (currentRoute) => {
|
|||
else state.defaultActive = path;
|
||||
}
|
||||
};
|
||||
// 打开外部链接
|
||||
const onALinkClick = (val) => {
|
||||
const { origin, pathname } = window.location;
|
||||
router.push(val.path);
|
||||
if (verifyUrl(val.meta.isLink)) window.open(val.meta.isLink);
|
||||
else window.open(`${origin}${pathname}#${val.meta.isLink}`);
|
||||
};
|
||||
// 页面加载前
|
||||
onBeforeMount(() => {
|
||||
setCurrentRouterHighlight(route);
|
||||
|
|
@ -119,7 +130,7 @@ onBeforeRouteUpdate((to) => {
|
|||
// 修复经典布局开启切割菜单时,点击tagsView后左侧导航菜单数据不变的问题
|
||||
let { layout, isClassicSplitMenu } = themeConfig.value;
|
||||
if (layout === 'classic' && isClassicSplitMenu) {
|
||||
proxy.mittBus.emit('setSendClassicChildren', setSendClassicChildren(to.path));
|
||||
mittBus.emit('setSendClassicChildren', setSendClassicChildren(to.path));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
<span>{{ val.meta.title }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a :href="val.meta.isLink" target="_blank" rel="opener" class="w100">
|
||||
<a class="w100" @click.prevent="onALinkClick(val)">
|
||||
<SvgIcon :name="val.meta.icon" />
|
||||
{{ val.meta.title }}
|
||||
</a>
|
||||
|
|
@ -25,15 +25,25 @@
|
|||
</template>
|
||||
|
||||
<script setup name="navMenuSubItem">
|
||||
import { useRouter } from 'vue-router';
|
||||
import { verifyUrl } from '/@/utils/toolsValidate';
|
||||
|
||||
const props = defineProps({
|
||||
chil: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
// 获取父级菜单数据
|
||||
const chils = computed(() => {
|
||||
return props.chil;
|
||||
});
|
||||
// 打开外部链接
|
||||
const onALinkClick = (val) => {
|
||||
const { origin, pathname } = window.location;
|
||||
router.push(val.path);
|
||||
if (verifyUrl(val.meta.isLink)) window.open(val.meta.isLink);
|
||||
else window.open(`${origin}${pathname}#${val.meta.isLink}`);
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
<span>{{ val.meta.title }}</span>
|
||||
</template>
|
||||
<template #title v-else>
|
||||
<a :href="val.meta.isLink" target="_blank" rel="opener" class="w100">{{ val.meta.title }}</a>
|
||||
<a class="w100" @click.prevent="onALinkClick(val)">{{ val.meta.title }}</a>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
|
@ -34,7 +34,9 @@
|
|||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { onBeforeRouteUpdate } from 'vue-router';
|
||||
import SubItem from '/@/layout/navMenu/subItem.vue';
|
||||
import { verifyUrl } from '/@/utils/toolsValidate';
|
||||
|
||||
const SubItem = defineAsyncComponent(() => import('/@/layout/navMenu/subItem.vue'));
|
||||
|
||||
const props = defineProps({
|
||||
menuList: {
|
||||
|
|
@ -45,6 +47,7 @@ const props = defineProps({
|
|||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const state = reactive({
|
||||
// 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G
|
||||
defaultActive: route.meta.isDynamic ? route.meta.isDynamicPath : route.path,
|
||||
|
|
@ -75,6 +78,13 @@ watch(
|
|||
immediate: true,
|
||||
}
|
||||
);
|
||||
// 打开外部链接
|
||||
const onALinkClick = (val) => {
|
||||
const { origin, pathname } = window.location;
|
||||
router.push(val.path);
|
||||
if (verifyUrl(val.meta.isLink)) window.open(val.meta.isLink);
|
||||
else window.open(`${origin}${pathname}#${val.meta.isLink}`);
|
||||
};
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
state.defaultActive = setParentHighlight(route);
|
||||
|
|
|
|||
|
|
@ -1,54 +1,77 @@
|
|||
<template>
|
||||
<div class="layout-view-bg-white flex mt1" :style="{ height: `calc(100vh - ${setIframeHeight}`, border: 'none' }" v-loading="state.iframeLoading">
|
||||
<iframe :src="iframeUrl" frameborder="0" height="100%" width="100%" ref="iframeDom" v-show="!iframeLoading"></iframe>
|
||||
<div class="layout-padding layout-padding-unset layout-iframe">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<div class="w100" v-for="v in setIframeList" :key="v.path" v-loading="v.meta.loading" element-loading-background="white">
|
||||
<transition-group :name="name" mode="out-in">
|
||||
<iframe
|
||||
:src="v.meta.isLink"
|
||||
:key="v.path"
|
||||
frameborder="0"
|
||||
height="100%"
|
||||
width="100%"
|
||||
style="position: absolute"
|
||||
:data-url="v.path"
|
||||
v-show="getRoutePath === v.path"
|
||||
ref="iframeRef"
|
||||
/>
|
||||
</transition-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="layoutIfameView">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||
|
||||
const props = defineProps({
|
||||
refreshKey: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: () => 'slide-right',
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
const iframeRef = ref();
|
||||
const route = useRoute();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
||||
const state = reactive({
|
||||
iframeLoading: true,
|
||||
iframeUrl: '',
|
||||
// 处理 list 列表,当打开时,才进行加载
|
||||
const setIframeList = computed(() => {
|
||||
return props.list.filter((v) => v.meta.isIframeOpen);
|
||||
});
|
||||
// 初始化页面加载 loading
|
||||
const initIframeLoad = () => {
|
||||
state.iframeUrl = route.meta.isLink;
|
||||
nextTick(() => {
|
||||
state.iframeLoading = true;
|
||||
const iframe = state.iframeDom;
|
||||
if (!iframe) return false;
|
||||
iframe.onload = () => {
|
||||
state.iframeLoading = false;
|
||||
};
|
||||
});
|
||||
};
|
||||
// 设置 iframe 的高度
|
||||
const setIframeHeight = computed(() => {
|
||||
let { isTagsview } = themeConfig.value;
|
||||
if (isTagsViewCurrenFull.value) {
|
||||
return `1px`;
|
||||
} else {
|
||||
if (isTagsview) return `86px`;
|
||||
else return `51px`;
|
||||
}
|
||||
// 获取 iframe 当前路由 path
|
||||
const getRoutePath = computed(() => {
|
||||
return route.path;
|
||||
});
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
initIframeLoad();
|
||||
});
|
||||
// 监听路由变化,多个 iframe 时使用
|
||||
// 监听路由变化,初始化 iframe 数据,防止多个 iframe 时,切换不生效
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
initIframeLoad();
|
||||
() => route.fullPath,
|
||||
(val) => {
|
||||
const item = props.list.find((v) => v.path === val);
|
||||
if (item && !item.meta.isIframeOpen) item.meta.isIframeOpen = true;
|
||||
nextTick(() => {
|
||||
if (!iframeRef.value) return false;
|
||||
iframeRef.value.forEach((v) => {
|
||||
if (v.dataset.url === val) {
|
||||
v.onload = () => {
|
||||
if (item && item.meta.isIframeOpen && item.meta.loading) item.meta.loading = false;
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
// 监听 iframe refreshKey 变化,用于 tagsview 右键菜单刷新
|
||||
watch(
|
||||
() => props.refreshKey,
|
||||
() => {},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,30 +1,34 @@
|
|||
<template>
|
||||
<div class="layout-view-bg-white flex layout-view-link" :style="{ height: `calc(100vh - ${setLinkHeight}` }">
|
||||
<a :href="state.currentRouteMeta.isLink" target="_blank" rel="opener" class="flex-margin">
|
||||
{{ state.currentRouteMeta.title }}:{{ state.currentRouteMeta.isLink }}
|
||||
</a>
|
||||
<div class="layout-padding layout-link-container">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<div class="layout-link-warp">
|
||||
<i class="layout-link-icon iconfont icon-xingqiu"></i>
|
||||
<div class="layout-link-msg">页面 "{{ state.currentRouteMeta.title }}" 已在新窗口中打开</div>
|
||||
<el-button class="mt30" round size="default" @click="onGotoFullPage">
|
||||
<i class="iconfont icon-lianjie"></i>
|
||||
<span>立即前往体验</span>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="layoutLinkView">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { verifyUrl } from '/@/utils/toolsValidate';
|
||||
|
||||
const route = useRoute();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const state = reactive({
|
||||
currentRouteMeta: {
|
||||
isLink: '',
|
||||
title: '',
|
||||
},
|
||||
});
|
||||
// 设置 link 的高度
|
||||
const setLinkHeight = computed(() => {
|
||||
let { isTagsview } = themeConfig.value;
|
||||
if (isTagsview) return `115px`;
|
||||
else return `80px`;
|
||||
});
|
||||
// 立即前往
|
||||
const onGotoFullPage = () => {
|
||||
const { origin, pathname } = window.location;
|
||||
if (verifyUrl(state.currentRouteMeta.isLink)) window.open(state.currentRouteMeta.isLink);
|
||||
else window.open(`${origin}${pathname}#${state.currentRouteMeta.isLink}`);
|
||||
};
|
||||
// 监听路由的变化,设置内容
|
||||
watch(
|
||||
() => route.path,
|
||||
|
|
@ -36,3 +40,51 @@ watch(
|
|||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.layout-link-container {
|
||||
.layout-link-warp {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
i.layout-link-icon {
|
||||
position: relative;
|
||||
font-size: 100px;
|
||||
color: var(--el-color-primary);
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
top: 0;
|
||||
width: 15px;
|
||||
height: 100px;
|
||||
background: linear-gradient(
|
||||
rgba(255, 255, 255, 0.01),
|
||||
rgba(255, 255, 255, 0.01),
|
||||
rgba(255, 255, 255, 0.01),
|
||||
rgba(255, 255, 255, 0.05),
|
||||
rgba(255, 255, 255, 0.05),
|
||||
rgba(255, 255, 255, 0.05),
|
||||
rgba(235, 255, 255, 0.5),
|
||||
rgba(255, 255, 255, 0.05),
|
||||
rgba(255, 255, 255, 0.05),
|
||||
rgba(255, 255, 255, 0.05),
|
||||
rgba(255, 255, 255, 0.01),
|
||||
rgba(255, 255, 255, 0.01),
|
||||
rgba(255, 255, 255, 0.01)
|
||||
);
|
||||
transform: rotate(-15deg);
|
||||
animation: toRight 5s linear infinite;
|
||||
}
|
||||
}
|
||||
.layout-link-msg {
|
||||
font-size: 12px;
|
||||
color: var(--next-bg-topBarColor);
|
||||
opacity: 0.7;
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
<template>
|
||||
<div class="h100">
|
||||
<div class="layout-parent">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition :name="setTransitionName" mode="out-in">
|
||||
<keep-alive :include="getKeepAliveNames">
|
||||
<component :is="Component" :key="state.refreshRouterViewKey" class="w100" />
|
||||
<component :is="Component" :key="state.refreshRouterViewKey" class="w100" v-show="!isIframePage" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
<transition :name="setTransitionName" mode="out-in">
|
||||
<Iframes class="w100" v-show="isIframePage" :refreshKey="state.iframeRefreshKey" :name="setTransitionName" :list="state.iframeList" />
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -15,16 +18,21 @@ import { storeToRefs } from 'pinia';
|
|||
import { useKeepALiveNames } from '/@/stores/keepAliveNames';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { Session } from '/@/utils/storage';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
|
||||
const Iframes = defineAsyncComponent(() => import('/@/layout/routerView/iframes.vue'));
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const storesKeepAliveNames = useKeepALiveNames();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { keepAliveNames, cachedViews } = storeToRefs(storesKeepAliveNames);
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const state = reactive({
|
||||
refreshRouterViewKey: null,
|
||||
refreshRouterViewKey: '', // 非 iframe tagsview 右键菜单刷新时
|
||||
iframeRefreshKey: '', // iframe tagsview 右键菜单刷新时
|
||||
keepAliveNameList: [],
|
||||
iframeList: [],
|
||||
});
|
||||
// 设置主界面切换动画
|
||||
const setTransitionName = computed(() => {
|
||||
|
|
@ -34,19 +42,36 @@ const setTransitionName = computed(() => {
|
|||
const getKeepAliveNames = computed(() => {
|
||||
return themeConfig.value.isTagsview ? cachedViews.value : state.keepAliveNameList;
|
||||
});
|
||||
// 设置 iframe 显示/隐藏
|
||||
const isIframePage = computed(() => {
|
||||
return route.meta.isIframe;
|
||||
});
|
||||
// 获取 iframe 组件列表(未进行渲染)
|
||||
const getIframeListRoutes = async () => {
|
||||
router.getRoutes().forEach((v) => {
|
||||
if (v.meta.isIframe) {
|
||||
v.meta.isIframeOpen = false;
|
||||
v.meta.loading = true;
|
||||
state.iframeList.push({ ...v });
|
||||
}
|
||||
});
|
||||
};
|
||||
// 页面加载前,处理缓存,页面刷新时路由缓存处理
|
||||
onBeforeMount(() => {
|
||||
state.keepAliveNameList = keepAliveNames.value;
|
||||
proxy.mittBus.on('onTagsViewRefreshRouterView', (fullPath) => {
|
||||
mittBus.on('onTagsViewRefreshRouterView', (fullPath) => {
|
||||
state.keepAliveNameList = keepAliveNames.value.filter((name) => route.name !== name);
|
||||
state.refreshRouterViewKey = null;
|
||||
state.refreshRouterViewKey = '';
|
||||
state.iframeRefreshKey = '';
|
||||
nextTick(() => {
|
||||
state.refreshRouterViewKey = fullPath;
|
||||
state.iframeRefreshKey = fullPath;
|
||||
state.keepAliveNameList = keepAliveNames.value;
|
||||
});
|
||||
});
|
||||
}); // 页面加载时
|
||||
onMounted(() => {
|
||||
getIframeListRoutes();
|
||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I58U75
|
||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I59RXK
|
||||
nextTick(() => {
|
||||
|
|
@ -57,13 +82,17 @@ onMounted(() => {
|
|||
});
|
||||
// 页面卸载时
|
||||
onUnmounted(() => {
|
||||
proxy.mittBus.off('onTagsViewRefreshRouterView');
|
||||
mittBus.off('onTagsViewRefreshRouterView');
|
||||
});
|
||||
// 监听路由变化,防止 tagsView 多标签时,切换动画消失
|
||||
// https://toscode.gitee.com/lyt-top/vue-next-admin/pulls/38/files
|
||||
watch(
|
||||
() => route.fullPath,
|
||||
() => {
|
||||
state.refreshRouterViewKey = decodeURI(route.fullPath);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import other from '/@/utils/other';
|
|||
import ElementPlus from 'element-plus';
|
||||
import 'element-plus/dist/index.css';
|
||||
import '/@/theme/index.scss';
|
||||
import mitt from 'mitt';
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
|
|
@ -16,5 +15,3 @@ directive(app);
|
|||
other.elSvg(app);
|
||||
|
||||
app.use(pinia).use(router).use(ElementPlus).mount('#app');
|
||||
|
||||
app.config.globalProperties.mittBus = mitt();
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ export function setCacheTagsViewRoutes() {
|
|||
*/
|
||||
export function setFilterRouteEnd() {
|
||||
let filterRouteEnd = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
|
||||
// notFoundAndNoPower 防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
|
||||
// 关联问题 No match found for location with path 'xxx'
|
||||
filterRouteEnd[0].children = [...filterRouteEnd[0].children, ...notFoundAndNoPower];
|
||||
return filterRouteEnd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ export async function frontEndsResetRoute() {
|
|||
*/
|
||||
export function setFilterRouteEnd() {
|
||||
let filterRouteEnd = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
|
||||
// notFoundAndNoPower 防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
|
||||
// 关联问题 No match found for location with path 'xxx'
|
||||
filterRouteEnd[0].children = [...setFilterRoute(filterRouteEnd[0].children), ...notFoundAndNoPower];
|
||||
return filterRouteEnd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { useKeepALiveNames } from '/@/stores/keepAliveNames';
|
|||
import { useRoutesList } from '/@/stores/routesList';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { Session } from '/@/utils/storage';
|
||||
import { staticRoutes } from '/@/router/route';
|
||||
import { staticRoutes, notFoundAndNoPower } from '/@/router/route';
|
||||
import { initFrontEndControlRoutes } from '/@/router/frontEnd';
|
||||
import { initBackEndControlRoutes } from '/@/router/backEnd';
|
||||
|
||||
|
|
@ -32,7 +32,13 @@ const { isRequestRoutes } = themeConfig.value;
|
|||
*/
|
||||
export const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes: staticRoutes,
|
||||
/**
|
||||
* 说明:
|
||||
* 1、notFoundAndNoPower 默认添加 404、401 界面,防止一直提示 No match found for location with path 'xxx'
|
||||
* 2、backEnd.ts(后端控制路由)、frontEnd.ts(前端控制路由) 中也需要加 notFoundAndNoPower 404、401 界面。
|
||||
* 防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
|
||||
*/
|
||||
routes: [...notFoundAndNoPower, ...staticRoutes],
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -107,13 +113,12 @@ router.beforeEach(async (to, from, next) => {
|
|||
if (isRequestRoutes) {
|
||||
// 后端控制路由:路由数据初始化,防止刷新时丢失
|
||||
await initBackEndControlRoutes();
|
||||
// 动态添加路由:防止非首页刷新时跳转回首页的问题
|
||||
// 确保 addRoute() 时动态添加的路由已经被完全加载上去
|
||||
next({ ...to, replace: true });
|
||||
// 解决刷新时,一直跳 404 页面问题,关联问题 No match found for location with path 'xxx'
|
||||
next({ path: to.path });
|
||||
} else {
|
||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
|
||||
await initFrontEndControlRoutes();
|
||||
next({ ...to, replace: true });
|
||||
next({ path: to.path });
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* 路由meta对象参数说明
|
||||
* meta: {
|
||||
* title: 菜单栏及 tagsView 栏、菜单搜索名称(国际化)
|
||||
* isLink: 是否超链接菜单,开启外链条件,`1、isLink: 链接地址不为空`
|
||||
* isLink: 是否超链接菜单,开启外链条件,`1、isLink: 链接地址不为空 2、isIframe:false`
|
||||
* isHide: 是否隐藏此路由
|
||||
* isKeepAlive: 是否缓存组件状态
|
||||
* isAffix: 是否固定在 tagsView 栏上
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@ export const useKeepALiveNames = defineStore('keepALiveNames', {
|
|||
this.keepAliveNames = data;
|
||||
},
|
||||
async addCachedView(view) {
|
||||
if (this.cachedViews.includes(view.name)) return;
|
||||
if (view.meta.isKeepAlive) this.cachedViews.push(view.name);
|
||||
if (view.meta.isKeepAlive) this.cachedViews?.push(view.name);
|
||||
},
|
||||
async delCachedView(view) {
|
||||
const index = this.cachedViews.indexOf(view.name);
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ export const useThemeConfig = defineStore('themeConfig', {
|
|||
columnsMenuBarColor: '#e6e6e6',
|
||||
// 是否开启分栏菜单背景颜色渐变
|
||||
isColumnsMenuBarColorGradual: false,
|
||||
// 是否开启分栏菜单鼠标悬停预加载(预览菜单)
|
||||
isColumnsMenuHoverPreload: false,
|
||||
|
||||
/**
|
||||
* 界面设置
|
||||
|
|
@ -53,7 +55,7 @@ export const useThemeConfig = defineStore('themeConfig', {
|
|||
// 是否开启菜单水平折叠效果
|
||||
isCollapse: false,
|
||||
// 是否开启菜单手风琴效果
|
||||
isUniqueOpened: false,
|
||||
isUniqueOpened: true,
|
||||
// 是否开启固定 Header
|
||||
isFixedHeader: false,
|
||||
// 初始化变量,用于更新菜单 el-scrollbar 的高度,请勿删除
|
||||
|
|
@ -87,15 +89,15 @@ export const useThemeConfig = defineStore('themeConfig', {
|
|||
// 是否开启 TagsView 共用
|
||||
isShareTagsView: false,
|
||||
// 是否开启 Footer 底部版权信息
|
||||
isFooter: false,
|
||||
isFooter: true,
|
||||
// 是否开启灰色模式
|
||||
isGrayscale: false,
|
||||
// 是否开启色弱模式
|
||||
isInvert: false,
|
||||
// 是否开启水印
|
||||
isWartermark: false,
|
||||
isWartermark: true,
|
||||
// 水印文案
|
||||
wartermarkText: 'small@小柒',
|
||||
wartermarkText: 'vue-next-admin',
|
||||
|
||||
/**
|
||||
* 其它设置
|
||||
|
|
@ -131,6 +133,8 @@ export const useThemeConfig = defineStore('themeConfig', {
|
|||
globalTitle: 'vue-next-admin',
|
||||
// 网站副标题(登录页顶部文字)
|
||||
globalViceTitle: 'vueNextAdmin',
|
||||
// 网站副标题(登录页顶部文字)
|
||||
globalViceTitleMsg: '专注、免费、开源、维护、解疑',
|
||||
// 默认初始语言,可选值"<zh-cn|en|zh-tw>",默认 zh-cn
|
||||
globalI18n: 'zh-cn',
|
||||
// 默认全局组件大小,可选值"<large|'default'|small>",默认 'large'
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export const useUserInfo = defineStore('userInfo', {
|
|||
// 存储用户信息到浏览器缓存
|
||||
Session.set('userInfo', userInfos);
|
||||
resolve(userInfos);
|
||||
}, 3000);
|
||||
}, 0);
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -46,6 +46,14 @@ body,
|
|||
.layout-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.layout-pd {
|
||||
padding: 15px !important;
|
||||
}
|
||||
.layout-flex {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
.layout-aside {
|
||||
background: var(--next-bg-menuBar);
|
||||
box-shadow: 2px 0 6px rgb(0 21 41 / 1%);
|
||||
|
|
@ -61,24 +69,63 @@ body,
|
|||
}
|
||||
.layout-header {
|
||||
padding: 0 !important;
|
||||
height: auto !important;
|
||||
}
|
||||
.layout-main {
|
||||
padding: 0 !important;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
background-color: var(--next-bg-main-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// 内层 el-scrollbar样式,用于界面高度自适应(main.vue)
|
||||
.layout-main-scroll {
|
||||
@extend .layout-flex;
|
||||
.layout-parent {
|
||||
@extend .layout-flex;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 用于界面高度自适应
|
||||
.layout-padding {
|
||||
@extend .layout-pd;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
@extend .layout-flex;
|
||||
&-auto {
|
||||
height: inherit;
|
||||
@extend .layout-flex;
|
||||
}
|
||||
&-view {
|
||||
background: var(--el-color-white);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--el-border-color-light, #ebeef5);
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
// 用于界面高度自适应,主视图区 main 的内边距,用于 iframe
|
||||
.layout-padding-unset {
|
||||
padding: 0 !important;
|
||||
&-view {
|
||||
border-radius: 0 !important;
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
// 用于设置 iframe loading 时的高度(loading 垂直居中显示)
|
||||
.layout-iframe {
|
||||
.el-loading-parent--relative {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.el-scrollbar {
|
||||
width: 100%;
|
||||
}
|
||||
// 此字段多次用到,建议不删除,如需修改,请重写覆盖样式
|
||||
.layout-view-bg-white {
|
||||
background: var(--el-color-white);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--el-border-color-light, #ebeef5);
|
||||
}
|
||||
.layout-el-aside-br-color {
|
||||
border-right: 1px solid var(--el-border-color-light, #ebeef5);
|
||||
}
|
||||
|
|
@ -122,10 +169,6 @@ body,
|
|||
z-index: 9999998;
|
||||
animation: error-img 0.3s;
|
||||
}
|
||||
.layout-scrollbar {
|
||||
@extend .el-scrollbar;
|
||||
padding: 15px;
|
||||
}
|
||||
.layout-mian-height-50 {
|
||||
height: calc(100vh - 50px);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,3 +92,56 @@
|
|||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 登录页动画
|
||||
------------------------------- */
|
||||
@keyframes loginLeft {
|
||||
0% {
|
||||
left: -100%;
|
||||
}
|
||||
50%,
|
||||
100% {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
@keyframes loginTop {
|
||||
0% {
|
||||
top: -100%;
|
||||
}
|
||||
50%,
|
||||
100% {
|
||||
top: 100%;
|
||||
}
|
||||
}
|
||||
@keyframes loginRight {
|
||||
0% {
|
||||
right: -100%;
|
||||
}
|
||||
50%,
|
||||
100% {
|
||||
right: 100%;
|
||||
}
|
||||
}
|
||||
@keyframes loginBottom {
|
||||
0% {
|
||||
bottom: -100%;
|
||||
}
|
||||
50%,
|
||||
100% {
|
||||
bottom: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 左右左 link.vue
|
||||
------------------------------- */
|
||||
@keyframes toRight {
|
||||
0% {
|
||||
left: -5px;
|
||||
}
|
||||
50% {
|
||||
left: 100%;
|
||||
}
|
||||
100% {
|
||||
left: -5px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,4 +233,9 @@
|
|||
border-color: var(--el-border-color-lighter) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// loading
|
||||
.el-loading-mask {
|
||||
background-color: var(--next-bg-main) !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,6 @@
|
|||
font-size: 12px !important;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.el-button.is-circle i.el-icon {
|
||||
margin-right: unset !important;
|
||||
}
|
||||
|
||||
/* Input 输入框、InputNumber 计数器
|
||||
------------------------------- */
|
||||
|
|
@ -47,6 +44,10 @@
|
|||
margin-bottom: 18px !important;
|
||||
}
|
||||
}
|
||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I5K1PM
|
||||
.el-form-item .el-form-item__label .el-icon {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Alert 警告
|
||||
|
|
@ -262,17 +263,24 @@
|
|||
.el-scrollbar__bar {
|
||||
z-index: 4;
|
||||
}
|
||||
/*防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)*/
|
||||
.el-scrollbar__wrap {
|
||||
max-height: 100%; /*防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)*/
|
||||
max-height: 100%;
|
||||
}
|
||||
.el-select-dropdown .el-scrollbar__wrap {
|
||||
overflow-x: scroll !important;
|
||||
}
|
||||
/*修复Select 选择器高度问题*/
|
||||
.el-select-dropdown__wrap {
|
||||
max-height: 274px !important; /*修复Select 选择器高度问题*/
|
||||
max-height: 274px !important;
|
||||
}
|
||||
/*修复Cascader 级联选择器高度问题*/
|
||||
.el-cascader-menu__wrap.el-scrollbar__wrap {
|
||||
height: 204px !important; /*修复Cascader 级联选择器高度问题*/
|
||||
height: 204px !important;
|
||||
}
|
||||
/*用于界面高度自适应(main.vue),区分 scrollbar__view,防止其它使用 scrollbar 的地方出现滚动条消失*/
|
||||
.layout-container-view .el-scrollbar__view {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Drawer 抽屉
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
margin-left: 0 !important;
|
||||
}
|
||||
.el-form-item {
|
||||
// 响应式表单时,登录页需要重新处理
|
||||
display: unset !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,23 @@
|
|||
@import './index.scss';
|
||||
|
||||
/* 页面宽度小于992px
|
||||
/* 页面宽度小于1200px
|
||||
------------------------------- */
|
||||
@media screen and (max-width: $lg) {
|
||||
@media screen and (max-width: $lg) and (min-width: $xs) {
|
||||
.login-container {
|
||||
.login-icon-group {
|
||||
&::before {
|
||||
content: '';
|
||||
height: 70% !important;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
&::after {
|
||||
content: '';
|
||||
width: 100px !important;
|
||||
height: 200px !important;
|
||||
transition: all 0.3s ease;
|
||||
.login-left {
|
||||
.login-left-img {
|
||||
top: 90% !important;
|
||||
left: 12% !important;
|
||||
width: 30% !important;
|
||||
height: 18% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 页面宽度小于992px
|
||||
------------------------------- */
|
||||
@media screen and (max-width: $md) {
|
||||
.login-content {
|
||||
right: unset !important;
|
||||
left: 50% !important;
|
||||
transform: translate(-50%, -50%) translate3d(0, 0, 0) !important;
|
||||
.login-right {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -34,19 +25,34 @@
|
|||
------------------------------- */
|
||||
@media screen and (max-width: $xs) {
|
||||
.login-container {
|
||||
.login-icon-group {
|
||||
display: none !important;
|
||||
.login-left {
|
||||
display: none;
|
||||
}
|
||||
.login-content {
|
||||
.login-right {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
padding: 20px 0 !important;
|
||||
border-radius: 0 !important;
|
||||
box-shadow: unset !important;
|
||||
border: none !important;
|
||||
}
|
||||
.el-form-item {
|
||||
display: flex !important;
|
||||
.login-right-warp {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
border: none !important;
|
||||
.login-right-warp-mian {
|
||||
.el-form-item {
|
||||
display: flex !important;
|
||||
}
|
||||
.login-right-warp-main-title {
|
||||
font-size: 20px !important;
|
||||
}
|
||||
}
|
||||
.login-right-warp-one {
|
||||
&::after {
|
||||
right: 0 !important;
|
||||
}
|
||||
}
|
||||
.login-right-warp-two {
|
||||
&::before {
|
||||
bottom: 1px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -55,9 +61,14 @@
|
|||
------------------------------- */
|
||||
@media screen and (max-width: $us) {
|
||||
.login-container {
|
||||
.login-content-title {
|
||||
font-size: 18px !important;
|
||||
transition: all 0.3s ease;
|
||||
.login-right {
|
||||
.login-right-warp {
|
||||
.login-right-warp-mian {
|
||||
.login-right-warp-main-title {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* wangeditor富文本编辑器
|
||||
/* wangeditor 富文本编辑器
|
||||
------------------------------- */
|
||||
.editor-container {
|
||||
z-index: 9999;
|
||||
z-index: 10; // 用于 wangeditor 点击全屏时
|
||||
.w-e-toolbar {
|
||||
border: 1px solid var(--el-border-color-light, #ebeef5) !important;
|
||||
border-bottom: 1px solid var(--el-border-color-light, #ebeef5) !important;
|
||||
|
|
|
|||
|
|
@ -32,11 +32,13 @@ export const NextLoading = {
|
|||
window.nextLoading = true;
|
||||
},
|
||||
// 移除 loading
|
||||
done: () => {
|
||||
done: (time = 0) => {
|
||||
nextTick(() => {
|
||||
window.nextLoading = false;
|
||||
const el = document.querySelector('.loading-next');
|
||||
el?.parentNode?.removeChild(el);
|
||||
setTimeout(() => {
|
||||
window.nextLoading = false;
|
||||
const el = document.querySelector('.loading-next');
|
||||
el?.parentNode?.removeChild(el);
|
||||
}, time);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
// https://www.npmjs.com/package/mitt
|
||||
import mitt from 'mitt';
|
||||
|
||||
// 类型
|
||||
const emitter = mitt();
|
||||
|
||||
// 导出
|
||||
export default emitter;
|
||||
|
|
@ -1,45 +1,30 @@
|
|||
<template>
|
||||
<div class="error layout-view-bg-white" :style="{ height: `calc(100vh - ${initTagViewHeight}` }">
|
||||
<div class="error-flex">
|
||||
<div class="left">
|
||||
<div class="left-item">
|
||||
<div class="left-item-animation left-item-num">401</div>
|
||||
<div class="left-item-animation left-item-title">您未被授权,没有操作权限~</div>
|
||||
<div class="left-item-animation left-item-msg">联系方式:加QQ群探讨 665452019</div>
|
||||
<div class="left-item-animation left-item-btn">
|
||||
<el-button type="primary" round @click="onSetAuth">重新授权</el-button>
|
||||
<div class="error layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<div class="error-flex">
|
||||
<div class="left">
|
||||
<div class="left-item">
|
||||
<div class="left-item-animation left-item-num">401</div>
|
||||
<div class="left-item-animation left-item-title">您未被授权,没有操作权限~</div>
|
||||
<div class="left-item-animation left-item-msg">联系方式:加QQ群探讨 665452019</div>
|
||||
<div class="left-item-animation left-item-btn">
|
||||
<el-button type="primary" size="default" round @click="onSetAuth">重新授权</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<img
|
||||
src="https://img-blog.csdnimg.cn/3333f265772a4fa89287993500ecbf96.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16"
|
||||
/>
|
||||
<div class="right">
|
||||
<img
|
||||
src="https://img-blog.csdnimg.cn/3333f265772a4fa89287993500ecbf96.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="401">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||
import { Session } from '/@/utils/storage';
|
||||
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
||||
// 设置主内容的高度
|
||||
const initTagViewHeight = computed(() => {
|
||||
let { isTagsview } = themeConfig.value;
|
||||
if (isTagsViewCurrenFull.value) {
|
||||
return `30px`;
|
||||
} else {
|
||||
if (isTagsview) return `114px`;
|
||||
else return `80px`;
|
||||
}
|
||||
});
|
||||
// 重新授权
|
||||
const onSetAuth = () => {
|
||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I5C3JS
|
||||
|
|
@ -53,8 +38,6 @@ const onSetAuth = () => {
|
|||
<style scoped lang="scss">
|
||||
.error {
|
||||
height: 100%;
|
||||
background-color: var(--el-color-white);
|
||||
display: flex;
|
||||
.error-flex {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -1,45 +1,29 @@
|
|||
<template>
|
||||
<div class="error layout-view-bg-white" :style="{ height: `calc(100vh - ${initTagViewHeight}` }">
|
||||
<div class="error-flex">
|
||||
<div class="left">
|
||||
<div class="left-item">
|
||||
<div class="left-item-animation left-item-num">404</div>
|
||||
<div class="left-item-animation left-item-title">地址输入错误,请重新输入地址~</div>
|
||||
<div class="left-item-animation left-item-msg">您可以先检查网址,然后重新输入或给我们反馈问题。</div>
|
||||
<div class="left-item-animation left-item-btn">
|
||||
<el-button type="primary" round @click="onGoHome">返回首页</el-button>
|
||||
<div class="error layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<div class="error-flex">
|
||||
<div class="left">
|
||||
<div class="left-item">
|
||||
<div class="left-item-animation left-item-num">404</div>
|
||||
<div class="left-item-animation left-item-title">地址输入错误,请重新输入地址~</div>
|
||||
<div class="left-item-animation left-item-msg">您可以先检查网址,然后重新输入或给我们反馈问题。</div>
|
||||
<div class="left-item-animation left-item-btn">
|
||||
<el-button type="primary" size="default" round @click="onGoHome">返回首页</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<img
|
||||
src="https://img-blog.csdnimg.cn/9eb1d85a417f4ed1ba7107f149ce3da1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16"
|
||||
/>
|
||||
<div class="right">
|
||||
<img
|
||||
src="https://img-blog.csdnimg.cn/9eb1d85a417f4ed1ba7107f149ce3da1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="404">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||
|
||||
const router = useRouter();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
||||
// 设置主内容的高度
|
||||
const initTagViewHeight = computed(() => {
|
||||
let { isTagsview } = themeConfig.value;
|
||||
if (isTagsViewCurrenFull.value) {
|
||||
return `30px`;
|
||||
} else {
|
||||
if (isTagsview) return `114px`;
|
||||
else return `80px`;
|
||||
}
|
||||
});
|
||||
// 返回首页
|
||||
const onGoHome = () => {
|
||||
router.push('/');
|
||||
|
|
@ -49,8 +33,6 @@ const onGoHome = () => {
|
|||
<style scoped lang="scss">
|
||||
.error {
|
||||
height: 100%;
|
||||
background-color: var(--el-color-white);
|
||||
display: flex;
|
||||
.error-flex {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="home-container">
|
||||
<div class="home-container layout-pd">
|
||||
<el-row :gutter="15" class="home-card-one mb15">
|
||||
<el-col
|
||||
:xs="24"
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@
|
|||
</el-col>
|
||||
<el-col :span="1"></el-col>
|
||||
<el-col :span="8">
|
||||
<el-button class="login-content-code">1234</el-button>
|
||||
<el-button class="login-content-code" v-waves>1234</el-button>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item class="login-animation4">
|
||||
<el-button type="primary" class="login-content-submit" round @click="onSignIn" :loading="state.loading.signIn">
|
||||
<el-button type="primary" class="login-content-submit" round v-waves @click="onSignIn" :loading="state.loading.signIn">
|
||||
<span>登 录</span>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
|
@ -54,10 +54,10 @@ import { Session } from '/@/utils/storage';
|
|||
import { formatAxis } from '/@/utils/formatTime';
|
||||
import { NextLoading } from '/@/utils/loading';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const state = reactive({
|
||||
isShowPassword: false,
|
||||
ruleForm: {
|
||||
|
|
@ -75,9 +75,10 @@ const currentTime = computed(() => {
|
|||
});
|
||||
// 登录
|
||||
const onSignIn = async () => {
|
||||
state.loading.signIn = true;
|
||||
// 存储 token 到浏览器缓存
|
||||
Session.set('token', Math.random().toString(36).substr(0));
|
||||
// 模拟数据,对接接口时,记得删除多余代码及对应依赖的引入。用于 `/src/stores/userInfo.js` 中不同用户登录判断(模拟数据)
|
||||
// 模拟数据,对接接口时,记得删除多余代码及对应依赖的引入。用于 `/src/stores/userInfo.ts` 中不同用户登录判断(模拟数据)
|
||||
Cookies.set('userName', state.ruleForm.userName);
|
||||
if (!themeConfig.value.isRequestRoutes) {
|
||||
// 前端控制路由,2、请注意执行顺序
|
||||
|
|
@ -85,6 +86,7 @@ const onSignIn = async () => {
|
|||
signInSuccess();
|
||||
} else {
|
||||
// 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
|
||||
// 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
|
||||
await initBackEndControlRoutes();
|
||||
// 执行完 initBackEndControlRoutes,再执行 signInSuccess
|
||||
signInSuccess();
|
||||
|
|
@ -95,7 +97,6 @@ const signInSuccess = () => {
|
|||
// 初始化登录成功时间问候语
|
||||
let currentTimeInfo = currentTime.value;
|
||||
// 登录成功,跳到转首页
|
||||
// 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
|
||||
// 如果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
|
||||
if (route.query?.redirect) {
|
||||
router.push({
|
||||
|
|
@ -110,6 +111,7 @@ const signInSuccess = () => {
|
|||
state.loading.signIn = true;
|
||||
const signInText = '欢迎回来!';
|
||||
ElMessage.success(`${currentTimeInfo},${signInText}`);
|
||||
// 添加 loading,防止第一次进入界面时出现短暂空白
|
||||
NextLoading.start();
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@
|
|||
</el-col>
|
||||
<el-col :span="1"></el-col>
|
||||
<el-col :span="8">
|
||||
<el-button class="login-content-code">获取验证码</el-button>
|
||||
<el-button v-waves class="login-content-code">获取验证码</el-button>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item class="login-animation3">
|
||||
<el-button round type="primary" class="login-content-submit">
|
||||
<el-button round type="primary" v-waves class="login-content-submit">
|
||||
<span>登 录</span>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,28 @@
|
|||
<template>
|
||||
<div class="login-scan-container">
|
||||
<div ref="qrcodeRef"></div>
|
||||
<div class="font12 mt20 login-msg">打开手机扫一扫,快速登录/注册</div>
|
||||
<div class="font12 mt20 login-msg">
|
||||
<i class="iconfont icon-saoyisao mr5"></i>
|
||||
<span>打开手机扫一扫,快速登录/注册</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="loginScan">
|
||||
import QRCode from 'qrcodejs2-fixes';
|
||||
|
||||
const qrcodeRef = ref('');
|
||||
const qrcodeRef = ref(null);
|
||||
// 初始化生成二维码
|
||||
const initQrcode = () => {
|
||||
qrcodeRef.value.innerHTML = '';
|
||||
new QRCode(qrcodeRef.value, {
|
||||
text: `https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi`,
|
||||
width: 260,
|
||||
height: 260,
|
||||
colorDark: '#000000',
|
||||
colorLight: '#ffffff',
|
||||
nextTick(() => {
|
||||
qrcodeRef.value.innerHTML = '';
|
||||
new QRCode(qrcodeRef.value, {
|
||||
text: `https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi`,
|
||||
width: 260,
|
||||
height: 260,
|
||||
colorDark: '#000000',
|
||||
colorLight: '#ffffff',
|
||||
});
|
||||
});
|
||||
};
|
||||
// 页面加载时
|
||||
|
|
@ -34,7 +39,7 @@ onMounted(() => {
|
|||
animation-fill-mode: forwards;
|
||||
}
|
||||
.login-scan-container {
|
||||
padding: 20px;
|
||||
padding: 0 20px 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
|
|
@ -44,6 +49,9 @@ onMounted(() => {
|
|||
margin: auto;
|
||||
}
|
||||
.login-msg {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--el-text-color-placeholder);
|
||||
@extend .login-scan-animation;
|
||||
animation-delay: 0.2s;
|
||||
|
|
|
|||
|
|
@ -1,44 +1,58 @@
|
|||
<template>
|
||||
<div class="login-container">
|
||||
<div class="login-icon-group">
|
||||
<div class="login-icon-group-title">
|
||||
<div class="login-container flex">
|
||||
<div class="login-left">
|
||||
<div class="login-left-logo">
|
||||
<img :src="logoMini" />
|
||||
<div class="login-icon-group-title-text font25">{{ getThemeConfig.globalViceTitle }}</div>
|
||||
</div>
|
||||
<img :src="loginIconTwo" class="login-icon-group-icon" />
|
||||
</div>
|
||||
<div class="login-content">
|
||||
<div class="login-content-main">
|
||||
<h4 class="login-content-title ml15">{{ getThemeConfig.globalTitle }}后台模板</h4>
|
||||
<div v-if="!state.isScan">
|
||||
<el-tabs v-model="state.tabsActiveName">
|
||||
<el-tab-pane label="账号密码登录" name="account">
|
||||
<Account />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="手机号登录" name="mobile">
|
||||
<Mobile />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="login-left-logo-text">
|
||||
<span>{{ getThemeConfig.globalViceTitle }}</span>
|
||||
<span class="login-left-logo-text-msg">{{ getThemeConfig.globalViceTitleMsg }}</span>
|
||||
</div>
|
||||
<Scan v-if="state.isScan" />
|
||||
<div class="login-content-main-sacn" @click="state.isScan = !state.isScan">
|
||||
<i class="iconfont" :class="state.isScan ? 'icon-diannao1' : 'icon-barcode-qr'"></i>
|
||||
<div class="login-content-main-sacn-delta"></div>
|
||||
</div>
|
||||
<div class="login-left-img">
|
||||
<img :src="loginMain" />
|
||||
</div>
|
||||
<img :src="loginBg" class="login-left-waves" />
|
||||
</div>
|
||||
<div class="login-right flex">
|
||||
<div class="login-right-warp flex-margin">
|
||||
<span class="login-right-warp-one"></span>
|
||||
<span class="login-right-warp-two"></span>
|
||||
<div class="login-right-warp-mian">
|
||||
<div class="login-right-warp-main-title">{{ getThemeConfig.globalTitle }} 欢迎您!</div>
|
||||
<div class="login-right-warp-main-form">
|
||||
<div v-if="!state.isScan">
|
||||
<el-tabs v-model="state.tabsActiveName">
|
||||
<el-tab-pane label="账号密码登录" name="account">
|
||||
<Account />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="手机号登录" name="mobile">
|
||||
<Mobile />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<Scan v-if="state.isScan" />
|
||||
<div class="login-content-main-sacn" @click="state.isScan = !state.isScan">
|
||||
<i class="iconfont" :class="state.isScan ? 'icon-diannao1' : 'icon-barcode-qr'"></i>
|
||||
<div class="login-content-main-sacn-delta"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="login">
|
||||
<script setup name="loginIndex">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { NextLoading } from '/@/utils/loading';
|
||||
import Account from '/@/views/login/component/account.vue';
|
||||
import Mobile from '/@/views/login/component/mobile.vue';
|
||||
import Scan from '/@/views/login/component/scan.vue';
|
||||
import logoMini from '/@/assets/logo-mini.svg';
|
||||
import loginIconTwo from '/@/assets/login-icon-two.svg';
|
||||
import loginMain from '/@/assets/login-main.svg';
|
||||
import loginBg from '/@/assets/login-bg.svg';
|
||||
|
||||
const Account = defineAsyncComponent(() => import('/@/views/login/component/account.vue'));
|
||||
const Mobile = defineAsyncComponent(() => import('/@/views/login/component/mobile.vue'));
|
||||
const Scan = defineAsyncComponent(() => import('/@/views/login/component/scan.vue'));
|
||||
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
|
|
@ -58,122 +72,176 @@ onMounted(() => {
|
|||
|
||||
<style scoped lang="scss">
|
||||
.login-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
background: var(--el-color-white);
|
||||
.login-icon-group {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.login-left {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
.login-icon-group-title {
|
||||
background-color: rgba(211, 239, 255, 1);
|
||||
margin-right: 100px;
|
||||
.login-left-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 80px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
z-index: 1;
|
||||
animation: logoAnimation 0.3s ease;
|
||||
img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
}
|
||||
&-text {
|
||||
padding-left: 15px;
|
||||
color: var(--el-color-primary);
|
||||
.login-left-logo-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
span {
|
||||
margin-left: 10px;
|
||||
font-size: 28px;
|
||||
color: #26a59a;
|
||||
}
|
||||
.login-left-logo-text-msg {
|
||||
font-size: 12px;
|
||||
color: #32a99e;
|
||||
}
|
||||
}
|
||||
}
|
||||
&::before {
|
||||
content: '';
|
||||
.login-left-img {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 60%;
|
||||
overflow: hidden;
|
||||
height: 80%;
|
||||
-webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='1200' height='770' xmlns='http://www.w3.org/2000/svg' fill='none'%3E%3Cg%3E%3Cpath id='svg_1' d='M58.4 47.77C104.6 59.51 135.26 67.37 162.11 78.04C188.97 88.72 226.33 102.69 265.92 123.55C305.51 144.4 366.96 167.09 441.43 121.52C515.9 75.95 546.48 61.01 577.69 46.27C608.9 31.53 625.86 23.69 680.26 12.28C734.65 0.87 837.29 10.7 867.29 21.8C897.29 32.9 935.51 51.9 962.21 95.45C988.9 139.01 972.91 177.36 951.37 221.39C929.83 265.43 883.49 306 890.44 337.33C897.4 368.66 974.73 412.18 974.73 411.47C974.73 412.18 1066.36 457.62 1106.36 491.06C1146.36 524.5 1178.8 563.36 1184.03 579.63C1189.26 595.9 1200.4 622.49 1181.55 676.88C1162.71 731.26 1127.16 764.32 1115.31 778.64C1103.45 792.96 5.34 783.61 4.32 784.63C3.3 785.65 -172.34 2.38 1.13 35.04L58.4 47.77L58.4 47.77Z' fill='%23409eff'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
||||
background: var(--el-color-primary-light-5);
|
||||
transition: all 0.3s ease;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100%;
|
||||
height: 52%;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
animation: error-num 0.6s ease;
|
||||
}
|
||||
}
|
||||
&::after {
|
||||
content: '';
|
||||
width: 150px;
|
||||
height: 300px;
|
||||
.login-left-waves {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
-webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='150' height='300' xmlns='http://www.w3.org/2000/svg' fill='none'%3E%3Cg%3E%3Cpath id='svg_1' d='M-0.56 -0.28C41.94 36.17 67.73 18.94 93.33 33.96C118.93 48.98 107.58 73.56 101.94 89.76C96.29 105.96 50.09 217.83 47.87 231.18C45.64 244.52 46.02 255.2 64.4 270.05C82.79 284.91 121.99 292.31 111.98 289.81C101.97 287.32 153.96 301.48 151.83 299.9C149.69 298.32 149.98 -1.36 149.71 -1.18C149.98 -1.36 -43.06 -36.74 -0.56 -0.28L-0.56 -0.28Z' fill='%23409eff'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
||||
background: var(--el-color-primary-light-5);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
&-icon {
|
||||
width: 60%;
|
||||
height: 70%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: -100px;
|
||||
}
|
||||
}
|
||||
.login-content {
|
||||
width: 500px;
|
||||
padding: 20px;
|
||||
position: absolute;
|
||||
right: 200px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%) translate3d(0, 0, 0);
|
||||
background-color: var(--el-color-white);
|
||||
border: 5px solid var(--el-color-primary-light-8);
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
height: 460px;
|
||||
.login-content-main {
|
||||
margin: 0 auto;
|
||||
width: 80%;
|
||||
.login-content-title {
|
||||
color: var(--el-text-color-primary);
|
||||
font-weight: 500;
|
||||
font-size: 22px;
|
||||
text-align: center;
|
||||
letter-spacing: 4px;
|
||||
margin: 15px 0 30px;
|
||||
white-space: nowrap;
|
||||
z-index: 5;
|
||||
position: relative;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
}
|
||||
.login-content-main-sacn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
.login-right {
|
||||
width: 700px;
|
||||
.login-right-warp {
|
||||
border: 1px solid var(--el-color-primary-light-3);
|
||||
border-radius: 3px;
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
color: var(--el-text-color-primary);
|
||||
&-delta {
|
||||
background-color: var(--el-color-white);
|
||||
.login-right-warp-one,
|
||||
.login-right-warp-two {
|
||||
position: absolute;
|
||||
width: 35px;
|
||||
height: 70px;
|
||||
z-index: 2;
|
||||
top: 2px;
|
||||
right: 21px;
|
||||
background: var(--el-color-white);
|
||||
transform: rotate(-45deg);
|
||||
display: block;
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
transition: all ease 0.3s;
|
||||
color: var(--el-color-primary) !important;
|
||||
.login-right-warp-one {
|
||||
&::before {
|
||||
filter: hue-rotate(0deg);
|
||||
top: 0px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, transparent, var(--el-color-primary));
|
||||
animation: loginLeft 3s linear infinite;
|
||||
}
|
||||
&::after {
|
||||
filter: hue-rotate(60deg);
|
||||
top: -100%;
|
||||
right: 2px;
|
||||
width: 3px;
|
||||
height: 100%;
|
||||
background: linear-gradient(180deg, transparent, var(--el-color-primary));
|
||||
animation: loginTop 3s linear infinite;
|
||||
animation-delay: 0.7s;
|
||||
}
|
||||
}
|
||||
i {
|
||||
width: 47px;
|
||||
height: 50px;
|
||||
display: inline-block;
|
||||
font-size: 48px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: -1px;
|
||||
.login-right-warp-two {
|
||||
&::before {
|
||||
filter: hue-rotate(120deg);
|
||||
bottom: 2px;
|
||||
right: -100%;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: linear-gradient(270deg, transparent, var(--el-color-primary));
|
||||
animation: loginRight 3s linear infinite;
|
||||
animation-delay: 1.4s;
|
||||
}
|
||||
&::after {
|
||||
filter: hue-rotate(300deg);
|
||||
bottom: -100%;
|
||||
left: 0px;
|
||||
width: 3px;
|
||||
height: 100%;
|
||||
background: linear-gradient(360deg, transparent, var(--el-color-primary));
|
||||
animation: loginBottom 3s linear infinite;
|
||||
animation-delay: 2.1s;
|
||||
}
|
||||
}
|
||||
.login-right-warp-mian {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
.login-right-warp-main-title {
|
||||
height: 130px;
|
||||
line-height: 130px;
|
||||
font-size: 27px;
|
||||
text-align: center;
|
||||
letter-spacing: 3px;
|
||||
animation: logoAnimation 0.3s ease;
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
.login-right-warp-main-form {
|
||||
flex: 1;
|
||||
padding: 0 50px 50px;
|
||||
.login-content-main-sacn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
color: var(--el-color-primary);
|
||||
&-delta {
|
||||
position: absolute;
|
||||
width: 35px;
|
||||
height: 70px;
|
||||
z-index: 2;
|
||||
top: 2px;
|
||||
right: 21px;
|
||||
background: var(--el-color-white);
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
transition: all ease 0.3s;
|
||||
color: var(--el-color-primary) !important;
|
||||
}
|
||||
i {
|
||||
width: 47px;
|
||||
height: 50px;
|
||||
display: inline-block;
|
||||
font-size: 48px;
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
top: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="system-dept-container">
|
||||
<el-card shadow="hover">
|
||||
<div class="system-dept-container layout-padding">
|
||||
<el-card shadow="hover" class="layout-padding-auto">
|
||||
<div class="system-dept-search mb15">
|
||||
<el-input size="default" placeholder="请输入部门名称" style="max-width: 180px"> </el-input>
|
||||
<el-button size="default" type="primary" class="ml10">
|
||||
|
|
@ -53,8 +53,9 @@
|
|||
|
||||
<script setup name="systemDept">
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import AddDept from '/@/views/system/dept/component/addDept.vue';
|
||||
import EditDept from '/@/views/system/dept/component/editDept.vue';
|
||||
|
||||
const AddDept = defineAsyncComponent(() => import('/@/views/system/dept/component/addDept.vue'));
|
||||
const EditDept = defineAsyncComponent(() => import('/@/views/system/dept/component/editDept.vue'));
|
||||
|
||||
const addDeptRef = ref();
|
||||
const editDeptRef = ref();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="system-dic-container">
|
||||
<el-card shadow="hover">
|
||||
<div class="system-dic-container layout-padding">
|
||||
<el-card shadow="hover" class="layout-padding-auto">
|
||||
<div class="system-user-search mb15">
|
||||
<el-input size="default" placeholder="请输入字典名称" style="max-width: 180px"> </el-input>
|
||||
<el-button size="default" type="primary" class="ml10">
|
||||
|
|
@ -56,8 +56,9 @@
|
|||
|
||||
<script setup name="systemDic">
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import AddDic from '/@/views/system/dic/component/addDic.vue';
|
||||
import EditDic from '/@/views/system/dic/component/editDic.vue';
|
||||
|
||||
const AddDic = defineAsyncComponent(() => import('/@/views/system/dic/component/addDic.vue'));
|
||||
const EditDic = defineAsyncComponent(() => import('/@/views/system/dic/component/editDic.vue'));
|
||||
|
||||
const addDicRef = ref();
|
||||
const editDicRef = ref();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="system-menu-container">
|
||||
<div class="system-menu-container layout-pd">
|
||||
<el-card shadow="hover">
|
||||
<div class="system-menu-search mb15">
|
||||
<el-input size="default" placeholder="请输入菜单名称" style="max-width: 180px"> </el-input>
|
||||
|
|
@ -62,8 +62,9 @@
|
|||
import { storeToRefs } from 'pinia';
|
||||
import { useRoutesList } from '/@/stores/routesList';
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import AddMenu from '/@/views/system/menu/component/addMenu.vue';
|
||||
import EditMenu from '/@/views/system/menu/component/editMenu.vue';
|
||||
|
||||
const AddMenu = defineAsyncComponent(() => import('/@/views/system/menu/component/addMenu.vue'));
|
||||
const EditMenu = defineAsyncComponent(() => import('/@/views/system/menu/component/editMenu.vue'));
|
||||
|
||||
const addMenuRef = ref();
|
||||
const editMenuRef = ref();
|
||||
|
|
|
|||
|
|
@ -1,20 +1,6 @@
|
|||
<template>
|
||||
<div class="system-role-container">
|
||||
<el-form :inline="true" :model="state.formInline" class="demo-form-inline" size="default">
|
||||
<el-form-item label="Approved by">
|
||||
<el-input v-model="state.formInline.user" placeholder="Approved by" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Activity zone">
|
||||
<el-select v-model="state.formInline.region" placeholder="Activity zone">
|
||||
<el-option label="Zone one" value="shanghai" />
|
||||
<el-option label="Zone two" value="beijing" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary">Query</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-card shadow="hover">
|
||||
<div class="system-role-container layout-padding">
|
||||
<div class="system-role-padding layout-padding-auto layout-padding-view">
|
||||
<div class="system-user-search mb15">
|
||||
<el-input size="default" placeholder="请输入角色名称" style="max-width: 180px"> </el-input>
|
||||
<el-button size="default" type="primary" class="ml10">
|
||||
|
|
@ -65,16 +51,17 @@
|
|||
:total="state.tableData.total"
|
||||
>
|
||||
</el-pagination>
|
||||
</el-card>
|
||||
<AddRole ref="addRoleRef" />
|
||||
<EditRole ref="editRoleRef" />
|
||||
<AddRole ref="addRoleRef" />
|
||||
<EditRole ref="editRoleRef" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="systemRole">
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import AddRole from '/@/views/system/role/component/addRole.vue';
|
||||
import EditRole from '/@/views/system/role/component/editRole.vue';
|
||||
|
||||
const AddRole = defineAsyncComponent(() => import('/@/views/system/role/component/addRole.vue'));
|
||||
const EditRole = defineAsyncComponent(() => import('/@/views/system/role/component/editRole.vue'));
|
||||
|
||||
const addRoleRef = ref();
|
||||
const editRoleRef = ref();
|
||||
|
|
@ -142,3 +129,14 @@ onMounted(() => {
|
|||
initTableData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.system-role-container {
|
||||
.system-role-padding {
|
||||
padding: 15px;
|
||||
.el-table {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="system-user-container">
|
||||
<el-card shadow="hover">
|
||||
<div class="system-user-container layout-padding">
|
||||
<el-card shadow="hover" class="layout-padding-auto">
|
||||
<div class="system-user-search mb15">
|
||||
<el-input size="default" placeholder="请输入用户名称" style="max-width: 180px"> </el-input>
|
||||
<el-button size="default" type="primary" class="ml10">
|
||||
|
|
@ -60,8 +60,9 @@
|
|||
|
||||
<script setup name="systemUser">
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import AddUer from '/@/views/system/user/component/addUser.vue';
|
||||
import EditUser from '/@/views/system/user/component/editUser.vue';
|
||||
|
||||
const AddUer = defineAsyncComponent(() => import('/@/views/system/user/component/addUser.vue'));
|
||||
const EditUser = defineAsyncComponent(() => import('/@/views/system/user/component/editUser.vue'));
|
||||
|
||||
const addUserRef = ref();
|
||||
const editUserRef = ref();
|
||||
|
|
|
|||
Loading…
Reference in New Issue