perf:优化缓存,布局,样式
This commit is contained in:
parent
4784ff379e
commit
a985df0af7
|
|
@ -49,7 +49,7 @@
|
||||||
v-if="item.type"
|
v-if="item.type"
|
||||||
:type="item.type"
|
:type="item.type"
|
||||||
:width="item.width"
|
:width="item.width"
|
||||||
:align="item.align"
|
:align="item.align!=null?item.align:'center'"
|
||||||
:fixed="item.fixed"
|
:fixed="item.fixed"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
/>
|
/>
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
v-else
|
v-else
|
||||||
:prop="item.name"
|
:prop="item.name"
|
||||||
:width="item.width"
|
:width="item.width"
|
||||||
:align="item.align"
|
:align="item.align!=null?item.align:'center'"
|
||||||
:fixed="item.fixed"
|
:fixed="item.fixed"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
>
|
>
|
||||||
|
|
@ -186,18 +186,23 @@ const deleteAction = (row) => {
|
||||||
flex-direction:column;
|
flex-direction:column;
|
||||||
|
|
||||||
.header{
|
.header{
|
||||||
|
display: flex;
|
||||||
padding: 16px 16px 0 16px;
|
padding: 16px 16px 0 16px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
display: flex;
|
border-radius: 4px;
|
||||||
background: white;
|
background: white;
|
||||||
|
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||||
|
|
||||||
}
|
}
|
||||||
.footer{
|
.footer{
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
border-radius: 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: white;
|
background: white;
|
||||||
|
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||||
.operator{
|
.operator{
|
||||||
margin-bottom: 15px
|
margin-bottom: 15px
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<el-breadcrumb class="app-breadcrumb" separator="/">
|
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||||
<transition-group name="breadcrumb" mode="out-in">
|
<transition-group name="breadcrumb" mode="out-in">
|
||||||
<el-breadcrumb-item v-for="(item, index) in obj.levelList" :key="item.path">
|
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
|
||||||
<span
|
<span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
|
||||||
v-if="item.redirect === 'noRedirect' || index == obj.levelList.length - 1"
|
|
||||||
class="no-redirect"
|
|
||||||
>{{ item.meta.title }}</span
|
|
||||||
>
|
|
||||||
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
|
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
|
||||||
</el-breadcrumb-item>
|
</el-breadcrumb-item>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
|
|
@ -15,20 +11,25 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import pathToRegexp from 'path-to-regexp'
|
import pathToRegexp from 'path-to-regexp'
|
||||||
import { onMounted, reactive, watch } from 'vue'
|
import { onMounted, ref, watch } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
const obj = reactive({ levelList: {} })
|
const levelList = ref([])
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
// 获取面包屑
|
// 获取面包屑
|
||||||
const getBreadcrumb = () => {
|
const getBreadcrumb = () => {
|
||||||
let matched = route.matched.filter((item) => item.meta && item.meta.title)
|
let matched = route.matched.filter((item) => item.meta && item.meta.title)
|
||||||
const first = matched[0]
|
const first = matched[0]
|
||||||
obj.levelList = matched.filter(
|
levelList.value = matched.filter(
|
||||||
(item) => item.meta && item.meta.title && item.meta.breadcrumb !== false,
|
(item) => item.meta && item.meta.title && item.meta.breadcrumb !== false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleLink = ()=>{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getBreadcrumb()
|
getBreadcrumb()
|
||||||
watch(route, () => {
|
watch(route, () => {
|
||||||
|
|
@ -47,6 +48,7 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
.no-redirect {
|
.no-redirect {
|
||||||
|
color:#303133;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="m-layout-header"
|
class="m-layout-header"
|
||||||
:class="[SettingStore.themeConfig.fixedHeader&&'zb-fixed-header']"
|
:class="[
|
||||||
:style="{ left: `${mode === 'horizontal' ? 0 : isCollapse ? '60' : '210'}px` }"
|
SettingStore.themeConfig.fixedHeader&&'zb-fixed-header',
|
||||||
|
isCollapse?'fixed-header-collapse':'fixed-header-no-collapse'
|
||||||
|
]"
|
||||||
|
|
||||||
>
|
>
|
||||||
|
<!-- :style="{ left: `${mode === 'horizontal' ? 0 : isCollapse ? '60' : '210'}px` }"-->
|
||||||
<div
|
<div
|
||||||
class="header"
|
class="header"
|
||||||
:class="{
|
:class="{
|
||||||
|
|
@ -122,6 +126,7 @@
|
||||||
.mobile {
|
.mobile {
|
||||||
.m-layout-header {
|
.m-layout-header {
|
||||||
left: 0 !important;
|
left: 0 !important;
|
||||||
|
width: 100%!important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.icon {
|
.icon {
|
||||||
|
|
@ -152,17 +157,24 @@
|
||||||
.zb-fixed-header{
|
.zb-fixed-header{
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 9;
|
z-index: 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.m-layout-header {
|
.m-layout-header {
|
||||||
|
width: 100%;
|
||||||
background: white;
|
background: white;
|
||||||
transition: left 0.3s;
|
transition: width 0.28s;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
|
box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
|
||||||
}
|
}
|
||||||
|
.fixed-header-collapse{
|
||||||
|
width: calc(100% - 60px);
|
||||||
|
}
|
||||||
|
.fixed-header-no-collapse{
|
||||||
|
width: calc(100% - 210px);
|
||||||
|
}
|
||||||
.el-dropdown {
|
.el-dropdown {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,9 @@
|
||||||
<div class="app-main" v-if="isReload">
|
<div class="app-main" v-if="isReload">
|
||||||
<router-view v-slot="{ Component, route }">
|
<router-view v-slot="{ Component, route }">
|
||||||
<transition name="fade-slide" mode="out-in" appear>
|
<transition name="fade-slide" mode="out-in" appear>
|
||||||
<keep-alive v-if="route.meta && route.meta.keepAlive">
|
<keep-alive :include="cacheRoutes">
|
||||||
<component :is="Component" :key="route.path" />
|
<component :is="Component" :key="route.path" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
<component :is="Component" :key="route.path" v-else />
|
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
<u-theme />
|
<u-theme />
|
||||||
|
|
@ -14,15 +13,13 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import UTheme from '@/components/u-theme/index.vue'
|
import UTheme from '@/components/u-theme/index.vue'
|
||||||
|
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import {useSettingStore} from "@/store/modules/setting"
|
||||||
import {useTagsViewStore} from "@/store/modules/tagsView"
|
import {usePermissionStore} from "@/store/modules/permission"
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
const TagsViewStore = useTagsViewStore()
|
const PermissionStor = usePermissionStore()
|
||||||
|
|
||||||
const cachedViews = computed(() =>TagsViewStore.cachedViews)
|
|
||||||
|
|
||||||
|
const cacheRoutes = computed(() =>PermissionStor.cacheRoutes)
|
||||||
const isReload = computed(() => SettingStore.isReload)
|
const isReload = computed(() => SettingStore.isReload)
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ interface extendRoute {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
//
|
|
||||||
import tableRouter from './modules/table'
|
import tableRouter from './modules/table'
|
||||||
import dataScreenRouter from './modules/dataScreen'
|
import dataScreenRouter from './modules/dataScreen'
|
||||||
import errorRouter from './modules/error'
|
import errorRouter from './modules/error'
|
||||||
|
|
@ -19,6 +18,30 @@ import chatRouter from './modules/chat'
|
||||||
import othersRouter from './modules/other'
|
import othersRouter from './modules/other'
|
||||||
import externalLink from './modules/externalLink'
|
import externalLink from './modules/externalLink'
|
||||||
import formRouter from './modules/from'
|
import formRouter from './modules/from'
|
||||||
|
import zipRoutes from './modules/zip'
|
||||||
|
import clipboardTable from './modules/clipboard'
|
||||||
|
|
||||||
|
|
||||||
|
// 异步组件
|
||||||
|
export const asyncRoutes = [
|
||||||
|
dataScreenRouter,
|
||||||
|
chartsRouter,
|
||||||
|
tableRouter,
|
||||||
|
formRouter,
|
||||||
|
chatRouter,
|
||||||
|
othersRouter,
|
||||||
|
nestedRouter,
|
||||||
|
excelRouter,
|
||||||
|
zipRoutes,
|
||||||
|
errorRouter,
|
||||||
|
externalLink,
|
||||||
|
clipboardTable,
|
||||||
|
systemRouter,
|
||||||
|
{
|
||||||
|
path: '/:pathMatch(.*)',
|
||||||
|
redirect: '/error/404'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path ==> 路由路径
|
* path ==> 路由路径
|
||||||
|
|
@ -32,6 +55,7 @@ import formRouter from './modules/from'
|
||||||
* meta.title ==> 路由标题
|
* meta.title ==> 路由标题
|
||||||
* meta.icon ==> 菜单icon
|
* meta.icon ==> 菜单icon
|
||||||
* meta.affix ==> 如果设置为true将会出现在 标签栏中
|
* meta.affix ==> 如果设置为true将会出现在 标签栏中
|
||||||
|
* meta.breadcrumb ==> 如果设置为false,该项将隐藏在breadcrumb中(默认值为true)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const constantRoutes: Array<RouteRecordRaw&extendRoute> = [
|
export const constantRoutes: Array<RouteRecordRaw&extendRoute> = [
|
||||||
|
|
@ -58,70 +82,8 @@ export const constantRoutes: Array<RouteRecordRaw&extendRoute> = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const clipboardTable = {
|
|
||||||
path: '/clipboard',
|
|
||||||
component: Layout,
|
|
||||||
redirect: 'noRedirect',
|
|
||||||
name: 'clipboard',
|
|
||||||
meta: {
|
|
||||||
title: 'clipboard',
|
|
||||||
icon: 'document-copy',
|
|
||||||
roles:['other']
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'index',
|
|
||||||
component: () => import('@/views/clipboard/index.vue'),
|
|
||||||
name: 'map',
|
|
||||||
meta: { title: '剪贴板', roles:['other'] ,icon: 'document-copy',}
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
// //
|
|
||||||
const zipRoutes = {
|
|
||||||
path: '/zip',
|
|
||||||
component: Layout,
|
|
||||||
isShow:true,
|
|
||||||
redirect: 'noRedirect',
|
|
||||||
name: 'zip',
|
|
||||||
alwaysShow:true,
|
|
||||||
meta: {
|
|
||||||
title: 'Zip',
|
|
||||||
icon: 'document-copy',
|
|
||||||
roles:['other']
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'download',
|
|
||||||
component: () => import('@/views/zip/download.vue'),
|
|
||||||
name: 'download',
|
|
||||||
meta: { title: 'Zip', roles:['other'] ,icon: 'document-copy',}
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// // 异步组件
|
|
||||||
export const asyncRoutes = [
|
|
||||||
dataScreenRouter,
|
|
||||||
chartsRouter,
|
|
||||||
tableRouter,
|
|
||||||
formRouter,
|
|
||||||
chatRouter,
|
|
||||||
othersRouter,
|
|
||||||
nestedRouter,
|
|
||||||
excelRouter,
|
|
||||||
zipRoutes,
|
|
||||||
errorRouter,
|
|
||||||
externalLink,
|
|
||||||
clipboardTable,
|
|
||||||
systemRouter,
|
|
||||||
{
|
|
||||||
path: '/:pathMatch(.*)',
|
|
||||||
redirect: '/error/404'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
// history: createWebHistory(process.env.BASE_URL), // history
|
// history: createWebHistory(process.env.BASE_URL), // history
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import Layout from '@/layout/index.vue'
|
||||||
|
|
||||||
|
const clipboardTable = {
|
||||||
|
path: '/clipboard',
|
||||||
|
component: Layout,
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
name: 'clipboard',
|
||||||
|
meta: {
|
||||||
|
title: 'clipboard',
|
||||||
|
icon: 'document-copy',
|
||||||
|
roles:['other']
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: () => import('@/views/clipboard/index.vue'),
|
||||||
|
name: 'map',
|
||||||
|
meta: { title: '剪贴板', roles:['other'] ,icon: 'document-copy',}
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
export default clipboardTable
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import Layout from '@/layout/index.vue'
|
||||||
|
|
||||||
|
const zipRoutes = {
|
||||||
|
path: '/zip',
|
||||||
|
component: Layout,
|
||||||
|
isShow:true,
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
name: 'zip',
|
||||||
|
alwaysShow:true,
|
||||||
|
meta: {
|
||||||
|
title: 'Zip',
|
||||||
|
icon: 'document-copy',
|
||||||
|
roles:['other']
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'download',
|
||||||
|
component: () => import('@/views/zip/download.vue'),
|
||||||
|
name: 'download',
|
||||||
|
meta: { title: 'Zip', roles:['other'] ,icon: 'document-copy',}
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default zipRoutes
|
||||||
|
|
@ -1,40 +1,7 @@
|
||||||
import {defineStore} from 'pinia'
|
import {defineStore} from 'pinia'
|
||||||
import { asyncRoutes, constantRoutes } from '@/router/index'
|
import { asyncRoutes, constantRoutes } from '@/router/index'
|
||||||
/**
|
import {hasPermission,filterAsyncRoutes} from "@/utils/routers"
|
||||||
* 通过递归过滤异步路由表
|
import {filterKeepAlive} from "../../utils/routers";
|
||||||
* @param routes asyncRoutes
|
|
||||||
* @param roles
|
|
||||||
*/
|
|
||||||
export function filterAsyncRoutes(routes, roles) {
|
|
||||||
const res = []
|
|
||||||
routes.forEach(route => {
|
|
||||||
const tmp = { ...route }
|
|
||||||
if (hasPermission(roles, tmp)) {
|
|
||||||
if (tmp.children) {
|
|
||||||
tmp.children = filterAsyncRoutes(tmp.children, roles)
|
|
||||||
}
|
|
||||||
res.push(tmp)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用 meta.role 来确定当前用户是否具有权限
|
|
||||||
* @param roles
|
|
||||||
* @param route
|
|
||||||
*/
|
|
||||||
function hasPermission(roles, route) {
|
|
||||||
if (route.meta && route.meta.roles) {
|
|
||||||
return roles.some(role => route.meta.roles.includes(role))
|
|
||||||
} else {
|
|
||||||
// return true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const usePermissionStore = defineStore({
|
export const usePermissionStore = defineStore({
|
||||||
// id: 必须的,在所有 Store 中唯一
|
// id: 必须的,在所有 Store 中唯一
|
||||||
id:'permissionState',
|
id:'permissionState',
|
||||||
|
|
@ -43,7 +10,9 @@ export const usePermissionStore = defineStore({
|
||||||
// 路由
|
// 路由
|
||||||
routes:[],
|
routes:[],
|
||||||
// 动态路由
|
// 动态路由
|
||||||
addRoutes:{},
|
addRoutes:[],
|
||||||
|
// 缓存路由
|
||||||
|
cacheRoutes:{},
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
permission_routes:state=> {
|
permission_routes:state=> {
|
||||||
|
|
@ -55,6 +24,7 @@ export const usePermissionStore = defineStore({
|
||||||
// 生成路由
|
// 生成路由
|
||||||
generateRoutes(roles){
|
generateRoutes(roles){
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
|
this.getCacheRoutes()
|
||||||
// 在这判断是否有权限,哪些角色拥有哪些权限
|
// 在这判断是否有权限,哪些角色拥有哪些权限
|
||||||
let accessedRoutes
|
let accessedRoutes
|
||||||
if (roles&&roles.length&&!roles.includes('admin')) {
|
if (roles&&roles.length&&!roles.includes('admin')) {
|
||||||
|
|
@ -71,13 +41,14 @@ export const usePermissionStore = defineStore({
|
||||||
clearRoutes(){
|
clearRoutes(){
|
||||||
this.routes = []
|
this.routes = []
|
||||||
this.addRoutes = []
|
this.addRoutes = []
|
||||||
|
this.cacheRoutes = []
|
||||||
|
},
|
||||||
|
getCacheRoutes(){
|
||||||
|
this.cacheRoutes = filterKeepAlive(asyncRoutes)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// persist: {
|
|
||||||
// // 本地存储的名称
|
|
||||||
// key: "permissionState",
|
|
||||||
// //保存的位置
|
|
||||||
// storage: window.localStorage,//localstorage
|
|
||||||
// },
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,10 @@ body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
body{
|
body{
|
||||||
background: #f6f8f9;
|
background: #f0f2f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* 常用 flex */
|
/* 常用 flex */
|
||||||
.flex-center {
|
.flex-center {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,17 @@
|
||||||
/* 路由 */
|
/* 路由 */
|
||||||
.fade-slide-leave-active,
|
.fade-slide-leave-active,
|
||||||
.fade-slide-enter-active {
|
.fade-slide-enter-active {
|
||||||
transition: all 0.2s;
|
transition: all 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-slide-enter-from {
|
.fade-slide-enter-from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(-20px);
|
transform: translateX(-30px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-slide-leave-to {
|
.fade-slide-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(20px);
|
transform: translateX(30px);
|
||||||
}
|
}
|
||||||
|
|
||||||
// logo动画
|
// logo动画
|
||||||
|
|
@ -41,28 +41,28 @@
|
||||||
|
|
||||||
|
|
||||||
// 面包屑动画 方案1
|
// 面包屑动画 方案1
|
||||||
//.breadcrumb-enter-active {
|
.breadcrumb-enter-active {
|
||||||
// transition: all 0.25s;
|
transition: all 0.25s;
|
||||||
//}
|
|
||||||
//.breadcrumb-enter-from,
|
|
||||||
//.breadcrumb-leave-active {
|
|
||||||
// opacity: 0;
|
|
||||||
// transform: translateX(30px) skewX(-50deg);
|
|
||||||
//}
|
|
||||||
/* 面包屑动画 方案2 */
|
|
||||||
.breadcrumb-enter-active,
|
|
||||||
.breadcrumb-leave-active {
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
}
|
||||||
.breadcrumb-enter-from,
|
.breadcrumb-enter-from,
|
||||||
.breadcrumb-leave-active {
|
.breadcrumb-leave-active {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(10px);
|
transform: translateX(30px) skewX(-50deg);
|
||||||
}
|
|
||||||
.breadcrumb-leave-active {
|
|
||||||
position: absolute;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
}
|
||||||
|
/* 面包屑动画 方案2 */
|
||||||
|
//.breadcrumb-enter-active,
|
||||||
|
//.breadcrumb-leave-active {
|
||||||
|
// transition: all 0.2s ease;
|
||||||
|
//}
|
||||||
|
//.breadcrumb-enter-from,
|
||||||
|
//.breadcrumb-leave-active {
|
||||||
|
// opacity: 0;
|
||||||
|
// transform: translateX(10px);
|
||||||
|
//}
|
||||||
|
//.breadcrumb-leave-active {
|
||||||
|
// position: absolute;
|
||||||
|
// z-index: -1;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
.fade-transform-leave-active,
|
.fade-transform-leave-active,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过递归过滤异步路由表
|
||||||
|
* @param routes asyncRoutes
|
||||||
|
* @param roles
|
||||||
|
*/
|
||||||
|
export function filterAsyncRoutes(routes, roles) {
|
||||||
|
const res = []
|
||||||
|
routes.forEach(route => {
|
||||||
|
const tmp = { ...route }
|
||||||
|
if (hasPermission(roles, tmp)) {
|
||||||
|
if (tmp.children) {
|
||||||
|
tmp.children = filterAsyncRoutes(tmp.children, roles)
|
||||||
|
}
|
||||||
|
res.push(tmp)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 meta.role 来确定当前用户是否具有权限
|
||||||
|
* @param roles
|
||||||
|
* @param route
|
||||||
|
*/
|
||||||
|
export function hasPermission(roles, route) {
|
||||||
|
if (route.meta && route.meta.roles) {
|
||||||
|
return roles.some(role => route.meta.roles.includes(role))
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 使用递归,过滤需要缓存的路由
|
||||||
|
* @param {Array} _route 所有路由表
|
||||||
|
* @param {Array} _cache 缓存的路由表
|
||||||
|
* @return void
|
||||||
|
* */
|
||||||
|
|
||||||
|
|
||||||
|
export function filterKeepAlive(routers){
|
||||||
|
let cacheRouter: any[] = [];
|
||||||
|
let deep = (routers)=>{
|
||||||
|
routers.forEach(item=>{
|
||||||
|
if(item.meta?.keepAlive&& item.name){
|
||||||
|
cacheRouter.push(item.name)
|
||||||
|
}
|
||||||
|
if(item.children&&item.children.length){
|
||||||
|
deep(item.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
deep(routers)
|
||||||
|
return cacheRouter
|
||||||
|
}
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="about">
|
|
||||||
<h1>This is an about page</h1>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="home">
|
|
||||||
<img alt="Vue logo" src="../assets/logo.png" />
|
|
||||||
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
import HelloWorld from '@/components/HelloWorld.vue' // @ is an alias to /src
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'Home',
|
|
||||||
components: {
|
|
||||||
HelloWorld,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -2,11 +2,15 @@ $dark_gray: #889aa4;
|
||||||
::v-deep(input) {
|
::v-deep(input) {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: 0;
|
border: 0;
|
||||||
|
color: white;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
padding: 12px 5px 12px 15px;
|
padding: 12px 5px 12px 15px;
|
||||||
height: 47px;
|
height: 47px;
|
||||||
}
|
}
|
||||||
|
::v-deep(.el-input__wrapper){
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
.login-box {
|
.login-box {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,6 @@ for (let i = 0; i < 100; i++) {
|
||||||
}
|
}
|
||||||
const column = [
|
const column = [
|
||||||
{ type: 'selection', width: 60 ,fixed: 'left'},
|
{ type: 'selection', width: 60 ,fixed: 'left'},
|
||||||
{ name: 'id', label: 'id', width: 80,fixed: 'left' },
|
|
||||||
{ name: 'name', label: '姓名', inSearch: true, valueType: 'input', width: 80 },
|
{ name: 'name', label: '姓名', inSearch: true, valueType: 'input', width: 80 },
|
||||||
{ name: 'age', label: '年龄', align: 'right' },
|
{ name: 'age', label: '年龄', align: 'right' },
|
||||||
{
|
{
|
||||||
|
|
@ -107,16 +106,11 @@ const column = [
|
||||||
],
|
],
|
||||||
valueType: 'select',
|
valueType: 'select',
|
||||||
},
|
},
|
||||||
{
|
{name: 'price', label: '价格', inSearch: true, valueType: 'input',},
|
||||||
name: 'price',
|
|
||||||
label: '价格',
|
|
||||||
inSearch: true,
|
|
||||||
valueType: 'input',
|
|
||||||
},
|
|
||||||
{ name: 'admin', label: '账号', inSearch: true, valueType: 'input' },
|
{ name: 'admin', label: '账号', inSearch: true, valueType: 'input' },
|
||||||
{ name: 'address', label: '地址', inSearch: true, valueType: 'input' },
|
{ name: 'address', label: '地址', inSearch: true, valueType: 'input' , width: 180},
|
||||||
{ name: 'date', label: '日期', sorter: true, inSearch: true, valueType: 'input' },
|
{ name: 'date', label: '日期', sorter: true, inSearch: true, valueType: 'input', width: 180 },
|
||||||
{ name: 'province', label: '省份' },
|
{ name: 'province', label: '省份' , width: 100},
|
||||||
{ name: 'city', label: '城市' },
|
{ name: 'city', label: '城市' },
|
||||||
{ name: 'zip', label: '邮编' },
|
{ name: 'zip', label: '邮编' },
|
||||||
{ name: 'operation', slot: true, fixed: 'right', width: 200,label: '操作' },
|
{ name: 'operation', slot: true, fixed: 'right', width: 200,label: '操作' },
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,9 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="price" label="价格" />
|
<el-table-column prop="price" label="价格" />
|
||||||
<el-table-column prop="admin" label="账号" />
|
<el-table-column prop="admin" label="账号" />
|
||||||
<el-table-column prop="address" label="地址" />
|
<el-table-column prop="address" label="地址" width="180"/>
|
||||||
<el-table-column prop="date" label="日期" />
|
<el-table-column prop="date" label="日期" width="180"/>
|
||||||
<el-table-column prop="province" label="省份" />
|
<el-table-column prop="province" label="省份" width="120"/>
|
||||||
<el-table-column prop="city" label="城市" />
|
<el-table-column prop="city" label="城市" />
|
||||||
<el-table-column prop="operator" label="操作" width="180px" fixed="right">
|
<el-table-column prop="operator" label="操作" width="180px" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue