create-young-proj 0.10.2 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.mjs +9 -9
- package/package.json +1 -1
- package/template-nuxt-admin/README.md +42 -1
- package/template-nuxt-admin/components/layout/Main.vue +2 -2
- package/template-nuxt-admin/components/layout/NavBar.vue +11 -2
- package/template-nuxt-admin/components/layout/SideBar.vue +6 -2
- package/template-nuxt-admin/components/layout/SubMenu.vue +9 -2
- package/template-nuxt-admin/components/layout/TabsBar.vue +4 -5
- package/template-nuxt-admin/composables/api.ts +17 -3
- package/template-nuxt-admin/composables/nav.ts +20 -3
- package/template-nuxt-admin/composables/tags.ts +29 -1
- package/template-nuxt-admin/middleware/auth.global.ts +16 -4
- package/template-nuxt-admin/nuxt.config.ts +5 -1
- package/template-nuxt-admin/pages/home/[id].vue +2 -2
- package/template-nuxt-admin/pages/index.vue +2 -7
- package/template-nuxt-admin/pages/login.vue +2 -2
- package/template-nuxt-admin/pages/system/menuList.vue +0 -1
- package/template-nuxt-admin/public/bg.webp +0 -0
- package/template-nuxt-admin/public/favicon.svg +2 -0
- package/template-nuxt-admin/public/logo.svg +2 -0
- package/template-nuxt-admin/server/plugins/env.ts +3 -4
- package/template-nuxt-admin/utils/tool.ts +17 -1
- package/template-nuxt-admin/public/favicon.ico +0 -0
- package/template-vue-admin/.vscode/extensions.json +0 -10
- package/template-vue-admin/.vscode/list-add.code-snippets +0 -108
- package/template-vue-admin/.vscode/list-export.code-snippets +0 -72
- package/template-vue-admin/.vscode/list.code-snippets +0 -61
- package/template-vue-admin/.vscode/settings.json +0 -7
- package/template-vue-admin/Dockerfile +0 -42
- package/template-vue-admin/README.md +0 -75
- package/template-vue-admin/_env +0 -8
- package/template-vue-admin/_gitignore +0 -30
- package/template-vue-admin/boot.mjs +0 -16
- package/template-vue-admin/build/custom-plugin.ts +0 -57
- package/template-vue-admin/build/index.ts +0 -7
- package/template-vue-admin/build/plugins.ts +0 -59
- package/template-vue-admin/config/.devrc +0 -2
- package/template-vue-admin/config/.onlinerc +0 -2
- package/template-vue-admin/config/.testrc +0 -2
- package/template-vue-admin/index.html +0 -21
- package/template-vue-admin/nitro.config.ts +0 -19
- package/template-vue-admin/package.json +0 -51
- package/template-vue-admin/plugins/init.ts +0 -31
- package/template-vue-admin/public/vite.svg +0 -1
- package/template-vue-admin/rome.json +0 -26
- package/template-vue-admin/routes/api/[...all].ts +0 -49
- package/template-vue-admin/routes/get/env.ts +0 -18
- package/template-vue-admin/src/App.vue +0 -14
- package/template-vue-admin/src/apis/delete.ts +0 -36
- package/template-vue-admin/src/apis/get.ts +0 -83
- package/template-vue-admin/src/apis/index.ts +0 -10
- package/template-vue-admin/src/apis/patch.ts +0 -78
- package/template-vue-admin/src/apis/post.ts +0 -76
- package/template-vue-admin/src/assets/img/login_background.jpg +0 -0
- package/template-vue-admin/src/auto-components.d.ts +0 -38
- package/template-vue-admin/src/auto-imports.d.ts +0 -302
- package/template-vue-admin/src/layouts/blank.vue +0 -9
- package/template-vue-admin/src/layouts/default/components/Link.vue +0 -23
- package/template-vue-admin/src/layouts/default/components/Logo.vue +0 -20
- package/template-vue-admin/src/layouts/default/components/Menu.vue +0 -54
- package/template-vue-admin/src/layouts/default/components/NavSearch.vue +0 -52
- package/template-vue-admin/src/layouts/default/components/ScrollPane.vue +0 -79
- package/template-vue-admin/src/layouts/default/components/TagsView.vue +0 -137
- package/template-vue-admin/src/layouts/default/components/TopMenu.vue +0 -21
- package/template-vue-admin/src/layouts/default/components/UserCenter.vue +0 -50
- package/template-vue-admin/src/layouts/default/index.vue +0 -95
- package/template-vue-admin/src/main.ts +0 -46
- package/template-vue-admin/src/modules/1-router.ts +0 -48
- package/template-vue-admin/src/modules/2-pinia.ts +0 -10
- package/template-vue-admin/src/modules/3-net.ts +0 -79
- package/template-vue-admin/src/modules/4-auth.ts +0 -124
- package/template-vue-admin/src/modules/5-checkupdate.ts +0 -38
- package/template-vue-admin/src/shims.d.ts +0 -12
- package/template-vue-admin/src/stores/index.ts +0 -9
- package/template-vue-admin/src/stores/local/index.ts +0 -31
- package/template-vue-admin/src/stores/session/index.ts +0 -63
- package/template-vue-admin/src/stores/tags.ts +0 -109
- package/template-vue-admin/src/typings/global.d.ts +0 -70
- package/template-vue-admin/src/typings/index.ts +0 -13
- package/template-vue-admin/src/typings/system.d.ts +0 -46
- package/template-vue-admin/src/views/403.vue +0 -33
- package/template-vue-admin/src/views/[...all_404].vue +0 -557
- package/template-vue-admin/src/views/base/login.vue +0 -194
- package/template-vue-admin/src/views/dashboard/[name].vue +0 -28
- package/template-vue-admin/src/views/index.vue +0 -25
- package/template-vue-admin/src/views/system/api.vue +0 -160
- package/template-vue-admin/src/views/system/hooks/useRole.ts +0 -286
- package/template-vue-admin/src/views/system/menuList.vue +0 -194
- package/template-vue-admin/src/views/system/role.vue +0 -131
- package/template-vue-admin/src/views/system/user.vue +0 -192
- package/template-vue-admin/src/vite-env.d.ts +0 -52
- package/template-vue-admin/tsconfig.json +0 -21
- package/template-vue-admin/tsconfig.node.json +0 -9
- package/template-vue-admin/unocss.config.ts +0 -47
- package/template-vue-admin/vite.config.ts +0 -32
@@ -1,137 +0,0 @@
|
|
1
|
-
<!--
|
2
|
-
* @Author: zhangyang
|
3
|
-
* @Date: 2020-12-11 13:35:58
|
4
|
-
* @LastEditTime: 2023-01-05 16:00:11
|
5
|
-
* @Description: 标签选项卡组件
|
6
|
-
-->
|
7
|
-
<template>
|
8
|
-
<div class="tags-view-container px-2">
|
9
|
-
<ScrollPane ref="scrollPane" class="tags-view-wrapper">
|
10
|
-
<ElTag v-for="(tag, index) in visitedViews" :key="index + 'fadsrhewioru'" effect="dark" size="large"
|
11
|
-
class="inline-block mx-1 my-0.2vh hover:cursor-pointer" :type="isActive(tag) ? 'success' : 'info'"
|
12
|
-
:closable="!tag.meta.affix && visitedViews.length > 1" @click="router.push(tag.fullPath)"
|
13
|
-
@close.stop="menuHandlers['closeThis'](tag)" @contextmenu.prevent="openContextMenu(tag, $event)">
|
14
|
-
{{ tag.meta.title }}
|
15
|
-
</ElTag>
|
16
|
-
</ScrollPane>
|
17
|
-
|
18
|
-
<YoungContextMenu v-model="showContextMenu" :menu-list="menuList" @clickItem="clickItemHandler" />
|
19
|
-
</div>
|
20
|
-
</template>
|
21
|
-
<script lang="ts" setup>
|
22
|
-
import { YoungContextMenu } from '@bluesyoung/ui-vue3';
|
23
|
-
import ScrollPane from './ScrollPane.vue';
|
24
|
-
import { storeToRefs } from 'pinia';
|
25
|
-
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router';
|
26
|
-
import { useTagsStore } from '@/stores';
|
27
|
-
|
28
|
-
const showContextMenu = ref(false);
|
29
|
-
|
30
|
-
const tagsState = useTagsStore();
|
31
|
-
const { visitedViews, cachedViews } = storeToRefs(tagsState);
|
32
|
-
const menuList = computed(() => {
|
33
|
-
let baseMenu = [
|
34
|
-
{ title: '关闭此页面', handlerName: 'closeThis' },
|
35
|
-
{ title: '关闭其他页面', handlerName: 'closeOthers' }
|
36
|
-
];
|
37
|
-
if (visitedViews.value.length === 1) {
|
38
|
-
baseMenu = [];
|
39
|
-
}
|
40
|
-
const { name } = route;
|
41
|
-
const s_name = selectedTag.value?.name ?? '';
|
42
|
-
// 当前页为激活状态才允许刷新
|
43
|
-
const res = (cachedViews.value.includes(s_name) && name === s_name) ? [{ title: '刷新此页面', handlerName: 'refresh' }].concat(baseMenu) : baseMenu;
|
44
|
-
return res;
|
45
|
-
});
|
46
|
-
const router = useRouter();
|
47
|
-
const route = useRoute();
|
48
|
-
/**
|
49
|
-
* 当前选中的标签
|
50
|
-
*/
|
51
|
-
const selectedTag = ref<RouteLocationNormalized | null>(null);
|
52
|
-
/**
|
53
|
-
* 所有固定的标签(禁止关闭)
|
54
|
-
*/
|
55
|
-
const affixTags = ref<RouteLocationNormalized[]>([]);
|
56
|
-
|
57
|
-
const isActive = (view: RouteLocationNormalized) => view.path === route.path;
|
58
|
-
const isAffix = (route: RouteLocationNormalized | RouteRecordRaw) => route?.meta?.affix ?? false;
|
59
|
-
|
60
|
-
const toLastView = (visitedViews: RouteLocationNormalized[], view: RouteLocationNormalized) => {
|
61
|
-
const lastView = visitedViews.slice(-1)[0];
|
62
|
-
if (lastView) {
|
63
|
-
router.push(lastView.fullPath);
|
64
|
-
}
|
65
|
-
};
|
66
|
-
|
67
|
-
const scrollPane = ref<any | null>(null);
|
68
|
-
|
69
|
-
const moveToCurrentTag = () => {
|
70
|
-
nextTick(() => {
|
71
|
-
const SP = scrollPane.value;
|
72
|
-
SP?.moveToTarget?.();
|
73
|
-
});
|
74
|
-
};
|
75
|
-
|
76
|
-
const menuHandlers: Record<string, Function> = {
|
77
|
-
'refresh': () => {
|
78
|
-
const tag = selectedTag.value;
|
79
|
-
tag && tagsState.delCachedView(tag);
|
80
|
-
},
|
81
|
-
'closeThis': (tag = selectedTag.value) => {
|
82
|
-
if (tag) {
|
83
|
-
if (!isAffix(tag)) {
|
84
|
-
tagsState.delView(tag);
|
85
|
-
isActive(tag) && toLastView(visitedViews.value, tag);
|
86
|
-
}
|
87
|
-
}
|
88
|
-
},
|
89
|
-
'closeOthers': () => {
|
90
|
-
const tag = selectedTag.value;
|
91
|
-
if (tag) {
|
92
|
-
router.push(tag);
|
93
|
-
tagsState.delOtherViews(tag);
|
94
|
-
}
|
95
|
-
},
|
96
|
-
'closeAll': () => {
|
97
|
-
tagsState.delAllViews();
|
98
|
-
const sTag = selectedTag.value;
|
99
|
-
if (sTag) {
|
100
|
-
if (affixTags.value.some((tag) => tag.path === sTag.path)) {
|
101
|
-
return;
|
102
|
-
}
|
103
|
-
toLastView(visitedViews.value, sTag);
|
104
|
-
}
|
105
|
-
}
|
106
|
-
};
|
107
|
-
const clickItemHandler = (handler: string) => {
|
108
|
-
menuHandlers?.[handler]?.();
|
109
|
-
showContextMenu.value = false;
|
110
|
-
};
|
111
|
-
const openContextMenu = (tag: RouteLocationNormalized, e: MouseEvent) => {
|
112
|
-
nextTick(() => {
|
113
|
-
if (menuList.value.length === 0) {
|
114
|
-
return;
|
115
|
-
}
|
116
|
-
showContextMenu.value = true;
|
117
|
-
selectedTag.value = tag;
|
118
|
-
});
|
119
|
-
};
|
120
|
-
|
121
|
-
router.afterEach((to) => {
|
122
|
-
tagsState.addView(to);
|
123
|
-
moveToCurrentTag();
|
124
|
-
});
|
125
|
-
|
126
|
-
onMounted(() => {
|
127
|
-
tagsState.addView(route);
|
128
|
-
});
|
129
|
-
</script>
|
130
|
-
|
131
|
-
<style lang="scss" scoped>
|
132
|
-
.tags-view-container {
|
133
|
-
background: #fff;
|
134
|
-
border-bottom: 1px solid #d8dce5;
|
135
|
-
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
|
136
|
-
}
|
137
|
-
</style>
|
@@ -1,21 +0,0 @@
|
|
1
|
-
<!--
|
2
|
-
* @Author: zhangyang
|
3
|
-
* @Date: 2022-12-07 14:13:25
|
4
|
-
* @LastEditTime: 2023-01-05 16:08:30
|
5
|
-
* @Description:
|
6
|
-
-->
|
7
|
-
<script lang="ts" setup>
|
8
|
-
import { useNavStore, TopIndex } from '@/stores';
|
9
|
-
|
10
|
-
const { TopMenu } = useNavStore();
|
11
|
-
</script>
|
12
|
-
<template>
|
13
|
-
<div>
|
14
|
-
<ElMenu mode="horizontal" :default-active="TopIndex" :ellipsis="(TopMenu.length > 10)">
|
15
|
-
<ElMenuItem v-for="(nav, index) in TopMenu" :key="index + 'fdsjakr'" :index="index + ''"
|
16
|
-
@click="(TopIndex = index + '')">
|
17
|
-
{{ nav.title }}
|
18
|
-
</ElMenuItem>
|
19
|
-
</ElMenu>
|
20
|
-
</div>
|
21
|
-
</template>
|
@@ -1,50 +0,0 @@
|
|
1
|
-
<!--
|
2
|
-
* @Author: zhangyang
|
3
|
-
* @Date: 2020-12-10 11:30:30
|
4
|
-
* @LastEditTime: 2023-01-05 14:16:52
|
5
|
-
* @Description: 顶部导航栏组件
|
6
|
-
-->
|
7
|
-
<script lang="ts" setup>
|
8
|
-
import NavSearch from './NavSearch.vue';
|
9
|
-
import TopMenu from './TopMenu.vue';
|
10
|
-
import { useUserStore, useNavStore, removeToken } from '@/stores';
|
11
|
-
|
12
|
-
const router = useRouter();
|
13
|
-
const { CurrUserInfo } = useUserStore();
|
14
|
-
|
15
|
-
const loginOut = async () => {
|
16
|
-
removeToken();
|
17
|
-
useUserStore().reset();
|
18
|
-
useNavStore().reset();
|
19
|
-
router.replace('/base/login');
|
20
|
-
};
|
21
|
-
</script>
|
22
|
-
|
23
|
-
<template>
|
24
|
-
<!-- 快捷菜单 -->
|
25
|
-
<NavSearch />
|
26
|
-
<div v-bind="$attrs" class="flex w-full justify-between px-5">
|
27
|
-
<!-- 顶部导航栏 -->
|
28
|
-
<TopMenu />
|
29
|
-
<!-- 右侧个人中心下拉框 -->
|
30
|
-
<ElDropdown class="avatar-container" trigger="click">
|
31
|
-
<div class="inline-flex justify-center items-center mx-2 hover:cursor-pointer">
|
32
|
-
<ElAvatar v-if="CurrUserInfo.avatar" :src="CurrUserInfo.avatar" />
|
33
|
-
<ElAvatar v-else color="transparent">
|
34
|
-
<div class="text-xl i-noto-v1-man-technologist-light-skin-tone" />
|
35
|
-
</ElAvatar>
|
36
|
-
|
37
|
-
<div class="text-sm ml-2">{{ CurrUserInfo.nickname }}</div>
|
38
|
-
<div class="mr-2 text-sm i-ion-md-arrow-dropdown" />
|
39
|
-
</div>
|
40
|
-
<template #dropdown>
|
41
|
-
<ElDropdownMenu class="user-dropdown">
|
42
|
-
<ElDropdownItem @click="loginOut">
|
43
|
-
<div>退出登录</div>
|
44
|
-
</ElDropdownItem>
|
45
|
-
</ElDropdownMenu>
|
46
|
-
</template>
|
47
|
-
</ElDropdown>
|
48
|
-
</div>
|
49
|
-
</template>
|
50
|
-
|
@@ -1,95 +0,0 @@
|
|
1
|
-
<!--
|
2
|
-
* @Author: zhangyang
|
3
|
-
* @Date: 2022-10-25 17:43:30
|
4
|
-
* @LastEditTime: 2023-01-09 09:08:54
|
5
|
-
* @Description:
|
6
|
-
-->
|
7
|
-
<script lang="ts" setup>
|
8
|
-
import Logo from './components/Logo.vue';
|
9
|
-
import Menu from './components/Menu.vue';
|
10
|
-
import UserCenter from './components/UserCenter.vue';
|
11
|
-
import TagsView from './components/TagsView.vue';
|
12
|
-
import { useTagsStore } from '@/stores';
|
13
|
-
|
14
|
-
const { cachedViews, visitedViews } = storeToRefs(useTagsStore());
|
15
|
-
const route = useRoute();
|
16
|
-
const path = computed(() => route.path);
|
17
|
-
const name = computed(() => route.name);
|
18
|
-
const isCached = computed(() => {
|
19
|
-
// 无需缓存的界面
|
20
|
-
if (route.meta.noCache) {
|
21
|
-
return false;
|
22
|
-
}
|
23
|
-
const arr = visitedViews.value.map((view) => view.name);
|
24
|
-
// 已经缓存,或者首次打开(防止二次初始化)
|
25
|
-
return cachedViews.value.includes(name.value) || !arr.includes(name.value as unknown as string);
|
26
|
-
});
|
27
|
-
</script>
|
28
|
-
<template>
|
29
|
-
<div class="parent">
|
30
|
-
<div class="left">
|
31
|
-
<div class="logo">
|
32
|
-
<Logo />
|
33
|
-
</div>
|
34
|
-
<div class="menu">
|
35
|
-
<Menu />
|
36
|
-
</div>
|
37
|
-
</div>
|
38
|
-
<div class="right">
|
39
|
-
<div class="top">
|
40
|
-
<UserCenter />
|
41
|
-
</div>
|
42
|
-
<div class="tags">
|
43
|
-
<TagsView />
|
44
|
-
</div>
|
45
|
-
<div class="main">
|
46
|
-
<RouterView v-slot="{ Component: PageComponent }">
|
47
|
-
<Transition name="fade-transform" mode="out-in">
|
48
|
-
<div>
|
49
|
-
<KeepAlive>
|
50
|
-
<Component v-if="isCached" :is="PageComponent" :key="path" />
|
51
|
-
</KeepAlive>
|
52
|
-
<Component v-if="!isCached" :is="PageComponent" :key="path" />
|
53
|
-
</div>
|
54
|
-
</Transition>
|
55
|
-
</RouterView>
|
56
|
-
</div>
|
57
|
-
</div>
|
58
|
-
</div>
|
59
|
-
</template>
|
60
|
-
|
61
|
-
<style lang="scss" scoped>
|
62
|
-
.parent {
|
63
|
-
@apply w-100vw h-100vh overflow-auto flex;
|
64
|
-
|
65
|
-
.left {
|
66
|
-
@apply h-full flex flex-col w-210px;
|
67
|
-
background-color: rgb(48, 65, 86);
|
68
|
-
|
69
|
-
.logo {
|
70
|
-
@apply w-full h-60px flex justify-center items-center bg-[#2b2f3a] text-white;
|
71
|
-
}
|
72
|
-
|
73
|
-
.menu {
|
74
|
-
@apply flex-1 overflow-y-auto overflow-x-hidden;
|
75
|
-
background-color: rgb(48, 65, 86);
|
76
|
-
}
|
77
|
-
}
|
78
|
-
|
79
|
-
.right {
|
80
|
-
@apply flex-1;
|
81
|
-
|
82
|
-
.top {
|
83
|
-
@apply h-60px w-full flex items-center;
|
84
|
-
}
|
85
|
-
|
86
|
-
.tags {
|
87
|
-
@apply h-30px w-full relative z-10;
|
88
|
-
}
|
89
|
-
|
90
|
-
.main {
|
91
|
-
@apply p-5 h-[calc(100vh-100px)] w-[calc(100vw-210px)] overflow-auto;
|
92
|
-
}
|
93
|
-
}
|
94
|
-
}
|
95
|
-
</style>
|
@@ -1,46 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* @Author: zhangyang
|
3
|
-
* @Date: 2022-12-03 15:57:40
|
4
|
-
* @LastEditTime: 2023-01-10 15:09:29
|
5
|
-
* @Description:
|
6
|
-
*/
|
7
|
-
// polyfill
|
8
|
-
import 'core-js/stable';
|
9
|
-
import 'regenerator-runtime/runtime';
|
10
|
-
// 统一浏览器样式
|
11
|
-
import '@unocss/reset/tailwind.css';
|
12
|
-
import 'uno.css';
|
13
|
-
import 'element-plus/dist/index.css';
|
14
|
-
|
15
|
-
import { createApp } from 'vue';
|
16
|
-
import { server } from 'virtual:local-server';
|
17
|
-
import App from './App.vue';
|
18
|
-
import { CurrentVersion } from './stores';
|
19
|
-
|
20
|
-
(async () => {
|
21
|
-
// 获取环境变量
|
22
|
-
let viteEnv;
|
23
|
-
// 注入此环境变量,可以兼容现有的部署方式
|
24
|
-
if (import.meta.env.VITE_USE_DEFAULT_DEPLOY_METHOD) {
|
25
|
-
viteEnv = import.meta.env;
|
26
|
-
console.log('🚀 ~ file: main.ts ~ line 19 ~ viteEnv', viteEnv);
|
27
|
-
} else if (import.meta.env.DEV) {
|
28
|
-
// 开发环境,局域网 ip
|
29
|
-
viteEnv = await (await fetch(server + '/get/env')).json();
|
30
|
-
console.log('🚀 ~ file: main.ts ~ line 24 ~ viteEnv', viteEnv);
|
31
|
-
} else {
|
32
|
-
// 部署环境,需要配合 nginx 使用
|
33
|
-
viteEnv = await (await fetch(`/get/env`)).json();
|
34
|
-
console.log('🚀 ~ file: main.ts ~ line 28 ~ viteEnv', viteEnv);
|
35
|
-
}
|
36
|
-
window.__YOUNG_VITE_ENV__ = viteEnv;
|
37
|
-
CurrentVersion.value = viteEnv.VITE_CURRENT_VERSION;
|
38
|
-
|
39
|
-
const app = createApp(App);
|
40
|
-
Object.values(
|
41
|
-
// 模块按数字命名,确保安装的顺序
|
42
|
-
import.meta.glob<{ install: UserModule }>('./modules/*.ts', { eager: true }),
|
43
|
-
).map(({ install }) => install(app));
|
44
|
-
|
45
|
-
app.mount('#app');
|
46
|
-
})();
|
@@ -1,48 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* @Author: zhangyang
|
3
|
-
* @Date: 2023-01-04 10:15:03
|
4
|
-
* @LastEditTime: 2023-05-18 15:45:18
|
5
|
-
* @Description: 路由模块
|
6
|
-
*/
|
7
|
-
import { createRouter, createWebHashHistory } from 'vue-router';
|
8
|
-
import { setupLayouts } from 'virtual:generated-layouts';
|
9
|
-
import routes from '~pages';
|
10
|
-
|
11
|
-
/**
|
12
|
-
* 路由元数据类型扩展
|
13
|
-
*/
|
14
|
-
declare module 'vue-router' {
|
15
|
-
interface RouteMeta {
|
16
|
-
/**
|
17
|
-
* 页面标题
|
18
|
-
*/
|
19
|
-
title: string;
|
20
|
-
/**
|
21
|
-
* 是否固定
|
22
|
-
*/
|
23
|
-
affix?: boolean;
|
24
|
-
/**
|
25
|
-
* 是否禁用缓存
|
26
|
-
*/
|
27
|
-
noCache?: boolean;
|
28
|
-
/**
|
29
|
-
* 设置 false 不参与鉴权,否则鉴权路径为当前路由
|
30
|
-
*/
|
31
|
-
auth?: false;
|
32
|
-
/**
|
33
|
-
* 页面布局,对应 layouts 目录下的布局页面,不写默认为 default/index
|
34
|
-
*/
|
35
|
-
layout?: 'blank';
|
36
|
-
}
|
37
|
-
}
|
38
|
-
|
39
|
-
export const finalRoutes = setupLayouts(routes);
|
40
|
-
|
41
|
-
export const router = createRouter({
|
42
|
-
history: createWebHashHistory(),
|
43
|
-
routes: finalRoutes,
|
44
|
-
});
|
45
|
-
|
46
|
-
export const install: UserModule = (app) => {
|
47
|
-
app.use(router);
|
48
|
-
};
|
@@ -1,79 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* @Author: zhangyang
|
3
|
-
* @Date: 2022-03-01 14:01:31
|
4
|
-
* @LastEditTime: 2023-05-18 16:21:55
|
5
|
-
* @Description: 网络请求
|
6
|
-
*/
|
7
|
-
import { useHttp } from '@bluesyoung/http';
|
8
|
-
import { getToken } from '@/stores';
|
9
|
-
import type { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
|
10
|
-
import { useGetReq, usePostReq, usePatchReq, useDeleteReq } from '@/apis';
|
11
|
-
|
12
|
-
let loading: LoadingInstance;
|
13
|
-
|
14
|
-
const startLoading = () => {
|
15
|
-
loading = ElLoadingService({
|
16
|
-
lock: true,
|
17
|
-
text: '拼命加载中...',
|
18
|
-
background: 'rgba(0, 0, 0, 0.7)',
|
19
|
-
});
|
20
|
-
};
|
21
|
-
|
22
|
-
const endLoading = () => loading?.close?.();
|
23
|
-
|
24
|
-
export const http = useHttp<ResponseMsg>({
|
25
|
-
timeout: -1,
|
26
|
-
loading: {
|
27
|
-
start: startLoading,
|
28
|
-
end: endLoading,
|
29
|
-
},
|
30
|
-
fail: (err: any) => {
|
31
|
-
console.log('🚀 ~ file: 3-net.ts:60 ~ err', err, typeof err);
|
32
|
-
if (err?.response?.status === 401) {
|
33
|
-
ElMessage.error('无权限,请联系管理员');
|
34
|
-
}
|
35
|
-
|
36
|
-
if (typeof err === 'string') {
|
37
|
-
// 通用失败,弹出提示信息
|
38
|
-
ElMessage.error(err);
|
39
|
-
}
|
40
|
-
|
41
|
-
if (err instanceof Error) {
|
42
|
-
ElMessage.error(
|
43
|
-
// @ts-ignore 接口出错
|
44
|
-
err?.response?.data?.message || err?.response?.data?.msg || err.message || '网络错误!',
|
45
|
-
);
|
46
|
-
}
|
47
|
-
|
48
|
-
throw err;
|
49
|
-
},
|
50
|
-
checkFn: ({ code, msg, data }) => {
|
51
|
-
if (code === 0) {
|
52
|
-
// 通用成功
|
53
|
-
return data;
|
54
|
-
} else if (code === -1) {
|
55
|
-
// 通用失败
|
56
|
-
throw msg;
|
57
|
-
} else {
|
58
|
-
// 特殊状态码
|
59
|
-
throw code;
|
60
|
-
}
|
61
|
-
},
|
62
|
-
headers: {
|
63
|
-
getAuthHeaders: () => {
|
64
|
-
const token = getToken();
|
65
|
-
return {
|
66
|
-
Authorization: `Bearer ${token}`,
|
67
|
-
};
|
68
|
-
},
|
69
|
-
},
|
70
|
-
});
|
71
|
-
|
72
|
-
export const apis = http.__mixin__({
|
73
|
-
get: useGetReq(),
|
74
|
-
post: usePostReq(),
|
75
|
-
patch: usePatchReq(),
|
76
|
-
delete: useDeleteReq(),
|
77
|
-
});
|
78
|
-
|
79
|
-
export const install: UserModule = (ctx) => {};
|
@@ -1,124 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* @Author: zhangyang
|
3
|
-
* @Date: 2022-03-01 19:40:13
|
4
|
-
* @LastEditTime: 2023-05-18 16:17:02
|
5
|
-
* @Description: 权限校验
|
6
|
-
*/
|
7
|
-
import { router } from './1-router';
|
8
|
-
import type { RouteLocationNormalized } from 'vue-router';
|
9
|
-
import { useNavStore, useTagsStore, useUserStore, getToken, getLoginInfo } from '@/stores';
|
10
|
-
import { apis } from './3-net';
|
11
|
-
|
12
|
-
const changeTitle = (route: RouteLocationNormalized) => {
|
13
|
-
document.title =
|
14
|
-
(route.meta.title as string) || window.__YOUNG_VITE_ENV__.VITE_TITLE || '管理后台';
|
15
|
-
};
|
16
|
-
|
17
|
-
const { CurrUserInfo } = useUserStore();
|
18
|
-
const { NavArrAll, RoleRoute, FlatNavArr, RawNav } = useNavStore();
|
19
|
-
|
20
|
-
let role_route: string[] = [];
|
21
|
-
const generateRoleRoute = (arr: NavArrItem[], num?: number): string[] => {
|
22
|
-
if (num === 1) {
|
23
|
-
role_route = [];
|
24
|
-
FlatNavArr.value = [];
|
25
|
-
}
|
26
|
-
for (const item of arr) {
|
27
|
-
if (item.component) {
|
28
|
-
role_route.push(item.component);
|
29
|
-
+item.visible === 1 && FlatNavArr.value.push(item);
|
30
|
-
}
|
31
|
-
// 子节点递归遍历
|
32
|
-
if (Array.isArray(item.children) && item.children.length > 0) {
|
33
|
-
const part = JSON.parse(JSON.stringify(item.children));
|
34
|
-
// 尾递归优化
|
35
|
-
generateRoleRoute(part);
|
36
|
-
}
|
37
|
-
}
|
38
|
-
return role_route;
|
39
|
-
};
|
40
|
-
// 清除没有子元素的children
|
41
|
-
export const clearChildren = <T extends Record<string, any>>(arr: T[]) => {
|
42
|
-
for (const item of arr) {
|
43
|
-
if (item?.children.length === 0) {
|
44
|
-
delete item.children;
|
45
|
-
} else if (item.children) {
|
46
|
-
clearChildren(item.children);
|
47
|
-
}
|
48
|
-
}
|
49
|
-
return arr;
|
50
|
-
};
|
51
|
-
|
52
|
-
export const generateNavData = async (force = false) => {
|
53
|
-
const info = getLoginInfo();
|
54
|
-
|
55
|
-
if (!info) {
|
56
|
-
// 登录过期
|
57
|
-
ElMessage.error('登录过期,请重新登录!');
|
58
|
-
router.replace('/base/login');
|
59
|
-
return;
|
60
|
-
}
|
61
|
-
|
62
|
-
const menu = Object.values(await apis.get.getMenuTree(force)) as any[];
|
63
|
-
RawNav.value = menu;
|
64
|
-
|
65
|
-
// 刷新右上角角色信息
|
66
|
-
apis.post.getCurrUserInfo().then((res) => {
|
67
|
-
CurrUserInfo.value = res;
|
68
|
-
});
|
69
|
-
|
70
|
-
// 后端获取用户可见节点
|
71
|
-
const navArr: NavArrItem[] = menu;
|
72
|
-
const routes: string[] = generateRoleRoute(menu, 1);
|
73
|
-
|
74
|
-
// 导航数组
|
75
|
-
NavArrAll.value = navArr.filter((item) => +item.visible === 1);
|
76
|
-
// 生成角色有权访问的路由
|
77
|
-
RoleRoute.value = routes.slice();
|
78
|
-
};
|
79
|
-
|
80
|
-
export const hasPermission = (path: string) => {
|
81
|
-
const { RoleRoute } = useNavStore();
|
82
|
-
const roleRoute = RoleRoute.value;
|
83
|
-
return roleRoute.includes(path);
|
84
|
-
};
|
85
|
-
|
86
|
-
export const install: UserModule = (app) => {
|
87
|
-
router.beforeEach(async (to, from) => {
|
88
|
-
if (to.path !== '/base/login') {
|
89
|
-
// 页面无需权限
|
90
|
-
if (to.meta.auth === false) {
|
91
|
-
return true;
|
92
|
-
}
|
93
|
-
// 已登录
|
94
|
-
if (getToken()) {
|
95
|
-
// 生成权限树
|
96
|
-
await generateNavData();
|
97
|
-
if (hasPermission(to.path)) {
|
98
|
-
// 拥有对应页面的权限
|
99
|
-
return true;
|
100
|
-
}
|
101
|
-
if (!hasPermission(to.path)) {
|
102
|
-
// 已登录,并且无权限
|
103
|
-
return '/403';
|
104
|
-
}
|
105
|
-
} else {
|
106
|
-
return '/base/login';
|
107
|
-
}
|
108
|
-
} else {
|
109
|
-
return true;
|
110
|
-
}
|
111
|
-
});
|
112
|
-
|
113
|
-
router.afterEach((to) => {
|
114
|
-
const { addView } = useTagsStore();
|
115
|
-
const nav = FlatNavArr.value.find((item) => item.component === to.path);
|
116
|
-
if (nav && nav.title) {
|
117
|
-
// console.log('before: ', to.meta);
|
118
|
-
to.meta.title = nav.title as string;
|
119
|
-
// console.log('after: ', to.meta);
|
120
|
-
}
|
121
|
-
addView(to);
|
122
|
-
changeTitle(to);
|
123
|
-
});
|
124
|
-
};
|
@@ -1,38 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* @Author: zhangyang
|
3
|
-
* @Date: 2023-03-02 16:50:48
|
4
|
-
* @LastEditTime: 2023-03-24 10:35:36
|
5
|
-
* @Description: 检查更新
|
6
|
-
*/
|
7
|
-
import { CurrentVersion } from '@/stores';
|
8
|
-
import { sleep } from '@bluesyoung/utils';
|
9
|
-
import { server } from 'virtual:local-server';
|
10
|
-
import { generateNavData } from './4-auth';
|
11
|
-
|
12
|
-
export const install: UserModule = (app) => {
|
13
|
-
let viteEnv: ImportMetaEnv;
|
14
|
-
// 每分钟一次,检查更新
|
15
|
-
setInterval(async () => {
|
16
|
-
if (import.meta.env.DEV) {
|
17
|
-
// 开发环境,局域网 ip
|
18
|
-
viteEnv = await (await fetch(server + '/get/env')).json(); // console.log('🚀 ~ file: 5-checkupdate.ts:187~ setInterval ~ viteEnv:"' viteEnv)
|
19
|
-
} else {
|
20
|
-
// 部署环境
|
21
|
-
viteEnv = await (await fetch(location.origin + location.pathname + `get/env`)).json();
|
22
|
-
// console.log('🚀 ~ file: 5-checkupdate.ts:231~ setInterval ~ viteEnv:', viteEnv);
|
23
|
-
}
|
24
|
-
|
25
|
-
const refresh = async () => {
|
26
|
-
await generateNavData(true);
|
27
|
-
await sleep(0.5);
|
28
|
-
location.reload();
|
29
|
-
};
|
30
|
-
|
31
|
-
if (viteEnv.VITE_CURRENT_VERSION !== CurrentVersion.value) {
|
32
|
-
setTimeout(refresh, 3e4);
|
33
|
-
ElMessageBox.alert('新版本已发布,点击立即重新加载(30s后自动刷新)', '温馨提示', {
|
34
|
-
type: 'warning',
|
35
|
-
}).then(() => refresh());
|
36
|
-
}
|
37
|
-
}, 6e4);
|
38
|
-
};
|