refactor: refactor route
This commit is contained in:
parent
7bfe5f753d
commit
c303ec1a23
|
|
@ -0,0 +1,22 @@
|
||||||
|
name: deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run build
|
||||||
|
|
||||||
|
- name: Deploy
|
||||||
|
uses: peaceiris/actions-gh-pages@v2.5.0
|
||||||
|
env:
|
||||||
|
ACTIONS_DEPLOY_KEY: ${{secrets.ACTIONS_DEPLOY_KEY}}
|
||||||
|
PUBLISH_BRANCH: gh-pages
|
||||||
|
PUBLISH_DIR: dist
|
||||||
|
|
@ -1,48 +1,13 @@
|
||||||
{
|
{
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
// node环境调试当前激活编辑器ts/js代码
|
|
||||||
{
|
{
|
||||||
"type": "node",
|
"type": "chrome",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "file",
|
"name": "Launch Chrome",
|
||||||
"cwd": "${workspaceFolder}",
|
"url": "http://localhost:3100",
|
||||||
"program": "${file}",
|
"webRoot": "${workspaceFolder}/src",
|
||||||
// .vscode 目录又不认识了???
|
"sourceMaps": true
|
||||||
"preLaunchTask": "tsc: 监视 - build/tsconfig.json", // cn
|
|
||||||
// "preLaunchTask": "tsc: watch - build/tsconfig.json", // en
|
|
||||||
"outFiles": ["${workspaceFolder}/compile/**/*.js"]
|
|
||||||
// "args": ["--experimental-modules", "--loader", "./loader.mjs"]
|
|
||||||
},
|
},
|
||||||
// 调试开发环境脚本
|
|
||||||
{
|
|
||||||
"type": "node",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "dev",
|
|
||||||
// "stopOnEntry": true,
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
"program": "${workspaceFolder}/node_modules/@vue/cli-service/bin/vue-cli-service.js",
|
|
||||||
"args": ["serve", "--open"]
|
|
||||||
},
|
|
||||||
// 调试生产环境脚本
|
|
||||||
{
|
|
||||||
"type": "node",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "build",
|
|
||||||
// "stopOnEntry": true,
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
"program": "${workspaceFolder}/node_modules/@vue/cli-service/bin/vue-cli-service.js",
|
|
||||||
"args": ["build"]
|
|
||||||
},
|
|
||||||
// 调试单元测试脚本
|
|
||||||
{
|
|
||||||
"type": "node",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "test:unit",
|
|
||||||
// "stopOnEntry": true,
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
"program": "${workspaceFolder}/node_modules/@vue/cli-service/bin/vue-cli-service.js",
|
|
||||||
"args": ["test:unit", "--detectOpenHandles"]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -163,12 +163,6 @@
|
||||||
"[typescriptreact]": {
|
"[typescriptreact]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
},
|
},
|
||||||
"[json]": {
|
|
||||||
"editor.defaultFormatter": "vscode.json-language-features"
|
|
||||||
},
|
|
||||||
"[jsonc]": {
|
|
||||||
"editor.defaultFormatter": "vscode.json-language-features"
|
|
||||||
},
|
|
||||||
"[html]": {
|
"[html]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
},
|
},
|
||||||
|
|
@ -198,5 +192,8 @@
|
||||||
"ts"
|
"ts"
|
||||||
],
|
],
|
||||||
"i18n-ally.sourceLanguage": "zh",
|
"i18n-ally.sourceLanguage": "zh",
|
||||||
"i18n-ally.enabledFrameworks":["vue","react"]
|
"i18n-ally.enabledFrameworks": [
|
||||||
|
"vue",
|
||||||
|
"react"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -1,14 +1,24 @@
|
||||||
## Wip
|
## Wip
|
||||||
|
|
||||||
|
## (破坏性更新) Breaking changes
|
||||||
|
|
||||||
|
- 路由重构, 不再支持以前的格式。改为支持 vue-router 最初的默认结构,具体格式可以参考示例更改。实现多级路由缓存,不再将路由转化为 2 级。
|
||||||
|
- 重构面包屑,使用 antd 的面包屑组件。之前的组件已删除
|
||||||
|
|
||||||
### ✨ Features
|
### ✨ Features
|
||||||
|
|
||||||
- 还原 antdv 默认 loading,重构 `Loading` 组件,增加`useLoading`和`v-loading`指令。并增加示例
|
- 还原 antdv 默认 loading,重构 `Loading` 组件,增加`useLoading`和`v-loading`指令。并增加示例
|
||||||
- i18n 支持 vscode `i18n-ally`插件
|
- i18n 支持 vscode `i18n-ally`插件
|
||||||
|
- 新增多级路由缓存示例
|
||||||
|
|
||||||
### 🎫 Chores
|
### 🎫 Chores
|
||||||
|
|
||||||
- 首屏 loading 修改
|
- 首屏 loading 修改
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
-修复表格 i18n 错误
|
||||||
|
|
||||||
## 2.0.0-rc.12 (2020-11-30)
|
## 2.0.0-rc.12 (2020-11-30)
|
||||||
|
|
||||||
## (破坏性更新) Breaking changes
|
## (破坏性更新) Breaking changes
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ const dynamicImportTransform = function (enableDynamicImport: boolean): Transfor
|
||||||
test({ path }) {
|
test({ path }) {
|
||||||
// Only convert the file
|
// Only convert the file
|
||||||
return (
|
return (
|
||||||
path.includes('/src/utils/helper/dynamicImport.ts') ||
|
path.includes('/src/router/helper/dynamicImport.ts') ||
|
||||||
path.includes(`\\src\\utils\\helper\\dynamicImport.ts`)
|
path.includes(`\\src\\router\\helper\\dynamicImport.ts`)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
transform({ code }) {
|
transform({ code }) {
|
||||||
|
|
|
||||||
113
mock/sys/menu.ts
113
mock/sys/menu.ts
|
|
@ -1,33 +1,23 @@
|
||||||
import { resultSuccess } from '../_util';
|
import { resultSuccess } from '../_util';
|
||||||
import { MockMethod } from 'vite-plugin-mock';
|
import { MockMethod } from 'vite-plugin-mock';
|
||||||
|
|
||||||
|
// single
|
||||||
const dashboardRoute = {
|
const dashboardRoute = {
|
||||||
path: '/dashboard',
|
path: '/home',
|
||||||
name: 'Dashboard',
|
name: 'Home',
|
||||||
component: 'PAGE_LAYOUT',
|
|
||||||
redirect: '/dashboard/welcome',
|
|
||||||
meta: {
|
|
||||||
icon: 'ant-design:home-outlined',
|
|
||||||
title: 'Dashboard',
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '/welcome',
|
|
||||||
name: 'Welcome',
|
|
||||||
component: '/dashboard/welcome/index',
|
component: '/dashboard/welcome/index',
|
||||||
meta: {
|
meta: {
|
||||||
title: '欢迎页',
|
title: 'routes.dashboard.welcome',
|
||||||
affix: true,
|
affix: true,
|
||||||
|
icon: 'ant-design:home-outlined',
|
||||||
},
|
},
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const frontRoute = {
|
const frontRoute = {
|
||||||
path: '/front',
|
path: 'front',
|
||||||
name: 'PermissionFrontDemo',
|
name: 'PermissionFrontDemo',
|
||||||
meta: {
|
meta: {
|
||||||
title: '基于前端权限',
|
title: 'routes.demo.permission.front',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
|
@ -35,7 +25,7 @@ const frontRoute = {
|
||||||
name: 'FrontPageAuth',
|
name: 'FrontPageAuth',
|
||||||
component: '/demo/permission/front/index',
|
component: '/demo/permission/front/index',
|
||||||
meta: {
|
meta: {
|
||||||
title: '页面权限',
|
title: 'routes.demo.permission.frontPage',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -43,7 +33,7 @@ const frontRoute = {
|
||||||
name: 'FrontBtnAuth',
|
name: 'FrontBtnAuth',
|
||||||
component: '/demo/permission/front/Btn',
|
component: '/demo/permission/front/Btn',
|
||||||
meta: {
|
meta: {
|
||||||
title: '按钮权限',
|
title: 'routes.demo.permission.frontBtn',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -51,7 +41,7 @@ const frontRoute = {
|
||||||
name: 'FrontAuthPageA',
|
name: 'FrontAuthPageA',
|
||||||
component: '/demo/permission/front/AuthPageA',
|
component: '/demo/permission/front/AuthPageA',
|
||||||
meta: {
|
meta: {
|
||||||
title: '权限测试页A',
|
title: 'routes.demo.permission.frontTestA',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -59,24 +49,25 @@ const frontRoute = {
|
||||||
name: 'FrontAuthPageB',
|
name: 'FrontAuthPageB',
|
||||||
component: '/demo/permission/front/AuthPageB',
|
component: '/demo/permission/front/AuthPageB',
|
||||||
meta: {
|
meta: {
|
||||||
title: '权限测试页B',
|
title: 'routes.demo.permission.frontTestB',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
const backRoute = {
|
const backRoute = {
|
||||||
path: '/back',
|
path: 'back',
|
||||||
name: 'PermissionBackDemo',
|
name: 'PermissionBackDemo',
|
||||||
meta: {
|
meta: {
|
||||||
title: '基于后台权限',
|
title: 'routes.demo.permission.back',
|
||||||
},
|
},
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'page',
|
path: 'page',
|
||||||
name: 'BackAuthPage',
|
name: 'BackAuthPage',
|
||||||
component: '/demo/permission/back/index',
|
component: '/demo/permission/back/index',
|
||||||
meta: {
|
meta: {
|
||||||
title: '页面权限',
|
title: 'routes.demo.permission.backPage',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -84,7 +75,7 @@ const backRoute = {
|
||||||
name: 'BackAuthBtn',
|
name: 'BackAuthBtn',
|
||||||
component: '/demo/permission/back/Btn',
|
component: '/demo/permission/back/Btn',
|
||||||
meta: {
|
meta: {
|
||||||
title: '按钮权限',
|
title: 'routes.demo.permission.backBtn',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -92,11 +83,11 @@ const backRoute = {
|
||||||
const authRoute = {
|
const authRoute = {
|
||||||
path: '/permission',
|
path: '/permission',
|
||||||
name: 'Permission',
|
name: 'Permission',
|
||||||
component: 'PAGE_LAYOUT',
|
component: 'LAYOUT',
|
||||||
redirect: '/permission/front/page',
|
redirect: '/permission/front/page',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ant-design:home-outlined',
|
icon: 'carbon:user-role',
|
||||||
title: '权限管理',
|
title: 'routes.demo.permission.permission',
|
||||||
},
|
},
|
||||||
children: [frontRoute, backRoute],
|
children: [frontRoute, backRoute],
|
||||||
};
|
};
|
||||||
|
|
@ -104,14 +95,70 @@ const authRoute = {
|
||||||
const authRoute1 = {
|
const authRoute1 = {
|
||||||
path: '/permission',
|
path: '/permission',
|
||||||
name: 'Permission',
|
name: 'Permission',
|
||||||
component: 'PAGE_LAYOUT',
|
component: 'LAYOUT',
|
||||||
redirect: '/permission/front/page',
|
redirect: '/permission/front/page',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ant-design:home-outlined',
|
icon: 'carbon:user-role',
|
||||||
title: '权限管理',
|
title: 'routes.demo.permission.permission',
|
||||||
},
|
},
|
||||||
children: [backRoute],
|
children: [backRoute],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const levelRoute = {
|
||||||
|
path: '/level',
|
||||||
|
name: 'Level',
|
||||||
|
component: 'LAYOUT',
|
||||||
|
redirect: '/level/menu1/menu1-1',
|
||||||
|
meta: {
|
||||||
|
icon: 'carbon:user-role',
|
||||||
|
title: 'routes.demo.level.level',
|
||||||
|
},
|
||||||
|
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1',
|
||||||
|
name: 'Menu1Demo',
|
||||||
|
meta: {
|
||||||
|
title: 'Menu1',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-1',
|
||||||
|
name: 'Menu11Demo',
|
||||||
|
meta: {
|
||||||
|
title: 'Menu1-1',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-1-1',
|
||||||
|
name: 'Menu111Demo',
|
||||||
|
component: '/demo/level/Menu111',
|
||||||
|
meta: {
|
||||||
|
title: 'Menu111',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu1-2',
|
||||||
|
name: 'Menu12Demo',
|
||||||
|
component: '/demo/level/Menu12',
|
||||||
|
meta: {
|
||||||
|
title: 'Menu1-2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu2',
|
||||||
|
name: 'Menu2Demo',
|
||||||
|
component: '/demo/level/Menu2',
|
||||||
|
meta: {
|
||||||
|
title: 'Menu2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
url: '/api/getMenuListById',
|
url: '/api/getMenuListById',
|
||||||
|
|
@ -120,10 +167,10 @@ export default [
|
||||||
response: ({ query }) => {
|
response: ({ query }) => {
|
||||||
const { id } = query;
|
const { id } = query;
|
||||||
if (!id || id === '1') {
|
if (!id || id === '1') {
|
||||||
return resultSuccess([dashboardRoute, authRoute]);
|
return resultSuccess([dashboardRoute, authRoute, levelRoute]);
|
||||||
}
|
}
|
||||||
if (id === '2') {
|
if (id === '2') {
|
||||||
return resultSuccess([dashboardRoute, authRoute1]);
|
return resultSuccess([dashboardRoute, authRoute1, levelRoute]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
12
package.json
12
package.json
|
|
@ -35,7 +35,7 @@
|
||||||
"qrcode": "^1.4.4",
|
"qrcode": "^1.4.4",
|
||||||
"sortablejs": "^1.12.0",
|
"sortablejs": "^1.12.0",
|
||||||
"vditor": "^3.7.0",
|
"vditor": "^3.7.0",
|
||||||
"vue": "^3.0.3",
|
"vue": "^3.0.4",
|
||||||
"vue-i18n": "^9.0.0-beta.8",
|
"vue-i18n": "^9.0.0-beta.8",
|
||||||
"vue-router": "^4.0.0-rc.6",
|
"vue-router": "^4.0.0-rc.6",
|
||||||
"vue-types": "^3.0.1",
|
"vue-types": "^3.0.1",
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^11.0.0",
|
"@commitlint/cli": "^11.0.0",
|
||||||
"@commitlint/config-conventional": "^11.0.0",
|
"@commitlint/config-conventional": "^11.0.0",
|
||||||
"@iconify/json": "^1.1.266",
|
"@iconify/json": "^1.1.267",
|
||||||
"@ls-lint/ls-lint": "^1.9.2",
|
"@ls-lint/ls-lint": "^1.9.2",
|
||||||
"@purge-icons/generated": "^0.4.1",
|
"@purge-icons/generated": "^0.4.1",
|
||||||
"@types/echarts": "^4.9.2",
|
"@types/echarts": "^4.9.2",
|
||||||
|
|
@ -60,25 +60,25 @@
|
||||||
"@types/qrcode": "^1.3.5",
|
"@types/qrcode": "^1.3.5",
|
||||||
"@types/rollup-plugin-visualizer": "^2.6.0",
|
"@types/rollup-plugin-visualizer": "^2.6.0",
|
||||||
"@types/sortablejs": "^1.10.6",
|
"@types/sortablejs": "^1.10.6",
|
||||||
"@types/yargs": "^15.0.10",
|
"@types/yargs": "^15.0.11",
|
||||||
"@types/zxcvbn": "^4.4.0",
|
"@types/zxcvbn": "^4.4.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.9.0",
|
"@typescript-eslint/eslint-plugin": "^4.9.0",
|
||||||
"@typescript-eslint/parser": "^4.9.0",
|
"@typescript-eslint/parser": "^4.9.0",
|
||||||
"@vue/compiler-sfc": "^3.0.3",
|
"@vue/compiler-sfc": "^3.0.4",
|
||||||
"@vuedx/typecheck": "^0.2.4-0",
|
"@vuedx/typecheck": "^0.2.4-0",
|
||||||
"@vuedx/typescript-plugin-vue": "^0.2.4-0",
|
"@vuedx/typescript-plugin-vue": "^0.2.4-0",
|
||||||
"autoprefixer": "^9.8.6",
|
"autoprefixer": "^9.8.6",
|
||||||
"commitizen": "^4.2.2",
|
"commitizen": "^4.2.2",
|
||||||
"conventional-changelog-cli": "^2.1.1",
|
"conventional-changelog-cli": "^2.1.1",
|
||||||
"conventional-changelog-custom-config": "^0.3.1",
|
"conventional-changelog-custom-config": "^0.3.1",
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.3",
|
||||||
"dot-prop": "^6.0.1",
|
"dot-prop": "^6.0.1",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"eslint": "^7.14.0",
|
"eslint": "^7.14.0",
|
||||||
"eslint-config-prettier": "^6.15.0",
|
"eslint-config-prettier": "^6.15.0",
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"eslint-plugin-vue": "^7.1.0",
|
"eslint-plugin-vue": "^7.1.0",
|
||||||
"esno": "^0.2.4",
|
"esno": "^0.3.0",
|
||||||
"fs-extra": "^9.0.1",
|
"fs-extra": "^9.0.1",
|
||||||
"globrex": "^0.1.2",
|
"globrex": "^0.1.2",
|
||||||
"husky": "^4.3.0",
|
"husky": "^4.3.0",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
import BreadcrumbLib from './src/Breadcrumb.vue';
|
|
||||||
import BreadcrumbItemLib from './src/BreadcrumbItem.vue';
|
|
||||||
import { withInstall } from '../util';
|
|
||||||
|
|
||||||
export const Breadcrumb = withInstall(BreadcrumbLib);
|
|
||||||
export const BreadcrumbItem = withInstall(BreadcrumbItemLib);
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
<template>
|
|
||||||
<div ref="breadcrumbRef" class="breadcrumb">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, provide, ref } from 'vue';
|
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'Breadcrumb',
|
|
||||||
props: {
|
|
||||||
separator: propTypes.string.def('/'),
|
|
||||||
separatorClass: propTypes.string,
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const breadcrumbRef = ref<Nullable<HTMLElement>>(null);
|
|
||||||
|
|
||||||
provide('breadcrumb', props);
|
|
||||||
|
|
||||||
return {
|
|
||||||
breadcrumbRef,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style lang="less">
|
|
||||||
@import (reference) '../../../design/index.less';
|
|
||||||
|
|
||||||
.breadcrumb {
|
|
||||||
.unselect();
|
|
||||||
|
|
||||||
height: @header-height;
|
|
||||||
padding-right: 20px;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: @header-height;
|
|
||||||
// line-height: 1;
|
|
||||||
|
|
||||||
&::after,
|
|
||||||
&::before {
|
|
||||||
display: table;
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__separator {
|
|
||||||
margin: 0 9px;
|
|
||||||
font-weight: 700;
|
|
||||||
color: @breadcrumb-item-normal-color;
|
|
||||||
|
|
||||||
&[class*='icon'] {
|
|
||||||
margin: 0 6px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__inner {
|
|
||||||
color: @breadcrumb-item-normal-color;
|
|
||||||
|
|
||||||
&.is-link,
|
|
||||||
a {
|
|
||||||
font-weight: 500;
|
|
||||||
color: @text-color-base;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover,
|
|
||||||
&.is-link:hover {
|
|
||||||
color: @primary-color;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item:last-child .breadcrumb__inner,
|
|
||||||
&__item:last-child &__inner a,
|
|
||||||
&__item:last-child &__inner a:hover,
|
|
||||||
&__item:last-child &__inner:hover {
|
|
||||||
font-weight: 400;
|
|
||||||
color: @breadcrumb-item-normal-color;
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item:last-child &__separator {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
<template>
|
|
||||||
<span class="breadcrumb__item">
|
|
||||||
<span ref="linkRef" :class="['breadcrumb__inner', to || isLink ? 'is-link' : '']">
|
|
||||||
<slot />
|
|
||||||
</span>
|
|
||||||
<i v-if="separatorClass" class="breadcrumb__separator" :class="separatorClass"></i>
|
|
||||||
<span v-else class="breadcrumb__separator">{{ separator }}</span>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, inject, ref, onMounted, unref } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { useEventListener } from '/@/hooks/event/useEventListener';
|
|
||||||
|
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'BreadcrumbItem',
|
|
||||||
props: {
|
|
||||||
to: propTypes.oneOfType([propTypes.string, propTypes.object]),
|
|
||||||
replace: propTypes.bool,
|
|
||||||
isLink: propTypes.bool,
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const linkRef = ref<Nullable<HTMLElement>>(null);
|
|
||||||
|
|
||||||
const parent = inject('breadcrumb') as {
|
|
||||||
separator: string;
|
|
||||||
separatorClass: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const { push, replace } = useRouter();
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
const link = unref(linkRef);
|
|
||||||
if (!link) return;
|
|
||||||
useEventListener({
|
|
||||||
el: link,
|
|
||||||
listener: () => {
|
|
||||||
const { to } = props;
|
|
||||||
if (!props.to) return;
|
|
||||||
props.replace ? replace(to) : push(to);
|
|
||||||
},
|
|
||||||
name: 'click',
|
|
||||||
wait: 0,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
linkRef,
|
|
||||||
separator: parent.separator && parent.separator,
|
|
||||||
separatorClass: parent.separatorClass && parent.separatorClass,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
@ -36,6 +36,7 @@ import { getCurrentParentPath } from '/@/router/menus';
|
||||||
|
|
||||||
import { basicProps } from './props';
|
import { basicProps } from './props';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||||
|
import { REDIRECT_NAME } from '/@/router/constant';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BasicMenu',
|
name: 'BasicMenu',
|
||||||
props: basicProps,
|
props: basicProps,
|
||||||
|
|
@ -120,7 +121,7 @@ export default defineComponent({
|
||||||
watch(
|
watch(
|
||||||
() => currentRoute.value.name,
|
() => currentRoute.value.name,
|
||||||
(name: string) => {
|
(name: string) => {
|
||||||
if (name === 'Redirect') return;
|
if (name === REDIRECT_NAME) return;
|
||||||
handleMenuChange();
|
handleMenuChange();
|
||||||
props.isHorizontal && appStore.getProjectConfig.menuSetting.split && getParentPath();
|
props.isHorizontal && appStore.getProjectConfig.menuSetting.split && getParentPath();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import type { MenuState } from '../types';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
import { unref } from 'vue';
|
import { unref } from 'vue';
|
||||||
import { getAllParentPath } from '/@/utils/helper/menuHelper';
|
import { getAllParentPath } from '/@/router/helper/menuHelper';
|
||||||
import { es6Unique } from '/@/utils';
|
import { es6Unique } from '/@/utils';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import type { Ref } from 'vue';
|
||||||
import { isString } from '/@/utils/is';
|
import { isString } from '/@/utils/is';
|
||||||
import { unref } from 'vue';
|
import { unref } from 'vue';
|
||||||
import { es6Unique } from '/@/utils';
|
import { es6Unique } from '/@/utils';
|
||||||
import { getAllParentPath } from '/@/utils/helper/menuHelper';
|
import { getAllParentPath } from '/@/router/helper/menuHelper';
|
||||||
|
|
||||||
interface UseSearchInputOptions {
|
interface UseSearchInputOptions {
|
||||||
menuState: MenuState;
|
menuState: MenuState;
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
<Tooltip placement="top" v-if="getSetting.setting">
|
<Tooltip placement="top" v-if="getSetting.setting">
|
||||||
<template #title>
|
<template #title>
|
||||||
<span>{{ t('settingColumn') }}</span>
|
<span>{{ t('component.table.settingColumn') }}</span>
|
||||||
</template>
|
</template>
|
||||||
<Popover
|
<Popover
|
||||||
placement="bottomLeft"
|
placement="bottomLeft"
|
||||||
|
|
@ -58,9 +58,11 @@
|
||||||
v-model:checked="checkAll"
|
v-model:checked="checkAll"
|
||||||
@change="onCheckAllChange"
|
@change="onCheckAllChange"
|
||||||
>
|
>
|
||||||
{{ t('settingColumnShow') }}
|
{{ t('component.table.settingColumnShow') }}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
<a-button size="small" type="link" @click="reset"> {{ t('settingReset') }}</a-button>
|
<a-button size="small" type="link" @click="reset">
|
||||||
|
{{ t('component.table.settingReset') }}</a-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<SettingOutlined />
|
<SettingOutlined />
|
||||||
|
|
@ -69,7 +71,7 @@
|
||||||
|
|
||||||
<Tooltip placement="top" v-if="getSetting.fullScreen">
|
<Tooltip placement="top" v-if="getSetting.fullScreen">
|
||||||
<template #title>
|
<template #title>
|
||||||
<span>{{ t('settingFullScreen') }}</span>
|
<span>{{ t('component.table.settingFullScreen') }}</span>
|
||||||
</template>
|
</template>
|
||||||
<FullscreenOutlined @click="handleFullScreen" v-if="!isFullscreenRef" />
|
<FullscreenOutlined @click="handleFullScreen" v-if="!isFullscreenRef" />
|
||||||
<FullscreenExitOutlined @click="handleFullScreen" v-else />
|
<FullscreenExitOutlined @click="handleFullScreen" v-else />
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import {
|
||||||
Empty,
|
Empty,
|
||||||
Avatar,
|
Avatar,
|
||||||
Menu,
|
Menu,
|
||||||
|
Breadcrumb,
|
||||||
} from 'ant-design-vue';
|
} from 'ant-design-vue';
|
||||||
import { getApp } from '/@/setup/App';
|
import { getApp } from '/@/setup/App';
|
||||||
|
|
||||||
|
|
@ -55,6 +56,7 @@ export function registerGlobComp() {
|
||||||
getApp()
|
getApp()
|
||||||
.use(Select)
|
.use(Select)
|
||||||
.use(Alert)
|
.use(Alert)
|
||||||
|
.use(Breadcrumb)
|
||||||
.use(Checkbox)
|
.use(Checkbox)
|
||||||
.use(DatePicker)
|
.use(DatePicker)
|
||||||
.use(Radio)
|
.use(Radio)
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
.breadcrumb-enter-active,
|
|
||||||
.breadcrumb-leave-active {
|
|
||||||
transition: all 0.24s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.breadcrumb-enter-from,
|
|
||||||
.breadcrumb-leave-active {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateX(16px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.breadcrumb-move {
|
|
||||||
transition: all 0.38s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.breadcrumb-leave-active {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
@ -4,4 +4,3 @@
|
||||||
@import './slide.less';
|
@import './slide.less';
|
||||||
@import './scroll.less';
|
@import './scroll.less';
|
||||||
@import './zoom.less';
|
@import './zoom.less';
|
||||||
@import './breadcrumb.less';
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ export enum PageEnum {
|
||||||
// basic login path
|
// basic login path
|
||||||
BASE_LOGIN = '/login',
|
BASE_LOGIN = '/login',
|
||||||
// basic home path
|
// basic home path
|
||||||
BASE_HOME = '/dashboard',
|
BASE_HOME = '/home',
|
||||||
// error page path
|
// error page path
|
||||||
ERROR_PAGE = '/exception',
|
ERROR_PAGE = '/exception',
|
||||||
// error log page path
|
// error log page path
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import { appStore } from '/@/store/modules/app';
|
import { appStore } from '/@/store/modules/app';
|
||||||
import type { RouteLocationRaw } from 'vue-router';
|
import type { RouteLocationRaw } from 'vue-router';
|
||||||
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { PageEnum } from '/@/enums/pageEnum';
|
import { PageEnum } from '/@/enums/pageEnum';
|
||||||
import { isString } from '/@/utils/is';
|
import { isString } from '/@/utils/is';
|
||||||
import { unref } from 'vue';
|
import { unref } from 'vue';
|
||||||
|
|
||||||
|
import router from '/@/router';
|
||||||
|
|
||||||
export type RouteLocationRawEx = Omit<RouteLocationRaw, 'path'> & { path: PageEnum };
|
export type RouteLocationRawEx = Omit<RouteLocationRaw, 'path'> & { path: PageEnum };
|
||||||
|
|
||||||
function handleError(e: Error) {
|
function handleError(e: Error) {
|
||||||
|
|
@ -18,7 +19,7 @@ function handleError(e: Error) {
|
||||||
|
|
||||||
// page switch
|
// page switch
|
||||||
export function useGo() {
|
export function useGo() {
|
||||||
const { push, replace } = useRouter();
|
const { push, replace } = router;
|
||||||
function go(opt: PageEnum | RouteLocationRawEx | string = PageEnum.BASE_HOME, isReplace = false) {
|
function go(opt: PageEnum | RouteLocationRawEx | string = PageEnum.BASE_HOME, isReplace = false) {
|
||||||
if (!opt) return;
|
if (!opt) return;
|
||||||
if (isString(opt)) {
|
if (isString(opt)) {
|
||||||
|
|
@ -35,7 +36,7 @@ export function useGo() {
|
||||||
* @description: redo current page
|
* @description: redo current page
|
||||||
*/
|
*/
|
||||||
export const useRedo = () => {
|
export const useRedo = () => {
|
||||||
const { push, currentRoute } = useRouter();
|
const { push, currentRoute } = router;
|
||||||
const { query, params } = currentRoute.value;
|
const { query, params } = currentRoute.value;
|
||||||
function redo() {
|
function redo() {
|
||||||
push({
|
push({
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,14 @@ import { userStore } from '/@/store/modules/user';
|
||||||
import { useTabs } from './useTabs';
|
import { useTabs } from './useTabs';
|
||||||
|
|
||||||
import router, { resetRouter } from '/@/router';
|
import router, { resetRouter } from '/@/router';
|
||||||
import { RootRoute } from '/@/router/routes';
|
// import { RootRoute } from '/@/router/routes';
|
||||||
|
|
||||||
import { PermissionModeEnum } from '/@/enums/appEnum';
|
import { PermissionModeEnum } from '/@/enums/appEnum';
|
||||||
import { RoleEnum } from '/@/enums/roleEnum';
|
import { RoleEnum } from '/@/enums/roleEnum';
|
||||||
|
|
||||||
import { intersection } from 'lodash-es';
|
import { intersection } from 'lodash-es';
|
||||||
import { isArray } from '/@/utils/is';
|
import { isArray } from '/@/utils/is';
|
||||||
|
import { tabStore } from '/@/store/modules/tab';
|
||||||
|
|
||||||
// User permissions related operations
|
// User permissions related operations
|
||||||
export function usePermission() {
|
export function usePermission() {
|
||||||
|
|
@ -27,8 +28,7 @@ export function usePermission() {
|
||||||
? PermissionModeEnum.ROLE
|
? PermissionModeEnum.ROLE
|
||||||
: PermissionModeEnum.BACK,
|
: PermissionModeEnum.BACK,
|
||||||
});
|
});
|
||||||
resume();
|
location.reload();
|
||||||
// location.reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -36,18 +36,15 @@ export function usePermission() {
|
||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
async function resume(id?: string | number) {
|
async function resume(id?: string | number) {
|
||||||
|
tabStore.commitClearCache();
|
||||||
resetRouter();
|
resetRouter();
|
||||||
const routes = await permissionStore.buildRoutesAction(id);
|
const routes = await permissionStore.buildRoutesAction(id);
|
||||||
routes.forEach((route) => {
|
routes.forEach((route) => {
|
||||||
router.addRoute(RootRoute.name!, route as RouteRecordRaw);
|
router.addRoute(route as RouteRecordRaw);
|
||||||
});
|
});
|
||||||
permissionStore.commitLastBuildMenuTimeState();
|
permissionStore.commitLastBuildMenuTimeState();
|
||||||
const {
|
const { closeAll } = useTabs();
|
||||||
// closeAll,
|
closeAll();
|
||||||
closeOther,
|
|
||||||
} = useTabs();
|
|
||||||
// closeAll();
|
|
||||||
closeOther();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,72 +1,21 @@
|
||||||
import { TabItem, tabStore } from '/@/store/modules/tab';
|
import { tabStore } from '/@/store/modules/tab';
|
||||||
import { appStore } from '/@/store/modules/app';
|
import { appStore } from '/@/store/modules/app';
|
||||||
|
|
||||||
type RouteFn = (tabItem: TabItem) => void;
|
|
||||||
|
|
||||||
interface TabFn {
|
|
||||||
refreshPageFn: RouteFn;
|
|
||||||
closeAllFn: Fn;
|
|
||||||
closeLeftFn: RouteFn;
|
|
||||||
closeRightFn: RouteFn;
|
|
||||||
closeOtherFn: RouteFn;
|
|
||||||
closeCurrentFn: RouteFn;
|
|
||||||
}
|
|
||||||
|
|
||||||
let refreshPage: RouteFn;
|
|
||||||
let closeAll: Fn;
|
|
||||||
let closeLeft: RouteFn;
|
|
||||||
let closeRight: RouteFn;
|
|
||||||
let closeOther: RouteFn;
|
|
||||||
let closeCurrent: RouteFn;
|
|
||||||
|
|
||||||
export let isInitUseTab = false;
|
|
||||||
|
|
||||||
export function useTabs() {
|
export function useTabs() {
|
||||||
function initTabFn({
|
|
||||||
refreshPageFn,
|
|
||||||
closeAllFn,
|
|
||||||
closeLeftFn,
|
|
||||||
closeRightFn,
|
|
||||||
closeOtherFn,
|
|
||||||
closeCurrentFn,
|
|
||||||
}: TabFn) {
|
|
||||||
if (isInitUseTab) return;
|
|
||||||
|
|
||||||
refreshPageFn && (refreshPage = refreshPageFn);
|
|
||||||
closeAllFn && (closeAll = closeAllFn);
|
|
||||||
closeLeftFn && (closeLeft = closeLeftFn);
|
|
||||||
closeRightFn && (closeRight = closeRightFn);
|
|
||||||
closeOtherFn && (closeOther = closeOtherFn);
|
|
||||||
closeCurrentFn && (closeCurrent = closeCurrentFn);
|
|
||||||
isInitUseTab = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetCache() {
|
|
||||||
const def = undefined as any;
|
|
||||||
refreshPage = def;
|
|
||||||
closeAll = def;
|
|
||||||
closeLeft = def;
|
|
||||||
closeRight = def;
|
|
||||||
closeOther = def;
|
|
||||||
closeCurrent = def;
|
|
||||||
}
|
|
||||||
|
|
||||||
function canIUseFn(): boolean {
|
function canIUseFn(): boolean {
|
||||||
const { multiTabsSetting: { show } = {} } = appStore.getProjectConfig;
|
const { multiTabsSetting: { show } = {} } = appStore.getProjectConfig;
|
||||||
if (!show) {
|
if (!show) {
|
||||||
throw new Error('当前未开启多标签页,请在设置中打开!');
|
throw new Error('The multi-tab page is currently not open, please open it in the settings!');
|
||||||
}
|
}
|
||||||
return !!show;
|
return !!show;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
initTabFn,
|
refreshPage: () => canIUseFn() && tabStore.commitRedoPage(),
|
||||||
refreshPage: () => canIUseFn() && refreshPage(tabStore.getCurrentTab),
|
closeAll: () => canIUseFn() && tabStore.closeAllTabAction(),
|
||||||
closeAll: () => canIUseFn() && closeAll(),
|
closeLeft: () => canIUseFn() && tabStore.closeLeftTabAction(tabStore.getCurrentTab),
|
||||||
closeLeft: () => canIUseFn() && closeLeft(tabStore.getCurrentTab),
|
closeRight: () => canIUseFn() && tabStore.closeRightTabAction(tabStore.getCurrentTab),
|
||||||
closeRight: () => canIUseFn() && closeRight(tabStore.getCurrentTab),
|
closeOther: () => canIUseFn() && tabStore.closeOtherTabAction(tabStore.getCurrentTab),
|
||||||
closeOther: () => canIUseFn() && closeOther(tabStore.getCurrentTab),
|
closeCurrent: () => canIUseFn() && tabStore.closeTabAction(tabStore.getCurrentTab),
|
||||||
closeCurrent: () => canIUseFn() && closeCurrent(tabStore.getCurrentTab),
|
|
||||||
resetCache: () => canIUseFn() && resetCache(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@ import './index.less';
|
||||||
import { defineComponent, unref } from 'vue';
|
import { defineComponent, unref } from 'vue';
|
||||||
import { Loading } from '/@/components/Loading';
|
import { Loading } from '/@/components/Loading';
|
||||||
|
|
||||||
import { RouterView } from 'vue-router';
|
|
||||||
|
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||||
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
||||||
|
import PageLayout from '/@/layouts/page/index.vue';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'LayoutContent',
|
name: 'LayoutContent',
|
||||||
setup() {
|
setup() {
|
||||||
|
|
@ -20,7 +18,7 @@ export default defineComponent({
|
||||||
{unref(getOpenPageLoading) && (
|
{unref(getOpenPageLoading) && (
|
||||||
<Loading loading={unref(getPageLoading)} absolute class="layout-content__loading" />
|
<Loading loading={unref(getPageLoading)} absolute class="layout-content__loading" />
|
||||||
)}
|
)}
|
||||||
<RouterView />
|
<PageLayout />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,128 +0,0 @@
|
||||||
import type { AppRouteRecordRaw } from '/@/router/types';
|
|
||||||
import type { RouteLocationMatched } from 'vue-router';
|
|
||||||
import type { PropType } from 'vue';
|
|
||||||
|
|
||||||
import { defineComponent, TransitionGroup, unref, watch, ref } from 'vue';
|
|
||||||
import Icon from '/@/components/Icon';
|
|
||||||
|
|
||||||
import { Breadcrumb, BreadcrumbItem } from '/@/components/Breadcrumb';
|
|
||||||
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
|
|
||||||
import { isBoolean } from '/@/utils/is';
|
|
||||||
import { compile } from 'path-to-regexp';
|
|
||||||
|
|
||||||
import router from '/@/router';
|
|
||||||
|
|
||||||
import { PageEnum } from '/@/enums/pageEnum';
|
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'BasicBreadcrumb',
|
|
||||||
props: {
|
|
||||||
showIcon: {
|
|
||||||
type: Boolean as PropType<boolean>,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const itemList = ref<AppRouteRecordRaw[]>([]);
|
|
||||||
|
|
||||||
const { currentRoute, push } = useRouter();
|
|
||||||
const { t } = useI18n();
|
|
||||||
watch(
|
|
||||||
() => currentRoute.value,
|
|
||||||
() => {
|
|
||||||
if (unref(currentRoute).name === 'Redirect') return;
|
|
||||||
getBreadcrumb();
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
function getBreadcrumb() {
|
|
||||||
const { matched } = unref(currentRoute);
|
|
||||||
const matchedList = matched.filter((item) => item.meta && item.meta.title).slice(1);
|
|
||||||
const firstItem = matchedList[0];
|
|
||||||
const ret = getHomeRoute(firstItem);
|
|
||||||
if (!isBoolean(ret)) {
|
|
||||||
matchedList.unshift(ret);
|
|
||||||
}
|
|
||||||
itemList.value = ((matchedList as any) as AppRouteRecordRaw[]).filter(
|
|
||||||
(item) => item.meta && item.meta.title && !item.meta.hideBreadcrumb
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHomeRoute(firstItem: RouteLocationMatched) {
|
|
||||||
if (!firstItem || !firstItem.name) return false;
|
|
||||||
const routes = router.getRoutes();
|
|
||||||
const homeRoute = routes.find((item) => item.path === PageEnum.BASE_HOME);
|
|
||||||
if (!homeRoute) return false;
|
|
||||||
if (homeRoute.name === firstItem.name) return false;
|
|
||||||
return homeRoute;
|
|
||||||
}
|
|
||||||
|
|
||||||
function pathCompile(path: string) {
|
|
||||||
const { params } = unref(currentRoute);
|
|
||||||
const toPath = compile(path);
|
|
||||||
return toPath(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleItemClick(item: AppRouteRecordRaw) {
|
|
||||||
const { redirect, path, meta } = item;
|
|
||||||
if (meta.disabledRedirect) return;
|
|
||||||
if (redirect) {
|
|
||||||
push(redirect as string);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return push(pathCompile(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderItemContent(item: AppRouteRecordRaw) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{props.showIcon && item.meta.icon && item.meta.icon.trim() !== '' && (
|
|
||||||
<Icon
|
|
||||||
icon={item.meta.icon}
|
|
||||||
class="icon mr-1 "
|
|
||||||
style={{
|
|
||||||
marginBottom: '2px',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{t(item.meta.title)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderBreadcrumbItemList() {
|
|
||||||
return unref(itemList).map((item) => {
|
|
||||||
const isLink =
|
|
||||||
(!!item.redirect && !item.meta.disabledRedirect) ||
|
|
||||||
!item.children ||
|
|
||||||
item.children.length === 0;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BreadcrumbItem
|
|
||||||
key={item.path}
|
|
||||||
isLink={isLink}
|
|
||||||
onClick={handleItemClick.bind(null, item)}
|
|
||||||
>
|
|
||||||
{() => renderItemContent(item as AppRouteRecordRaw)}
|
|
||||||
</BreadcrumbItem>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderBreadcrumbDefault() {
|
|
||||||
return (
|
|
||||||
<TransitionGroup name="breadcrumb">{() => renderBreadcrumbItemList()}</TransitionGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => (
|
|
||||||
<Breadcrumb class={['layout-breadcrumb', unref(itemList).length === 0 ? 'hidden' : '']}>
|
|
||||||
{() => renderBreadcrumbDefault()}
|
|
||||||
</Breadcrumb>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
<template>
|
||||||
|
<div class="layout-breadcrumb">
|
||||||
|
<a-breadcrumb :routes="routes">
|
||||||
|
<template #itemRender="{ route, routes }">
|
||||||
|
<Icon :icon="route.meta.icon" v-if="showIcon && route.meta.icon" />
|
||||||
|
<span v-if="routes.indexOf(route) === routes.length - 1">
|
||||||
|
{{ t(route.meta.title) }}
|
||||||
|
</span>
|
||||||
|
<router-link v-else :to="route.path">
|
||||||
|
{{ t(route.meta.title) }}
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
</a-breadcrumb>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { PropType } from 'vue';
|
||||||
|
import { defineComponent, ref, toRaw, watchEffect } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import type { RouteLocationMatched } from 'vue-router';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { filter } from '/@/utils/helper/treeHelper';
|
||||||
|
import { REDIRECT_NAME } from '/@/router/constant';
|
||||||
|
import Icon from '/@/components/Icon';
|
||||||
|
|
||||||
|
import { HomeOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { PageEnum } from '/@/enums/pageEnum';
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'LayoutBreadcrumb',
|
||||||
|
components: { HomeOutlined, Icon },
|
||||||
|
props: {
|
||||||
|
showIcon: {
|
||||||
|
type: Boolean as PropType<boolean>,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const routes = ref<RouteLocationMatched[]>([]);
|
||||||
|
const { currentRoute } = useRouter();
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
watchEffect(() => {
|
||||||
|
if (currentRoute.value.name === REDIRECT_NAME) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const matched = currentRoute.value.matched;
|
||||||
|
if (!matched || matched.length === 0) return;
|
||||||
|
|
||||||
|
let breadcrumbList = filter(toRaw(matched), (item) => {
|
||||||
|
if (!item.meta) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const { title, hideBreadcrumb } = item.meta;
|
||||||
|
if (!title || hideBreadcrumb) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const filterBreadcrumbList = breadcrumbList.filter(
|
||||||
|
(item) => item.path !== PageEnum.BASE_HOME
|
||||||
|
);
|
||||||
|
|
||||||
|
if (filterBreadcrumbList.length === breadcrumbList.length) {
|
||||||
|
filterBreadcrumbList.unshift({
|
||||||
|
path: PageEnum.BASE_HOME,
|
||||||
|
meta: {
|
||||||
|
title: t('layout.header.home'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
routes.value = filterBreadcrumbList;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { routes, t };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -9,7 +9,7 @@ import { Layout, Tooltip, Badge } from 'ant-design-vue';
|
||||||
import { AppLogo } from '/@/components/Application';
|
import { AppLogo } from '/@/components/Application';
|
||||||
import UserDropdown from './UserDropdown';
|
import UserDropdown from './UserDropdown';
|
||||||
import LayoutMenu from '../menu';
|
import LayoutMenu from '../menu';
|
||||||
import LayoutBreadcrumb from './LayoutBreadcrumb';
|
import LayoutBreadcrumb from './LayoutBreadcrumb.vue';
|
||||||
import LockAction from '../lock/LockAction';
|
import LockAction from '../lock/LockAction';
|
||||||
import LayoutTrigger from '../LayoutTrigger';
|
import LayoutTrigger from '../LayoutTrigger';
|
||||||
import NoticeAction from './notice/NoticeActionItem.vue';
|
import NoticeAction from './notice/NoticeActionItem.vue';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.multiple-tab-header {
|
.multiple-tab-header {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
margin-left: -1px;
|
||||||
|
|
||||||
&.fixed {
|
&.fixed {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,15 @@
|
||||||
|
|
||||||
&__left {
|
&__left {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.layout-trigger {
|
.layout-trigger {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
padding: 1px 10px 0 16px;
|
padding: 1px 10px 0 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.anticon {
|
.anticon {
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
|
|
@ -49,12 +53,22 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-breadcrumb {
|
.layout-breadcrumb {
|
||||||
|
display: flex;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.ant-breadcrumb-link {
|
||||||
|
.anticon {
|
||||||
|
margin-right: 4px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
@ -72,6 +86,24 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layout-breadcrumb {
|
||||||
|
.ant-breadcrumb-link {
|
||||||
|
color: @breadcrumb-item-normal-color;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: @text-color-base;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-breadcrumb-separator {
|
||||||
|
color: @breadcrumb-item-normal-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.layout-header__logo {
|
.layout-header__logo {
|
||||||
height: @header-height;
|
height: @header-height;
|
||||||
color: @text-color-base;
|
color: @text-color-base;
|
||||||
|
|
@ -152,20 +184,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumb {
|
.layout-breadcrumb {
|
||||||
&__item:last-child .breadcrumb__inner,
|
.ant-breadcrumb-link {
|
||||||
&__item:last-child &__inner a,
|
|
||||||
&__item:last-child &__inner a:hover,
|
|
||||||
&__item:last-child &__inner:hover {
|
|
||||||
font-weight: 400;
|
|
||||||
color: rgba(255, 255, 255, 0.6);
|
color: rgba(255, 255, 255, 0.6);
|
||||||
cursor: text;
|
|
||||||
|
a {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @white;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__inner,
|
.ant-breadcrumb-separator,
|
||||||
&__inner.is-link,
|
.anticon {
|
||||||
&__separator {
|
color: rgba(255, 255, 255, 0.8);
|
||||||
color: @white;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,19 @@
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
|
|
||||||
import { defineComponent, unref, computed, FunctionalComponent } from 'vue';
|
|
||||||
|
|
||||||
import { TabItem, tabStore } from '/@/store/modules/tab';
|
|
||||||
import { getScaleAction, TabContentProps } from './data';
|
|
||||||
|
|
||||||
import { Dropdown } from '/@/components/Dropdown/index';
|
import { Dropdown } from '/@/components/Dropdown/index';
|
||||||
|
|
||||||
|
import { defineComponent, unref, FunctionalComponent } from 'vue';
|
||||||
|
|
||||||
|
import { TabContentProps } from './types';
|
||||||
|
|
||||||
import { RightOutlined } from '@ant-design/icons-vue';
|
import { RightOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
import { TabContentEnum } from './data';
|
import { TabContentEnum } from './types';
|
||||||
|
|
||||||
import { useTabDropdown } from './useTabDropdown';
|
import { useTabDropdown } from './useTabDropdown';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
|
||||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
|
||||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
|
||||||
|
import { RouteLocationNormalized } from 'vue-router';
|
||||||
|
|
||||||
const { t: titleT } = useI18n();
|
const { t: titleT } = useI18n();
|
||||||
|
|
||||||
const ExtraContent: FunctionalComponent = () => {
|
const ExtraContent: FunctionalComponent = () => {
|
||||||
|
|
@ -25,21 +24,13 @@ const ExtraContent: FunctionalComponent = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const TabContent: FunctionalComponent<{ tabItem: TabItem }> = (props) => {
|
const TabContent: FunctionalComponent<{ tabItem: RouteLocationNormalized; handler: Fn }> = (
|
||||||
|
props
|
||||||
|
) => {
|
||||||
const { tabItem: { meta } = {} } = props;
|
const { tabItem: { meta } = {} } = props;
|
||||||
|
|
||||||
function handleContextMenu(e: Event) {
|
|
||||||
if (!props.tabItem) return;
|
|
||||||
const tableItem = props.tabItem;
|
|
||||||
e?.preventDefault();
|
|
||||||
const index = unref(tabStore.getTabsState).findIndex((tab) => tab.path === tableItem.path);
|
|
||||||
|
|
||||||
tabStore.commitCurrentContextMenuIndexState(index);
|
|
||||||
tabStore.commitCurrentContextMenuState(props.tabItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={`multiple-tabs-content__content `} onContextmenu={handleContextMenu}>
|
<div class={`multiple-tabs-content__content `} onContextmenu={props.handler(props.tabItem)}>
|
||||||
<span class="ml-1">{meta && titleT(meta.title)}</span>
|
<span class="ml-1">{meta && titleT(meta.title)}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -49,7 +40,7 @@ export default defineComponent({
|
||||||
name: 'TabContent',
|
name: 'TabContent',
|
||||||
props: {
|
props: {
|
||||||
tabItem: {
|
tabItem: {
|
||||||
type: Object as PropType<TabItem>,
|
type: Object as PropType<RouteLocationNormalized>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -59,36 +50,27 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const { t } = useI18n();
|
const {
|
||||||
const { getShowMenu } = useMenuSetting();
|
getDropMenuList,
|
||||||
const { getShowHeader } = useHeaderSetting();
|
handleMenuEvent,
|
||||||
const { getShowQuick } = useMultipleTabSetting();
|
handleContextMenu,
|
||||||
|
getTrigger,
|
||||||
const getIsScale = computed(() => {
|
isTabs,
|
||||||
return !unref(getShowMenu) && !unref(getShowHeader);
|
} = useTabDropdown(props as TabContentProps);
|
||||||
});
|
|
||||||
|
|
||||||
const getIsTab = computed(() => {
|
|
||||||
return !unref(getShowQuick) ? true : props.type === TabContentEnum.TAB_TYPE;
|
|
||||||
});
|
|
||||||
|
|
||||||
const { getDropMenuList, handleMenuEvent } = useTabDropdown(props as TabContentProps);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const scaleAction = getScaleAction(
|
|
||||||
unref(getIsScale) ? t('layout.multipleTab.putAway') : t('layout.multipleTab.unfold'),
|
|
||||||
unref(getIsScale)
|
|
||||||
);
|
|
||||||
const dropMenuList = unref(getDropMenuList) || [];
|
|
||||||
|
|
||||||
const isTab = unref(getIsTab);
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
dropMenuList={!isTab ? [scaleAction, ...dropMenuList] : dropMenuList}
|
dropMenuList={unref(getDropMenuList)}
|
||||||
trigger={isTab ? ['contextmenu'] : ['click']}
|
trigger={unref(getTrigger)}
|
||||||
onMenuEvent={handleMenuEvent}
|
onMenuEvent={handleMenuEvent}
|
||||||
>
|
>
|
||||||
{() => (isTab ? <TabContent tabItem={props.tabItem} /> : <ExtraContent />)}
|
{() => {
|
||||||
|
if (!unref(isTabs)) {
|
||||||
|
return <ExtraContent />;
|
||||||
|
}
|
||||||
|
return <TabContent handler={handleContextMenu} tabItem={props.tabItem} />;
|
||||||
|
}}
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
import { DropMenu } from '/@/components/Dropdown/index';
|
|
||||||
import { AppRouteRecordRaw } from '/@/router/types';
|
|
||||||
import type { TabItem } from '/@/store/modules/tab';
|
|
||||||
|
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
export enum TabContentEnum {
|
|
||||||
TAB_TYPE,
|
|
||||||
EXTRA_TYPE,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabContentProps {
|
|
||||||
tabItem: TabItem | AppRouteRecordRaw;
|
|
||||||
type?: TabContentEnum;
|
|
||||||
trigger?: Array<'click' | 'hover' | 'contextmenu'>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: 右键:下拉菜单文字
|
|
||||||
*/
|
|
||||||
export enum MenuEventEnum {
|
|
||||||
// 刷新
|
|
||||||
REFRESH_PAGE,
|
|
||||||
// 关闭当前
|
|
||||||
CLOSE_CURRENT,
|
|
||||||
// 关闭左侧
|
|
||||||
CLOSE_LEFT,
|
|
||||||
// 关闭右侧
|
|
||||||
CLOSE_RIGHT,
|
|
||||||
// 关闭其他
|
|
||||||
CLOSE_OTHER,
|
|
||||||
// 关闭所有
|
|
||||||
CLOSE_ALL,
|
|
||||||
// 放大
|
|
||||||
SCALE,
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getActions() {
|
|
||||||
const REFRESH_PAGE: DropMenu = {
|
|
||||||
icon: 'ant-design:reload-outlined',
|
|
||||||
event: MenuEventEnum.REFRESH_PAGE,
|
|
||||||
text: t('layout.multipleTab.redo'),
|
|
||||||
disabled: false,
|
|
||||||
};
|
|
||||||
const CLOSE_CURRENT: DropMenu = {
|
|
||||||
icon: 'ant-design:close-outlined',
|
|
||||||
event: MenuEventEnum.CLOSE_CURRENT,
|
|
||||||
text: t('layout.multipleTab.close'),
|
|
||||||
disabled: false,
|
|
||||||
divider: true,
|
|
||||||
};
|
|
||||||
const CLOSE_LEFT: DropMenu = {
|
|
||||||
icon: 'ant-design:pic-left-outlined',
|
|
||||||
event: MenuEventEnum.CLOSE_LEFT,
|
|
||||||
text: t('layout.multipleTab.closeLeft'),
|
|
||||||
disabled: false,
|
|
||||||
divider: false,
|
|
||||||
};
|
|
||||||
const CLOSE_RIGHT: DropMenu = {
|
|
||||||
icon: 'ant-design:pic-right-outlined',
|
|
||||||
event: MenuEventEnum.CLOSE_RIGHT,
|
|
||||||
text: t('layout.multipleTab.closeRight'),
|
|
||||||
disabled: false,
|
|
||||||
divider: true,
|
|
||||||
};
|
|
||||||
const CLOSE_OTHER: DropMenu = {
|
|
||||||
icon: 'ant-design:pic-center-outlined',
|
|
||||||
event: MenuEventEnum.CLOSE_OTHER,
|
|
||||||
text: t('layout.multipleTab.closeOther'),
|
|
||||||
disabled: false,
|
|
||||||
};
|
|
||||||
const CLOSE_ALL: DropMenu = {
|
|
||||||
icon: 'ant-design:line-outlined',
|
|
||||||
event: MenuEventEnum.CLOSE_ALL,
|
|
||||||
text: t('layout.multipleTab.closeAll'),
|
|
||||||
disabled: false,
|
|
||||||
};
|
|
||||||
return [REFRESH_PAGE, CLOSE_CURRENT, CLOSE_LEFT, CLOSE_RIGHT, CLOSE_OTHER, CLOSE_ALL];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getScaleAction(text: string, isZoom = false) {
|
|
||||||
return {
|
|
||||||
icon: isZoom ? 'codicon:screen-normal' : 'codicon:screen-full',
|
|
||||||
event: MenuEventEnum.SCALE,
|
|
||||||
text: text,
|
|
||||||
disabled: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
|
||||||
import type { TabContentProps } from './data';
|
import type { TabContentProps } from './types';
|
||||||
import type { TabItem } from '/@/store/modules/tab';
|
|
||||||
import type { AppRouteRecordRaw } from '/@/router/types';
|
|
||||||
|
|
||||||
import { defineComponent, watch, computed, unref, ref, onMounted, nextTick } from 'vue';
|
|
||||||
import Sortable from 'sortablejs';
|
|
||||||
|
|
||||||
|
import { defineComponent, watch, computed, unref, ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { Tabs } from 'ant-design-vue';
|
import { Tabs } from 'ant-design-vue';
|
||||||
|
|
@ -14,15 +10,12 @@ import TabContent from './TabContent';
|
||||||
|
|
||||||
import { useGo } from '/@/hooks/web/usePage';
|
import { useGo } from '/@/hooks/web/usePage';
|
||||||
|
|
||||||
import { TabContentEnum } from './data';
|
import { TabContentEnum } from './types';
|
||||||
|
|
||||||
import { tabStore } from '/@/store/modules/tab';
|
import { tabStore } from '/@/store/modules/tab';
|
||||||
import { userStore } from '/@/store/modules/user';
|
import { userStore } from '/@/store/modules/user';
|
||||||
|
|
||||||
import { closeTab } from './useTabDropdown';
|
import { initAffixTabs, useTabsDrag } from './useMultipleTabs';
|
||||||
import { initAffixTabs } from './useMultipleTabs';
|
|
||||||
import { isNullAndUnDef } from '/@/utils/is';
|
|
||||||
import { useProjectSetting } from '/@/hooks/setting';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'MultipleTabs',
|
name: 'MultipleTabs',
|
||||||
|
|
@ -31,28 +24,25 @@ export default defineComponent({
|
||||||
|
|
||||||
const affixTextList = initAffixTabs();
|
const affixTextList = initAffixTabs();
|
||||||
|
|
||||||
const go = useGo();
|
useTabsDrag(affixTextList);
|
||||||
|
|
||||||
const { multiTabsSetting } = useProjectSetting();
|
const go = useGo();
|
||||||
|
|
||||||
const { currentRoute } = useRouter();
|
const { currentRoute } = useRouter();
|
||||||
|
|
||||||
const getTabsState = computed(() => tabStore.getTabsState);
|
const getTabsState = computed(() => tabStore.getTabsState);
|
||||||
|
|
||||||
// If you monitor routing changes, tab switching will be stuck. So setting this method
|
|
||||||
watch(
|
watch(
|
||||||
() => tabStore.getLastChangeRouteState,
|
() => tabStore.getLastChangeRouteState?.path,
|
||||||
() => {
|
() => {
|
||||||
const lastChangeRoute = unref(tabStore.getLastChangeRouteState);
|
const lastChangeRoute = unref(tabStore.getLastChangeRouteState);
|
||||||
|
|
||||||
if (!lastChangeRoute || !userStore.getTokenState) return;
|
if (!lastChangeRoute || !userStore.getTokenState) return;
|
||||||
|
const { path, fullPath } = lastChangeRoute;
|
||||||
const { path, fullPath } = lastChangeRoute as AppRouteRecordRaw;
|
|
||||||
const p = fullPath || path;
|
const p = fullPath || path;
|
||||||
if (activeKeyRef.value !== p) {
|
if (activeKeyRef.value !== p) {
|
||||||
activeKeyRef.value = p;
|
activeKeyRef.value = p;
|
||||||
}
|
}
|
||||||
tabStore.commitAddTab(lastChangeRoute);
|
tabStore.addTabAction(lastChangeRoute);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
|
|
@ -67,22 +57,19 @@ export default defineComponent({
|
||||||
// Close the current tab
|
// Close the current tab
|
||||||
function handleEdit(targetKey: string) {
|
function handleEdit(targetKey: string) {
|
||||||
// Added operation to hide, currently only use delete operation
|
// Added operation to hide, currently only use delete operation
|
||||||
const index = unref(getTabsState).findIndex(
|
tabStore.closeTabByKeyAction(targetKey);
|
||||||
(item) => (item.fullPath || item.path) === targetKey
|
|
||||||
);
|
|
||||||
index !== -1 && closeTab(unref(getTabsState)[index]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderQuick() {
|
function renderQuick() {
|
||||||
const tabContentProps: TabContentProps = {
|
const tabContentProps: TabContentProps = {
|
||||||
tabItem: (currentRoute as unknown) as AppRouteRecordRaw,
|
tabItem: currentRoute.value,
|
||||||
type: TabContentEnum.EXTRA_TYPE,
|
type: TabContentEnum.EXTRA_TYPE,
|
||||||
};
|
};
|
||||||
return <TabContent {...(tabContentProps as any)} />;
|
return <TabContent {...tabContentProps} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderTabs() {
|
function renderTabs() {
|
||||||
return unref(getTabsState).map((item: TabItem) => {
|
return unref(getTabsState).map((item) => {
|
||||||
const key = item.query ? item.fullPath : item.path;
|
const key = item.query ? item.fullPath : item.path;
|
||||||
const closable = !(item && item.meta && item.meta.affix);
|
const closable = !(item && item.meta && item.meta.affix);
|
||||||
|
|
||||||
|
|
@ -97,40 +84,6 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initSortableTabs() {
|
|
||||||
if (!multiTabsSetting.canDrag) return;
|
|
||||||
nextTick(() => {
|
|
||||||
const el = document.querySelectorAll(
|
|
||||||
'.multiple-tabs .ant-tabs-nav > div'
|
|
||||||
)?.[0] as HTMLElement;
|
|
||||||
|
|
||||||
if (!el) return;
|
|
||||||
Sortable.create(el, {
|
|
||||||
animation: 500,
|
|
||||||
delay: 400,
|
|
||||||
delayOnTouchOnly: true,
|
|
||||||
filter: (e: ChangeEvent) => {
|
|
||||||
const text = e?.target?.innerText;
|
|
||||||
if (!text) return false;
|
|
||||||
return affixTextList.includes(text);
|
|
||||||
},
|
|
||||||
onEnd: (evt) => {
|
|
||||||
const { oldIndex, newIndex } = evt;
|
|
||||||
|
|
||||||
if (isNullAndUnDef(oldIndex) || isNullAndUnDef(newIndex) || oldIndex === newIndex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabStore.commitSortTabs({ oldIndex, newIndex });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
initSortableTabs();
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const slots = {
|
const slots = {
|
||||||
default: () => renderTabs(),
|
default: () => renderTabs(),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import type { DropMenu } from '/@/components/Dropdown/index';
|
||||||
|
import type { RouteLocationNormalized } from 'vue-router';
|
||||||
|
|
||||||
|
export enum TabContentEnum {
|
||||||
|
TAB_TYPE,
|
||||||
|
EXTRA_TYPE,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type { DropMenu };
|
||||||
|
|
||||||
|
export interface TabContentProps {
|
||||||
|
tabItem: RouteLocationNormalized;
|
||||||
|
type?: TabContentEnum;
|
||||||
|
trigger?: ('click' | 'hover' | 'contextmenu')[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 右键:下拉菜单文字
|
||||||
|
*/
|
||||||
|
export enum MenuEventEnum {
|
||||||
|
// 刷新
|
||||||
|
REFRESH_PAGE,
|
||||||
|
// 关闭当前
|
||||||
|
CLOSE_CURRENT,
|
||||||
|
// 关闭左侧
|
||||||
|
CLOSE_LEFT,
|
||||||
|
// 关闭右侧
|
||||||
|
CLOSE_RIGHT,
|
||||||
|
// 关闭其他
|
||||||
|
CLOSE_OTHER,
|
||||||
|
// 关闭所有
|
||||||
|
CLOSE_ALL,
|
||||||
|
// 放大
|
||||||
|
SCALE,
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,22 @@
|
||||||
import { toRaw, ref } from 'vue';
|
import Sortable from 'sortablejs';
|
||||||
|
import { toRaw, ref, nextTick, onMounted } from 'vue';
|
||||||
|
import { RouteLocationNormalized } from 'vue-router';
|
||||||
|
import { useProjectSetting } from '/@/hooks/setting';
|
||||||
import router from '/@/router';
|
import router from '/@/router';
|
||||||
import { AppRouteRecordRaw } from '/@/router/types';
|
import { tabStore } from '/@/store/modules/tab';
|
||||||
import { TabItem, tabStore } from '/@/store/modules/tab';
|
import { isNullAndUnDef } from '/@/utils/is';
|
||||||
|
|
||||||
export function initAffixTabs() {
|
export function initAffixTabs(): string[] {
|
||||||
const affixList = ref<TabItem[]>([]);
|
const affixList = ref<RouteLocationNormalized[]>([]);
|
||||||
/**
|
/**
|
||||||
* @description: Filter all fixed routes
|
* @description: Filter all fixed routes
|
||||||
*/
|
*/
|
||||||
function filterAffixTabs(routes: AppRouteRecordRaw[]) {
|
function filterAffixTabs(routes: RouteLocationNormalized[]) {
|
||||||
const tabs: TabItem[] = [];
|
const tabs: RouteLocationNormalized[] = [];
|
||||||
routes &&
|
routes &&
|
||||||
routes.forEach((route) => {
|
routes.forEach((route) => {
|
||||||
if (route.meta && route.meta.affix) {
|
if (route.meta && route.meta.affix) {
|
||||||
tabs.push(toRaw(route) as TabItem);
|
tabs.push(toRaw(route));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return tabs;
|
return tabs;
|
||||||
|
|
@ -23,10 +26,14 @@ export function initAffixTabs() {
|
||||||
* @description: Set fixed tabs
|
* @description: Set fixed tabs
|
||||||
*/
|
*/
|
||||||
function addAffixTabs(): void {
|
function addAffixTabs(): void {
|
||||||
const affixTabs = filterAffixTabs((router.getRoutes() as unknown) as AppRouteRecordRaw[]);
|
const affixTabs = filterAffixTabs((router.getRoutes() as unknown) as RouteLocationNormalized[]);
|
||||||
affixList.value = affixTabs;
|
affixList.value = affixTabs;
|
||||||
for (const tab of affixTabs) {
|
for (const tab of affixTabs) {
|
||||||
tabStore.commitAddTab(tab);
|
tabStore.addTabAction(({
|
||||||
|
meta: tab.meta,
|
||||||
|
name: tab.name,
|
||||||
|
path: tab.path,
|
||||||
|
} as unknown) as RouteLocationNormalized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,3 +44,41 @@ export function initAffixTabs() {
|
||||||
}
|
}
|
||||||
return affixList.value.map((item) => item.meta?.title).filter(Boolean);
|
return affixList.value.map((item) => item.meta?.title).filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useTabsDrag(affixTextList: string[]) {
|
||||||
|
const { multiTabsSetting } = useProjectSetting();
|
||||||
|
|
||||||
|
function initSortableTabs() {
|
||||||
|
if (!multiTabsSetting.canDrag) return;
|
||||||
|
nextTick(() => {
|
||||||
|
const el = document.querySelectorAll(
|
||||||
|
'.multiple-tabs .ant-tabs-nav > div'
|
||||||
|
)?.[0] as HTMLElement;
|
||||||
|
|
||||||
|
if (!el) return;
|
||||||
|
Sortable.create(el, {
|
||||||
|
animation: 500,
|
||||||
|
delay: 400,
|
||||||
|
delayOnTouchOnly: true,
|
||||||
|
filter: (e: ChangeEvent) => {
|
||||||
|
const text = e?.target?.innerText;
|
||||||
|
if (!text) return false;
|
||||||
|
return affixTextList.includes(text);
|
||||||
|
},
|
||||||
|
onEnd: (evt) => {
|
||||||
|
const { oldIndex, newIndex } = evt;
|
||||||
|
|
||||||
|
if (isNullAndUnDef(oldIndex) || isNullAndUnDef(newIndex) || oldIndex === newIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabStore.commitSortTabs({ oldIndex, newIndex });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initSortableTabs();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,168 +1,148 @@
|
||||||
import type { AppRouteRecordRaw } from '/@/router/types';
|
import type { TabContentProps } from './types';
|
||||||
import type { TabContentProps } from './data';
|
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import type { TabItem } from '/@/store/modules/tab';
|
|
||||||
import type { DropMenu } from '/@/components/Dropdown';
|
import type { DropMenu } from '/@/components/Dropdown';
|
||||||
|
|
||||||
import { computed, unref } from 'vue';
|
import { computed, unref, reactive } from 'vue';
|
||||||
import { TabContentEnum, MenuEventEnum, getActions } from './data';
|
import { TabContentEnum, MenuEventEnum } from './types';
|
||||||
import { tabStore } from '/@/store/modules/tab';
|
import { tabStore } from '/@/store/modules/tab';
|
||||||
import { appStore } from '/@/store/modules/app';
|
|
||||||
import { PageEnum } from '/@/enums/pageEnum';
|
|
||||||
import { useGo, useRedo } from '/@/hooks/web/usePage';
|
|
||||||
import router from '/@/router';
|
import router from '/@/router';
|
||||||
import { useTabs, isInitUseTab } from '/@/hooks/web/useTabs';
|
import { RouteLocationNormalized } from 'vue-router';
|
||||||
import { RouteLocationRaw } from 'vue-router';
|
import { useTabs } from '/@/hooks/web/useTabs';
|
||||||
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||||
|
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||||
|
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||||
|
|
||||||
const { initTabFn } = useTabs();
|
const { t } = useI18n();
|
||||||
|
|
||||||
export function useTabDropdown(tabContentProps: TabContentProps) {
|
export function useTabDropdown(tabContentProps: TabContentProps) {
|
||||||
const { currentRoute } = router;
|
const state = reactive({
|
||||||
const redo = useRedo();
|
current: null as Nullable<RouteLocationNormalized>,
|
||||||
const go = useGo();
|
currentIndex: 0,
|
||||||
|
|
||||||
const isTabsRef = computed(() => tabContentProps.type === TabContentEnum.TAB_TYPE);
|
|
||||||
const getCurrentTab: Ref<TabItem | AppRouteRecordRaw> = computed(() => {
|
|
||||||
return unref(isTabsRef)
|
|
||||||
? tabContentProps.tabItem
|
|
||||||
: ((unref(currentRoute) as any) as AppRouteRecordRaw);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Current tab list
|
const { currentRoute } = router;
|
||||||
const getTabsState = computed(() => tabStore.getTabsState);
|
|
||||||
|
const { getShowMenu, setMenuSetting } = useMenuSetting();
|
||||||
|
const { getShowHeader, setHeaderSetting } = useHeaderSetting();
|
||||||
|
const { getShowQuick } = useMultipleTabSetting();
|
||||||
|
|
||||||
|
const isTabs = computed(() =>
|
||||||
|
!unref(getShowQuick) ? true : tabContentProps.type === TabContentEnum.TAB_TYPE
|
||||||
|
);
|
||||||
|
|
||||||
|
const getCurrentTab = computed(
|
||||||
|
(): RouteLocationNormalized => {
|
||||||
|
return unref(isTabs) ? tabContentProps.tabItem : unref(currentRoute);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const getIsScale = computed(() => {
|
||||||
|
return !unref(getShowMenu) && !unref(getShowHeader);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: drop-down list
|
* @description: drop-down list
|
||||||
*/
|
*/
|
||||||
const getDropMenuList = computed(() => {
|
const getDropMenuList = computed(() => {
|
||||||
const dropMenuList = getActions();
|
|
||||||
// Reset to initial state
|
|
||||||
for (const item of dropMenuList) {
|
|
||||||
item.disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No tab
|
|
||||||
if (!unref(getTabsState) || unref(getTabsState).length <= 0) {
|
|
||||||
return dropMenuList;
|
|
||||||
} else if (unref(getTabsState).length === 1) {
|
|
||||||
// Only one tab
|
|
||||||
for (const item of dropMenuList) {
|
|
||||||
if (item.event !== MenuEventEnum.REFRESH_PAGE) {
|
|
||||||
item.disabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dropMenuList;
|
|
||||||
}
|
|
||||||
if (!unref(getCurrentTab)) return;
|
if (!unref(getCurrentTab)) return;
|
||||||
const { meta, path } = unref(getCurrentTab);
|
const { meta } = unref(getCurrentTab);
|
||||||
|
const { path } = unref(currentRoute);
|
||||||
|
|
||||||
// Refresh button
|
// Refresh button
|
||||||
const curItem = tabStore.getCurrentContextMenuState;
|
const curItem = state.current;
|
||||||
const index = tabStore.getCurrentContextMenuIndexState;
|
const index = state.currentIndex;
|
||||||
const refreshDisabled = curItem ? curItem.path !== path : true;
|
const refreshDisabled = curItem ? curItem.path !== path : true;
|
||||||
// Close left
|
// Close left
|
||||||
const closeLeftDisabled = index === 0;
|
const closeLeftDisabled = index === 0;
|
||||||
|
|
||||||
|
const disabled = tabStore.getTabsState.length === 1;
|
||||||
|
|
||||||
// Close right
|
// Close right
|
||||||
const closeRightDisabled = index === unref(getTabsState).length - 1;
|
const closeRightDisabled =
|
||||||
// Currently fixed tab
|
index === tabStore.getTabsState.length - 1 && tabStore.getLastDragEndIndexState >= 0;
|
||||||
// TODO PERf
|
const dropMenuList: DropMenu[] = [
|
||||||
dropMenuList[0].disabled = unref(isTabsRef) ? refreshDisabled : false;
|
{
|
||||||
if (meta && meta.affix) {
|
icon: 'ant-design:reload-outlined',
|
||||||
dropMenuList[1].disabled = true;
|
event: MenuEventEnum.REFRESH_PAGE,
|
||||||
|
text: t('layout.multipleTab.redo'),
|
||||||
|
disabled: refreshDisabled,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'ant-design:close-outlined',
|
||||||
|
event: MenuEventEnum.CLOSE_CURRENT,
|
||||||
|
text: t('layout.multipleTab.close'),
|
||||||
|
disabled: meta?.affix || disabled,
|
||||||
|
divider: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'ant-design:pic-left-outlined',
|
||||||
|
event: MenuEventEnum.CLOSE_LEFT,
|
||||||
|
text: t('layout.multipleTab.closeLeft'),
|
||||||
|
disabled: closeLeftDisabled,
|
||||||
|
divider: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'ant-design:pic-right-outlined',
|
||||||
|
event: MenuEventEnum.CLOSE_RIGHT,
|
||||||
|
text: t('layout.multipleTab.closeRight'),
|
||||||
|
disabled: closeRightDisabled,
|
||||||
|
divider: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'ant-design:pic-center-outlined',
|
||||||
|
event: MenuEventEnum.CLOSE_OTHER,
|
||||||
|
text: t('layout.multipleTab.closeOther'),
|
||||||
|
disabled: disabled,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'ant-design:line-outlined',
|
||||||
|
event: MenuEventEnum.CLOSE_ALL,
|
||||||
|
text: t('layout.multipleTab.closeAll'),
|
||||||
|
disabled: disabled,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!unref(isTabs)) {
|
||||||
|
const isScale = unref(getIsScale);
|
||||||
|
dropMenuList.unshift({
|
||||||
|
icon: isScale ? 'codicon:screen-normal' : 'codicon:screen-full',
|
||||||
|
event: MenuEventEnum.SCALE,
|
||||||
|
text: isScale ? t('layout.multipleTab.putAway') : t('layout.multipleTab.unfold'),
|
||||||
|
disabled: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
dropMenuList[2].disabled = closeLeftDisabled;
|
|
||||||
dropMenuList[3].disabled = closeRightDisabled;
|
|
||||||
|
|
||||||
return dropMenuList;
|
return dropMenuList;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
const getTrigger = computed(() => {
|
||||||
* @description: Jump to page when closing all pages
|
return unref(isTabs) ? ['contextmenu'] : ['click'];
|
||||||
*/
|
});
|
||||||
function gotoPage() {
|
|
||||||
const len = unref(getTabsState).length;
|
|
||||||
const { path } = unref(currentRoute);
|
|
||||||
|
|
||||||
let toPath: PageEnum | string = PageEnum.BASE_HOME;
|
function handleContextMenu(tabItem: RouteLocationNormalized) {
|
||||||
|
return (e: Event) => {
|
||||||
if (len > 0) {
|
if (!tabItem) return;
|
||||||
const page = unref(getTabsState)[len - 1];
|
e?.preventDefault();
|
||||||
const p = page.fullPath || page.path;
|
const index = tabStore.getTabsState.findIndex((tab) => tab.path === tabItem.path);
|
||||||
if (p) {
|
state.current = tabItem;
|
||||||
toPath = p;
|
state.currentIndex = index;
|
||||||
}
|
};
|
||||||
}
|
|
||||||
// Jump to the current page and report an error
|
|
||||||
path !== toPath && go(toPath as PageEnum, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isGotoPage(currentTab?: TabItem) {
|
|
||||||
const { path } = unref(currentRoute);
|
|
||||||
const currentPath = (currentTab || unref(getCurrentTab)).path;
|
|
||||||
// Not the current tab, when you close the left/right side, you need to jump to the page
|
|
||||||
if (path !== currentPath) {
|
|
||||||
go(currentPath as PageEnum, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function refreshPage(tabItem?: TabItem) {
|
|
||||||
try {
|
|
||||||
tabStore.commitCloseTabKeepAlive(tabItem || unref(getCurrentTab));
|
|
||||||
} catch (error) {}
|
|
||||||
redo();
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeAll() {
|
|
||||||
tabStore.commitCloseAllTab();
|
|
||||||
gotoPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeLeft(tabItem?: TabItem) {
|
|
||||||
tabStore.closeLeftTabAction(tabItem || unref(getCurrentTab));
|
|
||||||
isGotoPage(tabItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeRight(tabItem?: TabItem) {
|
|
||||||
tabStore.closeRightTabAction(tabItem || unref(getCurrentTab));
|
|
||||||
isGotoPage(tabItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeOther(tabItem?: TabItem) {
|
|
||||||
tabStore.closeOtherTabAction(tabItem || unref(getCurrentTab));
|
|
||||||
isGotoPage(tabItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeCurrent(tabItem?: TabItem) {
|
|
||||||
closeTab(unref(tabItem || unref(getCurrentTab)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function scaleScreen() {
|
function scaleScreen() {
|
||||||
const {
|
const isScale = !unref(getShowMenu) && !unref(getShowHeader);
|
||||||
headerSetting: { show: showHeader },
|
setMenuSetting({
|
||||||
menuSetting: { show: showMenu },
|
show: isScale,
|
||||||
} = appStore.getProjectConfig;
|
|
||||||
const isScale = !showHeader && !showMenu;
|
|
||||||
appStore.commitProjectConfigState({
|
|
||||||
headerSetting: { show: isScale },
|
|
||||||
menuSetting: { show: isScale },
|
|
||||||
});
|
});
|
||||||
}
|
setHeaderSetting({
|
||||||
|
show: isScale,
|
||||||
if (!isInitUseTab) {
|
|
||||||
initTabFn({
|
|
||||||
refreshPageFn: refreshPage,
|
|
||||||
closeAllFn: closeAll,
|
|
||||||
closeCurrentFn: closeCurrent,
|
|
||||||
closeLeftFn: closeLeft,
|
|
||||||
closeOtherFn: closeOther,
|
|
||||||
closeRightFn: closeRight,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle right click event
|
// Handle right click event
|
||||||
function handleMenuEvent(menu: DropMenu): void {
|
function handleMenuEvent(menu: DropMenu): void {
|
||||||
|
const { refreshPage, closeAll, closeCurrent, closeLeft, closeOther, closeRight } = useTabs();
|
||||||
const { event } = menu;
|
const { event } = menu;
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case MenuEventEnum.SCALE:
|
case MenuEventEnum.SCALE:
|
||||||
scaleScreen();
|
scaleScreen();
|
||||||
|
|
@ -193,51 +173,5 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { getDropMenuList, handleMenuEvent };
|
return { getDropMenuList, handleMenuEvent, handleContextMenu, getTrigger, isTabs };
|
||||||
}
|
|
||||||
|
|
||||||
export function getObj(tabItem: TabItem) {
|
|
||||||
const { params, path, query } = tabItem;
|
|
||||||
return {
|
|
||||||
params: params || {},
|
|
||||||
path,
|
|
||||||
query: query || {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function closeTab(closedTab: TabItem | AppRouteRecordRaw) {
|
|
||||||
const { currentRoute, replace } = router;
|
|
||||||
// Current tab list
|
|
||||||
const getTabsState = computed(() => tabStore.getTabsState);
|
|
||||||
|
|
||||||
const { path } = unref(currentRoute);
|
|
||||||
if (path !== closedTab.path) {
|
|
||||||
// Closed is not the activation tab
|
|
||||||
tabStore.commitCloseTab(closedTab);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Closed is activated atb
|
|
||||||
let toObj: RouteLocationRaw = {};
|
|
||||||
|
|
||||||
const index = unref(getTabsState).findIndex((item) => item.path === path);
|
|
||||||
|
|
||||||
// If the current is the leftmost tab
|
|
||||||
if (index === 0) {
|
|
||||||
// There is only one tab, then jump to the homepage, otherwise jump to the right tab
|
|
||||||
if (unref(getTabsState).length === 1) {
|
|
||||||
toObj = PageEnum.BASE_HOME;
|
|
||||||
} else {
|
|
||||||
// Jump to the right tab
|
|
||||||
const page = unref(getTabsState)[index + 1];
|
|
||||||
toObj = getObj(page);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Close the current tab
|
|
||||||
const page = unref(getTabsState)[index - 1];
|
|
||||||
toObj = getObj(page);
|
|
||||||
}
|
|
||||||
const route = (unref(currentRoute) as unknown) as AppRouteRecordRaw;
|
|
||||||
tabStore.commitCloseTab(route);
|
|
||||||
replace(toObj);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<template v-for="frame in getFramePages" :key="frame.path">
|
<template v-for="frame in getFramePages" :key="frame.path">
|
||||||
<FramePage
|
<FramePage
|
||||||
v-if="frame.meta.frameSrc && hasRenderFrame(frame.path)"
|
v-if="frame.meta.frameSrc && hasRenderFrame(frame.name)"
|
||||||
v-show="showIframe(frame)"
|
v-show="showIframe(frame)"
|
||||||
:frameSrc="frame.meta.frameSrc"
|
:frameSrc="frame.meta.frameSrc"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ export function useFrameKeepAlive() {
|
||||||
const getOpenTabList = computed((): string[] => {
|
const getOpenTabList = computed((): string[] => {
|
||||||
return tabStore.getTabsState.reduce((prev: string[], next) => {
|
return tabStore.getTabsState.reduce((prev: string[], next) => {
|
||||||
if (next.meta && Reflect.has(next.meta, 'frameSrc')) {
|
if (next.meta && Reflect.has(next.meta, 'frameSrc')) {
|
||||||
prev.push(next.path!);
|
prev.push(next.name as string);
|
||||||
}
|
}
|
||||||
return prev;
|
return prev;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -45,11 +45,14 @@ export function useFrameKeepAlive() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showIframe(item: AppRouteRecordRaw) {
|
function showIframe(item: AppRouteRecordRaw) {
|
||||||
return item.path === unref(currentRoute).path;
|
return item.name === unref(currentRoute).name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasRenderFrame(path: string) {
|
function hasRenderFrame(name: string) {
|
||||||
return unref(getShowMultipleTab) ? unref(getOpenTabList).includes(path) : true;
|
if (!unref(getShowMultipleTab)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return unref(getOpenTabList).includes(name);
|
||||||
}
|
}
|
||||||
return { hasRenderFrame, getFramePages, showIframe, getAllFramePages };
|
return { hasRenderFrame, getFramePages, showIframe, getAllFramePages };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
import type { FunctionalComponent } from 'vue';
|
|
||||||
|
|
||||||
import { computed, defineComponent, unref, Transition, KeepAlive } from 'vue';
|
|
||||||
import { RouterView, RouteLocation } from 'vue-router';
|
|
||||||
|
|
||||||
import FrameLayout from '/@/layouts/iframe/index.vue';
|
|
||||||
|
|
||||||
import { useTransition } from './useTransition';
|
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
|
||||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
|
||||||
|
|
||||||
import { tabStore } from '/@/store/modules/tab';
|
|
||||||
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
|
||||||
|
|
||||||
interface DefaultContext {
|
|
||||||
Component: FunctionalComponent;
|
|
||||||
route: RouteLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'PageLayout',
|
|
||||||
setup() {
|
|
||||||
const { getShowMenu } = useMenuSetting();
|
|
||||||
|
|
||||||
const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
|
|
||||||
|
|
||||||
const { getBasicTransition, getEnableTransition } = useTransitionSetting();
|
|
||||||
|
|
||||||
const { getMax } = useMultipleTabSetting();
|
|
||||||
|
|
||||||
const transitionEvent = useTransition();
|
|
||||||
|
|
||||||
const openCacheRef = computed(() => unref(getOpenKeepAlive) && unref(getShowMenu));
|
|
||||||
|
|
||||||
const getCacheTabsRef = computed(() => tabStore.getKeepAliveTabsState as string[]);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<RouterView>
|
|
||||||
{{
|
|
||||||
default: ({ Component, route }: DefaultContext) => {
|
|
||||||
// No longer show animations that are already in the tab
|
|
||||||
const cacheTabs = unref(getCacheTabsRef);
|
|
||||||
const isInCache = cacheTabs.includes(route.name as string);
|
|
||||||
const name = isInCache && route.meta.inTab ? 'fade-slide' : null;
|
|
||||||
|
|
||||||
const renderComp = () => <Component key={route.fullPath} />;
|
|
||||||
|
|
||||||
const PageContent = unref(openCacheRef) ? (
|
|
||||||
<KeepAlive max={unref(getMax)} include={cacheTabs}>
|
|
||||||
{renderComp()}
|
|
||||||
</KeepAlive>
|
|
||||||
) : (
|
|
||||||
renderComp()
|
|
||||||
);
|
|
||||||
|
|
||||||
return unref(getEnableTransition) ? (
|
|
||||||
<Transition
|
|
||||||
{...transitionEvent}
|
|
||||||
name={name || route.meta.transitionName || unref(getBasicTransition)}
|
|
||||||
mode="out-in"
|
|
||||||
appear={true}
|
|
||||||
>
|
|
||||||
{() => PageContent}
|
|
||||||
</Transition>
|
|
||||||
) : (
|
|
||||||
PageContent
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
</RouterView>
|
|
||||||
{unref(getCanEmbedIFramePage) && <FrameLayout />}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<ParentLayout :isPage="true" />
|
||||||
|
<FrameLayout v-if="getCanEmbedIFramePage" />
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
import FrameLayout from '/@/layouts/iframe/index.vue';
|
||||||
|
|
||||||
|
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||||
|
|
||||||
|
import ParentLayout from '/@/layouts/parent/index.vue';
|
||||||
|
export default defineComponent({
|
||||||
|
components: { ParentLayout, FrameLayout },
|
||||||
|
setup() {
|
||||||
|
const { getCanEmbedIFramePage } = useRootSetting();
|
||||||
|
|
||||||
|
return { getCanEmbedIFramePage };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
<!--
|
||||||
|
* @Description: The reason is that tsx will report warnings under multi-level nesting.
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<router-view>
|
||||||
|
<template #default="{ Component, route }">
|
||||||
|
<transition v-bind="transitionEvent" :name="getName(route)" mode="out-in" appear>
|
||||||
|
<keep-alive v-if="openCache" :include="getCaches">
|
||||||
|
<component :max="getMax" :is="Component" :key="route.fullPath" />
|
||||||
|
</keep-alive>
|
||||||
|
<component v-else :max="getMax" :is="Component" :key="route.fullPath" />
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
</router-view>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, unref } from 'vue';
|
||||||
|
import { RouteLocationNormalized } from 'vue-router';
|
||||||
|
|
||||||
|
import { useTransition } from './useTransition';
|
||||||
|
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||||
|
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||||
|
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||||
|
|
||||||
|
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
||||||
|
import { useCache } from './useCache';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
isPage: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const { getCaches } = useCache(props.isPage);
|
||||||
|
|
||||||
|
const { getShowMenu } = useMenuSetting();
|
||||||
|
|
||||||
|
const { getOpenKeepAlive } = useRootSetting();
|
||||||
|
|
||||||
|
const { getBasicTransition, getEnableTransition } = useTransitionSetting();
|
||||||
|
|
||||||
|
const { getMax } = useMultipleTabSetting();
|
||||||
|
|
||||||
|
const transitionEvent = useTransition();
|
||||||
|
|
||||||
|
const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMenu));
|
||||||
|
|
||||||
|
function getName(route: RouteLocationNormalized) {
|
||||||
|
if (!unref(getEnableTransition)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const cacheTabs = unref(getCaches);
|
||||||
|
const isInCache = cacheTabs.includes(route.name as string);
|
||||||
|
const name = isInCache && route.meta.inTab ? 'fade-slide' : null;
|
||||||
|
|
||||||
|
return name || route.meta.transitionName || unref(getBasicTransition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getCaches,
|
||||||
|
getMax,
|
||||||
|
transitionEvent,
|
||||||
|
getBasicTransition,
|
||||||
|
getName,
|
||||||
|
openCache,
|
||||||
|
getEnableTransition,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { computed, ref, unref } from 'vue';
|
||||||
|
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||||
|
import { tryTsxEmit } from '/@/utils/helper/vueHelper';
|
||||||
|
import { tabStore, PAGE_LAYOUT_KEY } from '/@/store/modules/tab';
|
||||||
|
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
const ParentLayoutName = 'ParentLayout';
|
||||||
|
export function useCache(isPage: boolean) {
|
||||||
|
const name = ref('');
|
||||||
|
const { currentRoute } = useRouter();
|
||||||
|
|
||||||
|
tryTsxEmit((instance: any) => {
|
||||||
|
const routeName = instance.ctx.$options.name;
|
||||||
|
|
||||||
|
if (routeName && ![ParentLayoutName].includes(routeName)) {
|
||||||
|
name.value = routeName;
|
||||||
|
} else {
|
||||||
|
const matched = currentRoute.value.matched;
|
||||||
|
const len = matched.length;
|
||||||
|
if (len < 2) return;
|
||||||
|
name.value = matched[len - 2].name as string;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const { getOpenKeepAlive } = useRootSetting();
|
||||||
|
|
||||||
|
const getCaches = computed((): string[] => {
|
||||||
|
if (!unref(getOpenKeepAlive)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const cached = tabStore.getCachedMapState;
|
||||||
|
|
||||||
|
if (isPage) {
|
||||||
|
// page Layout
|
||||||
|
// not parent layout
|
||||||
|
return cached.get(PAGE_LAYOUT_KEY) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheSet = new Set<string>();
|
||||||
|
cacheSet.add(unref(name));
|
||||||
|
|
||||||
|
const list = cached.get(unref(name));
|
||||||
|
if (!list) {
|
||||||
|
return Array.from(cacheSet);
|
||||||
|
}
|
||||||
|
list.forEach((item) => {
|
||||||
|
cacheSet.add(item);
|
||||||
|
});
|
||||||
|
return Array.from(cacheSet);
|
||||||
|
});
|
||||||
|
return { getCaches };
|
||||||
|
}
|
||||||
|
|
@ -4,8 +4,8 @@ export default {
|
||||||
putAway: 'Put away',
|
putAway: 'Put away',
|
||||||
unfold: 'Unfold',
|
unfold: 'Unfold',
|
||||||
|
|
||||||
input: 'Please Input',
|
input: 'Please Input ',
|
||||||
choose: 'Please Choose',
|
choose: 'Please Choose ',
|
||||||
|
|
||||||
maxTip: 'The number of characters should be less than {0}',
|
maxTip: 'The number of characters should be less than {0}',
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,6 @@ export default {
|
||||||
lockScreen: 'Lock screen',
|
lockScreen: 'Lock screen',
|
||||||
lockScreenBtn: 'Locking',
|
lockScreenBtn: 'Locking',
|
||||||
notLockScreenPassword: 'No password lock screen',
|
notLockScreenPassword: 'No password lock screen',
|
||||||
|
|
||||||
|
home: 'Home',
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default {
|
||||||
|
level: 'Multi menu cache',
|
||||||
|
};
|
||||||
|
|
@ -16,4 +16,6 @@ export default {
|
||||||
lockScreen: '锁定屏幕',
|
lockScreen: '锁定屏幕',
|
||||||
lockScreenBtn: '锁定',
|
lockScreenBtn: '锁定',
|
||||||
notLockScreenPassword: '不设置密码锁屏',
|
notLockScreenPassword: '不设置密码锁屏',
|
||||||
|
|
||||||
|
home: '首页',
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
export default {
|
export default {
|
||||||
feat: '页面功能',
|
feat: '功能',
|
||||||
icon: '图标',
|
icon: '图标',
|
||||||
tabs: '标签页操作',
|
tabs: '标签页操作',
|
||||||
contextMenu: '右键菜单',
|
contextMenu: '右键菜单',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default {
|
||||||
|
level: '多级菜单缓存',
|
||||||
|
};
|
||||||
|
|
@ -1,16 +1,30 @@
|
||||||
import type { AppRouteRecordRaw } from '/@/router/types';
|
import type { AppRouteRecordRaw } from '/@/router/types';
|
||||||
|
import ParentLayout from '/@/layouts/parent/index.vue';
|
||||||
|
|
||||||
const EXCEPTION_COMPONENT = () => import('../views/sys/exception/Exception');
|
const EXCEPTION_COMPONENT = () => import('../views/sys/exception/Exception');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: default layout
|
* @description: default layout
|
||||||
*/
|
*/
|
||||||
export const DEFAULT_LAYOUT_COMPONENT = () => import('/@/layouts/default/index');
|
export const LAYOUT = () => import('/@/layouts/default/index');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: page-layout
|
* @description: page-layout
|
||||||
*/
|
*/
|
||||||
export const PAGE_LAYOUT_COMPONENT = () => import('/@/layouts/page/index');
|
export const PAGE_LAYOUT_COMPONENT = () => import('/@/layouts/page/index.vue');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: page-layout
|
||||||
|
*/
|
||||||
|
export const getParentLayout = (name: string) => {
|
||||||
|
return () =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
resolve({
|
||||||
|
...ParentLayout,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 404 on a page
|
// 404 on a page
|
||||||
export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
|
export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
|
||||||
|
|
@ -23,12 +37,25 @@ export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const REDIRECT_NAME = 'Redirect';
|
||||||
|
|
||||||
export const REDIRECT_ROUTE: AppRouteRecordRaw = {
|
export const REDIRECT_ROUTE: AppRouteRecordRaw = {
|
||||||
path: '/redirect/:path(.*)*',
|
path: '/redirect',
|
||||||
name: 'Redirect',
|
name: REDIRECT_NAME,
|
||||||
component: () => import('/@/views/sys/redirect/index.vue'),
|
component: LAYOUT,
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Redirect',
|
title: REDIRECT_NAME,
|
||||||
hideBreadcrumb: true,
|
hideBreadcrumb: true,
|
||||||
},
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/redirect/:path(.*)',
|
||||||
|
name: REDIRECT_NAME,
|
||||||
|
component: () => import('/@/views/sys/redirect/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: REDIRECT_NAME,
|
||||||
|
hideBreadcrumb: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,19 @@ import { createPageLoadingGuard } from './pageLoadingGuard';
|
||||||
|
|
||||||
import { useGlobSetting, useProjectSetting } from '/@/hooks/setting';
|
import { useGlobSetting, useProjectSetting } from '/@/hooks/setting';
|
||||||
|
|
||||||
import { getIsOpenTab, setCurrentTo } from '/@/utils/helper/routeHelper';
|
import { getIsOpenTab, getRoute } from '/@/router/helper/routeHelper';
|
||||||
import { setTitle } from '/@/utils/browser';
|
import { setTitle } from '/@/utils/browser';
|
||||||
import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel';
|
import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel';
|
||||||
|
|
||||||
import { tabStore } from '/@/store/modules/tab';
|
import { tabStore } from '/@/store/modules/tab';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
import { REDIRECT_NAME } from '/@/router/constant';
|
||||||
|
|
||||||
const { closeMessageOnSwitch, removeAllHttpPending } = useProjectSetting();
|
const { closeMessageOnSwitch, removeAllHttpPending } = useProjectSetting();
|
||||||
const globSetting = useGlobSetting();
|
const globSetting = useGlobSetting();
|
||||||
|
|
||||||
export function createGuard(router: Router) {
|
export function createGuard(router: Router) {
|
||||||
let axiosCanceler: AxiosCanceler | null;
|
let axiosCanceler: Nullable<AxiosCanceler>;
|
||||||
if (removeAllHttpPending) {
|
if (removeAllHttpPending) {
|
||||||
axiosCanceler = new AxiosCanceler();
|
axiosCanceler = new AxiosCanceler();
|
||||||
}
|
}
|
||||||
|
|
@ -30,15 +32,7 @@ export function createGuard(router: Router) {
|
||||||
to.meta.inTab = isOpen;
|
to.meta.inTab = isOpen;
|
||||||
|
|
||||||
// Notify routing changes
|
// Notify routing changes
|
||||||
const { fullPath, path, query, params, name, meta } = to;
|
tabStore.commitLastChangeRouteState(getRoute(to));
|
||||||
tabStore.commitLastChangeRouteState({
|
|
||||||
fullPath,
|
|
||||||
path,
|
|
||||||
query,
|
|
||||||
params,
|
|
||||||
name,
|
|
||||||
meta,
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (closeMessageOnSwitch) {
|
if (closeMessageOnSwitch) {
|
||||||
|
|
@ -50,14 +44,13 @@ export function createGuard(router: Router) {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('basic guard error:' + error);
|
console.warn('basic guard error:' + error);
|
||||||
}
|
}
|
||||||
setCurrentTo(to);
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
router.afterEach((to) => {
|
router.afterEach((to) => {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
// change html title
|
// change html title
|
||||||
to.name !== 'Redirect' && setTitle(t(to.meta.title), globSetting.title);
|
to.name !== REDIRECT_NAME && setTitle(t(to.meta.title), globSetting.title);
|
||||||
});
|
});
|
||||||
createProgressGuard(router);
|
createProgressGuard(router);
|
||||||
createPermissionGuard(router);
|
createPermissionGuard(router);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import type { Router } from 'vue-router';
|
||||||
import { tabStore } from '/@/store/modules/tab';
|
import { tabStore } from '/@/store/modules/tab';
|
||||||
import { appStore } from '/@/store/modules/app';
|
import { appStore } from '/@/store/modules/app';
|
||||||
import { userStore } from '/@/store/modules/user';
|
import { userStore } from '/@/store/modules/user';
|
||||||
import { getParams } from '/@/utils/helper/routeHelper';
|
import { getParams } from '/@/router/helper/routeHelper';
|
||||||
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
||||||
import { unref } from 'vue';
|
import { unref } from 'vue';
|
||||||
|
|
||||||
|
|
@ -14,6 +14,7 @@ export function createPageLoadingGuard(router: Router) {
|
||||||
if (!userStore.getTokenState) {
|
if (!userStore.getTokenState) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!unref(getEnableTransition) && unref(getOpenPageLoading)) {
|
if (!unref(getEnableTransition) && unref(getOpenPageLoading)) {
|
||||||
appStore.commitPageLoadingState(true);
|
appStore.commitPageLoadingState(true);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { PageEnum } from '/@/enums/pageEnum';
|
||||||
import { getToken } from '/@/utils/auth';
|
import { getToken } from '/@/utils/auth';
|
||||||
|
|
||||||
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/constant';
|
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/constant';
|
||||||
import { RootRoute } from '../routes/index';
|
// import { RootRoute } from '../routes/index';
|
||||||
|
|
||||||
const LOGIN_PATH = PageEnum.BASE_LOGIN;
|
const LOGIN_PATH = PageEnum.BASE_LOGIN;
|
||||||
|
|
||||||
|
|
@ -59,7 +59,8 @@ export function createPermissionGuard(router: Router) {
|
||||||
}
|
}
|
||||||
const routes = await permissionStore.buildRoutesAction();
|
const routes = await permissionStore.buildRoutesAction();
|
||||||
routes.forEach((route) => {
|
routes.forEach((route) => {
|
||||||
router.addRoute(RootRoute.name!, route as RouteRecordRaw);
|
// router.addRoute(RootRoute.name!, route as RouteRecordRaw);
|
||||||
|
router.addRoute(route as RouteRecordRaw);
|
||||||
});
|
});
|
||||||
|
|
||||||
const redirectPath = (from.query.redirect || to.path) as string;
|
const redirectPath = (from.query.redirect || to.path) as string;
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,6 @@ import { unref } from 'vue';
|
||||||
const { getOpenNProgress } = useTransitionSetting();
|
const { getOpenNProgress } = useTransitionSetting();
|
||||||
|
|
||||||
export function createProgressGuard(router: Router) {
|
export function createProgressGuard(router: Router) {
|
||||||
// NProgress.inc(0.1);
|
|
||||||
// NProgress.configure({ easing: 'ease', speed: 200, showSpinner: false });
|
|
||||||
|
|
||||||
router.beforeEach(async (to) => {
|
router.beforeEach(async (to) => {
|
||||||
!to.meta.inTab && unref(getOpenNProgress) && NProgress.start();
|
!to.meta.inTab && unref(getOpenNProgress) && NProgress.start();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
// The content here is just for type approval. The actual file content is overwritten by transform
|
||||||
|
// For specific coverage, see build/vite/plugin/transform/dynamic-import/index.ts
|
||||||
|
export default function (name: string) {
|
||||||
|
return name as any;
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { AppRouteModule, RouteModule } from '/@/router/types.d';
|
import { AppRouteModule } from '/@/router/types.d';
|
||||||
import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types';
|
import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types';
|
||||||
|
|
||||||
import { findPath, forEach, treeMap, treeToList } from './treeHelper';
|
import { findPath, forEach, treeMap, treeToList } from '/@/utils/helper/treeHelper';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
export function getAllParentPath(treeData: any[], path: string) {
|
export function getAllParentPath(treeData: any[], path: string) {
|
||||||
|
|
@ -48,12 +48,11 @@ export function transformRouteToMenu(routeModList: AppRouteModule[]) {
|
||||||
const cloneRouteModList = cloneDeep(routeModList);
|
const cloneRouteModList = cloneDeep(routeModList);
|
||||||
const routeList: AppRouteRecordRaw[] = [];
|
const routeList: AppRouteRecordRaw[] = [];
|
||||||
cloneRouteModList.forEach((item) => {
|
cloneRouteModList.forEach((item) => {
|
||||||
const { layout, routes, children } = item as RouteModule;
|
if (item.meta?.single) {
|
||||||
if (layout) {
|
const realItem = item?.children?.[0];
|
||||||
layout.children = routes || children;
|
realItem && routeList.push(realItem);
|
||||||
routeList.push(layout);
|
|
||||||
} else {
|
} else {
|
||||||
routes && routeList.push(...routes);
|
routeList.push(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return treeMap(routeList, {
|
return treeMap(routeList, {
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types';
|
||||||
|
import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router';
|
||||||
|
|
||||||
|
import { appStore } from '/@/store/modules/app';
|
||||||
|
import { tabStore } from '/@/store/modules/tab';
|
||||||
|
import { getParentLayout, LAYOUT } from '/@/router/constant';
|
||||||
|
import dynamicImport from './dynamicImport';
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
|
// 动态引入
|
||||||
|
function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
|
||||||
|
if (!routes) return;
|
||||||
|
routes.forEach((item) => {
|
||||||
|
const { component, name } = item;
|
||||||
|
const { children } = item;
|
||||||
|
if (component) {
|
||||||
|
item.component = dynamicImport(component);
|
||||||
|
} else if (name) {
|
||||||
|
item.component = getParentLayout(name);
|
||||||
|
}
|
||||||
|
children && asyncImportRoute(children);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLayoutComp(comp: string) {
|
||||||
|
return comp === 'LAYOUT' ? LAYOUT : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn background objects into routing objects
|
||||||
|
export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModule[]): T[] {
|
||||||
|
routeList.forEach((route) => {
|
||||||
|
if (route.component) {
|
||||||
|
if ((route.component as string).toUpperCase() === 'LAYOUT') {
|
||||||
|
route.component = getLayoutComp(route.component);
|
||||||
|
} else {
|
||||||
|
route.children = [cloneDeep(route)];
|
||||||
|
route.component = LAYOUT;
|
||||||
|
route.name = `${route.name}Parent`;
|
||||||
|
route.path = '';
|
||||||
|
const meta = route.meta || {};
|
||||||
|
meta.single = true;
|
||||||
|
meta.affix = false;
|
||||||
|
route.meta = meta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route.children && asyncImportRoute(route.children);
|
||||||
|
});
|
||||||
|
return (routeList as unknown) as T[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the tab has been opened
|
||||||
|
* @param toPath
|
||||||
|
*/
|
||||||
|
export function getIsOpenTab(toPath: string) {
|
||||||
|
const { openKeepAlive, multiTabsSetting: { show } = {} } = appStore.getProjectConfig;
|
||||||
|
|
||||||
|
if (show && openKeepAlive) {
|
||||||
|
const tabList = tabStore.getTabsState;
|
||||||
|
return tabList.some((tab) => tab.path === toPath);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getParams(data: any = {}) {
|
||||||
|
const { params = {} } = data;
|
||||||
|
let ret = '';
|
||||||
|
Object.keys(params).forEach((key) => {
|
||||||
|
const p = params[key];
|
||||||
|
ret += `/${p}`;
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return to the new routing structure, not affected by the original example
|
||||||
|
export function getRoute(route: RouteLocationNormalized): RouteLocationNormalized {
|
||||||
|
if (!route) return route;
|
||||||
|
const { matched, ...opt } = route;
|
||||||
|
return {
|
||||||
|
...opt,
|
||||||
|
matched: (matched
|
||||||
|
? matched.map((item) => ({
|
||||||
|
meta: item.meta,
|
||||||
|
name: item.name,
|
||||||
|
path: item.path,
|
||||||
|
}))
|
||||||
|
: undefined) as RouteRecordNormalized[],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ import type { Menu, MenuModule } from '/@/router/types';
|
||||||
import type { RouteRecordNormalized } from 'vue-router';
|
import type { RouteRecordNormalized } from 'vue-router';
|
||||||
import { appStore } from '/@/store/modules/app';
|
import { appStore } from '/@/store/modules/app';
|
||||||
import { permissionStore } from '/@/store/modules/permission';
|
import { permissionStore } from '/@/store/modules/permission';
|
||||||
import { transformMenuModule, flatMenus, getAllParentPath } from '/@/utils/helper/menuHelper';
|
import { transformMenuModule, flatMenus, getAllParentPath } from '/@/router/helper/menuHelper';
|
||||||
import { filter } from '/@/utils/helper/treeHelper';
|
import { filter } from '/@/utils/helper/treeHelper';
|
||||||
import router from '/@/router';
|
import router from '/@/router';
|
||||||
import { PermissionModeEnum } from '/@/enums/appEnum';
|
import { PermissionModeEnum } from '/@/enums/appEnum';
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,6 @@
|
||||||
import type { MenuModule } from '/@/router/types.d';
|
import type { MenuModule } from '/@/router/types.d';
|
||||||
|
|
||||||
const menu: MenuModule[] = [
|
const menu: MenuModule = {
|
||||||
{
|
|
||||||
orderNo: 0,
|
|
||||||
menu: {
|
|
||||||
path: '/dashboard/welcome',
|
|
||||||
name: 'routes.dashboard.welcome',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
orderNo: 10,
|
orderNo: 10,
|
||||||
menu: {
|
menu: {
|
||||||
name: 'routes.dashboard.dashboard',
|
name: 'routes.dashboard.dashboard',
|
||||||
|
|
@ -22,12 +14,7 @@ const menu: MenuModule[] = [
|
||||||
path: '/analysis',
|
path: '/analysis',
|
||||||
name: 'routes.dashboard.analysis',
|
name: 'routes.dashboard.analysis',
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// path: '/welcome',
|
|
||||||
// name: 'routes.dashboard.welcome',
|
|
||||||
// },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
];
|
|
||||||
export default menu;
|
export default menu;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
import type { MenuModule } from '/@/router/types.d';
|
||||||
|
|
||||||
|
const menu: MenuModule = {
|
||||||
|
orderNo: 2000,
|
||||||
|
menu: {
|
||||||
|
name: 'routes.demo.level.level',
|
||||||
|
path: '/level',
|
||||||
|
tag: {
|
||||||
|
dot: true,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1',
|
||||||
|
name: 'Menu1',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-1',
|
||||||
|
name: 'Menu1-1',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-1-1',
|
||||||
|
name: 'Menu1-1-1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu1-2',
|
||||||
|
name: 'Menu1-2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu2',
|
||||||
|
name: 'Menu2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export default menu;
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import type { MenuModule } from '/@/router/types.d';
|
||||||
|
|
||||||
|
const menu: MenuModule = {
|
||||||
|
orderNo: 0,
|
||||||
|
menu: {
|
||||||
|
path: '/home/welcome',
|
||||||
|
name: 'routes.dashboard.welcome',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export default menu;
|
||||||
|
|
@ -1,31 +1,28 @@
|
||||||
import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types';
|
import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { DEFAULT_LAYOUT_COMPONENT, PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '../constant';
|
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE, LAYOUT } from '../constant';
|
||||||
import { genRouteModule } from '/@/utils/helper/routeHelper';
|
import { PageEnum } from '/@/enums/pageEnum';
|
||||||
|
|
||||||
import modules from 'globby!/@/router/routes/modules/**/*.@(ts)';
|
import modules from 'globby!/@/router/routes/modules/**/*.@(ts)';
|
||||||
|
|
||||||
const routeModuleList: AppRouteModule[] = [];
|
const routeModuleList: AppRouteModule[] = [];
|
||||||
|
|
||||||
Object.keys(modules).forEach((key) => {
|
Object.keys(modules).forEach((key) => {
|
||||||
routeModuleList.push(modules[key]);
|
const mod = Array.isArray(modules[key]) ? [...modules[key]] : [modules[key]];
|
||||||
|
routeModuleList.push(...mod);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const asyncRoutes = [
|
export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList];
|
||||||
REDIRECT_ROUTE,
|
|
||||||
PAGE_NOT_FOUND_ROUTE,
|
|
||||||
...genRouteModule(routeModuleList),
|
|
||||||
];
|
|
||||||
|
|
||||||
// 主框架根路由
|
const MainRoute: AppRouteModule = {
|
||||||
export const RootRoute: AppRouteRecordRaw = {
|
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'Root',
|
name: 'MainRoute',
|
||||||
component: DEFAULT_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/dashboard',
|
redirect: PageEnum.BASE_HOME,
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Root',
|
icon: 'ant-design:home-outlined',
|
||||||
|
title: 'routes.dashboard.dashboard',
|
||||||
},
|
},
|
||||||
children: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LoginRoute: AppRouteRecordRaw = {
|
export const LoginRoute: AppRouteRecordRaw = {
|
||||||
|
|
@ -38,4 +35,4 @@ export const LoginRoute: AppRouteRecordRaw = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// 基础路由 不用权限
|
// 基础路由 不用权限
|
||||||
export const basicRoutes = [LoginRoute, RootRoute];
|
export const basicRoutes = [LoginRoute, MainRoute, REDIRECT_ROUTE];
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,19 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { LAYOUT } from '/@/router/constant';
|
||||||
|
|
||||||
const dashboard: AppRouteModule = {
|
const dashboard: AppRouteModule = {
|
||||||
layout: {
|
|
||||||
path: '/dashboard',
|
path: '/dashboard',
|
||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/dashboard/welcome',
|
redirect: '/dashboard/welcome',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ant-design:home-outlined',
|
icon: 'ant-design:home-outlined',
|
||||||
title: 'routes.dashboard.dashboard',
|
title: 'routes.dashboard.dashboard',
|
||||||
},
|
},
|
||||||
},
|
children: [
|
||||||
|
|
||||||
routes: [
|
|
||||||
{
|
{
|
||||||
path: '/welcome',
|
path: 'workbench',
|
||||||
name: 'Welcome',
|
|
||||||
component: () => import('/@/views/dashboard/welcome/index.vue'),
|
|
||||||
meta: {
|
|
||||||
title: 'routes.dashboard.welcome',
|
|
||||||
affix: true,
|
|
||||||
icon: 'ant-design:home-outlined',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/workbench',
|
|
||||||
name: 'Workbench',
|
name: 'Workbench',
|
||||||
component: () => import('/@/views/dashboard/workbench/index.vue'),
|
component: () => import('/@/views/dashboard/workbench/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -34,7 +21,7 @@ const dashboard: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/analysis',
|
path: 'analysis',
|
||||||
name: 'Analysis',
|
name: 'Analysis',
|
||||||
component: () => import('/@/views/dashboard/analysis/index.vue'),
|
component: () => import('/@/views/dashboard/analysis/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,21 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { getParentLayout, LAYOUT } from '/@/router/constant';
|
||||||
|
|
||||||
const charts: AppRouteModule = {
|
const charts: AppRouteModule = {
|
||||||
layout: {
|
|
||||||
path: '/charts',
|
path: '/charts',
|
||||||
name: 'Charts',
|
name: 'Charts',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/charts/apexChart',
|
redirect: '/charts/apexChart',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ant-design:area-chart-outlined',
|
icon: 'ant-design:area-chart-outlined',
|
||||||
title: 'routes.demo.charts.charts',
|
title: 'routes.demo.charts.charts',
|
||||||
},
|
},
|
||||||
},
|
children: [
|
||||||
|
|
||||||
routes: [
|
|
||||||
{
|
{
|
||||||
path: '/echarts',
|
path: 'echarts',
|
||||||
name: 'Echarts',
|
name: 'Echarts',
|
||||||
|
component: getParentLayout('Echarts'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Echarts',
|
title: 'Echarts',
|
||||||
},
|
},
|
||||||
|
|
@ -49,7 +47,7 @@ const charts: AppRouteModule = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/apexChart',
|
path: 'apexChart',
|
||||||
name: 'ApexChart',
|
name: 'ApexChart',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.charts.apexChart',
|
title: 'routes.demo.charts.apexChart',
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,20 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { getParentLayout, LAYOUT } from '/@/router/constant';
|
||||||
|
|
||||||
const comp: AppRouteModule = {
|
const comp: AppRouteModule = {
|
||||||
layout: {
|
|
||||||
path: '/comp',
|
path: '/comp',
|
||||||
name: 'Comp',
|
name: 'Comp',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/comp/basic',
|
redirect: '/comp/basic',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ant-design:table-outlined',
|
icon: 'ant-design:table-outlined',
|
||||||
title: 'routes.demo.comp.comp',
|
title: 'routes.demo.comp.comp',
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
routes: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/basic',
|
path: 'basic',
|
||||||
name: 'BasicDemo',
|
name: 'BasicDemo',
|
||||||
component: () => import('/@/views/demo/comp/button/index.vue'),
|
component: () => import('/@/views/demo/comp/button/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -24,7 +22,7 @@ const comp: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/transition',
|
path: 'transition',
|
||||||
name: 'transitionDemo',
|
name: 'transitionDemo',
|
||||||
component: () => import('/@/views/demo/comp/transition/index.vue'),
|
component: () => import('/@/views/demo/comp/transition/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -32,7 +30,7 @@ const comp: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/countTo',
|
path: 'countTo',
|
||||||
name: 'CountTo',
|
name: 'CountTo',
|
||||||
component: () => import('/@/views/demo/comp/count-to/index.vue'),
|
component: () => import('/@/views/demo/comp/count-to/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -41,9 +39,10 @@ const comp: AppRouteModule = {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/scroll',
|
path: 'scroll',
|
||||||
name: 'ScrollDemo',
|
name: 'ScrollDemo',
|
||||||
redirect: '/comp/scroll/basic',
|
redirect: '/comp/scroll/basic',
|
||||||
|
component: getParentLayout('ScrollDemo'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.comp.scroll',
|
title: 'routes.demo.comp.scroll',
|
||||||
},
|
},
|
||||||
|
|
@ -76,7 +75,7 @@ const comp: AppRouteModule = {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/modal',
|
path: 'modal',
|
||||||
name: 'ModalDemo',
|
name: 'ModalDemo',
|
||||||
component: () => import('/@/views/demo/comp/modal/index.vue'),
|
component: () => import('/@/views/demo/comp/modal/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -84,7 +83,7 @@ const comp: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/drawer',
|
path: 'drawer',
|
||||||
name: 'DrawerDemo',
|
name: 'DrawerDemo',
|
||||||
component: () => import('/@/views/demo/comp/drawer/index.vue'),
|
component: () => import('/@/views/demo/comp/drawer/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -92,7 +91,7 @@ const comp: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/desc',
|
path: 'desc',
|
||||||
name: 'DescDemo',
|
name: 'DescDemo',
|
||||||
component: () => import('/@/views/demo/comp/desc/index.vue'),
|
component: () => import('/@/views/demo/comp/desc/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -101,8 +100,9 @@ const comp: AppRouteModule = {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/lazy',
|
path: 'lazy',
|
||||||
name: 'lazyDemo',
|
name: 'LazyDemo',
|
||||||
|
component: getParentLayout('LazyDemo'),
|
||||||
redirect: '/comp/lazy/basic',
|
redirect: '/comp/lazy/basic',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.comp.lazy',
|
title: 'routes.demo.comp.lazy',
|
||||||
|
|
@ -127,8 +127,9 @@ const comp: AppRouteModule = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/verify',
|
path: 'verify',
|
||||||
name: 'VerifyDemo',
|
name: 'VerifyDemo',
|
||||||
|
component: getParentLayout('VerifyDemo'),
|
||||||
redirect: '/comp/verify/drag',
|
redirect: '/comp/verify/drag',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.comp.verify',
|
title: 'routes.demo.comp.verify',
|
||||||
|
|
@ -155,7 +156,7 @@ const comp: AppRouteModule = {
|
||||||
//
|
//
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/qrcode',
|
path: 'qrcode',
|
||||||
name: 'QrCodeDemo',
|
name: 'QrCodeDemo',
|
||||||
component: () => import('/@/views/demo/comp/qrcode/index.vue'),
|
component: () => import('/@/views/demo/comp/qrcode/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -163,7 +164,7 @@ const comp: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/strength-meter',
|
path: 'strength-meter',
|
||||||
name: 'StrengthMeterDemo',
|
name: 'StrengthMeterDemo',
|
||||||
component: () => import('/@/views/demo/comp/strength-meter/index.vue'),
|
component: () => import('/@/views/demo/comp/strength-meter/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -171,7 +172,7 @@ const comp: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/upload',
|
path: 'upload',
|
||||||
name: 'UploadDemo',
|
name: 'UploadDemo',
|
||||||
component: () => import('/@/views/demo/comp/upload/index.vue'),
|
component: () => import('/@/views/demo/comp/upload/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -179,7 +180,7 @@ const comp: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/loading',
|
path: 'loading',
|
||||||
name: 'LoadingDemo',
|
name: 'LoadingDemo',
|
||||||
component: () => import('/@/views/demo/comp/loading/index.vue'),
|
component: () => import('/@/views/demo/comp/loading/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,19 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { getParentLayout, LAYOUT } from '/@/router/constant';
|
||||||
|
|
||||||
const editor: AppRouteModule = {
|
const editor: AppRouteModule = {
|
||||||
layout: {
|
|
||||||
path: '/editor',
|
path: '/editor',
|
||||||
name: 'Editor',
|
name: 'Editor',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/editor/markdown',
|
redirect: '/editor/markdown',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ant-design:table-outlined',
|
icon: 'ant-design:table-outlined',
|
||||||
title: 'routes.demo.editor.editor',
|
title: 'routes.demo.editor.editor',
|
||||||
},
|
},
|
||||||
},
|
children: [
|
||||||
|
|
||||||
routes: [
|
|
||||||
{
|
{
|
||||||
path: '/markdown',
|
path: 'markdown',
|
||||||
name: 'MarkdownDemo',
|
name: 'MarkdownDemo',
|
||||||
component: () => import('/@/views/demo/editor/Markdown.vue'),
|
component: () => import('/@/views/demo/editor/Markdown.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -24,7 +21,8 @@ const editor: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/tinymce',
|
path: 'tinymce',
|
||||||
|
component: getParentLayout('TinymceDemo'),
|
||||||
name: 'TinymceDemo',
|
name: 'TinymceDemo',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.editor.tinymce',
|
title: 'routes.demo.editor.tinymce',
|
||||||
|
|
@ -39,7 +37,6 @@ const editor: AppRouteModule = {
|
||||||
title: 'routes.demo.editor.tinymceBasic',
|
title: 'routes.demo.editor.tinymceBasic',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// TODO
|
|
||||||
{
|
{
|
||||||
path: 'editor',
|
path: 'editor',
|
||||||
name: 'TinymceFormDemo',
|
name: 'TinymceFormDemo',
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,20 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { LAYOUT } from '/@/router/constant';
|
||||||
|
|
||||||
const excel: AppRouteModule = {
|
const excel: AppRouteModule = {
|
||||||
layout: {
|
|
||||||
path: '/excel',
|
path: '/excel',
|
||||||
name: 'Excel',
|
name: 'Excel',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/excel/customExport',
|
redirect: '/excel/customExport',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'mdi:microsoft-excel',
|
icon: 'mdi:microsoft-excel',
|
||||||
title: 'routes.demo.excel.excel',
|
title: 'routes.demo.excel.excel',
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
routes: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/customExport',
|
path: 'customExport',
|
||||||
name: 'CustomExport',
|
name: 'CustomExport',
|
||||||
component: () => import('/@/views/demo/excel/CustomExport.vue'),
|
component: () => import('/@/views/demo/excel/CustomExport.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -24,7 +22,7 @@ const excel: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/jsonExport',
|
path: 'jsonExport',
|
||||||
name: 'JsonExport',
|
name: 'JsonExport',
|
||||||
component: () => import('/@/views/demo/excel/JsonExport.vue'),
|
component: () => import('/@/views/demo/excel/JsonExport.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -32,7 +30,7 @@ const excel: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/arrayExport',
|
path: 'arrayExport',
|
||||||
name: 'ArrayExport',
|
name: 'ArrayExport',
|
||||||
component: () => import('/@/views/demo/excel/ArrayExport.vue'),
|
component: () => import('/@/views/demo/excel/ArrayExport.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -40,7 +38,7 @@ const excel: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/importExcel',
|
path: 'importExcel',
|
||||||
name: 'ImportExcel',
|
name: 'ImportExcel',
|
||||||
component: () => import('/@/views/demo/excel/ImportExcel.vue'),
|
component: () => import('/@/views/demo/excel/ImportExcel.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,19 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { LAYOUT } from '/@/router/constant';
|
||||||
|
|
||||||
const feat: AppRouteModule = {
|
const feat: AppRouteModule = {
|
||||||
layout: {
|
|
||||||
path: '/feat',
|
path: '/feat',
|
||||||
name: 'FeatDemo',
|
name: 'FeatDemo',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/feat/icon',
|
redirect: '/feat/icon',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ic:outline-featured-play-list',
|
icon: 'ic:outline-featured-play-list',
|
||||||
title: 'routes.demo.feat.feat',
|
title: 'routes.demo.feat.feat',
|
||||||
},
|
},
|
||||||
},
|
children: [
|
||||||
|
|
||||||
routes: [
|
|
||||||
{
|
{
|
||||||
path: '/icon',
|
path: 'icon',
|
||||||
name: 'IconDemo',
|
name: 'IconDemo',
|
||||||
component: () => import('/@/views/demo/feat/icon/index.vue'),
|
component: () => import('/@/views/demo/feat/icon/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -24,7 +21,7 @@ const feat: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/tabs',
|
path: 'tabs',
|
||||||
name: 'TabsDemo',
|
name: 'TabsDemo',
|
||||||
component: () => import('/@/views/demo/feat/tabs/index.vue'),
|
component: () => import('/@/views/demo/feat/tabs/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -33,7 +30,7 @@ const feat: AppRouteModule = {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/context-menu',
|
path: 'context-menu',
|
||||||
name: 'ContextMenuDemo',
|
name: 'ContextMenuDemo',
|
||||||
component: () => import('/@/views/demo/feat/context-menu/index.vue'),
|
component: () => import('/@/views/demo/feat/context-menu/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -41,7 +38,7 @@ const feat: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/download',
|
path: 'download',
|
||||||
name: 'DownLoadDemo',
|
name: 'DownLoadDemo',
|
||||||
component: () => import('/@/views/demo/feat/download/index.vue'),
|
component: () => import('/@/views/demo/feat/download/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -49,7 +46,7 @@ const feat: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/click-out-side',
|
path: 'click-out-side',
|
||||||
name: 'ClickOutSideDemo',
|
name: 'ClickOutSideDemo',
|
||||||
component: () => import('/@/views/demo/feat/click-out-side/index.vue'),
|
component: () => import('/@/views/demo/feat/click-out-side/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -57,7 +54,7 @@ const feat: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/img-preview',
|
path: 'img-preview',
|
||||||
name: 'ImgPreview',
|
name: 'ImgPreview',
|
||||||
component: () => import('/@/views/demo/feat/img-preview/index.vue'),
|
component: () => import('/@/views/demo/feat/img-preview/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -65,7 +62,7 @@ const feat: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/copy',
|
path: 'copy',
|
||||||
name: 'CopyDemo',
|
name: 'CopyDemo',
|
||||||
component: () => import('/@/views/demo/feat/copy/index.vue'),
|
component: () => import('/@/views/demo/feat/copy/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -73,7 +70,7 @@ const feat: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/msg',
|
path: 'msg',
|
||||||
name: 'MsgDemo',
|
name: 'MsgDemo',
|
||||||
component: () => import('/@/views/demo/feat/msg/index.vue'),
|
component: () => import('/@/views/demo/feat/msg/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -81,7 +78,7 @@ const feat: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/watermark',
|
path: 'watermark',
|
||||||
name: 'WatermarkDemo',
|
name: 'WatermarkDemo',
|
||||||
component: () => import('/@/views/demo/feat/watermark/index.vue'),
|
component: () => import('/@/views/demo/feat/watermark/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -89,7 +86,7 @@ const feat: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/full-screen',
|
path: 'full-screen',
|
||||||
name: 'FullScreenDemo',
|
name: 'FullScreenDemo',
|
||||||
component: () => import('/@/views/demo/feat/full-screen/index.vue'),
|
component: () => import('/@/views/demo/feat/full-screen/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -97,7 +94,7 @@ const feat: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/error-log',
|
path: 'error-log',
|
||||||
name: 'ErrorLog',
|
name: 'ErrorLog',
|
||||||
component: () => import('/@/views/sys/error-log/index.vue'),
|
component: () => import('/@/views/sys/error-log/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -105,7 +102,7 @@ const feat: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/testTab/:id',
|
path: 'testTab/:id',
|
||||||
name: 'TestTab',
|
name: 'TestTab',
|
||||||
component: () => import('/@/views/demo/feat/tab-params/index.vue'),
|
component: () => import('/@/views/demo/feat/tab-params/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,19 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { LAYOUT } from '/@/router/constant';
|
||||||
|
|
||||||
const form: AppRouteModule = {
|
const form: AppRouteModule = {
|
||||||
layout: {
|
|
||||||
path: '/form',
|
path: '/form',
|
||||||
name: 'FormDemo',
|
name: 'FormDemo',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/form/basic',
|
redirect: '/form/basic',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ant-design:table-outlined',
|
icon: 'ant-design:table-outlined',
|
||||||
title: 'routes.demo.form.form',
|
title: 'routes.demo.form.form',
|
||||||
},
|
},
|
||||||
},
|
children: [
|
||||||
|
|
||||||
routes: [
|
|
||||||
{
|
{
|
||||||
path: '/basic',
|
path: 'basic',
|
||||||
name: 'FormBasicDemo',
|
name: 'FormBasicDemo',
|
||||||
component: () => import('/@/views/demo/form/index.vue'),
|
component: () => import('/@/views/demo/form/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -24,7 +21,7 @@ const form: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/useForm',
|
path: 'useForm',
|
||||||
name: 'UseFormDemo',
|
name: 'UseFormDemo',
|
||||||
component: () => import('/@/views/demo/form/UseForm.vue'),
|
component: () => import('/@/views/demo/form/UseForm.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -32,7 +29,7 @@ const form: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/refForm',
|
path: 'refForm',
|
||||||
name: 'RefFormDemo',
|
name: 'RefFormDemo',
|
||||||
component: () => import('/@/views/demo/form/RefForm.vue'),
|
component: () => import('/@/views/demo/form/RefForm.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -40,7 +37,7 @@ const form: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/advancedForm',
|
path: 'advancedForm',
|
||||||
name: 'AdvancedFormDemo',
|
name: 'AdvancedFormDemo',
|
||||||
component: () => import('/@/views/demo/form/AdvancedForm.vue'),
|
component: () => import('/@/views/demo/form/AdvancedForm.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -48,7 +45,7 @@ const form: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/ruleForm',
|
path: 'ruleForm',
|
||||||
name: 'RuleFormDemo',
|
name: 'RuleFormDemo',
|
||||||
component: () => import('/@/views/demo/form/RuleForm.vue'),
|
component: () => import('/@/views/demo/form/RuleForm.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -56,7 +53,7 @@ const form: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/dynamicForm',
|
path: 'dynamicForm',
|
||||||
name: 'DynamicFormDemo',
|
name: 'DynamicFormDemo',
|
||||||
component: () => import('/@/views/demo/form/DynamicForm.vue'),
|
component: () => import('/@/views/demo/form/DynamicForm.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -64,7 +61,7 @@ const form: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/customerForm',
|
path: 'customerForm',
|
||||||
name: 'CustomerFormDemo',
|
name: 'CustomerFormDemo',
|
||||||
component: () => import('/@/views/demo/form/CustomerForm.vue'),
|
component: () => import('/@/views/demo/form/CustomerForm.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,21 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { LAYOUT } from '/@/router/constant';
|
||||||
const IFrame = () => import('/@/views/sys/iframe/FrameBlank.vue');
|
const IFrame = () => import('/@/views/sys/iframe/FrameBlank.vue');
|
||||||
|
|
||||||
const iframe: AppRouteModule = {
|
const iframe: AppRouteModule = {
|
||||||
layout: {
|
|
||||||
path: '/frame',
|
path: '/frame',
|
||||||
name: 'Frame',
|
name: 'Frame',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/frame/antv',
|
redirect: '/frame/antv',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'mdi:page-next-outline',
|
icon: 'mdi:page-next-outline',
|
||||||
title: 'routes.demo.iframe.frame',
|
title: 'routes.demo.iframe.frame',
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
routes: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/antv',
|
path: 'antv',
|
||||||
name: 'Antv',
|
name: 'Antv',
|
||||||
component: IFrame,
|
component: IFrame,
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -27,7 +25,7 @@ const iframe: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/doc',
|
path: 'doc',
|
||||||
name: 'Doc',
|
name: 'Doc',
|
||||||
component: IFrame,
|
component: IFrame,
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -37,7 +35,7 @@ const iframe: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/docExternal',
|
path: 'docExternal',
|
||||||
name: 'DocExternal',
|
name: 'DocExternal',
|
||||||
component: IFrame,
|
component: IFrame,
|
||||||
meta: {
|
meta: {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
|
import { getParentLayout, LAYOUT } from '/@/router/constant';
|
||||||
|
|
||||||
|
const permission: AppRouteModule = {
|
||||||
|
path: '/level',
|
||||||
|
name: 'Level',
|
||||||
|
component: LAYOUT,
|
||||||
|
redirect: '/level/menu1/menu1-1',
|
||||||
|
meta: {
|
||||||
|
icon: 'carbon:user-role',
|
||||||
|
title: 'routes.demo.level.level',
|
||||||
|
},
|
||||||
|
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1',
|
||||||
|
name: 'Menu1Demo',
|
||||||
|
component: getParentLayout('Menu1Demo'),
|
||||||
|
meta: {
|
||||||
|
title: 'Menu1',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-1',
|
||||||
|
name: 'Menu11Demo',
|
||||||
|
component: getParentLayout('Menu11Demo'),
|
||||||
|
meta: {
|
||||||
|
title: 'Menu1-1',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-1-1',
|
||||||
|
name: 'Menu111Demo',
|
||||||
|
component: () => import('/@/views/demo/level/Menu111.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'Menu111',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu1-2',
|
||||||
|
name: 'Menu12Demo',
|
||||||
|
component: () => import('/@/views/demo/level/Menu12.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'Menu1-2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu2',
|
||||||
|
name: 'Menu2Demo',
|
||||||
|
component: () => import('/@/views/demo/level/Menu2.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'Menu2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default permission;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { getParentLayout, LAYOUT } from '/@/router/constant';
|
||||||
import { ExceptionEnum } from '/@/enums/exceptionEnum';
|
import { ExceptionEnum } from '/@/enums/exceptionEnum';
|
||||||
|
|
||||||
const ExceptionPage = () => import('/@/views/sys/exception/Exception');
|
const ExceptionPage = () => import('/@/views/sys/exception/Exception');
|
||||||
|
|
@ -8,7 +8,7 @@ const ExceptionPage = () => import('/@/views/sys/exception/Exception');
|
||||||
const page: AppRouteModule = {
|
const page: AppRouteModule = {
|
||||||
path: '/page-demo',
|
path: '/page-demo',
|
||||||
name: 'PageDemo',
|
name: 'PageDemo',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/page-demo/exception',
|
redirect: '/page-demo/exception',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'mdi:page-next-outline',
|
icon: 'mdi:page-next-outline',
|
||||||
|
|
@ -17,9 +17,10 @@ const page: AppRouteModule = {
|
||||||
children: [
|
children: [
|
||||||
// =============================form start=============================
|
// =============================form start=============================
|
||||||
{
|
{
|
||||||
path: '/form',
|
path: 'form',
|
||||||
name: 'FormPage',
|
name: 'FormPage',
|
||||||
redirect: '/page-demo/form/basic',
|
redirect: '/page-demo/form/basic',
|
||||||
|
component: getParentLayout('FormPage'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.page.form',
|
title: 'routes.demo.page.form',
|
||||||
},
|
},
|
||||||
|
|
@ -53,8 +54,9 @@ const page: AppRouteModule = {
|
||||||
// =============================form end=============================
|
// =============================form end=============================
|
||||||
// =============================desc start=============================
|
// =============================desc start=============================
|
||||||
{
|
{
|
||||||
path: '/desc',
|
path: 'desc',
|
||||||
name: 'DescPage',
|
name: 'DescPage',
|
||||||
|
component: getParentLayout('DescPage'),
|
||||||
redirect: '/page-demo/desc/basic',
|
redirect: '/page-demo/desc/basic',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.page.desc',
|
title: 'routes.demo.page.desc',
|
||||||
|
|
@ -82,9 +84,11 @@ const page: AppRouteModule = {
|
||||||
|
|
||||||
// =============================result start=============================
|
// =============================result start=============================
|
||||||
{
|
{
|
||||||
path: '/result',
|
path: 'result',
|
||||||
name: 'ResultPage',
|
name: 'ResultPage',
|
||||||
redirect: '/page-demo/result/success',
|
redirect: '/page-demo/result/success',
|
||||||
|
component: getParentLayout('ResultPage'),
|
||||||
|
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.page.result',
|
title: 'routes.demo.page.result',
|
||||||
},
|
},
|
||||||
|
|
@ -111,8 +115,9 @@ const page: AppRouteModule = {
|
||||||
|
|
||||||
// =============================account start=============================
|
// =============================account start=============================
|
||||||
{
|
{
|
||||||
path: '/account',
|
path: 'account',
|
||||||
name: 'AccountPage',
|
name: 'AccountPage',
|
||||||
|
component: getParentLayout('AccountPage'),
|
||||||
redirect: '/page-demo/account/setting',
|
redirect: '/page-demo/account/setting',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.page.account',
|
title: 'routes.demo.page.account',
|
||||||
|
|
@ -139,8 +144,9 @@ const page: AppRouteModule = {
|
||||||
// =============================account end=============================
|
// =============================account end=============================
|
||||||
// =============================exception start=============================
|
// =============================exception start=============================
|
||||||
{
|
{
|
||||||
path: '/exception',
|
path: 'exception',
|
||||||
name: 'ExceptionPage',
|
name: 'ExceptionPage',
|
||||||
|
component: getParentLayout('ExceptionPage'),
|
||||||
redirect: '/page-demo/exception/404',
|
redirect: '/page-demo/exception/404',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.page.exception',
|
title: 'routes.demo.page.exception',
|
||||||
|
|
@ -211,8 +217,9 @@ const page: AppRouteModule = {
|
||||||
// =============================exception end=============================
|
// =============================exception end=============================
|
||||||
// =============================list start=============================
|
// =============================list start=============================
|
||||||
{
|
{
|
||||||
path: '/list',
|
path: 'list',
|
||||||
name: 'ListPage',
|
name: 'ListPage',
|
||||||
|
component: getParentLayout('ListPage'),
|
||||||
redirect: '/page-demo/list/card',
|
redirect: '/page-demo/list/card',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.page.list',
|
title: 'routes.demo.page.list',
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,23 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { getParentLayout, LAYOUT } from '/@/router/constant';
|
||||||
import { RoleEnum } from '/@/enums/roleEnum';
|
import { RoleEnum } from '/@/enums/roleEnum';
|
||||||
|
|
||||||
const permission: AppRouteModule = {
|
const permission: AppRouteModule = {
|
||||||
layout: {
|
|
||||||
path: '/permission',
|
path: '/permission',
|
||||||
name: 'Permission',
|
name: 'Permission',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/permission/front/page',
|
redirect: '/permission/front/page',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'carbon:user-role',
|
icon: 'carbon:user-role',
|
||||||
title: 'routes.demo.permission.permission',
|
title: 'routes.demo.permission.permission',
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
routes: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/front',
|
path: 'front',
|
||||||
name: 'PermissionFrontDemo',
|
name: 'PermissionFrontDemo',
|
||||||
|
component: getParentLayout('PermissionFrontDemo'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.permission.front',
|
title: 'routes.demo.permission.front',
|
||||||
},
|
},
|
||||||
|
|
@ -60,8 +59,9 @@ const permission: AppRouteModule = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/back',
|
path: 'back',
|
||||||
name: 'PermissionBackDemo',
|
name: 'PermissionBackDemo',
|
||||||
|
component: getParentLayout('PermissionBackDemo'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.demo.permission.back',
|
title: 'routes.demo.permission.back',
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,20 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { LAYOUT } from '/@/router/constant';
|
||||||
|
|
||||||
const table: AppRouteModule = {
|
const table: AppRouteModule = {
|
||||||
layout: {
|
|
||||||
path: '/table',
|
path: '/table',
|
||||||
name: 'TableDemo',
|
name: 'TableDemo',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/table/basic',
|
redirect: '/table/basic',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ant-design:table-outlined',
|
icon: 'ant-design:table-outlined',
|
||||||
title: 'routes.demo.table.table',
|
title: 'routes.demo.table.table',
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
routes: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/basic',
|
path: 'basic',
|
||||||
name: 'TableBasicDemo',
|
name: 'TableBasicDemo',
|
||||||
component: () => import('/@/views/demo/table/Basic.vue'),
|
component: () => import('/@/views/demo/table/Basic.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -24,7 +22,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/treeTable',
|
path: 'treeTable',
|
||||||
name: 'TreeTableDemo',
|
name: 'TreeTableDemo',
|
||||||
component: () => import('/@/views/demo/table/TreeTable.vue'),
|
component: () => import('/@/views/demo/table/TreeTable.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -32,7 +30,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/fetchTable',
|
path: 'fetchTable',
|
||||||
name: 'FetchTableDemo',
|
name: 'FetchTableDemo',
|
||||||
component: () => import('/@/views/demo/table/FetchTable.vue'),
|
component: () => import('/@/views/demo/table/FetchTable.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -40,7 +38,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/fixedColumn',
|
path: 'fixedColumn',
|
||||||
name: 'FixedColumnDemo',
|
name: 'FixedColumnDemo',
|
||||||
component: () => import('/@/views/demo/table/FixedColumn.vue'),
|
component: () => import('/@/views/demo/table/FixedColumn.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -48,7 +46,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/customerCell',
|
path: 'customerCell',
|
||||||
name: 'CustomerCellDemo',
|
name: 'CustomerCellDemo',
|
||||||
component: () => import('/@/views/demo/table/CustomerCell.vue'),
|
component: () => import('/@/views/demo/table/CustomerCell.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -56,7 +54,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/formTable',
|
path: 'formTable',
|
||||||
name: 'FormTableDemo',
|
name: 'FormTableDemo',
|
||||||
component: () => import('/@/views/demo/table/FormTable.vue'),
|
component: () => import('/@/views/demo/table/FormTable.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -64,7 +62,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/useTable',
|
path: 'useTable',
|
||||||
name: 'UseTableDemo',
|
name: 'UseTableDemo',
|
||||||
component: () => import('/@/views/demo/table/UseTable.vue'),
|
component: () => import('/@/views/demo/table/UseTable.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -72,7 +70,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/refTable',
|
path: 'refTable',
|
||||||
name: 'RefTableDemo',
|
name: 'RefTableDemo',
|
||||||
component: () => import('/@/views/demo/table/RefTable.vue'),
|
component: () => import('/@/views/demo/table/RefTable.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -80,7 +78,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/multipleHeader',
|
path: 'multipleHeader',
|
||||||
name: 'MultipleHeaderDemo',
|
name: 'MultipleHeaderDemo',
|
||||||
component: () => import('/@/views/demo/table/MultipleHeader.vue'),
|
component: () => import('/@/views/demo/table/MultipleHeader.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -88,7 +86,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/mergeHeader',
|
path: 'mergeHeader',
|
||||||
name: 'MergeHeaderDemo',
|
name: 'MergeHeaderDemo',
|
||||||
component: () => import('/@/views/demo/table/MergeHeader.vue'),
|
component: () => import('/@/views/demo/table/MergeHeader.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -96,7 +94,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/expandTable',
|
path: 'expandTable',
|
||||||
name: 'ExpandTableDemo',
|
name: 'ExpandTableDemo',
|
||||||
component: () => import('/@/views/demo/table/ExpandTable.vue'),
|
component: () => import('/@/views/demo/table/ExpandTable.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -104,7 +102,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/fixedHeight',
|
path: 'fixedHeight',
|
||||||
name: 'FixedHeightDemo',
|
name: 'FixedHeightDemo',
|
||||||
component: () => import('/@/views/demo/table/FixedHeight.vue'),
|
component: () => import('/@/views/demo/table/FixedHeight.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -112,7 +110,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/footerTable',
|
path: 'footerTable',
|
||||||
name: 'FooterTableDemo',
|
name: 'FooterTableDemo',
|
||||||
component: () => import('/@/views/demo/table/FooterTable.vue'),
|
component: () => import('/@/views/demo/table/FooterTable.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -120,7 +118,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/editCellTable',
|
path: 'editCellTable',
|
||||||
name: 'EditCellTableDemo',
|
name: 'EditCellTableDemo',
|
||||||
component: () => import('/@/views/demo/table/EditCellTable.vue'),
|
component: () => import('/@/views/demo/table/EditCellTable.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -128,7 +126,7 @@ const table: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/editRowTable',
|
path: 'editRowTable',
|
||||||
name: 'EditRowTableDemo',
|
name: 'EditRowTableDemo',
|
||||||
component: () => import('/@/views/demo/table/EditRowTable.vue'),
|
component: () => import('/@/views/demo/table/EditRowTable.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,19 @@
|
||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
import { LAYOUT } from '/@/router/constant';
|
||||||
|
|
||||||
const tree: AppRouteModule = {
|
const tree: AppRouteModule = {
|
||||||
layout: {
|
|
||||||
path: '/tree',
|
path: '/tree',
|
||||||
name: 'TreeDemo',
|
name: 'TreeDemo',
|
||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: LAYOUT,
|
||||||
redirect: '/tree/basic',
|
redirect: '/tree/basic',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'clarity:tree-view-line',
|
icon: 'clarity:tree-view-line',
|
||||||
title: 'routes.demo.tree.tree',
|
title: 'routes.demo.tree.tree',
|
||||||
},
|
},
|
||||||
},
|
children: [
|
||||||
routes: [
|
|
||||||
{
|
{
|
||||||
path: '/basic',
|
path: 'basic',
|
||||||
name: 'BasicTreeDemo',
|
name: 'BasicTreeDemo',
|
||||||
component: () => import('/@/views/demo/tree/index.vue'),
|
component: () => import('/@/views/demo/tree/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -23,7 +21,7 @@ const tree: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/editTree',
|
path: 'editTree',
|
||||||
name: 'EditTreeDemo',
|
name: 'EditTreeDemo',
|
||||||
component: () => import('/@/views/demo/tree/EditTree.vue'),
|
component: () => import('/@/views/demo/tree/EditTree.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -31,7 +29,7 @@ const tree: AppRouteModule = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/actionTree',
|
path: 'actionTree',
|
||||||
name: 'ActionTreeDemo',
|
name: 'ActionTreeDemo',
|
||||||
component: () => import('/@/views/demo/tree/ActionTree.vue'),
|
component: () => import('/@/views/demo/tree/ActionTree.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
|
||||||
|
import { LAYOUT } from '/@/router/constant';
|
||||||
|
|
||||||
|
const dashboard: AppRouteModule = {
|
||||||
|
path: '/home',
|
||||||
|
name: 'Home',
|
||||||
|
component: LAYOUT,
|
||||||
|
redirect: '/home/welcome',
|
||||||
|
meta: {
|
||||||
|
icon: 'ant-design:home-outlined',
|
||||||
|
title: 'routes.dashboard.welcome',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'welcome',
|
||||||
|
name: 'Welcome',
|
||||||
|
component: () => import('/@/views/dashboard/welcome/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'routes.dashboard.welcome',
|
||||||
|
affix: true,
|
||||||
|
icon: 'ant-design:home-outlined',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default dashboard;
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import type { RouteRecordRaw } from 'vue-router';
|
import type { RouteRecordRaw } from 'vue-router';
|
||||||
import { RoleEnum } from '/@/enums/roleEnum';
|
import { RoleEnum } from '/@/enums/roleEnum';
|
||||||
|
import Component from '/@/components/types';
|
||||||
export interface RouteMeta {
|
export interface RouteMeta {
|
||||||
// title
|
// title
|
||||||
title: string;
|
title: string;
|
||||||
|
|
@ -24,24 +25,23 @@ export interface RouteMeta {
|
||||||
// Whether the route has been dynamically added
|
// Whether the route has been dynamically added
|
||||||
hideBreadcrumb?: boolean;
|
hideBreadcrumb?: boolean;
|
||||||
|
|
||||||
// disabled redirect
|
|
||||||
disabledRedirect?: boolean;
|
|
||||||
|
|
||||||
// close loading
|
// close loading
|
||||||
afterCloseLoading?: boolean;
|
afterCloseLoading?: boolean;
|
||||||
// Is it in the tab
|
// Is it in the tab
|
||||||
inTab?: boolean;
|
inTab?: boolean;
|
||||||
// Carrying parameters
|
// Carrying parameters
|
||||||
carryParam?: boolean;
|
carryParam?: boolean;
|
||||||
|
|
||||||
|
single?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
|
export interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
|
||||||
name: string;
|
name: string;
|
||||||
meta: RouteMeta;
|
meta: RouteMeta;
|
||||||
component?: any;
|
component?: Component;
|
||||||
components?: any;
|
components?: Component;
|
||||||
children?: AppRouteRecordRaw[];
|
children?: AppRouteRecordRaw[];
|
||||||
props?: any;
|
props?: Record<string, any>;
|
||||||
fullPath?: string;
|
fullPath?: string;
|
||||||
}
|
}
|
||||||
export interface MenuTag {
|
export interface MenuTag {
|
||||||
|
|
@ -75,11 +75,12 @@ export interface MenuModule {
|
||||||
menu: Menu;
|
menu: Menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RouteModule {
|
// interface RouteModule {
|
||||||
layout: AppRouteRecordRaw;
|
// layout: AppRouteRecordRaw;
|
||||||
routes: AppRouteRecordRaw[];
|
// routes: AppRouteRecordRaw[];
|
||||||
children?: AppRouteRecordRaw[];
|
// children?: AppRouteRecordRaw[];
|
||||||
component?: any;
|
// component?: Component;
|
||||||
}
|
// }
|
||||||
|
|
||||||
export type AppRouteModule = RouteModule | AppRouteRecordRaw;
|
// export type AppRouteModule = RouteModule | AppRouteRecordRaw;
|
||||||
|
export type AppRouteModule = AppRouteRecordRaw;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { REDIRECT_ROUTE } from '/@/router/constant';
|
|
||||||
import type { AppRouteRecordRaw, Menu } from '/@/router/types';
|
import type { AppRouteRecordRaw, Menu } from '/@/router/types';
|
||||||
import store from '/@/store/index';
|
import store from '/@/store/index';
|
||||||
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
|
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
|
||||||
|
|
@ -15,15 +14,13 @@ import { filter } from '/@/utils/helper/treeHelper';
|
||||||
import { toRaw } from 'vue';
|
import { toRaw } from 'vue';
|
||||||
import { getMenuListById } from '/@/api/sys/menu';
|
import { getMenuListById } from '/@/api/sys/menu';
|
||||||
|
|
||||||
import { genRouteModule, transformObjToRoute } from '/@/utils/helper/routeHelper';
|
import { transformObjToRoute } from '/@/router/helper/routeHelper';
|
||||||
import { transformRouteToMenu } from '/@/utils/helper/menuHelper';
|
import { transformRouteToMenu } from '/@/router/helper/menuHelper';
|
||||||
|
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
// import { warn } from '/@/utils/log';
|
// import { warn } from '/@/utils/log';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const { createMessage } = useMessage();
|
const { createMessage } = useMessage();
|
||||||
const NAME = 'permission';
|
const NAME = 'permission';
|
||||||
hotModuleUnregisterModule(NAME);
|
hotModuleUnregisterModule(NAME);
|
||||||
|
|
@ -87,6 +84,7 @@ class Permission extends VuexModule {
|
||||||
|
|
||||||
@Action
|
@Action
|
||||||
async buildRoutesAction(id?: number | string): Promise<AppRouteRecordRaw[]> {
|
async buildRoutesAction(id?: number | string): Promise<AppRouteRecordRaw[]> {
|
||||||
|
const { t } = useI18n();
|
||||||
let routes: AppRouteRecordRaw[] = [];
|
let routes: AppRouteRecordRaw[] = [];
|
||||||
const roleList = toRaw(userStore.getRoleListState);
|
const roleList = toRaw(userStore.getRoleListState);
|
||||||
|
|
||||||
|
|
@ -95,17 +93,15 @@ class Permission extends VuexModule {
|
||||||
// role permissions
|
// role permissions
|
||||||
if (permissionMode === PermissionModeEnum.ROLE) {
|
if (permissionMode === PermissionModeEnum.ROLE) {
|
||||||
routes = filter(asyncRoutes, (route) => {
|
routes = filter(asyncRoutes, (route) => {
|
||||||
const { meta } = route;
|
const { meta } = route as AppRouteRecordRaw;
|
||||||
const { roles } = meta!;
|
const { roles } = meta || {};
|
||||||
if (!roles) return true;
|
if (!roles) return true;
|
||||||
return roleList.some((role) => roles.includes(role));
|
return roleList.some((role) => roles.includes(role));
|
||||||
});
|
});
|
||||||
// 如果确定不需要做后台动态权限,请将下面整个判断注释
|
// 如果确定不需要做后台动态权限,请将下面整个判断注释
|
||||||
} else if (permissionMode === PermissionModeEnum.BACK) {
|
} else if (permissionMode === PermissionModeEnum.BACK) {
|
||||||
const messageKey = 'loadMenu';
|
|
||||||
createMessage.loading({
|
createMessage.loading({
|
||||||
content: t('sys.app.menuLoading'),
|
content: t('sys.app.menuLoading'),
|
||||||
key: messageKey,
|
|
||||||
duration: 1,
|
duration: 1,
|
||||||
});
|
});
|
||||||
// 这里获取后台路由菜单逻辑自行修改
|
// 这里获取后台路由菜单逻辑自行修改
|
||||||
|
|
@ -118,10 +114,10 @@ class Permission extends VuexModule {
|
||||||
routeList = transformObjToRoute(routeList);
|
routeList = transformObjToRoute(routeList);
|
||||||
// 后台路由转菜单结构
|
// 后台路由转菜单结构
|
||||||
const backMenuList = transformRouteToMenu(routeList);
|
const backMenuList = transformRouteToMenu(routeList);
|
||||||
|
|
||||||
this.commitBackMenuListState(backMenuList);
|
this.commitBackMenuListState(backMenuList);
|
||||||
// 生成路由
|
|
||||||
routes = genRouteModule(routeList) as AppRouteRecordRaw[];
|
routes = routeList;
|
||||||
routes.push(REDIRECT_ROUTE);
|
|
||||||
}
|
}
|
||||||
return routes;
|
return routes;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,43 @@
|
||||||
import { computed, toRaw } from 'vue';
|
import { toRaw } from 'vue';
|
||||||
import type { AppRouteRecordRaw, RouteMeta } from '/@/router/types.d';
|
|
||||||
|
|
||||||
import { unref } from 'vue';
|
import { unref } from 'vue';
|
||||||
import { Action, Module, Mutation, VuexModule, getModule } from 'vuex-module-decorators';
|
import { Action, Module, Mutation, VuexModule, getModule } from 'vuex-module-decorators';
|
||||||
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
|
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
|
||||||
|
|
||||||
import { PageEnum } from '/@/enums/pageEnum';
|
import { PageEnum } from '/@/enums/pageEnum';
|
||||||
import { appStore } from '/@/store/modules/app';
|
|
||||||
import { userStore } from './user';
|
import { userStore } from './user';
|
||||||
|
|
||||||
import store from '/@/store';
|
import store from '/@/store';
|
||||||
import router from '/@/router';
|
import router from '/@/router';
|
||||||
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant';
|
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant';
|
||||||
import { getCurrentTo } from '/@/utils/helper/routeHelper';
|
import { RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
|
||||||
|
import { getRoute } from '/@/router/helper/routeHelper';
|
||||||
|
import { useGo, useRedo } from '/@/hooks/web/usePage';
|
||||||
|
|
||||||
type CacheName = string | symbol | null | undefined;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: vuex Tab模块
|
|
||||||
*/
|
|
||||||
// declare namespace TabsStore {
|
// declare namespace TabsStore {
|
||||||
export interface TabItem {
|
|
||||||
fullPath: string;
|
|
||||||
path?: string;
|
|
||||||
params?: any;
|
|
||||||
query?: any;
|
|
||||||
name?: CacheName;
|
|
||||||
meta?: RouteMeta;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NAME = 'tab';
|
const NAME = 'tab';
|
||||||
|
|
||||||
hotModuleUnregisterModule(NAME);
|
hotModuleUnregisterModule(NAME);
|
||||||
|
|
||||||
const getOpenKeepAliveRef = computed(() => appStore.getProjectConfig.openKeepAlive);
|
export const PAGE_LAYOUT_KEY = '__PAGE_LAYOUT__';
|
||||||
|
|
||||||
|
function isGotoPage() {
|
||||||
|
const go = useGo();
|
||||||
|
go(unref(router.currentRoute).path, true);
|
||||||
|
}
|
||||||
|
|
||||||
@Module({ namespaced: true, name: NAME, dynamic: true, store })
|
@Module({ namespaced: true, name: NAME, dynamic: true, store })
|
||||||
class Tab extends VuexModule {
|
class Tab extends VuexModule {
|
||||||
|
cachedMapState = new Map<string, string[]>();
|
||||||
|
|
||||||
// tab list
|
// tab list
|
||||||
tabsState: TabItem[] = [];
|
tabsState: RouteLocationNormalized[] = [];
|
||||||
// tab cache list
|
|
||||||
keepAliveTabsState: CacheName[] = [];
|
|
||||||
|
|
||||||
currentContextMenuIndexState = -1;
|
|
||||||
|
|
||||||
currentContextMenuState: TabItem | null = null;
|
|
||||||
|
|
||||||
// Last route change
|
// Last route change
|
||||||
lastChangeRouteState: AppRouteRecordRaw | null = null;
|
lastChangeRouteState: RouteLocationNormalized | null = null;
|
||||||
|
|
||||||
|
lastDragEndIndexState = 0;
|
||||||
|
|
||||||
get getTabsState() {
|
get getTabsState() {
|
||||||
return this.tabsState;
|
return this.tabsState;
|
||||||
|
|
@ -57,56 +47,93 @@ class Tab extends VuexModule {
|
||||||
return this.lastChangeRouteState;
|
return this.lastChangeRouteState;
|
||||||
}
|
}
|
||||||
|
|
||||||
get getCurrentContextMenuIndexState() {
|
get getCurrentTab(): RouteLocationNormalized {
|
||||||
return this.currentContextMenuIndexState;
|
|
||||||
}
|
|
||||||
|
|
||||||
get getCurrentContextMenuState() {
|
|
||||||
return this.currentContextMenuState;
|
|
||||||
}
|
|
||||||
|
|
||||||
get getKeepAliveTabsState() {
|
|
||||||
return this.keepAliveTabsState;
|
|
||||||
}
|
|
||||||
|
|
||||||
get getCurrentTab(): TabItem {
|
|
||||||
const route = unref(router.currentRoute);
|
const route = unref(router.currentRoute);
|
||||||
return this.tabsState.find((item) => item.path === route.path)!;
|
return this.tabsState.find((item) => item.path === route.path)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get getCachedMapState(): Map<string, string[]> {
|
||||||
|
return this.cachedMapState;
|
||||||
|
}
|
||||||
|
|
||||||
|
get getLastDragEndIndexState(): number {
|
||||||
|
return this.lastDragEndIndexState;
|
||||||
|
}
|
||||||
|
|
||||||
@Mutation
|
@Mutation
|
||||||
commitLastChangeRouteState(route: AppRouteRecordRaw): void {
|
commitLastChangeRouteState(route: RouteLocationNormalized): void {
|
||||||
if (!userStore.getTokenState) return;
|
if (!userStore.getTokenState) return;
|
||||||
this.lastChangeRouteState = route;
|
this.lastChangeRouteState = route;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation
|
@Mutation
|
||||||
commitClearCache(): void {
|
commitClearCache(): void {
|
||||||
this.keepAliveTabsState = [];
|
this.cachedMapState = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation
|
@Mutation
|
||||||
commitCurrentContextMenuIndexState(index: number): void {
|
goToPage() {
|
||||||
this.currentContextMenuIndexState = index;
|
const go = useGo();
|
||||||
|
const len = this.tabsState.length;
|
||||||
|
const { path } = unref(router.currentRoute);
|
||||||
|
|
||||||
|
let toPath: PageEnum | string = PageEnum.BASE_HOME;
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
const page = this.tabsState[len - 1];
|
||||||
|
const p = page.fullPath || page.path;
|
||||||
|
if (p) {
|
||||||
|
toPath = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Jump to the current page and report an error
|
||||||
|
path !== toPath && go(toPath as PageEnum, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation
|
@Mutation
|
||||||
commitCurrentContextMenuState(item: TabItem): void {
|
commitCachedMapState(): void {
|
||||||
this.currentContextMenuState = item;
|
const cacheMap = new Map<string, string[]>();
|
||||||
|
|
||||||
|
const pageCacheSet = new Set<string>();
|
||||||
|
this.tabsState.forEach((tab) => {
|
||||||
|
const item = getRoute(tab);
|
||||||
|
const needAuth = !item.meta.ignoreAuth;
|
||||||
|
if (item.meta.affix) {
|
||||||
|
const name = item.name as string;
|
||||||
|
pageCacheSet.add(name);
|
||||||
|
} else if (item.matched && needAuth) {
|
||||||
|
const matched = item.matched;
|
||||||
|
const len = matched.length;
|
||||||
|
|
||||||
|
if (len < 2) return;
|
||||||
|
|
||||||
|
for (let i = 0; i < matched.length; i++) {
|
||||||
|
const key = matched[i].name as string;
|
||||||
|
|
||||||
|
if (i < 2) {
|
||||||
|
pageCacheSet.add(key);
|
||||||
|
}
|
||||||
|
if (i < len - 1) {
|
||||||
|
const { meta, name } = matched[i + 1];
|
||||||
|
if (meta && (meta.affix || needAuth)) {
|
||||||
|
const mapList = cacheMap.get(key) || [];
|
||||||
|
if (!mapList.includes(name as string)) {
|
||||||
|
mapList.push(name as string);
|
||||||
|
}
|
||||||
|
cacheMap.set(key, mapList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cacheMap.set(PAGE_LAYOUT_KEY, Array.from(pageCacheSet));
|
||||||
|
this.cachedMapState = cacheMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: add tab
|
|
||||||
*/
|
|
||||||
@Mutation
|
@Mutation
|
||||||
commitAddTab(route: AppRouteRecordRaw | TabItem): void {
|
commitTabRoutesState(route: RouteLocationNormalized) {
|
||||||
const { path, name, meta, fullPath, params, query } = route as TabItem;
|
const { path, fullPath, params, query } = route;
|
||||||
// 404 页面不需要添加tab
|
|
||||||
if (path === PageEnum.ERROR_PAGE || !name) {
|
|
||||||
return;
|
|
||||||
} else if ([REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let updateIndex = -1;
|
let updateIndex = -1;
|
||||||
// 已经存在的页面,不重复添加tab
|
// 已经存在的页面,不重复添加tab
|
||||||
|
|
@ -123,39 +150,18 @@ class Tab extends VuexModule {
|
||||||
this.tabsState.splice(updateIndex, 1, curTab);
|
this.tabsState.splice(updateIndex, 1, curTab);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.tabsState.push({ path, fullPath, name, meta, params, query });
|
this.tabsState.push(route);
|
||||||
if (unref(getOpenKeepAliveRef) && name) {
|
|
||||||
const noKeepAlive = meta && meta.ignoreKeepAlive;
|
|
||||||
const hasName = this.keepAliveTabsState.includes(name);
|
|
||||||
!noKeepAlive && !hasName && this.keepAliveTabsState.push(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: close tab
|
* @description: close tab
|
||||||
*/
|
*/
|
||||||
@Mutation
|
@Mutation
|
||||||
commitCloseTab(route: AppRouteRecordRaw | TabItem): void {
|
commitCloseTab(route: RouteLocationNormalized): void {
|
||||||
try {
|
const { fullPath, meta: { affix } = {} } = route;
|
||||||
const { fullPath, name, meta: { affix } = {} } = route;
|
|
||||||
if (affix) return;
|
if (affix) return;
|
||||||
const index = this.tabsState.findIndex((item) => item.fullPath === fullPath);
|
const index = this.tabsState.findIndex((item) => item.fullPath === fullPath);
|
||||||
index !== -1 && this.tabsState.splice(index, 1);
|
index !== -1 && this.tabsState.splice(index, 1);
|
||||||
|
|
||||||
if (unref(getOpenKeepAliveRef) && name) {
|
|
||||||
const i = this.keepAliveTabsState.findIndex((item) => item === name);
|
|
||||||
i !== -1 && this.keepAliveTabsState.splice(i, 1);
|
|
||||||
}
|
|
||||||
} catch (error) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mutation
|
|
||||||
commitCloseTabKeepAlive(route: AppRouteRecordRaw | TabItem): void {
|
|
||||||
const { name } = route;
|
|
||||||
if (unref(getOpenKeepAliveRef) && name) {
|
|
||||||
const i = this.keepAliveTabsState.findIndex((item) => item === name);
|
|
||||||
i !== -1 && toRaw(this.keepAliveTabsState).splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation
|
@Mutation
|
||||||
|
|
@ -163,16 +169,12 @@ class Tab extends VuexModule {
|
||||||
this.tabsState = this.tabsState.filter((item) => {
|
this.tabsState = this.tabsState.filter((item) => {
|
||||||
return item.meta && item.meta.affix;
|
return item.meta && item.meta.affix;
|
||||||
});
|
});
|
||||||
const names = this.tabsState.map((item) => item.name);
|
|
||||||
this.keepAliveTabsState = names as string[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation
|
@Mutation
|
||||||
commitResetState(): void {
|
commitResetState(): void {
|
||||||
this.tabsState = [];
|
this.tabsState = [];
|
||||||
this.currentContextMenuState = null;
|
this.cachedMapState = new Map();
|
||||||
this.currentContextMenuIndexState = -1;
|
|
||||||
this.keepAliveTabsState = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation
|
@Mutation
|
||||||
|
|
@ -181,73 +183,149 @@ class Tab extends VuexModule {
|
||||||
|
|
||||||
this.tabsState.splice(oldIndex, 1);
|
this.tabsState.splice(oldIndex, 1);
|
||||||
this.tabsState.splice(newIndex, 0, currentTab);
|
this.tabsState.splice(newIndex, 0, currentTab);
|
||||||
|
this.lastDragEndIndexState = this.lastDragEndIndexState + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation
|
@Mutation
|
||||||
closeMultipleTab({ pathList, nameList }: { pathList: string[]; nameList: string[] }): void {
|
closeMultipleTab({ pathList }: { pathList: string[] }): void {
|
||||||
this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.fullPath));
|
this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.fullPath));
|
||||||
if (unref(getOpenKeepAliveRef) && nameList) {
|
|
||||||
this.keepAliveTabsState = toRaw(this.keepAliveTabsState).filter(
|
|
||||||
(item) => !nameList.includes(item as string)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Action
|
@Action
|
||||||
closeLeftTabAction(route: AppRouteRecordRaw | TabItem): void {
|
addTabAction(route: RouteLocationNormalized) {
|
||||||
|
const { path, name } = route;
|
||||||
|
// 404 页面不需要添加tab
|
||||||
|
if (
|
||||||
|
path === PageEnum.ERROR_PAGE ||
|
||||||
|
!name ||
|
||||||
|
[REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.commitTabRoutesState(getRoute(route));
|
||||||
|
|
||||||
|
this.commitCachedMapState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mutation
|
||||||
|
commitRedoPage() {
|
||||||
|
const route = router.currentRoute.value;
|
||||||
|
|
||||||
|
for (const [key, value] of this.cachedMapState) {
|
||||||
|
const index = value.findIndex((item) => item === (route.name as string));
|
||||||
|
if (index === -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (value.length === 1) {
|
||||||
|
this.cachedMapState.delete(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
value.splice(index, 1);
|
||||||
|
this.cachedMapState.set(key, value);
|
||||||
|
}
|
||||||
|
const redo = useRedo();
|
||||||
|
redo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Action
|
||||||
|
closeAllTabAction() {
|
||||||
|
this.commitCloseAllTab();
|
||||||
|
this.commitClearCache();
|
||||||
|
this.goToPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Action
|
||||||
|
closeTabAction(tab: RouteLocationNormalized) {
|
||||||
|
function getObj(tabItem: RouteLocationNormalized) {
|
||||||
|
const { params, path, query } = tabItem;
|
||||||
|
return {
|
||||||
|
params: params || {},
|
||||||
|
path,
|
||||||
|
query: query || {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const { currentRoute, replace } = router;
|
||||||
|
|
||||||
|
const { path } = unref(currentRoute);
|
||||||
|
if (path !== tab.path) {
|
||||||
|
// Closed is not the activation tab
|
||||||
|
this.commitCloseTab(tab);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closed is activated atb
|
||||||
|
let toObj: RouteLocationRaw = {};
|
||||||
|
|
||||||
|
const index = this.getTabsState.findIndex((item) => item.path === path);
|
||||||
|
|
||||||
|
// If the current is the leftmost tab
|
||||||
|
if (index === 0) {
|
||||||
|
// There is only one tab, then jump to the homepage, otherwise jump to the right tab
|
||||||
|
if (this.getTabsState.length === 1) {
|
||||||
|
toObj = PageEnum.BASE_HOME;
|
||||||
|
} else {
|
||||||
|
// Jump to the right tab
|
||||||
|
const page = this.getTabsState[index + 1];
|
||||||
|
toObj = getObj(page);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Close the current tab
|
||||||
|
const page = this.getTabsState[index - 1];
|
||||||
|
toObj = getObj(page);
|
||||||
|
}
|
||||||
|
this.commitCloseTab(currentRoute.value);
|
||||||
|
replace(toObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Action
|
||||||
|
closeTabByKeyAction(key: string) {
|
||||||
|
const index = this.tabsState.findIndex((item) => (item.fullPath || item.path) === key);
|
||||||
|
index !== -1 && this.closeTabAction(this.tabsState[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Action
|
||||||
|
closeLeftTabAction(route: RouteLocationNormalized): void {
|
||||||
const index = this.tabsState.findIndex((item) => item.path === route.path);
|
const index = this.tabsState.findIndex((item) => item.path === route.path);
|
||||||
|
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
const leftTabs = this.tabsState.slice(0, index);
|
const leftTabs = this.tabsState.slice(0, index);
|
||||||
const pathList: string[] = [];
|
const pathList: string[] = [];
|
||||||
const nameList: string[] = [];
|
|
||||||
for (const item of leftTabs) {
|
for (const item of leftTabs) {
|
||||||
const affix = item.meta ? item.meta.affix : false;
|
const affix = item.meta ? item.meta.affix : false;
|
||||||
if (!affix) {
|
if (!affix) {
|
||||||
pathList.push(item.fullPath);
|
pathList.push(item.fullPath);
|
||||||
nameList.push(item.name as string);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.closeMultipleTab({ pathList, nameList });
|
this.closeMultipleTab({ pathList });
|
||||||
}
|
}
|
||||||
|
this.commitCachedMapState();
|
||||||
|
isGotoPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Action
|
@Action
|
||||||
addTabByPathAction(): void {
|
closeRightTabAction(route: RouteLocationNormalized): void {
|
||||||
const toRoute = getCurrentTo();
|
|
||||||
if (!toRoute) return;
|
|
||||||
const { meta } = toRoute;
|
|
||||||
if (meta && meta.affix) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.commitAddTab((toRoute as unknown) as AppRouteRecordRaw);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Action
|
|
||||||
closeRightTabAction(route: AppRouteRecordRaw | TabItem): void {
|
|
||||||
const index = this.tabsState.findIndex((item) => item.fullPath === route.fullPath);
|
const index = this.tabsState.findIndex((item) => item.fullPath === route.fullPath);
|
||||||
|
|
||||||
if (index >= 0 && index < this.tabsState.length - 1) {
|
if (index >= 0 && index < this.tabsState.length - 1) {
|
||||||
const rightTabs = this.tabsState.slice(index + 1, this.tabsState.length);
|
const rightTabs = this.tabsState.slice(index + 1, this.tabsState.length);
|
||||||
|
|
||||||
const pathList: string[] = [];
|
const pathList: string[] = [];
|
||||||
const nameList: string[] = [];
|
|
||||||
for (const item of rightTabs) {
|
for (const item of rightTabs) {
|
||||||
const affix = item.meta ? item.meta.affix : false;
|
const affix = item.meta ? item.meta.affix : false;
|
||||||
if (!affix) {
|
if (!affix) {
|
||||||
pathList.push(item.fullPath);
|
pathList.push(item.fullPath);
|
||||||
nameList.push(item.name as string);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.closeMultipleTab({ pathList, nameList });
|
this.closeMultipleTab({ pathList });
|
||||||
}
|
}
|
||||||
|
this.commitCachedMapState();
|
||||||
|
isGotoPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Action
|
@Action
|
||||||
closeOtherTabAction(route: AppRouteRecordRaw | TabItem): void {
|
closeOtherTabAction(route: RouteLocationNormalized): void {
|
||||||
const closePathList = this.tabsState.map((item) => item.fullPath);
|
const closePathList = this.tabsState.map((item) => item.fullPath);
|
||||||
const pathList: string[] = [];
|
const pathList: string[] = [];
|
||||||
const nameList: string[] = [];
|
|
||||||
closePathList.forEach((path) => {
|
closePathList.forEach((path) => {
|
||||||
if (path !== route.fullPath) {
|
if (path !== route.fullPath) {
|
||||||
const closeItem = this.tabsState.find((item) => item.path === path);
|
const closeItem = this.tabsState.find((item) => item.path === path);
|
||||||
|
|
@ -255,11 +333,12 @@ class Tab extends VuexModule {
|
||||||
const affix = closeItem.meta ? closeItem.meta.affix : false;
|
const affix = closeItem.meta ? closeItem.meta.affix : false;
|
||||||
if (!affix) {
|
if (!affix) {
|
||||||
pathList.push(closeItem.fullPath);
|
pathList.push(closeItem.fullPath);
|
||||||
nameList.push(closeItem.name as string);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.closeMultipleTab({ pathList, nameList });
|
this.closeMultipleTab({ pathList });
|
||||||
|
this.commitCachedMapState();
|
||||||
|
isGotoPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const tabStore = getModule<Tab>(Tab);
|
export const tabStore = getModule<Tab>(Tab);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
// The content here is just for type approval. The actual file content is overwritten by transform
|
|
||||||
export default function (id: string) {
|
|
||||||
const dynamicImportModule: any = id;
|
|
||||||
return dynamicImportModule;
|
|
||||||
}
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
import type { AppRouteModule, AppRouteRecordRaw, RouteModule } from '/@/router/types';
|
|
||||||
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router';
|
|
||||||
import { createRouter, createWebHashHistory } from 'vue-router';
|
|
||||||
|
|
||||||
import { appStore } from '/@/store/modules/app';
|
|
||||||
import { tabStore } from '/@/store/modules/tab';
|
|
||||||
import { toRaw } from 'vue';
|
|
||||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
|
||||||
// import { isDevMode } from '/@/utils/env';
|
|
||||||
import dynamicImport from './dynamicImport';
|
|
||||||
import { omit } from 'lodash-es';
|
|
||||||
|
|
||||||
let currentTo: RouteLocationNormalized | null = null;
|
|
||||||
|
|
||||||
export function getCurrentTo() {
|
|
||||||
return currentTo;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setCurrentTo(to: RouteLocationNormalized) {
|
|
||||||
currentTo = to;
|
|
||||||
}
|
|
||||||
// 转化路由模块
|
|
||||||
// 将多级转成2层。keepAlive问题
|
|
||||||
export function genRouteModule(moduleList: AppRouteModule[] | AppRouteRecordRaw[]) {
|
|
||||||
const ret: AppRouteRecordRaw[] = [];
|
|
||||||
for (const routeMod of moduleList) {
|
|
||||||
let routes: RouteRecordRaw[] = [];
|
|
||||||
let layout: AppRouteRecordRaw | undefined;
|
|
||||||
if (Reflect.has(routeMod, 'routes')) {
|
|
||||||
routes = (routeMod as RouteModule).routes as any;
|
|
||||||
layout = (routeMod as RouteModule).layout;
|
|
||||||
} else if (Reflect.has(routeMod, 'path')) {
|
|
||||||
layout = omit(routeMod, 'children') as any;
|
|
||||||
routes = (routeMod.children as RouteRecordRaw[]) || ([] as RouteRecordRaw[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = createRouter({ routes, history: createWebHashHistory() });
|
|
||||||
|
|
||||||
const flatList = (toRaw(router.getRoutes()).filter(
|
|
||||||
(item) => item.children.length === 0
|
|
||||||
) as unknown) as AppRouteRecordRaw[];
|
|
||||||
flatList.forEach((item) => {
|
|
||||||
item.path = `${layout ? layout.path : ''}${item.path}`;
|
|
||||||
});
|
|
||||||
if (layout) {
|
|
||||||
layout.children = flatList;
|
|
||||||
ret.push(layout);
|
|
||||||
} else {
|
|
||||||
ret.push(...flatList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret as RouteRecordRaw[];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 动态引入
|
|
||||||
function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
|
|
||||||
if (!routes) return;
|
|
||||||
routes.forEach((item) => {
|
|
||||||
const { component } = item;
|
|
||||||
const { children } = item;
|
|
||||||
if (component) {
|
|
||||||
item.component = dynamicImport(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
children && asyncImportRoute(children);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLayoutComp(comp: string) {
|
|
||||||
return comp === 'PAGE_LAYOUT' ? PAGE_LAYOUT_COMPONENT : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将后台对象转成路由对象
|
|
||||||
export function transformObjToRoute<T = any>(routeList: AppRouteModule[]): T[] {
|
|
||||||
routeList.forEach((route) => {
|
|
||||||
asyncImportRoute(
|
|
||||||
Reflect.has(route, 'routes') ? (route as RouteModule).routes : route.children || []
|
|
||||||
);
|
|
||||||
if ((route as RouteModule).layout) {
|
|
||||||
(route as RouteModule).layout.component = getLayoutComp(
|
|
||||||
(route as RouteModule).layout.component
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
route.component = getLayoutComp(route.component);
|
|
||||||
(route as RouteModule).layout = omit(route, 'children') as any;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return (routeList as unknown) as T[];
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
export function getIsOpenTab(toPath: string) {
|
|
||||||
const { openKeepAlive, multiTabsSetting: { show } = {} } = appStore.getProjectConfig;
|
|
||||||
|
|
||||||
if (show && openKeepAlive) {
|
|
||||||
const tabList = tabStore.getTabsState;
|
|
||||||
return tabList.some((tab) => tab.path === toPath);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getParams(data: any = {}) {
|
|
||||||
const { params = {} } = data;
|
|
||||||
let ret = '';
|
|
||||||
Object.keys(params).forEach((key) => {
|
|
||||||
const p = params[key];
|
|
||||||
ret += `/${p}`;
|
|
||||||
});
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: 'Copy',
|
||||||
components: { CollapseContainer },
|
components: { CollapseContainer },
|
||||||
setup() {
|
setup() {
|
||||||
const valueRef = ref('');
|
const valueRef = ref('');
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<div class="p-5">
|
||||||
|
多层级缓存-页面1-1-1
|
||||||
|
<br />
|
||||||
|
<input />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
export default defineComponent({ name: 'Menu111Demo' });
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<div class="p-5">
|
||||||
|
多层级缓存-页面1-2
|
||||||
|
<br />
|
||||||
|
<input />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
export default defineComponent({ name: 'Menu12Demo' });
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<template>
|
||||||
|
<div class="p-5">
|
||||||
|
多层级缓存-页面2
|
||||||
|
<br />
|
||||||
|
<input />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Menu2Demo',
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
<template>
|
||||||
|
<div />
|
||||||
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, unref } from 'vue';
|
import { defineComponent, unref } from 'vue';
|
||||||
|
|
||||||
|
|
@ -18,12 +21,13 @@
|
||||||
path: '/' + _path,
|
path: '/' + _path,
|
||||||
query,
|
query,
|
||||||
});
|
});
|
||||||
|
// close loading
|
||||||
if (unref(getEnableTransition) && unref(getOpenPageLoading)) {
|
if (unref(getEnableTransition) && unref(getOpenPageLoading)) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
appStore.setPageLoadingAction(false);
|
appStore.setPageLoadingAction(false);
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
return () => null;
|
return {};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
138
yarn.lock
138
yarn.lock
|
|
@ -1061,10 +1061,10 @@
|
||||||
resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.2.tgz#c4a95ddc06ca9b9496df03604e66fdefb39f4c4b"
|
resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.2.tgz#c4a95ddc06ca9b9496df03604e66fdefb39f4c4b"
|
||||||
integrity sha512-BybEHU5/I9EQ0CcwKAqmreZ2bMnAXrqLCTptAc6vPetHMbrXdZfejP5mt57e/8PNSt/qE7BHniU5PCYA+PGIHw==
|
integrity sha512-BybEHU5/I9EQ0CcwKAqmreZ2bMnAXrqLCTptAc6vPetHMbrXdZfejP5mt57e/8PNSt/qE7BHniU5PCYA+PGIHw==
|
||||||
|
|
||||||
"@iconify/json@^1.1.266":
|
"@iconify/json@^1.1.267":
|
||||||
version "1.1.266"
|
version "1.1.267"
|
||||||
resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.266.tgz#3537de808399652b3ca2c89a561216324121b785"
|
resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.267.tgz#52ab5390fcaf95e0d68260523a3a3fbc575dfe01"
|
||||||
integrity sha512-I8S9lChQATaRroMGccdOQkFbBtMt4C2V/PQGiSjDq9yzdyqDCrPNN9X1qM4FoQt84zfW/+JMHIgShi42E+SXeA==
|
integrity sha512-VKNvyALvbuwsXO7r2XvdoqdctmvJzp1/XYOXRfhJ4w+sjtWYp8T3oRGDJ0AZTafzGiBBUaMwCZVP+j87rqgD3w==
|
||||||
|
|
||||||
"@koa/cors@^3.1.0":
|
"@koa/cors@^3.1.0":
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
|
|
@ -1535,10 +1535,10 @@
|
||||||
resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
|
resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
|
||||||
integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==
|
integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==
|
||||||
|
|
||||||
"@types/yargs@^15.0.10":
|
"@types/yargs@^15.0.11":
|
||||||
version "15.0.10"
|
version "15.0.11"
|
||||||
resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.10.tgz#0fe3c8173a0d5c3e780b389050140c3f5ea6ea74"
|
resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.11.tgz#361d7579ecdac1527687bcebf9946621c12ab78c"
|
||||||
integrity sha512-z8PNtlhrj7eJNLmrAivM7rjBESG6JwC5xP3RVk12i/8HVP7Xnx/sEmERnRImyEuUaJfO942X0qMOYsoupaJbZQ==
|
integrity sha512-jfcNBxHFYJ4nPIacsi3woz1+kvUO6s1CyeEhtnDHBjHUMNj5UlW2GynmnSgiJJEdNg9yW5C8lfoNRZrHGv5EqA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/yargs-parser" "*"
|
"@types/yargs-parser" "*"
|
||||||
|
|
||||||
|
|
@ -1644,6 +1644,17 @@
|
||||||
estree-walker "^2.0.1"
|
estree-walker "^2.0.1"
|
||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
|
|
||||||
|
"@vue/compiler-core@3.0.4":
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.0.4.tgz#0122aca6eada4cb28b39ed930af917444755e330"
|
||||||
|
integrity sha512-snpMICsbWTZqBFnPB03qr4DtiSxVYfDF3DvbDSkN9Z9NTM8Chl8E/lYhKBSsvauq91DAWAh8PU3lr9vrLyQsug==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.12.0"
|
||||||
|
"@babel/types" "^7.12.0"
|
||||||
|
"@vue/shared" "3.0.4"
|
||||||
|
estree-walker "^2.0.1"
|
||||||
|
source-map "^0.6.1"
|
||||||
|
|
||||||
"@vue/compiler-dom@3.0.2":
|
"@vue/compiler-dom@3.0.2":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.0.2.tgz#1d40de04bcdf9aabb79fb6a802dd70a2f3c2992a"
|
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.0.2.tgz#1d40de04bcdf9aabb79fb6a802dd70a2f3c2992a"
|
||||||
|
|
@ -1660,6 +1671,14 @@
|
||||||
"@vue/compiler-core" "3.0.3"
|
"@vue/compiler-core" "3.0.3"
|
||||||
"@vue/shared" "3.0.3"
|
"@vue/shared" "3.0.3"
|
||||||
|
|
||||||
|
"@vue/compiler-dom@3.0.4":
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.0.4.tgz#834fd4b15c5698cf9f4505c2bfbccca058a843eb"
|
||||||
|
integrity sha512-FOxbHBIkkGjYQeTz1DlXQjS1Ms8EPXQWsdTdTPeohoS0KzCz6RiOjiAG+jLtMi6Nr5GX2h0TlCvcnI8mcsicFQ==
|
||||||
|
dependencies:
|
||||||
|
"@vue/compiler-core" "3.0.4"
|
||||||
|
"@vue/shared" "3.0.4"
|
||||||
|
|
||||||
"@vue/compiler-sfc@*", "@vue/compiler-sfc@^3.0.0-rc.5":
|
"@vue/compiler-sfc@*", "@vue/compiler-sfc@^3.0.0-rc.5":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.0.2.tgz#22c70fed72c347a4d5fa2db2e80594b3193dce57"
|
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.0.2.tgz#22c70fed72c347a4d5fa2db2e80594b3193dce57"
|
||||||
|
|
@ -1704,6 +1723,28 @@
|
||||||
postcss-selector-parser "^6.0.4"
|
postcss-selector-parser "^6.0.4"
|
||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
|
|
||||||
|
"@vue/compiler-sfc@^3.0.4":
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.0.4.tgz#2119fe1e68d2c268aafa20461c82c139a9adf8e0"
|
||||||
|
integrity sha512-brDn6HTuK6R3oBCjtMPPsIpyJEZFinlnxjtBXww/goFJOJBAU9CrsdegwyZItNnixCFUIg4CLv4Nj1Eg/eKlfg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.12.0"
|
||||||
|
"@babel/types" "^7.12.0"
|
||||||
|
"@vue/compiler-core" "3.0.4"
|
||||||
|
"@vue/compiler-dom" "3.0.4"
|
||||||
|
"@vue/compiler-ssr" "3.0.4"
|
||||||
|
"@vue/shared" "3.0.4"
|
||||||
|
consolidate "^0.16.0"
|
||||||
|
estree-walker "^2.0.1"
|
||||||
|
hash-sum "^2.0.0"
|
||||||
|
lru-cache "^5.1.1"
|
||||||
|
magic-string "^0.25.7"
|
||||||
|
merge-source-map "^1.1.0"
|
||||||
|
postcss "^7.0.32"
|
||||||
|
postcss-modules "^3.2.2"
|
||||||
|
postcss-selector-parser "^6.0.4"
|
||||||
|
source-map "^0.6.1"
|
||||||
|
|
||||||
"@vue/compiler-ssr@3.0.2":
|
"@vue/compiler-ssr@3.0.2":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.0.2.tgz#73af4d274a79bfcc72a996a9b45f1072e7deaa26"
|
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.0.2.tgz#73af4d274a79bfcc72a996a9b45f1072e7deaa26"
|
||||||
|
|
@ -1720,6 +1761,14 @@
|
||||||
"@vue/compiler-dom" "3.0.3"
|
"@vue/compiler-dom" "3.0.3"
|
||||||
"@vue/shared" "3.0.3"
|
"@vue/shared" "3.0.3"
|
||||||
|
|
||||||
|
"@vue/compiler-ssr@3.0.4":
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.0.4.tgz#ccbd1f55734d51d1402fad825ac102002a7a07c7"
|
||||||
|
integrity sha512-4aYWQEL4+LS4+D44K9Z7xMOWMEjBsz4Li9nMcj2rxRQ35ewK6uFPodvs6ORP60iBDSkwUFZoldFlNemQlu1BFw==
|
||||||
|
dependencies:
|
||||||
|
"@vue/compiler-dom" "3.0.4"
|
||||||
|
"@vue/shared" "3.0.4"
|
||||||
|
|
||||||
"@vue/reactivity@3.0.2":
|
"@vue/reactivity@3.0.2":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.0.2.tgz#42ed5af6025b494a5e69b05169fcddf04eebfe77"
|
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.0.2.tgz#42ed5af6025b494a5e69b05169fcddf04eebfe77"
|
||||||
|
|
@ -1734,6 +1783,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vue/shared" "3.0.3"
|
"@vue/shared" "3.0.3"
|
||||||
|
|
||||||
|
"@vue/reactivity@3.0.4":
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.0.4.tgz#b6599dd8271a745960a03f05744ccf7991ba5d8d"
|
||||||
|
integrity sha512-AFTABrLhUYZY2on3ea9FxeXal7w3f6qIp9gT+/oG93H7dFTL5LvVnxygCopv7tvkIl/GSGQb/yK1D1gmXx1Pww==
|
||||||
|
dependencies:
|
||||||
|
"@vue/shared" "3.0.4"
|
||||||
|
|
||||||
"@vue/runtime-core@3.0.2":
|
"@vue/runtime-core@3.0.2":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.0.2.tgz#d7ed462af1cb0bf9836668e4e6fab3f2f4b1bc00"
|
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.0.2.tgz#d7ed462af1cb0bf9836668e4e6fab3f2f4b1bc00"
|
||||||
|
|
@ -1750,6 +1806,14 @@
|
||||||
"@vue/reactivity" "3.0.3"
|
"@vue/reactivity" "3.0.3"
|
||||||
"@vue/shared" "3.0.3"
|
"@vue/shared" "3.0.3"
|
||||||
|
|
||||||
|
"@vue/runtime-core@3.0.4":
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.0.4.tgz#a5b9a001560b1fd8c01a43f68b764c555de7836c"
|
||||||
|
integrity sha512-qH9e4kqU7b3u1JewvLmGmoAGY+mnuBqz7aEKb2mhpEgwa1yFv496BRuUfMXXMCix3+TndUVMJ8jt41FSdNppwg==
|
||||||
|
dependencies:
|
||||||
|
"@vue/reactivity" "3.0.4"
|
||||||
|
"@vue/shared" "3.0.4"
|
||||||
|
|
||||||
"@vue/runtime-dom@3.0.3":
|
"@vue/runtime-dom@3.0.3":
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.3.tgz#5e3e5e5418b9defcac988d2be0cf65596fa2cc03"
|
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.3.tgz#5e3e5e5418b9defcac988d2be0cf65596fa2cc03"
|
||||||
|
|
@ -1759,6 +1823,15 @@
|
||||||
"@vue/shared" "3.0.3"
|
"@vue/shared" "3.0.3"
|
||||||
csstype "^2.6.8"
|
csstype "^2.6.8"
|
||||||
|
|
||||||
|
"@vue/runtime-dom@3.0.4":
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.4.tgz#6f81aec545f24511d2c28a315aa3391420b69c68"
|
||||||
|
integrity sha512-BGIoiTSESzWUhN0Ofi2X/q+HN8f6IUFmUEyyBGKbmx7DTAJNZhFfjqsepfXQrM5IGeTfJLB1ZEVyroDQJNXq3g==
|
||||||
|
dependencies:
|
||||||
|
"@vue/runtime-core" "3.0.4"
|
||||||
|
"@vue/shared" "3.0.4"
|
||||||
|
csstype "^2.6.8"
|
||||||
|
|
||||||
"@vue/runtime-dom@^3.0.0":
|
"@vue/runtime-dom@^3.0.0":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.2.tgz#9d166d03225558025d3d80f5039b646e0051b71c"
|
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.2.tgz#9d166d03225558025d3d80f5039b646e0051b71c"
|
||||||
|
|
@ -1778,6 +1851,11 @@
|
||||||
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.0.3.tgz#ef12ebff93a446df281e8a0fd765b5aea8e7745b"
|
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.0.3.tgz#ef12ebff93a446df281e8a0fd765b5aea8e7745b"
|
||||||
integrity sha512-yGgkF7u4W0Dmwri9XdeY50kOowN4UIX7aBQ///jbxx37itpzVjK7QzvD3ltQtPfWaJDGBfssGL0wpAgwX9OJpQ==
|
integrity sha512-yGgkF7u4W0Dmwri9XdeY50kOowN4UIX7aBQ///jbxx37itpzVjK7QzvD3ltQtPfWaJDGBfssGL0wpAgwX9OJpQ==
|
||||||
|
|
||||||
|
"@vue/shared@3.0.4":
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.0.4.tgz#6dc50f593bdfdeaa6183d1dbc15e2d45e7c6b8b3"
|
||||||
|
integrity sha512-Swfbz31AaMX48CpFl+YmIrqOH9MgJMTrltG9e26A4ZxYx9LjGuMV+41WnxFzS3Bc9nbrc6sDPM37G6nIT8NJSg==
|
||||||
|
|
||||||
"@vuedx/analyze@0.2.4-0":
|
"@vuedx/analyze@0.2.4-0":
|
||||||
version "0.2.4-0"
|
version "0.2.4-0"
|
||||||
resolved "https://registry.npmjs.org/@vuedx/analyze/-/analyze-0.2.4-0.tgz#52766a6dcd2867320409fe517540fd0bf0394d48"
|
resolved "https://registry.npmjs.org/@vuedx/analyze/-/analyze-0.2.4-0.tgz#52766a6dcd2867320409fe517540fd0bf0394d48"
|
||||||
|
|
@ -3013,10 +3091,10 @@ crc-32@~1.2.0:
|
||||||
exit-on-epipe "~1.0.1"
|
exit-on-epipe "~1.0.1"
|
||||||
printj "~1.1.0"
|
printj "~1.1.0"
|
||||||
|
|
||||||
cross-env@^7.0.2:
|
cross-env@^7.0.3:
|
||||||
version "7.0.2"
|
version "7.0.3"
|
||||||
resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz#bd5ed31339a93a3418ac4f3ca9ca3403082ae5f9"
|
resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
|
||||||
integrity sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==
|
integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn "^7.0.1"
|
cross-spawn "^7.0.1"
|
||||||
|
|
||||||
|
|
@ -3449,17 +3527,17 @@ es-module-lexer@^0.3.25:
|
||||||
resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.3.26.tgz#7b507044e97d5b03b01d4392c74ffeb9c177a83b"
|
resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.3.26.tgz#7b507044e97d5b03b01d4392c74ffeb9c177a83b"
|
||||||
integrity sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==
|
integrity sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==
|
||||||
|
|
||||||
esbuild-register@^1.1.0:
|
esbuild-register@^1.1.1:
|
||||||
version "1.1.0"
|
version "1.1.1"
|
||||||
resolved "https://registry.npmjs.org/esbuild-register/-/esbuild-register-1.1.0.tgz#8ec1fbf6b84f0d7654b87eec04029a383dcb539d"
|
resolved "https://registry.npmjs.org/esbuild-register/-/esbuild-register-1.1.1.tgz#7d50e87ac0b9000085d9e6d9a78e4c2223fcce83"
|
||||||
integrity sha512-A+KGHDc7me/ATyNqnVQKsHxt2A/ORVvV2gmukx5ZtVcy5HVf19QBbHdfdP5QHFA8rF/WHmcnDxaxewu+VUvUhQ==
|
integrity sha512-hAPWuaUkPDLXCENc/AigJZaaDCvCkpmghRw8XPyT+rk08JHcIgUrmw1uabbUTfa6B6J9Wo2bFufb01JjbmzcfQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
joycon "^2.2.5"
|
joycon "^2.2.5"
|
||||||
pirates "^4.0.1"
|
pirates "^4.0.1"
|
||||||
source-map-support "^0.5.19"
|
source-map-support "^0.5.19"
|
||||||
strip-json-comments "^3.1.1"
|
strip-json-comments "^3.1.1"
|
||||||
|
|
||||||
esbuild@^0.7.17, esbuild@^0.7.19:
|
esbuild@^0.7.19:
|
||||||
version "0.7.22"
|
version "0.7.22"
|
||||||
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.7.22.tgz#9149b903f8128b7c45a754046c24199d76bbe08e"
|
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.7.22.tgz#9149b903f8128b7c45a754046c24199d76bbe08e"
|
||||||
integrity sha512-B43SYg8LGWYTCv9Gs0RnuLNwjzpuWOoCaZHTWEDEf5AfrnuDMerPVMdCEu7xOdhFvQ+UqfP2MGU9lxEy0JzccA==
|
integrity sha512-B43SYg8LGWYTCv9Gs0RnuLNwjzpuWOoCaZHTWEDEf5AfrnuDMerPVMdCEu7xOdhFvQ+UqfP2MGU9lxEy0JzccA==
|
||||||
|
|
@ -3469,6 +3547,11 @@ esbuild@^0.8.12:
|
||||||
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.8.15.tgz#cbc4d82a7fc4571d455233456e6fba83fd0364f1"
|
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.8.15.tgz#cbc4d82a7fc4571d455233456e6fba83fd0364f1"
|
||||||
integrity sha512-mSaLo9t/oYtQE6FRUEdO47Pr8PisSPzHtgr+LcihIcjBEhbYwjT6WLCQ7noDoTBfIatBCw229rtmIwl9u9UQwg==
|
integrity sha512-mSaLo9t/oYtQE6FRUEdO47Pr8PisSPzHtgr+LcihIcjBEhbYwjT6WLCQ7noDoTBfIatBCw229rtmIwl9u9UQwg==
|
||||||
|
|
||||||
|
esbuild@^0.8.17:
|
||||||
|
version "0.8.17"
|
||||||
|
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.8.17.tgz#1c16c6d5988dcfdcf27a7e1612b7fd05e1477c54"
|
||||||
|
integrity sha512-ReHap+Iyn5BQF0B8F3xrLwu+j57ri5uDUw2ej9XTPAuFDebYiWwRzBY4jhF610bklveXLbCGim/8/2wQKQlu1w==
|
||||||
|
|
||||||
escalade@^3.1.1:
|
escalade@^3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||||
|
|
@ -3581,13 +3664,13 @@ esm@^3.2.25:
|
||||||
resolved "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
|
resolved "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
|
||||||
integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
|
integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
|
||||||
|
|
||||||
esno@^0.2.4:
|
esno@^0.3.0:
|
||||||
version "0.2.4"
|
version "0.3.0"
|
||||||
resolved "https://registry.npmjs.org/esno/-/esno-0.2.4.tgz#b04a368181bc03e5d11d5147106bf0d0ac4f3a48"
|
resolved "https://registry.npmjs.org/esno/-/esno-0.3.0.tgz#c818996bdaaf2deaf81413d6f45538ffa6e41b42"
|
||||||
integrity sha512-XlgsQe2va257kc1xsZg/X22fRyLVRNkCKEXjONoltA7HeXtmhrQ3n19all0eK0X6YRNE8X9qiVyWV0vMLZvY3w==
|
integrity sha512-4sF/j8jruQv9jScU8tNkgoDFLjyGxTTB8bmjRmWHyNNygra3WS3X0U1Cc7GuOvfSEjn3NDS57P0LRnzgiupKJg==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.7.17"
|
esbuild "^0.8.17"
|
||||||
esbuild-register "^1.1.0"
|
esbuild-register "^1.1.1"
|
||||||
esm "^3.2.25"
|
esm "^3.2.25"
|
||||||
|
|
||||||
espree@^6.2.1:
|
espree@^6.2.1:
|
||||||
|
|
@ -8335,6 +8418,15 @@ vue@^3.0.3:
|
||||||
"@vue/runtime-dom" "3.0.3"
|
"@vue/runtime-dom" "3.0.3"
|
||||||
"@vue/shared" "3.0.3"
|
"@vue/shared" "3.0.3"
|
||||||
|
|
||||||
|
vue@^3.0.4:
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/vue/-/vue-3.0.4.tgz#872c65c143f5717bd5387c61613d9f55f4cc0f43"
|
||||||
|
integrity sha512-2o+AiQF8sAupyhbyl3oxVCl3WCwC/n5NI7VMM+gVQ231qvSB8eI7sCBloloqDJK6yA367EEtmRSeSCf4sxCC+A==
|
||||||
|
dependencies:
|
||||||
|
"@vue/compiler-dom" "3.0.4"
|
||||||
|
"@vue/runtime-dom" "3.0.4"
|
||||||
|
"@vue/shared" "3.0.4"
|
||||||
|
|
||||||
vuex-module-decorators@^1.0.1:
|
vuex-module-decorators@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.npmjs.org/vuex-module-decorators/-/vuex-module-decorators-1.0.1.tgz#d34dafb5428a3636f1c26d3d014c15fc9659ccd0"
|
resolved "https://registry.npmjs.org/vuex-module-decorators/-/vuex-module-decorators-1.0.1.tgz#d34dafb5428a3636f1c26d3d014c15fc9659ccd0"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue