增加基于文件系统的路由支持

This commit is contained in:
hooray
2022-02-25 14:24:51 +08:00
parent 35fd8f69ab
commit 7904ab66e8
65 changed files with 1148 additions and 83 deletions
+12 -16
View File
@@ -47,17 +47,17 @@ function handleCopy() {
<el-alert title="应用配置可实时预览效果,但仅是临时生效,要想真正作用于项目,可以点击下方的“复制配置”按钮,将配置粘贴到 src/settings.custom.json 中即可,或者也可在 src/settings.js 中直接修改默认配置。同时建议在生产环境隐藏应用配置功能。" type="error" :closable="false" />
<el-divider v-if="settingsStore.mode === 'pc'">导航栏模式</el-divider>
<div v-if="settingsStore.mode === 'pc'" class="menu-mode">
<el-tooltip content="侧边栏模式(含主导航)" placement="top" :show-after="500" :append-to-body="false">
<el-tooltip content="侧边栏模式(含主导航)" placement="top" :show-after="500" append-to=".container">
<div class="mode mode-side" :class="{'active': settings.menu.menuMode === 'side'}" @click="settings.menu.menuMode = 'side'">
<svg-icon name="el-icon-check" />
</div>
</el-tooltip>
<el-tooltip content="顶部模式" placement="top" :show-after="500" :append-to-body="false">
<el-tooltip content="顶部模式" placement="top" :show-after="500" append-to=".container">
<div class="mode mode-head" :class="{'active': settings.menu.menuMode === 'head'}" @click="settings.menu.menuMode = 'head'">
<svg-icon name="el-icon-check" />
</div>
</el-tooltip>
<el-tooltip content="侧边栏模式(不含主导航)" placement="top" :show-after="500" :append-to-body="false">
<el-tooltip content="侧边栏模式(不含主导航)" placement="top" :show-after="500" append-to=".container">
<div class="mode mode-single" :class="{'active': settings.menu.menuMode === 'single'}" @click="settings.menu.menuMode = 'single'">
<svg-icon name="el-icon-check" />
</div>
@@ -71,7 +71,7 @@ function handleCopy() {
<div class="setting-item">
<div class="label">
切换跳转
<el-tooltip content="开启该功能后,切换侧边栏时,页面自动跳转至该侧边栏导航下第一个路由地址" placement="top" :append-to-body="false">
<el-tooltip content="开启该功能后,切换侧边栏时,页面自动跳转至该侧边栏导航下第一个路由地址" placement="top" append-to=".container">
<svg-icon name="el-icon-question-filled" />
</el-tooltip>
</div>
@@ -80,7 +80,7 @@ function handleCopy() {
<div class="setting-item">
<div class="label">
保持展开一个
<el-tooltip content="开启该功能后,侧边栏只保持一个子菜单的展开" placement="top" :append-to-body="false">
<el-tooltip content="开启该功能后,侧边栏只保持一个子菜单的展开" placement="top" append-to=".container">
<svg-icon name="el-icon-question-filled" />
</el-tooltip>
</div>
@@ -102,7 +102,7 @@ function handleCopy() {
<div class="setting-item">
<div class="label">
导航栏搜索
<el-tooltip content="对导航栏进行快捷搜索" placement="top" :append-to-body="false">
<el-tooltip content="对导航栏进行快捷搜索" placement="top" append-to=".container">
<svg-icon name="el-icon-question-filled" />
</el-tooltip>
</div>
@@ -111,7 +111,7 @@ function handleCopy() {
<div v-if="settingsStore.mode === 'pc'" class="setting-item">
<div class="label">
全屏
<el-tooltip content="该功能使用场景极少,用户习惯于通过窗口“最大化”功能来扩大显示区域,以显示更多内容,并且使用 F11 键也可以进入全屏效果" placement="top" :append-to-body="false">
<el-tooltip content="该功能使用场景极少,用户习惯于通过窗口“最大化”功能来扩大显示区域,以显示更多内容,并且使用 F11 键也可以进入全屏效果" placement="top" append-to=".container">
<svg-icon name="el-icon-question-filled" />
</el-tooltip>
</div>
@@ -120,7 +120,7 @@ function handleCopy() {
<div class="setting-item">
<div class="label">
页面刷新
<el-tooltip content="开启时会阻止原生 F5 键刷新功能,并采用框架提供的刷新模式进行页面刷新" placement="top" :append-to-body="false">
<el-tooltip content="开启时会阻止原生 F5 键刷新功能,并采用框架提供的刷新模式进行页面刷新" placement="top" append-to=".container">
<svg-icon name="el-icon-question-filled" />
</el-tooltip>
</div>
@@ -147,7 +147,7 @@ function handleCopy() {
<div class="setting-item">
<div class="label">
是否开启
<el-tooltip content="该功能开启时,登录成功默认进入控制台页面,反之则默认进入导航栏里第一个导航页面" placement="top" :append-to-body="false">
<el-tooltip content="该功能开启时,登录成功默认进入控制台页面,反之则默认进入导航栏里第一个导航页面" placement="top" append-to=".container">
<svg-icon name="el-icon-question-filled" />
</el-tooltip>
</div>
@@ -161,7 +161,7 @@ function handleCopy() {
<div class="setting-item">
<div class="label">
组件尺寸
<el-tooltip content="全局设置 Element Plus 组件的默认尺寸大小" placement="top" :append-to-body="false">
<el-tooltip content="全局设置 Element Plus 组件的默认尺寸大小" placement="top" append-to=".container">
<svg-icon name="el-icon-question-filled" />
</el-tooltip>
</div>
@@ -175,14 +175,10 @@ function handleCopy() {
<div class="label">是否启用权限</div>
<el-switch v-model="settings.app.enablePermission" />
</div>
<div class="setting-item">
<div class="label">是否开启后端返回路由数据</div>
<el-switch v-model="settings.app.enableBackendReturnRoute" />
</div>
<div class="setting-item">
<div class="label">
载入进度条
<el-tooltip content="该功能开启时,跳转路由会看到页面顶部有进度条" placement="top" :append-to-body="false">
<el-tooltip content="该功能开启时,跳转路由会看到页面顶部有进度条" placement="top" append-to=".container">
<svg-icon name="el-icon-question-filled" />
</el-tooltip>
</div>
@@ -191,7 +187,7 @@ function handleCopy() {
<div class="setting-item">
<div class="label">
动态标题
<el-tooltip content="该功能开启时,页面标题会显示当前路由标题,格式为“页面标题 - 网站名称”;关闭时则显示网站名称,网站名称在项目根目录下 .env.* 文件里配置" placement="top" :append-to-body="false">
<el-tooltip content="该功能开启时,页面标题会显示当前路由标题,格式为“页面标题 - 网站名称”;关闭时则显示网站名称,网站名称在项目根目录下 .env.* 文件里配置" placement="top" append-to=".container">
<svg-icon name="el-icon-question-filled" />
</el-tooltip>
</div>
+11 -3
View File
@@ -7,6 +7,8 @@ import { useSettingsStore } from '@/store/modules/settings'
const settingsStore = useSettingsStore()
import { useRouteStore } from '@/store/modules/route'
const routeStore = useRouteStore()
import { useMenuStore } from '@/store/modules/menu'
const menuStore = useMenuStore()
const isShow = ref(false)
const searchInput = ref('')
@@ -68,9 +70,15 @@ onMounted(() => {
isShow.value = true
}
})
routeStore.routes.map(item => {
getSourceList(item.children)
})
if (settingsStore.app.routeBaseOn !== 'filesystem') {
routeStore.routes.map(item => {
getSourceList(item.children)
})
} else {
menuStore.menus.map(item => {
getSourceList(item.children)
})
}
})
function hasChildren(item) {
+2 -2
View File
@@ -30,8 +30,8 @@ function onSidebarScroll(e) {
}"
>
<transition-group name="sub-sidebar">
<template v-for="route in menuStore.sidebarMenus">
<SidebarItem v-if="route.meta.sidebar !== false" :key="route.path" :item="route" :base-path="route.path" />
<template v-for="(route, index) in menuStore.sidebarMenus">
<SidebarItem v-if="route.meta.sidebar !== false" :key="route.path || index" :item="route" :base-path="route.path" />
</template>
</transition-group>
</el-menu>
+1 -1
View File
@@ -57,7 +57,7 @@ function pathCompile(path) {
<div v-if="enableSidebarCollapse" class="sidebar-collapse" :class="{'is-collapse': settingsStore.menu.subMenuCollapse}" @click="settingsStore.toggleSidebarCollapse()">
<svg-icon name="toolbar-collapse" />
</div>
<el-breadcrumb v-if="settingsStore.topbar.enableBreadcrumb && settingsStore.mode === 'pc'" separator-class="el-icon-arrow-right">
<el-breadcrumb v-if="settingsStore.topbar.enableBreadcrumb && settingsStore.mode === 'pc' && settingsStore.app.routeBaseOn !== 'filesystem'" separator-class="el-icon-arrow-right">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item, index) in breadcrumbList" :key="item.path" :to="index < breadcrumbList.length - 1 ? pathCompile(item.path) : ''">
{{ item.title }}
+15
View File
@@ -0,0 +1,15 @@
import MultilevelMenuExample from './modules/multilevel.menu.example'
const menu = [
{
meta: {
title: '演示',
icon: 'sidebar-default'
},
children: [
MultilevelMenuExample
]
}
]
export default menu
@@ -0,0 +1,46 @@
export default {
meta: {
title: '多级导航',
icon: 'sidebar-menu'
},
children: [
{
path: '/multilevel_menu_example/page',
meta: {
title: '导航1'
}
},
{
meta: {
title: '导航2'
},
children: [
{
path: '/multilevel_menu_example/level2/page',
meta: {
title: '导航2-1'
}
},
{
meta: {
title: '导航2-2'
},
children: [
{
path: '/multilevel_menu_example/level2/level3/page1',
meta: {
title: '导航2-2-1'
}
},
{
path: '/multilevel_menu_example/level2/level3/page2',
meta: {
title: '导航2-2-2'
}
}
]
}
]
}
]
}
+68
View File
@@ -0,0 +1,68 @@
export default [
{
url: '/mock/menu/list',
method: 'get',
response: () => {
return {
error: '',
status: 1,
data: [
{
meta: {
title: '演示',
icon: 'sidebar-default'
},
children: [
{
meta: {
title: '多级导航',
icon: 'sidebar-menu'
},
children: [
{
path: '/multilevel_menu_example/page',
meta: {
title: '导航1'
}
},
{
meta: {
title: '导航2'
},
children: [
{
path: '/multilevel_menu_example/level2/page',
meta: {
title: '导航2-1'
}
},
{
meta: {
title: '导航2-2'
},
children: [
{
path: '/multilevel_menu_example/level2/level3/page1',
meta: {
title: '导航2-2-1'
}
},
{
path: '/multilevel_menu_example/level2/level3/page2',
meta: {
title: '导航2-2-2'
}
}
]
}
]
}
]
}
]
}
]
}
}
}
]
+41 -9
View File
@@ -10,7 +10,7 @@ import { useNProgress } from '@vueuse/integrations/useNProgress'
const { isLoading } = useNProgress()
// 固定路由
const constantRoutes = [
let constantRoutes = [
{
path: '/login',
name: 'login',
@@ -81,7 +81,7 @@ import EcologyExample from './modules/ecology.example'
import CooperationExample from './modules/cooperation.example'
// 动态路由(异步路由、导航栏路由)
const asyncRoutes = [
let asyncRoutes = [
{
meta: {
title: '演示',
@@ -129,13 +129,26 @@ const asyncRoutes = [
]
const lastRoute = {
path: '/:pathMatch(.*)*',
component: () => import('@/views/404.vue'),
path: '/:all(.*)*',
name: 'notFound',
component: () => import('@/views/[...all].vue'),
meta: {
title: '找不到页面'
}
}
import { setupLayouts } from 'virtual:generated-layouts'
import generatedRoutes from 'virtual:generated-pages'
if (useSettingsOutsideStore().app.routeBaseOn === 'filesystem') {
constantRoutes = generatedRoutes.filter(item => {
return item.meta?.enabled !== false && item.meta?.constant === true
})
asyncRoutes = setupLayouts(generatedRoutes.filter(item => {
return item.meta?.enabled !== false && item.meta?.constant !== true && item.meta?.layout !== false
}))
}
const router = createRouter({
history: createWebHashHistory(),
routes: constantRoutes
@@ -184,10 +197,24 @@ router.beforeEach(async(to, from, next) => {
next()
}
} else {
if (!settingsOutsideStore.app.enableBackendReturnRoute) {
await routeOutsideStore.generateRoutesAtFront(asyncRoutes)
} else {
await routeOutsideStore.generateRoutesAtBack()
switch (settingsOutsideStore.app.routeBaseOn) {
case 'frontend':
await routeOutsideStore.generateRoutesAtFront(asyncRoutes)
break
case 'backend':
await routeOutsideStore.generateRoutesAtBack()
break
case 'filesystem':
await routeOutsideStore.generateRoutesAtFilesystem(asyncRoutes)
switch (settingsOutsideStore.menu.baseOn) {
case 'frontend':
await menuOutsideStore.generateMenusAtFront()
break
case 'backend':
await menuOutsideStore.generateMenusAtBack()
break
}
break
}
let removeRoutes = []
routeOutsideStore.flatRoutes.forEach(route => {
@@ -195,7 +222,12 @@ router.beforeEach(async(to, from, next) => {
removeRoutes.push(router.addRoute(route))
}
})
removeRoutes.push(router.addRoute(lastRoute))
if (settingsOutsideStore.app.routeBaseOn === 'filesystem') {
const otherRoutes = generatedRoutes.filter(item => item.meta?.constant !== true && item.meta?.layout === false)
otherRoutes.length && removeRoutes.push(router.addRoute(...otherRoutes))
} else {
removeRoutes.push(router.addRoute(lastRoute))
}
// 记录的 accessRoutes 路由数据,在登出时会使用到,不使用 router.removeRoute 是考虑配置的路由可能不一定有设置 name ,则通过调用 router.addRoute() 返回的回调进行删除
routeOutsideStore.setCurrentRemoveRoutes(removeRoutes)
next({ ...to, replace: true })
+14 -3
View File
@@ -10,12 +10,17 @@ let globalSettings = {
* 4、鉴权函数:this.$auth()、this.$authAll()
*/
enablePermission: false,
// 是否开启后端返回路由数据
enableBackendReturnRoute: false,
// 是否开启载入进度条
enableProgress: true,
// 是否开启动态标题
enableDynamicTitle: false
enableDynamicTitle: false,
/**
* 路由数据来源
* frontend 前端
* backend 后端
* filesystem 文件系统
*/
routeBaseOn: 'frontend'
},
// 控制台
dashboard: {
@@ -31,6 +36,12 @@ let globalSettings = {
},
// 导航栏
menu: {
/**
* 数据来源,当 app.routeBaseOn 为 filesystem 时生效
* frontend 前端
* backend 后端
*/
baseOn: 'frontend',
/**
* 导航栏模式
* side 侧边栏模式(含主导航)
+100 -16
View File
@@ -1,9 +1,12 @@
import { defineStore } from 'pinia'
import { piniaStore } from '@/store'
import { resolveRoutePath } from '@/util'
import { deepClone, resolveRoutePath } from '@/util'
import path from 'path-browserify'
import api from '@/api'
import menu from '@/menu'
import { useSettingsStore } from './settings'
import { useUserStore } from './user'
import { useRouteStore } from './route'
function getDeepestPath(routes, rootPath = '') {
@@ -29,28 +32,67 @@ function getDeepestPath(routes, rootPath = '') {
return retnPath
}
function hasPermission(permissions, route) {
let isAuth = false
if (route.meta && route.meta.auth) {
isAuth = permissions.some(auth => {
if (typeof route.meta.auth == 'string') {
return route.meta.auth === auth
} else {
return route.meta.auth.some(routeAuth => {
return routeAuth === auth
})
}
})
} else {
isAuth = true
}
return isAuth
}
function filterAsyncMenus(menus, permissions) {
const res = []
menus.forEach(menu => {
let tmpMenu = deepClone(menu)
if (hasPermission(permissions, tmpMenu)) {
if (tmpMenu.children) {
tmpMenu.children = filterAsyncMenus(tmpMenu.children, permissions)
tmpMenu.children.length && res.push(tmpMenu)
} else {
res.push(tmpMenu)
}
}
})
return res
}
export const useMenuStore = defineStore(
// 唯一ID
'menu',
{
state: () => ({
menus: [],
actived: 0
}),
getters: {
// 完整导航数据
allMenus() {
const settingsStore = useSettingsStore()
const routeStore = useRouteStore()
let routes
if (settingsStore.menu.menuMode === 'single') {
routes = [{ children: [] }]
routeStore.routes.map(item => {
routes[0].children.push(...item.children)
})
let menus
if (settingsStore.app.routeBaseOn !== 'filesystem') {
const routeStore = useRouteStore()
if (settingsStore.menu.menuMode === 'single') {
menus = [{ children: [] }]
routeStore.routes.map(item => {
menus[0].children.push(...item.children)
})
} else {
menus = routeStore.routes
}
} else {
routes = routeStore.routes
menus = this.menus
}
return routes
return menus
},
// 次导航数据
sidebarMenus() {
@@ -61,18 +103,60 @@ export const useMenuStore = defineStore(
return this.allMenus.length > 0 ? getDeepestPath(this.sidebarMenus[0]) : '/'
},
defaultOpenedPaths() {
const routeStore = useRouteStore()
const settingsStore = useSettingsStore()
let defaultOpenedPaths = []
routeStore.routes.map(item => {
item.meta.defaultOpened && defaultOpenedPaths.push(item.path)
item.children && item.children.map(child => {
child.meta.defaultOpened && defaultOpenedPaths.push(path.resolve(item.path, child.path))
if (settingsStore.app.routeBaseOn !== 'filesystem') {
const routeStore = useRouteStore()
routeStore.routes.map(item => {
item.meta.defaultOpened && defaultOpenedPaths.push(item.path)
item.children && item.children.map(child => {
child.meta.defaultOpened && defaultOpenedPaths.push(path.resolve(item.path, child.path))
})
})
})
}
return defaultOpenedPaths
}
},
actions: {
// 生成导航(前端生成)
generateMenusAtFront() {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async resolve => {
const settingsStore = useSettingsStore()
const userStore = useUserStore()
let accessedMenus
// 如果权限功能开启,则需要对导航数据进行筛选过滤
if (settingsStore.app.enablePermission) {
const permissions = await userStore.getPermissions()
accessedMenus = filterAsyncMenus(menu, permissions)
} else {
accessedMenus = deepClone(menu)
}
this.menus = accessedMenus.filter(item => item.children.length != 0)
resolve()
})
},
// 生成导航(后端生成)
generateMenusAtBack() {
return new Promise(resolve => {
api.get('menu/list', {
baseURL: '/mock/'
}).then(async res => {
const settingsStore = useSettingsStore()
const userStore = useUserStore()
let accessedMenus
// 如果权限功能开启,则需要对导航数据进行筛选过滤
if (settingsStore.app.enablePermission) {
const permissions = await userStore.getPermissions()
accessedMenus = filterAsyncMenus(res.data, permissions)
} else {
accessedMenus = deepClone(res.data)
}
this.menus = accessedMenus.filter(item => item.children.length != 0)
resolve()
})
})
},
// 切换主导航
setActived(data) {
if (typeof data === 'number') {
+38 -11
View File
@@ -130,19 +130,26 @@ export const useRouteStore = defineStore(
getters: {
// 扁平化路由(将三级及以上路由数据拍平成二级)
flatRoutes: state => {
const settingsStore = useSettingsStore()
let routes = []
if (state.routes) {
state.routes.map(item => {
routes.push(...deepClone(item.children))
})
routes.map(item => {
if (item.children) {
item.children = flatAsyncRoutes(item.children, [{
path: item.path,
title: item.meta.title
}], item.path)
}
})
if (settingsStore.app.routeBaseOn !== 'filesystem') {
state.routes.map(item => {
routes.push(...deepClone(item.children))
})
routes.map(item => {
if (item.children) {
item.children = flatAsyncRoutes(item.children, [{
path: item.path,
title: item.meta.title
}], item.path)
}
})
} else {
state.routes.map(item => {
routes.push(deepClone(item))
})
}
}
return routes
}
@@ -192,6 +199,26 @@ export const useRouteStore = defineStore(
})
})
},
// 根据权限动态生成路由(文件系统生成)
generateRoutesAtFilesystem(asyncRoutes) {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async resolve => {
const settingsStore = useSettingsStore()
const userStore = useUserStore()
let accessedRoutes
// 如果权限功能开启,则需要对路由数据进行筛选过滤
if (settingsStore.app.enablePermission) {
const permissions = await userStore.getPermissions()
accessedRoutes = filterAsyncRoutes(asyncRoutes, permissions)
} else {
accessedRoutes = deepClone(asyncRoutes)
}
// 设置 routes 数据
this.isGenerate = true
this.routes = accessedRoutes.filter(item => item.children.length != 0)
resolve()
})
},
// 记录 accessRoutes 路由,用于登出时删除路由
setCurrentRemoveRoutes(routes) {
this.currentRemoveRoutes = routes
@@ -1,3 +1,13 @@
<route>
{
name: 'notFound',
meta: {
title: "找不到页面",
layout: false
}
}
</route>
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
const router = useRouter()
+8
View File
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<template>
<div>
<page-main>
+8
View File
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<template>
<div>
<page-main>
+8
View File
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<template>
<page-main>
<router-link :to="{name: 'breadcrumbExampleDetail1'}">查看详情页</router-link>
+8
View File
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<template>
<page-main>
<router-link :to="{name: 'breadcrumbExampleDetail2'}">查看详情页</router-link>
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script setup>
import Alert from './components/alert.vue'
import { Search, Edit, Check, Message, Star, Delete, Share, ArrowLeft } from '@element-plus/icons-vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
import Alert from './components/alert.vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
import Alert from './components/alert.vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
import Alert from './components/alert.vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script setup>
import Alert from './components/alert.vue'
import { Search } from '@element-plus/icons-vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
import Alert from './components/alert.vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
import Alert from './components/alert.vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script setup>
import Alert from './components/alert.vue'
import { Edit } from '@element-plus/icons-vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
import Alert from './components/alert.vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
import Alert from './components/alert.vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
import Alert from './components/alert.vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
import Alert from './components/alert.vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
import Alert from './components/alert.vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
import Alert from './components/alert.vue'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
export default {
data() {
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
export default {
name: 'ComponentExampleArea',
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
export default {
name: 'ComponentExampleBatchactionbar',
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script setup>
import { mavonEditor } from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
export default {
props: {},
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<template>
<div>
<page-header title="页头" content="PageHeader" />
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<template>
<div>
<page-header title="内容块" content="PageMain" />
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
export default {
data() {
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
export default {
data() {
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
export default {
name: 'ComponentExampleTableHeightAdaption',
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<template>
<div>
<page-header title="趋势符号">
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
export default {
data() {
+9
View File
@@ -1,3 +1,12 @@
<route>
{
name: 'dashboard',
meta: {
title: "控制台"
}
}
</route>
<script setup>
const locationOrigin = location.origin
+8
View File
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<template>
<page-main>
<el-button @click="$router.go(-1)">返回</el-button>
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script setup name="TabExampleNested1">
import { useKeepAliveStore } from '@/store/modules/keepAlive'
const keepAliveStore = useKeepAliveStore()
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script setup name="TabExampleNested2">
import { useKeepAliveStore } from '@/store/modules/keepAlive'
const keepAliveStore = useKeepAliveStore()
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
export default {
name: 'TabExampleNestedTest',
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script>
export default {
name: 'TabExampleNestedTest2',
+8
View File
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script setup name="KeepAliveExamplePage">
import { onBeforeRouteLeave } from 'vue-router'
+10
View File
@@ -1,3 +1,13 @@
<route>
{
meta: {
title: "登录",
constant: true,
layout: false
}
}
</route>
<script setup name="Login">
const { proxy } = getCurrentInstance()
const route = useRoute(), router = useRouter()
+8
View File
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script setup>
const { proxy } = getCurrentInstance()
@@ -1,3 +1,11 @@
<route>
{
meta: {
title: '导航2-2-1'
}
}
</route>
<template>
<div>
<page-main>
@@ -1,3 +1,11 @@
<route>
{
meta: {
title: '导航2-2-2'
}
}
</route>
<template>
<div>
<page-main>
@@ -1,3 +1,11 @@
<route>
{
meta: {
title: '导航2-1'
}
}
</route>
<template>
<div>
<page-main>
@@ -1,3 +1,11 @@
<route>
{
meta: {
title: '导航1'
}
}
</route>
<template>
<div>
<page-main>
+8
View File
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<script setup>
const { proxy } = getCurrentInstance()
+8
View File
@@ -1,3 +1,11 @@
<route>
{
meta: {
title: "修改密码"
}
}
</route>
<script setup name="PersonalEditPassword">
const route = useRoute(), router = useRouter()
const { proxy } = getCurrentInstance()
+9 -1
View File
@@ -1,3 +1,12 @@
<route>
{
meta: {
title: "个人设置",
cache: "personal-edit.password"
}
}
</route>
<script setup name="PersonalSetting">
const router = useRouter()
const { proxy } = getCurrentInstance()
@@ -26,7 +35,6 @@ function editPassword() {
<template>
<div>
<!-- 页面:Setting -->
<page-main>
<el-tabs tab-position="left" style="height: 600px;">
<el-tab-pane label="基本设置" class="basic">
+9
View File
@@ -1,3 +1,12 @@
<route>
{
meta: {
constant: true,
layout: false
}
}
</route>
<script setup>
const router = useRouter()
+8
View File
@@ -1,3 +1,11 @@
<route>
{
meta: {
enabled: false
}
}
</route>
<template>
<div>
<page-header title="即将推出 Vue3 版本视频教程,尽请期待" />