create-jnrs-template-vue 1.1.6 → 1.1.7
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/jnrs-template-vue/.env.development +4 -5
- package/jnrs-template-vue/.env.production +1 -1
- package/jnrs-template-vue/components.d.ts +4 -0
- package/jnrs-template-vue/package.json +1 -1
- package/jnrs-template-vue/public/system/menu.json +1 -2
- package/jnrs-template-vue/src/api/request.ts +4 -1
- package/jnrs-template-vue/src/api/system/index.ts +19 -15
- package/jnrs-template-vue/src/directives/permissions.ts +28 -0
- package/jnrs-template-vue/src/layout/SideMenu.vue +2 -4
- package/jnrs-template-vue/src/layout/TopHeader.vue +10 -6
- package/jnrs-template-vue/src/locales/index.ts +10 -3
- package/jnrs-template-vue/src/main.ts +3 -0
- package/jnrs-template-vue/src/router/index.ts +35 -6
- package/jnrs-template-vue/src/router/routes.ts +28 -28
- package/jnrs-template-vue/src/stores/mock.ts +4 -2
- package/jnrs-template-vue/src/utils/permissions.ts +16 -0
- package/jnrs-template-vue/src/views/common/403.vue +3 -7
- package/jnrs-template-vue/src/views/common/404.vue +3 -7
- package/jnrs-template-vue/src/views/home/index.vue +52 -18
- package/jnrs-template-vue/src/views/login/index.vue +27 -6
- package/jnrs-template-vue/src/views/system/dict/index.vue +13 -15
- package/jnrs-template-vue/src/views/system/menu/index.vue +22 -24
- package/jnrs-template-vue/src/views/system/mine/baseInfo.vue +2 -2
- package/jnrs-template-vue/src/views/system/mine/securitySettings.vue +2 -2
- package/jnrs-template-vue/src/views/system/role/index.vue +23 -9
- package/jnrs-template-vue/viteMockServe/index.ts +22 -6
- package/jnrs-template-vue/viteMockServe/{loginRes.json → loginRes_admin.json} +4 -4
- package/jnrs-template-vue/viteMockServe/loginRes_user.json +713 -0
- package/jnrs-template-vue/viteMockServe/roleRes.json +37 -0
- package/package.json +1 -1
- package/jnrs-template-vue/.env.example +0 -14
- package/jnrs-template-vue/src/types/index.d.ts +0 -6
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { FormInstance, FormRules } from 'element-plus'
|
|
3
3
|
import { ref } from 'vue'
|
|
4
|
-
import { LoginApi } from '@/api/system'
|
|
4
|
+
import { RoleApi, LoginApi } from '@/api/system'
|
|
5
5
|
import { useAuthStore } from '@/stores'
|
|
6
6
|
import { handleRouter, useRoute } from '@jnrs/vue-core/router'
|
|
7
7
|
import { isWeakPwd } from '@jnrs/shared/validator'
|
|
@@ -9,7 +9,12 @@ import { formatDateTime, formatWeekday } from '@jnrs/shared'
|
|
|
9
9
|
|
|
10
10
|
const route = useRoute()
|
|
11
11
|
const loading = ref(false)
|
|
12
|
-
const {
|
|
12
|
+
const {
|
|
13
|
+
setUserInfo,
|
|
14
|
+
setToken,
|
|
15
|
+
setDict
|
|
16
|
+
// setRole
|
|
17
|
+
} = useAuthStore()
|
|
13
18
|
|
|
14
19
|
// 表单 ref
|
|
15
20
|
const ruleFormRef = ref<FormInstance>()
|
|
@@ -28,24 +33,40 @@ const rules = ref<FormRules>({
|
|
|
28
33
|
})
|
|
29
34
|
|
|
30
35
|
// 提交函数
|
|
31
|
-
const submitForm = () => {
|
|
36
|
+
const submitForm = async () => {
|
|
32
37
|
if (!ruleFormRef.value) return
|
|
33
38
|
ruleFormRef.value.validate(async (valid) => {
|
|
34
39
|
if (!valid) return
|
|
35
40
|
loading.value = true
|
|
36
41
|
try {
|
|
37
|
-
const
|
|
38
|
-
const { token, dict, ...restParameter } =
|
|
42
|
+
const loginRes = await LoginApi(ruleForm.value)
|
|
43
|
+
const { token, dict, ...restParameter } = loginRes
|
|
39
44
|
const loginDateTime = formatDateTime() + ' ' + formatWeekday()
|
|
45
|
+
|
|
46
|
+
// 获取角色列表,将登录人角色对应的权限叠加给当前登录人(一次性获取叠加)
|
|
47
|
+
const roleRes = await RoleApi()
|
|
48
|
+
let permissionsMerger = restParameter.permissions
|
|
49
|
+
if (Array.isArray(restParameter.permissions)) {
|
|
50
|
+
permissionsMerger = [
|
|
51
|
+
...new Set([
|
|
52
|
+
...restParameter.permissions,
|
|
53
|
+
...(roleRes.find((r) => r.value === restParameter.role)?.permissions ?? []).flat()
|
|
54
|
+
])
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
// setRole(roleRes) // 由于是一次性获取叠加,此处不需要保存角色列表到全局状态
|
|
58
|
+
|
|
40
59
|
setUserInfo({
|
|
41
60
|
...restParameter,
|
|
61
|
+
permissions: permissionsMerger,
|
|
42
62
|
account: ruleForm.value.account,
|
|
43
63
|
loginDateTime
|
|
44
64
|
})
|
|
45
65
|
setToken(token)
|
|
46
66
|
setDict(dict)
|
|
47
67
|
handleRouter({ path: route.query.redirect?.toString() || '/' }, 'replace')
|
|
48
|
-
} catch {
|
|
68
|
+
} catch (e) {
|
|
69
|
+
console.log(e)
|
|
49
70
|
} finally {
|
|
50
71
|
loading.value = false
|
|
51
72
|
}
|
|
@@ -4,8 +4,10 @@ import { ref, onActivated } from 'vue'
|
|
|
4
4
|
import { DictApi, DictDetailApi, DictChangeApi } from '@/api/system'
|
|
5
5
|
import { useAsyncTableHeight } from '@jnrs/vue-core/composables'
|
|
6
6
|
import type { DictItem } from '@jnrs/shared'
|
|
7
|
+
import { hasPermission } from '@/utils/permissions'
|
|
7
8
|
|
|
8
9
|
const { maxHeight } = useAsyncTableHeight('el_table_dict', 0)
|
|
10
|
+
const PERMISSION_EDIT = ['dict:edit']
|
|
9
11
|
const loading = ref(false)
|
|
10
12
|
const tableData = ref<DictItem[]>()
|
|
11
13
|
const predefineColors = ref([
|
|
@@ -92,23 +94,19 @@ const editKeyValue = (row: DictItem) => {
|
|
|
92
94
|
<el-table-column prop="describe" label="说明" />
|
|
93
95
|
<el-table-column type="expand" fixed="right" label="字典值" width="100">
|
|
94
96
|
<template #default="scope">
|
|
95
|
-
<div
|
|
96
|
-
class="table_expand animation15"
|
|
97
|
-
style="animation-duration: 0.5s; animation-delay: 0s"
|
|
98
|
-
>
|
|
97
|
+
<div class="table_expand animation15" style="animation-duration: 0.5s; animation-delay: 0s">
|
|
99
98
|
<div class="table_expand_top">
|
|
100
99
|
<h5>字典值列表</h5>
|
|
101
100
|
</div>
|
|
102
101
|
<el-table :data="scope.row.options" :border="true" size="small" row-key="value">
|
|
103
|
-
<el-table-column
|
|
104
|
-
label="value"
|
|
105
|
-
prop="value"
|
|
106
|
-
width="100"
|
|
107
|
-
align="center"
|
|
108
|
-
></el-table-column>
|
|
102
|
+
<el-table-column label="value" prop="value" width="100" align="center"></el-table-column>
|
|
109
103
|
<el-table-column label="label" prop="label">
|
|
110
104
|
<template #default="optionScope">
|
|
111
|
-
<el-input
|
|
105
|
+
<el-input
|
|
106
|
+
v-model="optionScope.row.label"
|
|
107
|
+
maxlength="20"
|
|
108
|
+
:disabled="!hasPermission(PERMISSION_EDIT)"
|
|
109
|
+
/>
|
|
112
110
|
</template>
|
|
113
111
|
</el-table-column>
|
|
114
112
|
<el-table-column label="颜色" prop="displayColor">
|
|
@@ -116,6 +114,7 @@ const editKeyValue = (row: DictItem) => {
|
|
|
116
114
|
<el-color-picker
|
|
117
115
|
v-model="optionScope.row.displayColor"
|
|
118
116
|
:predefine="predefineColors"
|
|
117
|
+
:disabled="!hasPermission(PERMISSION_EDIT)"
|
|
119
118
|
/>
|
|
120
119
|
<span style="margin-left: 10px">
|
|
121
120
|
{{ optionScope.row.displayColor || '无' }}
|
|
@@ -131,15 +130,14 @@ const editKeyValue = (row: DictItem) => {
|
|
|
131
130
|
:step="1"
|
|
132
131
|
controls-position="right"
|
|
133
132
|
step-strictly
|
|
133
|
+
:disabled="!hasPermission(PERMISSION_EDIT)"
|
|
134
134
|
style="width: 140px"
|
|
135
135
|
/>
|
|
136
136
|
</template>
|
|
137
137
|
</el-table-column>
|
|
138
|
-
<el-table-column label="操作" width="100" align="center" fixed="right">
|
|
138
|
+
<el-table-column label="操作" width="100" align="center" fixed="right" v-permissions="PERMISSION_EDIT">
|
|
139
139
|
<template #default="optionScope">
|
|
140
|
-
<el-button type="success" size="small" @click="editKeyValue(optionScope.row)">
|
|
141
|
-
确认修改
|
|
142
|
-
</el-button>
|
|
140
|
+
<el-button type="success" size="small" @click="editKeyValue(optionScope.row)">确认修改</el-button>
|
|
143
141
|
</template>
|
|
144
142
|
</el-table-column>
|
|
145
143
|
</el-table>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref } from 'vue'
|
|
3
3
|
import { useMenuStore } from '@/stores'
|
|
4
|
-
import { getDictLabel } from '@/utils/common'
|
|
5
4
|
import { useAsyncTableHeight } from '@jnrs/vue-core/composables'
|
|
6
5
|
|
|
7
6
|
const { maxHeight } = useAsyncTableHeight('el_table_menu', 0)
|
|
@@ -27,38 +26,37 @@ const { menus } = useMenuStore()
|
|
|
27
26
|
border
|
|
28
27
|
v-loading="loading"
|
|
29
28
|
>
|
|
30
|
-
<el-table-column prop="meta.title" label="
|
|
31
|
-
<el-table-column prop="
|
|
32
|
-
<el-table-column prop="role" label="权限" min-width="120">
|
|
29
|
+
<el-table-column prop="meta.title" label="标题" min-width="120" header-align="center" />
|
|
30
|
+
<el-table-column prop="icon" label="图标" width="60" align="center">
|
|
33
31
|
<template #default="{ row }">
|
|
34
|
-
<
|
|
35
|
-
<template v-else>
|
|
36
|
-
{{ row.meta.role.map((d: string | number) => getDictLabel('role', d)) }}
|
|
37
|
-
</template>
|
|
32
|
+
<el-icon v-if="row.meta.icon"><component :is="row.meta.icon" /></el-icon>
|
|
38
33
|
</template>
|
|
39
34
|
</el-table-column>
|
|
40
|
-
<el-table-column prop="
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
</template>
|
|
48
|
-
<!-- <template v-else>
|
|
49
|
-
{{ scope.row.editRole.map((d) => getDictLabel('role', d.split('Role')[1])) }}
|
|
50
|
-
</template> -->
|
|
35
|
+
<el-table-column prop="path" label="路由地址" min-width="120" header-align="center" />
|
|
36
|
+
<el-table-column prop="component" label="component path" min-width="120" header-align="center" />
|
|
37
|
+
<el-table-column prop="redirect" label="redirect" min-width="120" header-align="center" />
|
|
38
|
+
<el-table-column prop="editRole" label="权限标识" min-width="120" header-align="center">
|
|
39
|
+
<template #default="{ row }">
|
|
40
|
+
<span v-if="!row.meta.permissions" style="color: #999">auto</span>
|
|
41
|
+
<span v-else>{{ row.meta.permissions }}</span>
|
|
51
42
|
</template>
|
|
52
43
|
</el-table-column>
|
|
53
44
|
<el-table-column prop="type" label="类型" width="80" align="center">
|
|
54
|
-
<template #default="
|
|
55
|
-
<el-tag type="primary" v-if="
|
|
45
|
+
<template #default="{ row }">
|
|
46
|
+
<el-tag type="primary" v-if="row.path">菜单</el-tag>
|
|
56
47
|
<el-tag type="success" v-else>目录</el-tag>
|
|
57
48
|
</template>
|
|
58
49
|
</el-table-column>
|
|
59
|
-
<el-table-column prop="
|
|
60
|
-
<template #default="
|
|
61
|
-
<el-
|
|
50
|
+
<el-table-column prop="type" label="NoAuth" width="80" align="center">
|
|
51
|
+
<template #default="{ row }">
|
|
52
|
+
<el-tag type="danger" v-if="row.meta.noAuth">否</el-tag>
|
|
53
|
+
<el-tag type="success" v-else>是</el-tag>
|
|
54
|
+
</template>
|
|
55
|
+
</el-table-column>
|
|
56
|
+
<el-table-column prop="type" label="Global" width="80" align="center">
|
|
57
|
+
<template #default="{ row }">
|
|
58
|
+
<el-tag type="success" v-if="row.meta.global">是</el-tag>
|
|
59
|
+
<el-tag type="primary" v-else>否</el-tag>
|
|
62
60
|
</template>
|
|
63
61
|
</el-table-column>
|
|
64
62
|
</el-table>
|
|
@@ -77,7 +77,7 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
|
|
77
77
|
<el-input v-model.trim="ruleForm.workNo" style="width: 200px" />
|
|
78
78
|
</el-form-item>
|
|
79
79
|
<el-form-item label="职称" prop="jobTitle">
|
|
80
|
-
<el-select v-model="ruleForm.jobTitle" style="width: 200px">
|
|
80
|
+
<el-select v-model="ruleForm.jobTitle" placeholder="" style="width: 200px">
|
|
81
81
|
<el-option
|
|
82
82
|
:label="item.label"
|
|
83
83
|
:value="item.value"
|
|
@@ -90,7 +90,7 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
|
|
90
90
|
<el-input v-model.trim="ruleForm.workgroup" style="width: 200px" />
|
|
91
91
|
</el-form-item>
|
|
92
92
|
<el-form-item label="职位/账号权限" prop="role">
|
|
93
|
-
<el-select v-model="ruleForm.role" style="width: 200px">
|
|
93
|
+
<el-select v-model="ruleForm.role" placeholder="" style="width: 200px">
|
|
94
94
|
<el-option
|
|
95
95
|
:label="item.label"
|
|
96
96
|
:value="item.value"
|
|
@@ -8,7 +8,7 @@ import type { FormInstance, FormItemRule } from 'element-plus'
|
|
|
8
8
|
import { ElMessage } from 'element-plus'
|
|
9
9
|
import { LogoutApi } from '@/api/system'
|
|
10
10
|
|
|
11
|
-
const { userInfo,
|
|
11
|
+
const { userInfo, clearAuth } = useAuthStore()
|
|
12
12
|
const loading = ref(false)
|
|
13
13
|
const formRef = ref<FormInstance>()
|
|
14
14
|
const ruleForm = ref({
|
|
@@ -53,7 +53,7 @@ const submitForm = async (formEl: FormInstance | undefined) => {
|
|
|
53
53
|
})
|
|
54
54
|
ElMessage.success('密码修改成功,请重新登录系统')
|
|
55
55
|
await LogoutApi()
|
|
56
|
-
await
|
|
56
|
+
await clearAuth()
|
|
57
57
|
handleRouter({ name: 'Login' }, 'replace')
|
|
58
58
|
}
|
|
59
59
|
} catch {
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref } from 'vue'
|
|
3
|
-
import {
|
|
2
|
+
import { ref, onMounted } from 'vue'
|
|
3
|
+
import { RoleApi } from '@/api/system'
|
|
4
4
|
|
|
5
|
-
const { dict } = useAuthStore()
|
|
6
5
|
const loading = ref(false)
|
|
7
|
-
const tableData = ref(
|
|
6
|
+
const tableData = ref()
|
|
7
|
+
|
|
8
|
+
const handleRoleApi = async () => {
|
|
9
|
+
try {
|
|
10
|
+
const res = await RoleApi()
|
|
11
|
+
tableData.value = res
|
|
12
|
+
} catch {}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
onMounted(() => {
|
|
16
|
+
handleRoleApi()
|
|
17
|
+
})
|
|
8
18
|
</script>
|
|
9
19
|
|
|
10
20
|
<template>
|
|
@@ -23,11 +33,15 @@ const tableData = ref(dict?.role)
|
|
|
23
33
|
border
|
|
24
34
|
v-loading="loading"
|
|
25
35
|
>
|
|
26
|
-
<el-table-column prop="label" label="角色名称" align="center" />
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
<el-table-column prop="label" label="角色名称" width="200" align="center" />
|
|
37
|
+
<el-table-column prop="value" label="值" width="200" align="center">
|
|
38
|
+
<template #default="{ row }">
|
|
39
|
+
{{ row.value + ' [' + typeof row.value + ']' }}
|
|
40
|
+
</template>
|
|
41
|
+
</el-table-column>
|
|
42
|
+
<el-table-column prop="permissions" label="可用权限" header-align="center">
|
|
43
|
+
<template #default="{ row }">
|
|
44
|
+
{{ row.permissions }}
|
|
31
45
|
</template>
|
|
32
46
|
</el-table-column>
|
|
33
47
|
</el-table>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import menuRes from '../public/system/menu.json'
|
|
1
2
|
import successMock from './success'
|
|
2
3
|
import failMock from './fail'
|
|
3
|
-
import
|
|
4
|
+
import loginRes_admin from './loginRes_admin.json'
|
|
5
|
+
import loginRes_user from './loginRes_user.json'
|
|
4
6
|
import dictRes from './dictRes.json'
|
|
5
7
|
import dictItemRes from './dictItemRes.json'
|
|
6
|
-
import
|
|
8
|
+
import roleRes from './roleRes.json'
|
|
7
9
|
|
|
8
10
|
export default [
|
|
9
11
|
...successMock,
|
|
@@ -20,16 +22,22 @@ export default [
|
|
|
20
22
|
{
|
|
21
23
|
url: '/mock/api/auth/login',
|
|
22
24
|
method: 'post',
|
|
23
|
-
response: () => {
|
|
24
|
-
|
|
25
|
+
response: ({ body }) => {
|
|
26
|
+
if (body.account === 'admin') {
|
|
27
|
+
return loginRes_admin
|
|
28
|
+
}
|
|
29
|
+
return loginRes_user
|
|
25
30
|
}
|
|
26
31
|
},
|
|
27
32
|
// 获取个人信息
|
|
28
33
|
{
|
|
29
34
|
url: '/mock/api/auth/user-info',
|
|
30
35
|
method: 'get',
|
|
31
|
-
response: () => {
|
|
32
|
-
|
|
36
|
+
response: ({ headers }) => {
|
|
37
|
+
if (headers.authorization.includes('admin')) {
|
|
38
|
+
return loginRes_admin
|
|
39
|
+
}
|
|
40
|
+
return loginRes_user
|
|
33
41
|
}
|
|
34
42
|
},
|
|
35
43
|
// 获取字典
|
|
@@ -47,5 +55,13 @@ export default [
|
|
|
47
55
|
response: () => {
|
|
48
56
|
return dictItemRes
|
|
49
57
|
}
|
|
58
|
+
},
|
|
59
|
+
// 获取角色
|
|
60
|
+
{
|
|
61
|
+
url: '/mock/api/role-manager',
|
|
62
|
+
method: 'get',
|
|
63
|
+
response: () => {
|
|
64
|
+
return roleRes
|
|
65
|
+
}
|
|
50
66
|
}
|
|
51
67
|
]
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"data": {
|
|
3
|
-
"token": "
|
|
3
|
+
"token": "***admin***token***",
|
|
4
4
|
"id": 1,
|
|
5
5
|
"name": "管理员",
|
|
6
6
|
"workNo": "000000",
|
|
7
|
-
"
|
|
7
|
+
"avatarFileName": "20251014181230905-b2bd246f-4174-4804-8122-37c826c56a7d.png",
|
|
8
8
|
"workgroup": null,
|
|
9
|
-
"jobTitle":
|
|
9
|
+
"jobTitle": 1,
|
|
10
10
|
"role": 6,
|
|
11
|
-
"permissions": [
|
|
11
|
+
"permissions": [],
|
|
12
12
|
"abilityCoefficient": 0.0,
|
|
13
13
|
"dict": {
|
|
14
14
|
"defectiveWorkHourStatus": [
|