vue3-admin-gpt 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.development +1 -1
- package/package.json +3 -3
- package/rspack.config.js +3 -1
- package/rspack.js +18 -13
- package/src/config/permission.js +11 -10
- package/src/config/setting.config.js +1 -1
- package/src/layouts/components/VabAppMain/index.vue +13 -9
- package/src/layouts/components/VabAvatar/index.vue +7 -6
- package/src/layouts/components/VabLogo/index.vue +8 -5
- package/src/layouts/components/VabNav/index.vue +4 -4
- package/src/layouts/components/VabSide/index.vue +5 -4
- package/src/layouts/components/VabTabs/index.vue +26 -26
- package/src/layouts/components/VabTheme/index.vue +23 -12
- package/src/layouts/components/VabTop/index.vue +7 -5
- package/src/layouts/index.vue +18 -18
- package/src/main.js +4 -3
- package/src/router/index.js +10 -1
- package/src/store/index.js +7 -23
- package/src/store/modules/errorLog.js +25 -22
- package/src/store/modules/routes.js +39 -28
- package/src/store/modules/settings.js +69 -64
- package/src/store/modules/table.js +20 -17
- package/src/store/modules/tabsBar.js +123 -86
- package/src/store/modules/user.js +115 -84
- package/src/styles/themes/default.scss +30 -1
- package/src/styles/themes/glory.scss +193 -0
- package/src/styles/themes/green.scss +281 -0
- package/src/utils/permission.js +3 -2
- package/src/utils/request.js +18 -11
- package/src/views/401.vue +4 -1
- package/src/views/404.vue +4 -1
- package/src/views/login/index.vue +3 -3
- package/src/views/pinia-guide/index.vue +791 -0
package/.env.development
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vue3-admin-gpt",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "A Vue3 admin template with Element Plus and Rspack",
|
|
5
5
|
"author": "pxq555",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,13 +47,13 @@
|
|
|
47
47
|
"mitt": "^3.0.1",
|
|
48
48
|
"mockjs": "^1.1.0",
|
|
49
49
|
"nprogress": "^0.2.0",
|
|
50
|
+
"pinia": "^3.0.4",
|
|
50
51
|
"qs": "^6.14.1",
|
|
51
52
|
"screenfull": "^6.0.2",
|
|
52
53
|
"vue": "^3.5.27",
|
|
53
54
|
"vue-echarts": "^8.0.1",
|
|
54
55
|
"vue-router": "^5.0.2",
|
|
55
|
-
"vuedraggable": "^2.24.3"
|
|
56
|
-
"vuex": "^4.1.0"
|
|
56
|
+
"vuedraggable": "^2.24.3"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@babel/core": "^7.29.0",
|
package/rspack.config.js
CHANGED
|
@@ -40,6 +40,8 @@ const resolve = (dir) => path.join(__dirname, dir);
|
|
|
40
40
|
module.exports = {
|
|
41
41
|
mode: mode,
|
|
42
42
|
context: __dirname,
|
|
43
|
+
// 配置 source map 以支持开发调试
|
|
44
|
+
devtool: mode === "production" ? "source-map" : "eval-cheap-module-source-map",
|
|
43
45
|
entry: {
|
|
44
46
|
app: "./src/main.js",
|
|
45
47
|
},
|
|
@@ -171,7 +173,7 @@ module.exports = {
|
|
|
171
173
|
"process.env.NODE_ENV": JSON.stringify(mode),
|
|
172
174
|
"process.env.BASE_URL": JSON.stringify(process.env.BASE_URL),
|
|
173
175
|
"process.env.VUE_APP_TITLE": JSON.stringify(process.env.VUE_APP_TITLE),
|
|
174
|
-
"process.env.VUE_APP_MOCK_ENABLE": JSON.stringify(
|
|
176
|
+
"process.env.VUE_APP_MOCK_ENABLE": JSON.stringify(process.env.VUE_APP_MOCK_ENABLE), // 确保在所有环境中mock都为true
|
|
175
177
|
"process.env.VUE_APP_AUTHOR": JSON.stringify(process.env.VUE_APP_AUTHOR),
|
|
176
178
|
"process.env.VUE_APP_BASE_API": JSON.stringify(process.env.VUE_APP_BASE_API),
|
|
177
179
|
"process.env.VUE_APP_UPDATE_TIME": JSON.stringify(
|
package/rspack.js
CHANGED
|
@@ -100,19 +100,24 @@ if (mode === "production") {
|
|
|
100
100
|
// 使用rspack.config.js中的所有devServer配置
|
|
101
101
|
const devServerOptions = config.devServer || {};
|
|
102
102
|
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
103
|
+
// 根据环境变量控制是否启用mock服务
|
|
104
|
+
if (process.env.VUE_APP_MOCK_ENABLE === "true") {
|
|
105
|
+
if (!devServerOptions.setupMiddlewares) {
|
|
106
|
+
devServerOptions.setupMiddlewares = (middlewares, devServer) => {
|
|
107
|
+
if (!devServer) {
|
|
108
|
+
throw new Error("dev-server is not defined");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const mockServer = require("./mock/index");
|
|
112
|
+
mockServer(devServer.app);
|
|
113
|
+
|
|
114
|
+
return middlewares;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
console.log("Mock服务已启用");
|
|
118
|
+
} else {
|
|
119
|
+
console.log("Mock服务未启用 (VUE_APP_MOCK_ENABLE=" + process.env.VUE_APP_MOCK_ENABLE + ")");
|
|
120
|
+
}
|
|
116
121
|
|
|
117
122
|
const server = new RspackDevServer(devServerOptions, compiler);
|
|
118
123
|
|
package/src/config/permission.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @description 路由守卫,目前两种模式:all模式与intelligence模式
|
|
3
3
|
*/
|
|
4
4
|
import router from "@/router";
|
|
5
|
-
import
|
|
5
|
+
import { useUserStore, useRoutesStore } from "@/store";
|
|
6
6
|
import VabProgress from "nprogress";
|
|
7
7
|
import "nprogress/nprogress.css";
|
|
8
8
|
import getPageTitle from "@/utils/pageTitle";
|
|
@@ -24,7 +24,9 @@ VabProgress.configure({
|
|
|
24
24
|
|
|
25
25
|
router.beforeEach(async (to, from, next) => {
|
|
26
26
|
if (progressBar) VabProgress.start();
|
|
27
|
-
|
|
27
|
+
const userStore = useUserStore();
|
|
28
|
+
const routesStore = useRoutesStore();
|
|
29
|
+
let hasToken = userStore.accessToken;
|
|
28
30
|
|
|
29
31
|
if (!loginInterception) hasToken = true;
|
|
30
32
|
|
|
@@ -34,8 +36,8 @@ router.beforeEach(async (to, from, next) => {
|
|
|
34
36
|
if (progressBar) VabProgress.done();
|
|
35
37
|
} else {
|
|
36
38
|
const hasPermissions =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
userStore.permissions &&
|
|
40
|
+
userStore.permissions.length > 0;
|
|
39
41
|
if (hasPermissions) {
|
|
40
42
|
next();
|
|
41
43
|
} else {
|
|
@@ -43,10 +45,10 @@ router.beforeEach(async (to, from, next) => {
|
|
|
43
45
|
let permissions;
|
|
44
46
|
if (!loginInterception) {
|
|
45
47
|
//settings.js loginInterception为false时,创建虚拟权限
|
|
46
|
-
await
|
|
48
|
+
await userStore.setPermissions(["admin"]);
|
|
47
49
|
permissions = ["admin"];
|
|
48
50
|
} else {
|
|
49
|
-
permissions = await
|
|
51
|
+
permissions = await userStore.getUserInfo();
|
|
50
52
|
if (!permissions) {
|
|
51
53
|
throw new Error("获取用户权限失败");
|
|
52
54
|
}
|
|
@@ -54,12 +56,11 @@ router.beforeEach(async (to, from, next) => {
|
|
|
54
56
|
|
|
55
57
|
let accessRoutes = [];
|
|
56
58
|
if (authentication === "intelligence") {
|
|
57
|
-
accessRoutes = await
|
|
58
|
-
"routes/setRoutes",
|
|
59
|
+
accessRoutes = await routesStore.setRoutes(
|
|
59
60
|
permissions
|
|
60
61
|
);
|
|
61
62
|
} else if (authentication === "all") {
|
|
62
|
-
accessRoutes = await
|
|
63
|
+
accessRoutes = await routesStore.setAllRoutes();
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
// 确保accessRoutes是数组
|
|
@@ -78,7 +79,7 @@ router.beforeEach(async (to, from, next) => {
|
|
|
78
79
|
} catch (error) {
|
|
79
80
|
console.error("路由守卫错误:", error);
|
|
80
81
|
ElMessage.error(error.message || "发生错误,请重新登录");
|
|
81
|
-
await
|
|
82
|
+
await userStore.resetAccessToken();
|
|
82
83
|
next(`/login?redirect=${to.path}`);
|
|
83
84
|
if (progressBar) VabProgress.done();
|
|
84
85
|
}
|
|
@@ -31,7 +31,7 @@ const setting = {
|
|
|
31
31
|
//加载时显示文字
|
|
32
32
|
loadingText: "正在加载中...",
|
|
33
33
|
//token名称
|
|
34
|
-
tokenName: "
|
|
34
|
+
tokenName: "Authorization",
|
|
35
35
|
//token在localStorage、sessionStorage存储的key的名称
|
|
36
36
|
tokenTableName: "admin-scaffold-token",
|
|
37
37
|
//token存储位置localStorage sessionStorage
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="app-main-container">
|
|
3
|
-
<router-view v-slot="{ Component }">
|
|
3
|
+
<router-view v-if="routerView" v-slot="{ Component }">
|
|
4
4
|
<transition mode="out-in" name="fade-transform">
|
|
5
5
|
<keep-alive :include="cachedRoutes" :max="keepAliveMaxNum">
|
|
6
6
|
<component :is="Component" class="app-main-height" />
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
</template>
|
|
14
14
|
|
|
15
15
|
<script>
|
|
16
|
-
import { mapActions, mapGetters } from "vuex";
|
|
17
16
|
import { copyright, footerCopyright, keepAliveMaxNum, title } from "@/config";
|
|
18
17
|
import { CopyDocument } from "@element-plus/icons-vue";
|
|
19
18
|
import eventBus from "@/utils/eventBus";
|
|
19
|
+
import { useTabsBarStore, useSettingsStore } from "@/store";
|
|
20
20
|
|
|
21
21
|
export default {
|
|
22
22
|
name: "VabAppMain",
|
|
@@ -32,13 +32,17 @@ export default {
|
|
|
32
32
|
keepAliveMaxNum,
|
|
33
33
|
routerView: true,
|
|
34
34
|
footerCopyright,
|
|
35
|
+
tabsBarStore: useTabsBarStore(),
|
|
36
|
+
settingsStore: useSettingsStore(),
|
|
35
37
|
};
|
|
36
38
|
},
|
|
37
39
|
computed: {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
visitedRoutes() {
|
|
41
|
+
return this.tabsBarStore.visitedRoutes;
|
|
42
|
+
},
|
|
43
|
+
device() {
|
|
44
|
+
return this.settingsStore.device;
|
|
45
|
+
},
|
|
42
46
|
cachedRoutes() {
|
|
43
47
|
const cachedRoutesArr = [];
|
|
44
48
|
this.visitedRoutes.forEach((item) => {
|
|
@@ -70,9 +74,9 @@ export default {
|
|
|
70
74
|
},
|
|
71
75
|
mounted() {},
|
|
72
76
|
methods: {
|
|
73
|
-
|
|
74
|
-
foldSideBar
|
|
75
|
-
}
|
|
77
|
+
foldSideBar() {
|
|
78
|
+
this.settingsStore.foldSideBar();
|
|
79
|
+
},
|
|
76
80
|
// 重新加载路由视图
|
|
77
81
|
reloadRouterView() {
|
|
78
82
|
this.routerView = false;
|
|
@@ -50,7 +50,6 @@
|
|
|
50
50
|
|
|
51
51
|
<script setup>
|
|
52
52
|
import { computed } from "vue";
|
|
53
|
-
import { useStore } from "vuex";
|
|
54
53
|
import { useRouter, useRoute } from "vue-router";
|
|
55
54
|
import { ElMessage } from "element-plus";
|
|
56
55
|
import { recordRoute } from "@/config";
|
|
@@ -61,19 +60,21 @@ import {
|
|
|
61
60
|
Link,
|
|
62
61
|
SwitchButton,
|
|
63
62
|
} from "@element-plus/icons-vue";
|
|
63
|
+
import { useUserStore, useSettingsStore } from "@/store";
|
|
64
64
|
|
|
65
65
|
defineOptions({
|
|
66
66
|
name: "VabAvatar",
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
const store = useStore();
|
|
70
69
|
const router = useRouter();
|
|
71
70
|
const route = useRoute();
|
|
71
|
+
const userStore = useUserStore();
|
|
72
|
+
const settingsStore = useSettingsStore();
|
|
72
73
|
|
|
73
74
|
// 计算属性
|
|
74
|
-
const avatar = computed(() =>
|
|
75
|
-
const username = computed(() =>
|
|
76
|
-
const layout = computed(() =>
|
|
75
|
+
const avatar = computed(() => userStore.avatar);
|
|
76
|
+
const username = computed(() => userStore.username);
|
|
77
|
+
const layout = computed(() => settingsStore.layout);
|
|
77
78
|
const isHorizontalLayout = computed(() => layout.value === "horizontal");
|
|
78
79
|
|
|
79
80
|
// 方法
|
|
@@ -100,7 +101,7 @@ const settings = () => {
|
|
|
100
101
|
};
|
|
101
102
|
|
|
102
103
|
const logout = () => {
|
|
103
|
-
|
|
104
|
+
userStore.logout();
|
|
104
105
|
if (recordRoute) {
|
|
105
106
|
const fullPath = route.fullPath;
|
|
106
107
|
router.push(`/login?redirect=${fullPath}`);
|
|
@@ -14,20 +14,23 @@
|
|
|
14
14
|
</div>
|
|
15
15
|
</template>
|
|
16
16
|
<script>
|
|
17
|
-
import {
|
|
17
|
+
import { useSettingsStore } from "@/store";
|
|
18
18
|
|
|
19
19
|
export default {
|
|
20
20
|
name: "VabLogo",
|
|
21
21
|
data() {
|
|
22
22
|
return {
|
|
23
23
|
title: this.$baseTitle,
|
|
24
|
+
settingsStore: useSettingsStore(),
|
|
24
25
|
};
|
|
25
26
|
},
|
|
26
27
|
computed: {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
logo() {
|
|
29
|
+
return this.settingsStore.logo;
|
|
30
|
+
},
|
|
31
|
+
layout() {
|
|
32
|
+
return this.settingsStore.layout;
|
|
33
|
+
},
|
|
31
34
|
},
|
|
32
35
|
};
|
|
33
36
|
</script>
|
|
@@ -30,21 +30,21 @@
|
|
|
30
30
|
|
|
31
31
|
<script setup>
|
|
32
32
|
import { ref, computed, onBeforeUnmount } from "vue";
|
|
33
|
-
import { useStore } from "vuex";
|
|
34
33
|
import { Refresh } from "@element-plus/icons-vue";
|
|
34
|
+
import { useSettingsStore } from "@/store";
|
|
35
35
|
|
|
36
36
|
defineOptions({
|
|
37
37
|
name: "VabNav",
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
const
|
|
40
|
+
const settingsStore = useSettingsStore();
|
|
41
41
|
const pulse = ref(false);
|
|
42
42
|
let timeOutID = null;
|
|
43
43
|
|
|
44
|
-
const collapse = computed(() =>
|
|
44
|
+
const collapse = computed(() => settingsStore.collapse);
|
|
45
45
|
|
|
46
46
|
const handleCollapse = () => {
|
|
47
|
-
|
|
47
|
+
settingsStore.changeCollapse();
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
const refreshRoute = async () => {
|
|
@@ -21,19 +21,20 @@
|
|
|
21
21
|
<script setup>
|
|
22
22
|
import variables from "@/styles/variables.scss";
|
|
23
23
|
import { computed } from "vue";
|
|
24
|
-
import { useStore } from "vuex";
|
|
25
24
|
import { useRoute } from "vue-router";
|
|
26
25
|
import { defaultOopeneds } from "@/config";
|
|
26
|
+
import { useSettingsStore, useRoutesStore } from "@/store";
|
|
27
27
|
|
|
28
28
|
defineOptions({
|
|
29
29
|
name: "VabSide",
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
const store = useStore();
|
|
33
32
|
const route = useRoute();
|
|
33
|
+
const settingsStore = useSettingsStore();
|
|
34
|
+
const routesStore = useRoutesStore();
|
|
34
35
|
|
|
35
|
-
const collapse = computed(() =>
|
|
36
|
-
const routes = computed(() =>
|
|
36
|
+
const collapse = computed(() => settingsStore.collapse);
|
|
37
|
+
const routes = computed(() => routesStore.routes);
|
|
37
38
|
|
|
38
39
|
const defaultOpens = computed(() => {
|
|
39
40
|
// 使用配置文件中的defaultOopeneds
|
|
@@ -53,7 +53,6 @@
|
|
|
53
53
|
|
|
54
54
|
<script>
|
|
55
55
|
import path from "path";
|
|
56
|
-
import { mapGetters } from "vuex";
|
|
57
56
|
import {
|
|
58
57
|
ArrowDown,
|
|
59
58
|
CircleClose,
|
|
@@ -71,6 +70,7 @@ import {
|
|
|
71
70
|
List,
|
|
72
71
|
Odometer,
|
|
73
72
|
} from "@element-plus/icons-vue";
|
|
73
|
+
import { useTabsBarStore, useRoutesStore } from "@/store";
|
|
74
74
|
|
|
75
75
|
export default {
|
|
76
76
|
name: "VabTabs",
|
|
@@ -95,20 +95,24 @@ export default {
|
|
|
95
95
|
return {
|
|
96
96
|
affixtabs: [],
|
|
97
97
|
tabActive: "",
|
|
98
|
+
tabsBarStore: useTabsBarStore(),
|
|
99
|
+
routesStore: useRoutesStore(),
|
|
98
100
|
};
|
|
99
101
|
},
|
|
100
102
|
|
|
101
103
|
computed: {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
visitedRoutes() {
|
|
105
|
+
return this.tabsBarStore.visitedRoutes;
|
|
106
|
+
},
|
|
107
|
+
routes() {
|
|
108
|
+
return this.routesStore.routes;
|
|
109
|
+
},
|
|
106
110
|
},
|
|
107
111
|
watch: {
|
|
108
112
|
$route: {
|
|
109
113
|
handler(route) {
|
|
110
|
-
this.
|
|
111
|
-
this.
|
|
114
|
+
this.initTabs();
|
|
115
|
+
this.addTab();
|
|
112
116
|
let tabActive = "";
|
|
113
117
|
this.visitedRoutes.forEach((item, index) => {
|
|
114
118
|
if (item.path === this.$route.path) {
|
|
@@ -131,8 +135,7 @@ export default {
|
|
|
131
135
|
view = item;
|
|
132
136
|
}
|
|
133
137
|
});
|
|
134
|
-
const { visitedRoutes } = await this
|
|
135
|
-
"tabsBar/delRoute",
|
|
138
|
+
const { visitedRoutes } = await this.tabsBarStore.delRoute(
|
|
136
139
|
view
|
|
137
140
|
);
|
|
138
141
|
if (this.isActive(view)) {
|
|
@@ -159,7 +162,7 @@ export default {
|
|
|
159
162
|
isAffix(tag) {
|
|
160
163
|
return tag.meta && tag.meta.affix;
|
|
161
164
|
},
|
|
162
|
-
|
|
165
|
+
filterAffixTabs(routes, basePath = "/") {
|
|
163
166
|
let tabs = [];
|
|
164
167
|
routes.forEach((route) => {
|
|
165
168
|
if (route.meta && route.meta.affix) {
|
|
@@ -172,26 +175,26 @@ export default {
|
|
|
172
175
|
});
|
|
173
176
|
}
|
|
174
177
|
if (route.children) {
|
|
175
|
-
const
|
|
176
|
-
if (
|
|
177
|
-
tabs = [...tabs, ...
|
|
178
|
+
const tempTabs = this.filterAffixTabs(route.children, route.path);
|
|
179
|
+
if (tempTabs.length >= 1) {
|
|
180
|
+
tabs = [...tabs, ...tempTabs];
|
|
178
181
|
}
|
|
179
182
|
}
|
|
180
183
|
});
|
|
181
184
|
return tabs;
|
|
182
185
|
},
|
|
183
|
-
|
|
184
|
-
const affixtabs = (this.affixtabs = this.
|
|
186
|
+
initTabs() {
|
|
187
|
+
const affixtabs = (this.affixtabs = this.filterAffixTabs(this.routes));
|
|
185
188
|
for (const tag of affixtabs) {
|
|
186
189
|
if (tag.name) {
|
|
187
|
-
this
|
|
190
|
+
this.tabsBarStore.addVisitedRoute(tag);
|
|
188
191
|
}
|
|
189
192
|
}
|
|
190
193
|
},
|
|
191
|
-
|
|
194
|
+
addTab() {
|
|
192
195
|
const { name } = this.$route;
|
|
193
196
|
if (name) {
|
|
194
|
-
this
|
|
197
|
+
this.tabsBarStore.addVisitedRoute(this.$route);
|
|
195
198
|
}
|
|
196
199
|
return false;
|
|
197
200
|
},
|
|
@@ -221,8 +224,7 @@ export default {
|
|
|
221
224
|
// this.$baseEventBus.$emit('reloadrouter-view')
|
|
222
225
|
},
|
|
223
226
|
async closeSelectedTag(view) {
|
|
224
|
-
const { visitedRoutes } = await this
|
|
225
|
-
"tabsBar/delRoute",
|
|
227
|
+
const { visitedRoutes } = await this.tabsBarStore.delRoute(
|
|
226
228
|
view
|
|
227
229
|
);
|
|
228
230
|
if (this.isActive(view)) {
|
|
@@ -231,21 +233,19 @@ export default {
|
|
|
231
233
|
},
|
|
232
234
|
async closeOtherstabs() {
|
|
233
235
|
const view = await this.toThisTag();
|
|
234
|
-
await this
|
|
236
|
+
await this.tabsBarStore.delOthersRoutes(view);
|
|
235
237
|
},
|
|
236
238
|
async closeLefttabs() {
|
|
237
239
|
const view = await this.toThisTag();
|
|
238
|
-
await this
|
|
240
|
+
await this.tabsBarStore.delLeftRoutes(view);
|
|
239
241
|
},
|
|
240
242
|
async closeRighttabs() {
|
|
241
243
|
const view = await this.toThisTag();
|
|
242
|
-
await this
|
|
244
|
+
await this.tabsBarStore.delRightRoutes(view);
|
|
243
245
|
},
|
|
244
246
|
async closeAlltabs() {
|
|
245
247
|
const view = await this.toThisTag();
|
|
246
|
-
const { visitedRoutes } = await this
|
|
247
|
-
"tabsBar/delAllRoutes"
|
|
248
|
-
);
|
|
248
|
+
const { visitedRoutes } = await this.tabsBarStore.delAllRoutes();
|
|
249
249
|
if (this.affixtabs.some((tag) => tag.path === view.path)) {
|
|
250
250
|
return;
|
|
251
251
|
}
|
|
@@ -153,9 +153,9 @@
|
|
|
153
153
|
</template>
|
|
154
154
|
|
|
155
155
|
<script>
|
|
156
|
-
import { mapActions, mapGetters } from "vuex";
|
|
157
156
|
import { layout as defaultLayout } from "@/config";
|
|
158
157
|
import { Brush, Picture, Grid, Setting } from "@element-plus/icons-vue";
|
|
158
|
+
import { useSettingsStore } from "@/store";
|
|
159
159
|
|
|
160
160
|
export default {
|
|
161
161
|
name: "VabTheme",
|
|
@@ -174,15 +174,22 @@ export default {
|
|
|
174
174
|
header: "fixed",
|
|
175
175
|
tabsBar: "",
|
|
176
176
|
},
|
|
177
|
+
settingsStore: useSettingsStore(),
|
|
177
178
|
};
|
|
178
179
|
},
|
|
179
180
|
computed: {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
181
|
+
layout() {
|
|
182
|
+
return this.settingsStore.layout;
|
|
183
|
+
},
|
|
184
|
+
header() {
|
|
185
|
+
return this.settingsStore.header;
|
|
186
|
+
},
|
|
187
|
+
tabsBar() {
|
|
188
|
+
return this.settingsStore.tabsBar;
|
|
189
|
+
},
|
|
190
|
+
themeBar() {
|
|
191
|
+
return this.settingsStore.themeBar;
|
|
192
|
+
},
|
|
186
193
|
},
|
|
187
194
|
created() {
|
|
188
195
|
// 在created钩子中初始化主题
|
|
@@ -198,11 +205,15 @@ export default {
|
|
|
198
205
|
}
|
|
199
206
|
},
|
|
200
207
|
methods: {
|
|
201
|
-
|
|
202
|
-
changeLayout
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
208
|
+
changeLayout(layout) {
|
|
209
|
+
this.settingsStore.changeLayout(layout);
|
|
210
|
+
},
|
|
211
|
+
changeHeader(header) {
|
|
212
|
+
this.settingsStore.changeHeader(header);
|
|
213
|
+
},
|
|
214
|
+
changeTabsBar(tabsBar) {
|
|
215
|
+
this.settingsStore.changeTabsBar(tabsBar);
|
|
216
|
+
},
|
|
206
217
|
handleIsMobile() {
|
|
207
218
|
return document.body.getBoundingClientRect().width - 1 < 992;
|
|
208
219
|
},
|
|
@@ -50,17 +50,19 @@
|
|
|
50
50
|
|
|
51
51
|
<script setup>
|
|
52
52
|
import { ref, computed, onBeforeUnmount } from "vue";
|
|
53
|
-
import { useStore } from "vuex";
|
|
54
53
|
import { useRoute } from "vue-router";
|
|
55
54
|
import variables from "@/styles/variables.scss";
|
|
56
55
|
import { Refresh } from "@element-plus/icons-vue";
|
|
56
|
+
import { useRoutesStore, useTabsBarStore, useSettingsStore } from "@/store";
|
|
57
57
|
|
|
58
58
|
defineOptions({
|
|
59
59
|
name: "VabTop",
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
const store = useStore();
|
|
63
62
|
const route = useRoute();
|
|
63
|
+
const routesStore = useRoutesStore();
|
|
64
|
+
const tabsBarStore = useTabsBarStore();
|
|
65
|
+
const settingsStore = useSettingsStore();
|
|
64
66
|
|
|
65
67
|
// 响应式数据
|
|
66
68
|
const pulse = ref(false);
|
|
@@ -68,9 +70,9 @@ const menuTrigger = ref("hover");
|
|
|
68
70
|
let timeOutID = null;
|
|
69
71
|
|
|
70
72
|
// 计算属性
|
|
71
|
-
const routes = computed(() =>
|
|
72
|
-
const visitedRoutes = computed(() =>
|
|
73
|
-
const collapse = computed(() =>
|
|
73
|
+
const routes = computed(() => routesStore.routes);
|
|
74
|
+
const visitedRoutes = computed(() => tabsBarStore.visitedRoutes);
|
|
75
|
+
const collapse = computed(() => settingsStore.collapse);
|
|
74
76
|
const defaultOpens = computed(() => []);
|
|
75
77
|
|
|
76
78
|
const activeMenu = computed(() => {
|
package/src/layouts/index.vue
CHANGED
|
@@ -51,21 +51,21 @@
|
|
|
51
51
|
|
|
52
52
|
<script setup>
|
|
53
53
|
import { ref, computed, onBeforeMount, onBeforeUnmount, onMounted, nextTick } from "vue";
|
|
54
|
-
import {
|
|
54
|
+
import { useSettingsStore } from "@/store";
|
|
55
55
|
import { tokenName } from "@/config";
|
|
56
56
|
import { debounce } from "lodash";
|
|
57
57
|
|
|
58
|
-
const
|
|
58
|
+
const settingsStore = useSettingsStore();
|
|
59
59
|
|
|
60
60
|
const oldLayout = ref("");
|
|
61
61
|
const controller = ref(new window.AbortController());
|
|
62
62
|
let timeOutID = null;
|
|
63
63
|
|
|
64
|
-
const layout = computed(() =>
|
|
65
|
-
const tabsBar = computed(() =>
|
|
66
|
-
const collapse = computed(() =>
|
|
67
|
-
const header = computed(() =>
|
|
68
|
-
const device = computed(() =>
|
|
64
|
+
const layout = computed(() => settingsStore.layout);
|
|
65
|
+
const tabsBar = computed(() => settingsStore.tabsBar);
|
|
66
|
+
const collapse = computed(() => settingsStore.collapse);
|
|
67
|
+
const header = computed(() => settingsStore.header);
|
|
68
|
+
const device = computed(() => settingsStore.device);
|
|
69
69
|
|
|
70
70
|
const classObj = computed(() => {
|
|
71
71
|
return {
|
|
@@ -74,7 +74,7 @@ const classObj = computed(() => {
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
const handleFoldSideBar = () => {
|
|
77
|
-
|
|
77
|
+
settingsStore.foldSideBar();
|
|
78
78
|
};
|
|
79
79
|
|
|
80
80
|
const handleIsMobile = () => {
|
|
@@ -86,24 +86,24 @@ const handleResize = debounce(() => {
|
|
|
86
86
|
const isMobile = handleIsMobile();
|
|
87
87
|
if (isMobile) {
|
|
88
88
|
//横向布局时如果是手机端访问那么改成纵向版
|
|
89
|
-
|
|
89
|
+
settingsStore.changeLayout("vertical");
|
|
90
90
|
} else {
|
|
91
|
-
|
|
91
|
+
settingsStore.changeLayout(oldLayout.value);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
settingsStore.toggleDevice(isMobile ? "mobile" : "desktop");
|
|
95
95
|
}
|
|
96
96
|
}, 100);
|
|
97
97
|
|
|
98
98
|
onBeforeMount(() => {
|
|
99
99
|
window.addEventListener("resize", handleResize);
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
// 页面加载时检查是否有保存的路由信息
|
|
102
102
|
const savedRoute = sessionStorage.getItem('currentRoute');
|
|
103
103
|
if (savedRoute) {
|
|
104
104
|
try {
|
|
105
105
|
const routeInfo = JSON.parse(savedRoute);
|
|
106
|
-
// 这里可以添加恢复路由状态的逻辑,比如重新设置
|
|
106
|
+
// 这里可以添加恢复路由状态的逻辑,比如重新设置Pinia中的路由状态
|
|
107
107
|
console.log('恢复保存的路由信息:', routeInfo);
|
|
108
108
|
// 清除保存的路由信息
|
|
109
109
|
sessionStorage.removeItem('currentRoute');
|
|
@@ -148,17 +148,17 @@ oldLayout.value = layout.value;
|
|
|
148
148
|
const isMobile = handleIsMobile();
|
|
149
149
|
if (isMobile) {
|
|
150
150
|
//横向布局时如果是手机端访问那么改成纵向版
|
|
151
|
-
|
|
151
|
+
settingsStore.changeLayout("vertical");
|
|
152
152
|
} else {
|
|
153
|
-
|
|
153
|
+
settingsStore.changeLayout(oldLayout.value);
|
|
154
154
|
}
|
|
155
|
-
|
|
155
|
+
settingsStore.toggleDevice(isMobile ? "mobile" : "desktop");
|
|
156
156
|
if (isMobile) {
|
|
157
157
|
timeOutID = setTimeout(() => {
|
|
158
|
-
|
|
158
|
+
settingsStore.foldSideBar();
|
|
159
159
|
}, 2000);
|
|
160
160
|
} else {
|
|
161
|
-
|
|
161
|
+
settingsStore.openSideBar();
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
nextTick(() => {
|