create-jnrs-template-vue 1.2.7 → 1.2.9
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/README.md +14 -10
- package/bin/create.mjs +22 -3
- package/jnrs-template-vue/README.md +1 -1
- package/jnrs-template-vue/package.json +4 -3
- package/jnrs-template-vue/public/system/menu.json +11 -0
- package/jnrs-template-vue/src/api/common/index.ts +1 -1
- package/jnrs-template-vue/src/api/demos/index.ts +12 -1
- package/jnrs-template-vue/src/api/request.ts +53 -0
- package/jnrs-template-vue/src/api/system/index.ts +3 -2
- package/jnrs-template-vue/src/api/user/index.ts +1 -1
- package/jnrs-template-vue/src/layout/RouterTabs /344/277/256/345/244/215/350/267/257/347/224/261/350/267/263/350/275/254/346/220/272/345/270/246/345/217/202/346/225/260/351/227/256/351/242/230.vue" +150 -0
- package/jnrs-template-vue/src/router/routes.ts +0 -13
- package/jnrs-template-vue/src/views/demos/unitTest/RequestPage.vue +3 -3
- package/jnrs-template-vue/src/views/lingshuSmart/editorPage.vue +9 -0
- package/jnrs-template-vue/src/views/login/index.vue +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,44 +9,48 @@ TypeScript、Vue3 生态
|
|
|
9
9
|
## 🧩 安装使用说明
|
|
10
10
|
新项目默认名称为 jnrs-template-vue
|
|
11
11
|
```shell
|
|
12
|
-
✅ 正确用法
|
|
12
|
+
# ✅ 正确用法
|
|
13
|
+
# 创建新项目
|
|
13
14
|
pnpm create jnrs-template-vue@latest
|
|
15
|
+
# 在当前目录下创建项目
|
|
16
|
+
pnpm create jnrs-template-vue@latest .
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
# 安装依赖/启动开发/打包构建
|
|
16
19
|
pnpm i
|
|
17
20
|
pnpm dev
|
|
18
21
|
pnpm build
|
|
19
22
|
|
|
20
|
-
❌
|
|
23
|
+
# ❌ 错误用法
|
|
21
24
|
pnpm add create-jnrs-template-vue
|
|
22
25
|
```
|
|
23
26
|
|
|
24
27
|
## 📂 模板项目主要结构
|
|
25
28
|
```Text
|
|
26
29
|
jnrs-template-vue/
|
|
27
|
-
├──
|
|
28
|
-
├── node_modules/ # 项目依赖
|
|
29
|
-
├── viteMockServe/ # Mock 服务配置(用于开发环境模拟 API)
|
|
30
|
+
├── viteMockServe/ # Mock 服务配置
|
|
30
31
|
├── public/ # 静态资源
|
|
31
32
|
├── src/ # 源码目录
|
|
32
33
|
│ ├── components/ # Vue 组件
|
|
33
34
|
│ ├── composables/ # 组合式函数
|
|
35
|
+
│ ├── layout/ # 布局
|
|
34
36
|
│ ├── views/ # 页面视图
|
|
35
37
|
│ ├── router/ # 路由配置
|
|
38
|
+
│ ├── api/ # 接口定义(已含 request 实例)
|
|
39
|
+
│ ├── types/ # 类型定义
|
|
36
40
|
│ ├── store/ # 状态管理
|
|
37
41
|
│ ├── utils/ # 工具函数
|
|
42
|
+
│ ├── locales/ # 国际化
|
|
38
43
|
│ └── main.ts # 应用入口
|
|
39
44
|
├── index.html # HTML 入口文件
|
|
40
45
|
├── eslint.config.js # ESLint 配置文件
|
|
41
|
-
├── package.json #
|
|
46
|
+
├── package.json # 包管理配置
|
|
42
47
|
└── vite.config.ts # Vite 构建配置
|
|
43
48
|
├── tsconfig.json # TypeScript 配置
|
|
44
49
|
├── auto-imports.d.ts # 自动导入类型声明
|
|
45
50
|
├── components.d.ts # 全局组件类型声明
|
|
46
51
|
├── README.md # 项目文档
|
|
47
|
-
├── .env.
|
|
48
|
-
├── .env.
|
|
49
|
-
├── .env.production # 生产环境变量(全局)
|
|
52
|
+
├── .env.development # 开发环境变量
|
|
53
|
+
├── .env.production # 生产环境变量
|
|
50
54
|
├── .gitignore # Git 忽略规则
|
|
51
55
|
├── .prettierrc.json # Prettier 格式化配置
|
|
52
56
|
```
|
package/bin/create.mjs
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @Author : TanRui
|
|
3
|
+
* @WeChat : Tan578853789
|
|
4
|
+
* @File : create.mjs
|
|
5
|
+
* @Date : 2026/01/01
|
|
6
|
+
* @Desc. : 脚手架创建脚本
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import { fileURLToPath } from 'url'
|
|
2
10
|
import { dirname, join, relative } from 'path'
|
|
3
11
|
import { promises as fs, existsSync } from 'fs'
|
|
@@ -68,6 +76,9 @@ async function main() {
|
|
|
68
76
|
const argv = minimist(process.argv.slice(2), { string: ['_'] })
|
|
69
77
|
let targetDir = argv._[0]
|
|
70
78
|
|
|
79
|
+
// 新增:判断是否使用当前目录
|
|
80
|
+
const isCurrentDir = targetDir === '.'
|
|
81
|
+
|
|
71
82
|
if (!targetDir) {
|
|
72
83
|
const { name } = await prompts({
|
|
73
84
|
type: 'text',
|
|
@@ -85,7 +96,8 @@ async function main() {
|
|
|
85
96
|
})
|
|
86
97
|
if (!name) process.exit(1)
|
|
87
98
|
targetDir = name
|
|
88
|
-
} else {
|
|
99
|
+
} else if (!isCurrentDir) {
|
|
100
|
+
// 仅当不是当前目录时,才校验包名和目录是否存在
|
|
89
101
|
if (!isValidPackageName(targetDir)) {
|
|
90
102
|
console.error('❌ 无效的项目名称:', targetDir)
|
|
91
103
|
console.error(' 包名称必须有效(小写、无空格等)')
|
|
@@ -97,7 +109,8 @@ async function main() {
|
|
|
97
109
|
}
|
|
98
110
|
}
|
|
99
111
|
|
|
100
|
-
|
|
112
|
+
// 设置根目录:如果是当前目录,则用 process.cwd()
|
|
113
|
+
const root = isCurrentDir ? process.cwd() : join(process.cwd(), targetDir.trim())
|
|
101
114
|
|
|
102
115
|
// 复制模板
|
|
103
116
|
const templateDir = join(__dirname, '..', 'jnrs-template-vue')
|
|
@@ -106,7 +119,13 @@ async function main() {
|
|
|
106
119
|
// 更新 package.json
|
|
107
120
|
const pkgPath = join(root, 'package.json')
|
|
108
121
|
const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'))
|
|
109
|
-
|
|
122
|
+
|
|
123
|
+
// 如果是当前目录,使用当前文件夹名称作为包名;否则使用 targetDir
|
|
124
|
+
const pkgName = isCurrentDir
|
|
125
|
+
? toValidPackageName(process.cwd().split(/[\\/]/).pop() || 'jnrs-template-vue')
|
|
126
|
+
: toValidPackageName(targetDir)
|
|
127
|
+
|
|
128
|
+
pkg.name = pkgName
|
|
110
129
|
await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2))
|
|
111
130
|
|
|
112
131
|
// 检测可用包管理器
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jnrs-template-vue",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.9",
|
|
4
4
|
"description": "JNRS 信息化管理系统",
|
|
5
5
|
"author": "talia_tan",
|
|
6
6
|
"private": true,
|
|
@@ -19,10 +19,11 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@element-plus/icons-vue": "^2.3.2",
|
|
22
|
-
"@jnrs/shared": "1.1.
|
|
22
|
+
"@jnrs/shared": "1.1.13",
|
|
23
23
|
"@jnrs/vue-core": "1.2.9",
|
|
24
|
+
"@jnrs/lingshu-smart": "*",
|
|
24
25
|
"@vueuse/core": "^14.1.0",
|
|
25
|
-
"element-plus": "^2.
|
|
26
|
+
"element-plus": "^2.13.3",
|
|
26
27
|
"pinia": "^3.0.4",
|
|
27
28
|
"pinia-plugin-persistedstate": "^4.7.1",
|
|
28
29
|
"vue": "^3.5.25",
|
|
@@ -66,6 +66,17 @@
|
|
|
66
66
|
},
|
|
67
67
|
"component": "/visual/index"
|
|
68
68
|
},
|
|
69
|
+
{
|
|
70
|
+
"path": "/lingshuSmart/editorPage",
|
|
71
|
+
"name": "LingshuSmartEditorPage",
|
|
72
|
+
"meta": {
|
|
73
|
+
"title": "Lingshu Smart",
|
|
74
|
+
"icon": "Promotion",
|
|
75
|
+
"noAuth": true,
|
|
76
|
+
"global": true
|
|
77
|
+
},
|
|
78
|
+
"component": "/lingshuSmart/editorPage"
|
|
79
|
+
},
|
|
69
80
|
{
|
|
70
81
|
"meta": {
|
|
71
82
|
"title": "系统管理",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Pagination, PageTableData, FileContainer } from '@/types'
|
|
2
|
-
import { axiosRequest } from '
|
|
2
|
+
import { axiosRequest } from '../request'
|
|
3
3
|
import { extractFieldId } from '@/utils/file'
|
|
4
4
|
import { objectToFormData } from '@/utils/packages'
|
|
5
5
|
|
|
@@ -63,6 +63,17 @@ export const NotFoundApi = () => {
|
|
|
63
63
|
})
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
/**
|
|
67
|
+
* 测试 不需要权限
|
|
68
|
+
*/
|
|
69
|
+
export const NoNeedAuthApi = () => {
|
|
70
|
+
return axiosRequest({
|
|
71
|
+
url: '/mock/auth/no',
|
|
72
|
+
method: 'post',
|
|
73
|
+
noAuth: true
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
66
77
|
/**
|
|
67
78
|
* 测试 无权限
|
|
68
79
|
* @param showErrorMsg 是否显示错误信息
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @Author : TanRui
|
|
3
|
+
* @WeChat : Tan578853789
|
|
4
|
+
* @File : request.ts
|
|
5
|
+
* @Date : 2025/11/10
|
|
6
|
+
* @Desc. : axios 网络请求实例
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { BusinessRequest, BusinessResponse } from '@jnrs/shared/request'
|
|
10
|
+
import { createAxiosInstance } from '@jnrs/shared/request'
|
|
11
|
+
import { useMockStore, useAuthStore } from '@jnrs/vue-core/pinia'
|
|
12
|
+
import { handleRouter } from '@jnrs/vue-core/router'
|
|
13
|
+
import { ElMessage } from 'element-plus'
|
|
14
|
+
|
|
15
|
+
const axiosInstance = createAxiosInstance({
|
|
16
|
+
// options: {
|
|
17
|
+
// noAuth: true // 全局设置为不需要权限
|
|
18
|
+
// },
|
|
19
|
+
handleMessageFn: ElMessage,
|
|
20
|
+
handleGetTokenFn: () => {
|
|
21
|
+
const { token } = useAuthStore()
|
|
22
|
+
return token
|
|
23
|
+
},
|
|
24
|
+
handleNoAuthFn: () => {
|
|
25
|
+
handleRouter({ name: 'Login' })
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* axios 请求方法(泛型拓展)
|
|
31
|
+
* @param options 请求配置项
|
|
32
|
+
* @returns Promise<T> 响应数据
|
|
33
|
+
*/
|
|
34
|
+
const axiosRequest = <T = BusinessResponse>(options: BusinessRequest): Promise<T> => {
|
|
35
|
+
if (!axiosInstance) {
|
|
36
|
+
throw new Error('请先调用 createRequest 初始化 axios 实例')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 如果是模拟请求,则将请求地址改为模拟地址
|
|
40
|
+
const { isMock } = useMockStore()
|
|
41
|
+
|
|
42
|
+
if (isMock) {
|
|
43
|
+
options.url = options.mockUrl
|
|
44
|
+
? options.mockUrl
|
|
45
|
+
: options.url.startsWith('/mock')
|
|
46
|
+
? options.url
|
|
47
|
+
: '/mock' + options.url
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return axiosInstance(options)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { axiosRequest }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Dict, DictItem, User, Role } from '@jnrs/shared'
|
|
2
2
|
import type { MenuItem } from '@jnrs/vue-core'
|
|
3
|
-
import { axiosRequest } from '
|
|
3
|
+
import { axiosRequest } from '../request'
|
|
4
4
|
import { objectToFormData } from '@/utils/packages'
|
|
5
5
|
|
|
6
6
|
// 菜单
|
|
@@ -8,7 +8,8 @@ export const MenuApi = (): Promise<MenuItem[]> => {
|
|
|
8
8
|
return axiosRequest({
|
|
9
9
|
url: '/system/menu.json', // /public 文件夹下
|
|
10
10
|
mockUrl: '/mock/menu',
|
|
11
|
-
method: 'get'
|
|
11
|
+
method: 'get',
|
|
12
|
+
noAuth: true // 本地数据忽略 token 验证
|
|
12
13
|
})
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="routerTabs">
|
|
3
|
+
<el-tabs v-model="activeTab" type="card" @tab-remove="removeTab" @tab-click="handleTabClick">
|
|
4
|
+
<el-tab-pane
|
|
5
|
+
v-for="item in tabs"
|
|
6
|
+
:key="item.fullPath"
|
|
7
|
+
:name="item.fullPath"
|
|
8
|
+
:closable="item.path !== HOME_PATH"
|
|
9
|
+
>
|
|
10
|
+
<template #label>
|
|
11
|
+
<span>{{ tabLabel(item) }}</span>
|
|
12
|
+
</template>
|
|
13
|
+
</el-tab-pane>
|
|
14
|
+
</el-tabs>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup>
|
|
19
|
+
import { ref, watch, computed, onMounted } from 'vue'
|
|
20
|
+
import { useRouter, useRoute } from 'vue-router'
|
|
21
|
+
|
|
22
|
+
const HOME_PATH = '/home/index'
|
|
23
|
+
const router = useRouter()
|
|
24
|
+
const route = useRoute()
|
|
25
|
+
|
|
26
|
+
// 使用 fullPath 作为激活 Tab 的值
|
|
27
|
+
const activeTab = ref(route.fullPath)
|
|
28
|
+
|
|
29
|
+
// Tab 列表:每个 tab 包含 fullPath、path、meta
|
|
30
|
+
const tabs = ref([
|
|
31
|
+
{
|
|
32
|
+
fullPath: route.fullPath,
|
|
33
|
+
path: route.path,
|
|
34
|
+
meta: route.meta
|
|
35
|
+
}
|
|
36
|
+
])
|
|
37
|
+
|
|
38
|
+
// 标签页标题计算
|
|
39
|
+
const tabLabel = computed(() => {
|
|
40
|
+
return function (item) {
|
|
41
|
+
let label = item.meta?.title || '未命名'
|
|
42
|
+
if (item.meta?.fullPathTitle) {
|
|
43
|
+
label = item.meta.fullPathTitle.replace(/,/g, '/')
|
|
44
|
+
}
|
|
45
|
+
return label
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
// 初始化:插入首页(如果当前不是首页)
|
|
50
|
+
onMounted(() => {
|
|
51
|
+
if (route.path !== HOME_PATH) {
|
|
52
|
+
tabs.value.unshift({
|
|
53
|
+
fullPath: HOME_PATH,
|
|
54
|
+
path: HOME_PATH,
|
|
55
|
+
meta: { title: '工作台' }
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// 添加标签页(基于当前 route)
|
|
61
|
+
const addTab = () => {
|
|
62
|
+
const currentRoute = route
|
|
63
|
+
|
|
64
|
+
// 如果已存在相同 fullPath 的 Tab,直接激活,不重复添加
|
|
65
|
+
const existingTab = tabs.value.find((tab) => tab.fullPath === currentRoute.fullPath)
|
|
66
|
+
if (existingTab) {
|
|
67
|
+
activeTab.value = currentRoute.fullPath
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 添加新 Tab
|
|
72
|
+
tabs.value.push({
|
|
73
|
+
fullPath: currentRoute.fullPath,
|
|
74
|
+
path: currentRoute.path,
|
|
75
|
+
meta: currentRoute.meta
|
|
76
|
+
})
|
|
77
|
+
activeTab.value = currentRoute.fullPath
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 移除标签页
|
|
81
|
+
const removeTab = (targetFullPath) => {
|
|
82
|
+
if (targetFullPath === HOME_PATH) return
|
|
83
|
+
|
|
84
|
+
const currentIndex = tabs.value.findIndex((tab) => tab.fullPath === targetFullPath)
|
|
85
|
+
if (currentIndex === -1) return
|
|
86
|
+
|
|
87
|
+
// 删除 Tab
|
|
88
|
+
tabs.value.splice(currentIndex, 1)
|
|
89
|
+
|
|
90
|
+
// 如果删除的是当前激活的 Tab
|
|
91
|
+
if (activeTab.value === targetFullPath) {
|
|
92
|
+
const nextTab = tabs.value[currentIndex] || tabs.value[currentIndex - 1]
|
|
93
|
+
if (nextTab) {
|
|
94
|
+
activeTab.value = nextTab.fullPath
|
|
95
|
+
router.push(nextTab.fullPath)
|
|
96
|
+
} else {
|
|
97
|
+
// 回退到首页
|
|
98
|
+
activeTab.value = HOME_PATH
|
|
99
|
+
router.push(HOME_PATH)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 监听路由变化(使用 fullPath)
|
|
105
|
+
watch(
|
|
106
|
+
() => route.fullPath,
|
|
107
|
+
(newFullPath) => {
|
|
108
|
+
// 避免由 Tab 点击触发的导航再次添加 Tab(防止循环)
|
|
109
|
+
if (newFullPath !== activeTab.value) {
|
|
110
|
+
addTab()
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{ immediate: true }
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
// 处理标签页点击
|
|
117
|
+
const handleTabClick = (tab) => {
|
|
118
|
+
const fullPath = tab.props.name // el-tab-pane 的 name 即 fullPath
|
|
119
|
+
if (fullPath !== activeTab.value) {
|
|
120
|
+
activeTab.value = fullPath
|
|
121
|
+
router.push(fullPath)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
</script>
|
|
125
|
+
|
|
126
|
+
<style lang="scss" scoped>
|
|
127
|
+
.routerTabs {
|
|
128
|
+
:deep(.el-tabs__header) {
|
|
129
|
+
margin-bottom: 0;
|
|
130
|
+
height: 32px;
|
|
131
|
+
}
|
|
132
|
+
:deep(.el-tabs__item) {
|
|
133
|
+
color: #888;
|
|
134
|
+
font-size: 12px;
|
|
135
|
+
height: 32px;
|
|
136
|
+
}
|
|
137
|
+
:deep(.el-tabs__item.is-active) {
|
|
138
|
+
color: #09a2a5;
|
|
139
|
+
border-bottom-color: #f2f2f2;
|
|
140
|
+
}
|
|
141
|
+
:deep(.el-tabs__nav-prev) {
|
|
142
|
+
color: #09a2a5;
|
|
143
|
+
background: #fff;
|
|
144
|
+
}
|
|
145
|
+
:deep(.el-tabs__nav-next) {
|
|
146
|
+
color: #09a2a5;
|
|
147
|
+
background: #fff;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
</style>
|
|
@@ -10,19 +10,6 @@ export const LAYOUT_NAME = 'Layout'
|
|
|
10
10
|
export const GLOBAL_COMPONENT = import('@/layout/BlankLayout.vue')
|
|
11
11
|
|
|
12
12
|
export const routes = [
|
|
13
|
-
// {
|
|
14
|
-
// path: '/login',
|
|
15
|
-
// component: () => import('@/layout/BlankLayout.vue'),
|
|
16
|
-
// meta: { title: '登录' },
|
|
17
|
-
// children: [
|
|
18
|
-
// {
|
|
19
|
-
// path: '',
|
|
20
|
-
// name: 'Login',
|
|
21
|
-
// meta: { title: '登录', noAuth: true },
|
|
22
|
-
// component: () => import('@/views/login/index.vue')
|
|
23
|
-
// }
|
|
24
|
-
// ]
|
|
25
|
-
// },
|
|
26
13
|
{
|
|
27
14
|
name: '403',
|
|
28
15
|
path: '/403',
|
|
@@ -94,9 +94,9 @@ const handleFileView = async () => {
|
|
|
94
94
|
<p>网络请求测试</p>
|
|
95
95
|
<el-button-group>
|
|
96
96
|
<el-button type="success" size="small" @click="handleInfoApi">获取用户数据</el-button>
|
|
97
|
-
<el-button type="primary" size="small" @click="handleNotFoundApi"
|
|
98
|
-
<el-button type="primary" size="small" @click="handleNoAuth()"
|
|
99
|
-
<el-button type="primary" size="small" @click="handleNoAuth(false)"
|
|
97
|
+
<el-button type="primary" size="small" @click="handleNotFoundApi">接口返回404</el-button>
|
|
98
|
+
<el-button type="primary" size="small" @click="handleNoAuth()">接口返回暂无权限</el-button>
|
|
99
|
+
<el-button type="primary" size="small" @click="handleNoAuth(false)">接口返回暂无权限(不显示 Message)</el-button>
|
|
100
100
|
</el-button-group>
|
|
101
101
|
<el-input v-model="loginParams.account" size="small" style="width: 200px">
|
|
102
102
|
<template #append>
|
|
@@ -40,14 +40,15 @@ const submitForm = async () => {
|
|
|
40
40
|
ruleFormRef.value.validate(async (valid) => {
|
|
41
41
|
if (!valid) return
|
|
42
42
|
loading.value = true
|
|
43
|
+
|
|
43
44
|
try {
|
|
44
45
|
const loginRes = await LoginApi(ruleForm.value)
|
|
45
46
|
const { token, dict, ...restParameter } = loginRes
|
|
46
47
|
const loginDateTime = formatDateTime() + ' ' + formatWeekday()
|
|
47
48
|
|
|
49
|
+
// 登录成功后,获取角色列表,将登录人角色对应的权限叠加给当前登录人(一次性获取叠加)
|
|
48
50
|
let permissionsMerger = restParameter.permissions
|
|
49
51
|
try {
|
|
50
|
-
// 获取角色列表,将登录人角色对应的权限叠加给当前登录人(一次性获取叠加)
|
|
51
52
|
const roleRes = await RoleApi()
|
|
52
53
|
if (Array.isArray(restParameter.permissions)) {
|
|
53
54
|
permissionsMerger = [
|
|
@@ -62,6 +63,7 @@ const submitForm = async () => {
|
|
|
62
63
|
console.log(e)
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
// 保存用户信息到全局状态
|
|
65
67
|
setUserInfo({
|
|
66
68
|
...restParameter,
|
|
67
69
|
permissions: permissionsMerger,
|