create-jnrs-template-vue 1.1.7 → 1.1.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/jnrs-template-vue/.env.development +3 -2
- package/jnrs-template-vue/package.json +4 -4
- package/jnrs-template-vue/public/system/menu.json +30 -11
- package/jnrs-template-vue/src/api/mock/index.ts +11 -0
- package/jnrs-template-vue/src/assets/styles/common.scss +23 -0
- package/jnrs-template-vue/src/assets/styles/main.scss +1 -0
- package/jnrs-template-vue/src/layout/TopHeader.vue +4 -23
- package/jnrs-template-vue/src/locales/en.ts +6 -1
- package/jnrs-template-vue/src/locales/zhCn.ts +6 -1
- package/jnrs-template-vue/src/types/index.ts +14 -0
- package/jnrs-template-vue/src/utils/common.ts +21 -0
- package/jnrs-template-vue/src/views/demos/unitTest/index.vue +184 -0
- package/jnrs-template-vue/src/views/home/index.vue +3 -146
- package/jnrs-template-vue/src/views/login/index.vue +43 -6
- package/jnrs-template-vue/tsconfig.json +1 -0
- package/jnrs-template-vue/viteMockServe/detailsRes.json +56 -0
- package/jnrs-template-vue/viteMockServe/index.ts +9 -0
- package/package.json +1 -1
- /package/jnrs-template-vue/src/views/{crud → demos/crud}/index.vue +0 -0
|
@@ -4,9 +4,10 @@ ENV = 'development'
|
|
|
4
4
|
VITE_USE_MOCK = true
|
|
5
5
|
|
|
6
6
|
# 后端接口基地址 - 开发环境
|
|
7
|
-
VITE_BASE_URL = '192.168.1.120:6001'
|
|
7
|
+
# VITE_BASE_URL = '192.168.1.120:6001'
|
|
8
|
+
VITE_BASE_URL = '192.168.1.120:5010'
|
|
8
9
|
|
|
9
10
|
# 应用运行主机(置空默认为 localhost)
|
|
10
11
|
VITE_APP_HOST = ''
|
|
11
|
-
#
|
|
12
|
+
# 应用运行端口(0 为自动分配)
|
|
12
13
|
VITE_APP_PORT = 5788
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jnrs-template-vue",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"description": "JNRS 信息化管理系统模板",
|
|
5
5
|
"author": "Talia-Tan",
|
|
6
6
|
"private": true,
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@element-plus/icons-vue": "^2.3.2",
|
|
22
|
-
"@jnrs/core": "
|
|
23
|
-
"@jnrs/shared": "
|
|
24
|
-
"@jnrs/vue-core": "
|
|
22
|
+
"@jnrs/core": "workspace:*",
|
|
23
|
+
"@jnrs/shared": "workspace:*",
|
|
24
|
+
"@jnrs/vue-core": "workspace:*",
|
|
25
25
|
"element-plus": "^2.11.9",
|
|
26
26
|
"pinia": "^3.0.4",
|
|
27
27
|
"pinia-plugin-persistedstate": "^4.7.1",
|
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
"code": 0,
|
|
3
3
|
"msg": "操作成功",
|
|
4
4
|
"data": [
|
|
5
|
+
{
|
|
6
|
+
"path": "/demos",
|
|
7
|
+
"name": "Demos",
|
|
8
|
+
"meta": {
|
|
9
|
+
"title": "功能演示",
|
|
10
|
+
"icon": "StarFilled",
|
|
11
|
+
"todoCount": 4
|
|
12
|
+
},
|
|
13
|
+
"children": [
|
|
14
|
+
{
|
|
15
|
+
"path": "/unitTest",
|
|
16
|
+
"name": "UnitTest",
|
|
17
|
+
"meta": {
|
|
18
|
+
"title": "测试页面",
|
|
19
|
+
"todoCount": 8
|
|
20
|
+
},
|
|
21
|
+
"component": "/demos/unitTest/index"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"path": "/crud",
|
|
25
|
+
"name": "Crud",
|
|
26
|
+
"meta": {
|
|
27
|
+
"title": "增删改查模板页面",
|
|
28
|
+
"todoCount": 0
|
|
29
|
+
},
|
|
30
|
+
"component": "/demos/crud/index"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
},
|
|
5
34
|
{
|
|
6
35
|
"path": "/visual",
|
|
7
36
|
"name": "Visual",
|
|
@@ -13,16 +42,6 @@
|
|
|
13
42
|
},
|
|
14
43
|
"component": "/visual/index"
|
|
15
44
|
},
|
|
16
|
-
{
|
|
17
|
-
"path": "/crud",
|
|
18
|
-
"name": "Crud",
|
|
19
|
-
"meta": {
|
|
20
|
-
"title": "测试页面",
|
|
21
|
-
"icon": "StarFilled",
|
|
22
|
-
"todoCount": 8
|
|
23
|
-
},
|
|
24
|
-
"component": "/crud/index"
|
|
25
|
-
},
|
|
26
45
|
{
|
|
27
46
|
"meta": {
|
|
28
47
|
"title": "系统管理",
|
|
@@ -35,7 +54,7 @@
|
|
|
35
54
|
"name": "SystemMine",
|
|
36
55
|
"meta": {
|
|
37
56
|
"title": "个人中心",
|
|
38
|
-
"todoCount":
|
|
57
|
+
"todoCount": 999,
|
|
39
58
|
"permissions": ["mine:view", "mine:edit"]
|
|
40
59
|
},
|
|
41
60
|
"component": "/system/mine/index"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { request } from '../request'
|
|
2
|
+
import type { ApiResponse } from '@/types'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* 404 错误
|
|
@@ -21,3 +22,13 @@ export const NoAuth = (showErrorMsg: boolean) => {
|
|
|
21
22
|
showErrorMsg
|
|
22
23
|
})
|
|
23
24
|
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 数据详情
|
|
28
|
+
*/
|
|
29
|
+
export const DetailsApi = (): Promise<ApiResponse> => {
|
|
30
|
+
return request({
|
|
31
|
+
url: '/details',
|
|
32
|
+
method: 'get'
|
|
33
|
+
})
|
|
34
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.topBarBtn {
|
|
2
|
+
position: relative;
|
|
3
|
+
margin: 0 8px;
|
|
4
|
+
font-size: 22px;
|
|
5
|
+
transition: all 0.25s ease 0s;
|
|
6
|
+
cursor: pointer;
|
|
7
|
+
&:hover {
|
|
8
|
+
color: var(--jnrs-color-primary);
|
|
9
|
+
&::after {
|
|
10
|
+
content: '';
|
|
11
|
+
position: absolute;
|
|
12
|
+
top: 50%;
|
|
13
|
+
left: 50%;
|
|
14
|
+
transform: translate(-50%, -50%);
|
|
15
|
+
width: 32px;
|
|
16
|
+
height: 32px;
|
|
17
|
+
background: var(--jnrs-color-primary);
|
|
18
|
+
opacity: 0.1;
|
|
19
|
+
border-radius: 50%;
|
|
20
|
+
transition: all 0.25s ease 0s;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -44,7 +44,7 @@ const showGlobalSetting = () => {
|
|
|
44
44
|
<div class="topHeader">
|
|
45
45
|
<div class="left">
|
|
46
46
|
<el-icon
|
|
47
|
-
class="
|
|
47
|
+
class="topBarBtn"
|
|
48
48
|
title="可视化看板"
|
|
49
49
|
@click="
|
|
50
50
|
handleRouter({
|
|
@@ -56,10 +56,10 @@ const showGlobalSetting = () => {
|
|
|
56
56
|
</el-icon>
|
|
57
57
|
</div>
|
|
58
58
|
<div class="right">
|
|
59
|
-
<el-icon class="
|
|
59
|
+
<el-icon class="topBarBtn" title="全局偏好设置" @click="showGlobalSetting()">
|
|
60
60
|
<el-icon><Setting /></el-icon>
|
|
61
61
|
</el-icon>
|
|
62
|
-
<el-icon class="
|
|
62
|
+
<el-icon class="topBarBtn" title="全屏切换" @click="toggleFullScreen()">
|
|
63
63
|
<component :is="!documentFullscreen ? 'FullScreen' : 'Rank'" />
|
|
64
64
|
</el-icon>
|
|
65
65
|
<!-- 头像和用户名 -->
|
|
@@ -118,27 +118,8 @@ $topHoverSize: 35px;
|
|
|
118
118
|
padding: 0 8px;
|
|
119
119
|
box-shadow: 0 1px 2px var(--jnrs-font-primary-03);
|
|
120
120
|
|
|
121
|
-
.
|
|
122
|
-
position: relative;
|
|
123
|
-
margin: 0 8px;
|
|
121
|
+
.topBarBtn {
|
|
124
122
|
font-size: 22px;
|
|
125
|
-
transition: all 0.25s ease 0s;
|
|
126
|
-
cursor: pointer;
|
|
127
|
-
&:hover {
|
|
128
|
-
color: var(--jnrs-color-primary);
|
|
129
|
-
&::after {
|
|
130
|
-
content: '';
|
|
131
|
-
position: absolute;
|
|
132
|
-
top: 50%;
|
|
133
|
-
left: 50%;
|
|
134
|
-
transform: translate(-50%, -50%);
|
|
135
|
-
width: $topHoverSize;
|
|
136
|
-
height: $topHoverSize;
|
|
137
|
-
background: var(--jnrs-color-primary);
|
|
138
|
-
opacity: 0.1;
|
|
139
|
-
border-radius: 50%;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
123
|
}
|
|
143
124
|
|
|
144
125
|
.left,
|
|
@@ -3,7 +3,12 @@ export default {
|
|
|
3
3
|
title: 'Management System'
|
|
4
4
|
},
|
|
5
5
|
login: {
|
|
6
|
-
title: '
|
|
6
|
+
title: 'Management System',
|
|
7
|
+
formTitle: 'Login',
|
|
8
|
+
formAccount: 'Please enter your account',
|
|
9
|
+
formPassword: 'Please enter your password',
|
|
10
|
+
formBtn: 'Log In',
|
|
11
|
+
greeting: 'Welcome to'
|
|
7
12
|
},
|
|
8
13
|
layout: {}
|
|
9
14
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface Attachment {
|
|
2
|
+
id: string
|
|
3
|
+
uniqueFileName: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface AttachmentDocument {
|
|
7
|
+
attachments: Attachment[]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ApiResponse {
|
|
11
|
+
attachmentDocument?: AttachmentDocument
|
|
12
|
+
imageDocument?: AttachmentDocument
|
|
13
|
+
[key: string]: unknown
|
|
14
|
+
}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
getDictColor as _getDictColor
|
|
6
6
|
} from '@jnrs/shared'
|
|
7
7
|
import { useAuthStore } from '@jnrs/vue-core/pinia'
|
|
8
|
+
import { objectToFormData as _objectToFormData } from '@jnrs/shared'
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* 根据字典名称获取字典数据
|
|
@@ -56,3 +57,23 @@ export const getDictColor = (name: string, value: string | number) => {
|
|
|
56
57
|
return _getDictColor(name, value, dict)
|
|
57
58
|
}
|
|
58
59
|
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 将对象转为 FormData
|
|
63
|
+
* @param obj 对象
|
|
64
|
+
* @returns FormData
|
|
65
|
+
*/
|
|
66
|
+
export const objectToFormData = (obj: Record<string, unknown>) => {
|
|
67
|
+
// 根据后端返回结果处理的映射关系
|
|
68
|
+
const mapConfig = {
|
|
69
|
+
// 图片
|
|
70
|
+
newImageFiles: { finallyKey: 'orginImageNames', valueKey: 'uniqueFileName' },
|
|
71
|
+
// 通用附件
|
|
72
|
+
newAttachmentFile: { finallyKey: 'orginAttachmentName', valueKey: 'uniqueFileName' },
|
|
73
|
+
// 程序文件
|
|
74
|
+
newProgramFile: { finallyKey: 'orginProgramName', valueKey: 'uniqueFileName' },
|
|
75
|
+
// 数据库
|
|
76
|
+
databaseFile: { finallyKey: 'databaseFile', valueKey: 'uniqueFileName' }
|
|
77
|
+
}
|
|
78
|
+
return _objectToFormData(obj, mapConfig)
|
|
79
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, onMounted } from 'vue'
|
|
3
|
+
import { storeToRefs } from 'pinia'
|
|
4
|
+
import { ElMessage } from 'element-plus'
|
|
5
|
+
import { MenuApi, LoginApi, UserInfoApi } from '@/api/system'
|
|
6
|
+
import { NotFoundApi, NoAuth, DetailsApi } from '@/api/mock'
|
|
7
|
+
import { handleRouter } from '@jnrs/vue-core/router'
|
|
8
|
+
import type { MenuItem } from '@jnrs/vue-core'
|
|
9
|
+
import { hasPermission } from '@/utils/permissions'
|
|
10
|
+
import { useMockStore } from '@/stores'
|
|
11
|
+
import { objectToFormData } from '@/utils/common'
|
|
12
|
+
|
|
13
|
+
const { isMock } = storeToRefs(useMockStore())
|
|
14
|
+
|
|
15
|
+
const loginParams = ref({
|
|
16
|
+
account: 'user',
|
|
17
|
+
password: '123456'
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const routeOptions = ref<MenuItem[]>([])
|
|
21
|
+
const currentRoute = ref('')
|
|
22
|
+
const datePicker = ref(new Date())
|
|
23
|
+
|
|
24
|
+
onMounted(() => {
|
|
25
|
+
handleDetailsApi()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const handleInfoApi = async () => {
|
|
29
|
+
try {
|
|
30
|
+
const res = await UserInfoApi()
|
|
31
|
+
console.log(res)
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.log(error)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const handleMenuApi = async () => {
|
|
38
|
+
try {
|
|
39
|
+
const res = await MenuApi()
|
|
40
|
+
routeOptions.value = res
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.log(error)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const handleNotFoundApi = async () => {
|
|
47
|
+
try {
|
|
48
|
+
const res = await NotFoundApi()
|
|
49
|
+
console.log(res)
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.log(error)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const handleNoAuth = async (showErrorMsg = true) => {
|
|
56
|
+
try {
|
|
57
|
+
const res = await NoAuth(showErrorMsg)
|
|
58
|
+
console.log(res)
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.log(error)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const handleDetailsApi = async () => {
|
|
65
|
+
try {
|
|
66
|
+
const res = await DetailsApi()
|
|
67
|
+
let formatData: Record<string, unknown> = {}
|
|
68
|
+
formatData = {
|
|
69
|
+
...res
|
|
70
|
+
}
|
|
71
|
+
if (res.attachmentDocument?.attachments) {
|
|
72
|
+
formatData.newAttachmentFile = res.attachmentDocument.attachments
|
|
73
|
+
}
|
|
74
|
+
if (res.imageDocument?.attachments) {
|
|
75
|
+
formatData.newImageFiles = res.imageDocument.attachments
|
|
76
|
+
}
|
|
77
|
+
console.log(formatData)
|
|
78
|
+
const formData = objectToFormData(formatData)
|
|
79
|
+
console.log(formData)
|
|
80
|
+
for (const [key, value] of formData.entries()) {
|
|
81
|
+
console.log(key, value)
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.log(error)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const handleLogin = async () => {
|
|
89
|
+
try {
|
|
90
|
+
const res = await LoginApi(loginParams.value)
|
|
91
|
+
ElMessage.success('登录成功')
|
|
92
|
+
console.log(res)
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.log(error)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const handleRouteChange = () => {
|
|
99
|
+
handleRouter({
|
|
100
|
+
name: currentRoute.value
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
</script>
|
|
104
|
+
|
|
105
|
+
<template>
|
|
106
|
+
<div>
|
|
107
|
+
<h3>Playground - 功能测试</h3>
|
|
108
|
+
<p>权限测试(admin 账号拥有全部权限,请用非 admin 账号测试该功能)</p>
|
|
109
|
+
<ul>
|
|
110
|
+
<li>
|
|
111
|
+
<span>有权限:(期望:正常显示按钮)</span>
|
|
112
|
+
<el-button type="primary" size="small" v-permissions="['mine:view']">添加</el-button>
|
|
113
|
+
</li>
|
|
114
|
+
<li>
|
|
115
|
+
<span>无权限:(期望:按钮禁用 -> UI 组件:使用 UI 框架提供的禁用属性)</span>
|
|
116
|
+
<el-button type="primary" size="small" :disabled="!hasPermission(['test:del'])">删除</el-button>
|
|
117
|
+
</li>
|
|
118
|
+
<li>
|
|
119
|
+
<span>无权限:(期望:按钮禁用 -> 原生元素:添加 disabled 属性和类名)</span>
|
|
120
|
+
<button size="small" v-permissions.disabled="['test:del']">删除</button>
|
|
121
|
+
</li>
|
|
122
|
+
<li>
|
|
123
|
+
<span>无权限:(期望:按钮不可见 -> 添加样式 display:none)</span>
|
|
124
|
+
<button size="small" v-permissions.display="['test:del']">删除</button>
|
|
125
|
+
</li>
|
|
126
|
+
<li>
|
|
127
|
+
<span>无权限:(期望:按钮不可见 -> remove HTMLElement)</span>
|
|
128
|
+
<button size="small" v-permissions="['test:del']">删除</button>
|
|
129
|
+
</li>
|
|
130
|
+
</ul>
|
|
131
|
+
<p>网络请求测试</p>
|
|
132
|
+
<div>
|
|
133
|
+
<span>服务器类型:</span>
|
|
134
|
+
<el-switch v-model="isMock" active-text="Mock 服务器" inactive-text="后端服务器" />
|
|
135
|
+
</div>
|
|
136
|
+
<el-button-group>
|
|
137
|
+
<el-button type="success" size="small" @click="handleMenuApi">获取完整菜单数据</el-button>
|
|
138
|
+
<el-button type="success" size="small" @click="handleInfoApi">获取用户数据</el-button>
|
|
139
|
+
<el-button type="primary" size="small" @click="handleNotFoundApi">404</el-button>
|
|
140
|
+
<el-button type="primary" size="small" @click="handleNoAuth()">暂无权限</el-button>
|
|
141
|
+
<el-button type="primary" size="small" @click="handleNoAuth(false)">暂无权限(不显示 Message)</el-button>
|
|
142
|
+
</el-button-group>
|
|
143
|
+
<el-input v-model="loginParams.account" size="small" style="width: 200px">
|
|
144
|
+
<template #append>
|
|
145
|
+
<el-button size="small" @click="handleLogin">验证登录接口</el-button>
|
|
146
|
+
</template>
|
|
147
|
+
</el-input>
|
|
148
|
+
<div>
|
|
149
|
+
<el-button-group>
|
|
150
|
+
<el-button type="primary" plain size="small" @click="handleDetailsApi">获取数据列表单个数据</el-button>
|
|
151
|
+
</el-button-group>
|
|
152
|
+
</div>
|
|
153
|
+
<p>完整路由测试(先点击按钮,获取完整菜单数据)</p>
|
|
154
|
+
<el-cascader
|
|
155
|
+
v-model="currentRoute"
|
|
156
|
+
:options="routeOptions"
|
|
157
|
+
:props="{
|
|
158
|
+
emitPath: false,
|
|
159
|
+
value: 'name',
|
|
160
|
+
label: 'name'
|
|
161
|
+
}"
|
|
162
|
+
:show-all-levels="false"
|
|
163
|
+
@change="handleRouteChange"
|
|
164
|
+
>
|
|
165
|
+
<template #default="{ data }">
|
|
166
|
+
<span>{{ data.meta.title }}</span>
|
|
167
|
+
</template>
|
|
168
|
+
</el-cascader>
|
|
169
|
+
<p>Element 组件测试</p>
|
|
170
|
+
<el-date-picker-panel v-model="datePicker" />
|
|
171
|
+
</div>
|
|
172
|
+
<router-view></router-view>
|
|
173
|
+
</template>
|
|
174
|
+
|
|
175
|
+
<style scoped lang="scss">
|
|
176
|
+
h3 {
|
|
177
|
+
color: var(--jnrs-color-primary);
|
|
178
|
+
}
|
|
179
|
+
p {
|
|
180
|
+
margin: 24px 0 8px;
|
|
181
|
+
color: var(--jnrs-background-primary);
|
|
182
|
+
background: var(--jnrs-font-primary);
|
|
183
|
+
}
|
|
184
|
+
</style>
|
|
@@ -1,152 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref
|
|
3
|
-
import { storeToRefs } from 'pinia'
|
|
4
|
-
import { ElMessage } from 'element-plus'
|
|
5
|
-
import { MenuApi, LoginApi, UserInfoApi } from '@/api/system'
|
|
6
|
-
import { NotFoundApi, NoAuth } from '@/api/mock'
|
|
7
|
-
import { handleRouter } from '@jnrs/vue-core/router'
|
|
8
|
-
import type { MenuItem } from '@jnrs/vue-core'
|
|
9
|
-
import { hasPermission } from '@/utils/permissions'
|
|
10
|
-
import { useMockStore } from '@/stores'
|
|
11
|
-
|
|
12
|
-
const { isMock } = storeToRefs(useMockStore())
|
|
13
|
-
|
|
14
|
-
const loginParams = ref({
|
|
15
|
-
account: 'user',
|
|
16
|
-
password: '123456'
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
const routeOptions = ref<MenuItem[]>([])
|
|
20
|
-
const currentRoute = ref('')
|
|
21
|
-
const datePicker = ref(new Date())
|
|
22
|
-
|
|
23
|
-
onMounted(() => {})
|
|
24
|
-
|
|
25
|
-
const handleInfoApi = async () => {
|
|
26
|
-
try {
|
|
27
|
-
const res = await UserInfoApi()
|
|
28
|
-
console.log(res)
|
|
29
|
-
} catch (error) {
|
|
30
|
-
console.log(error)
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const handleMenuApi = async () => {
|
|
35
|
-
try {
|
|
36
|
-
const res = await MenuApi()
|
|
37
|
-
routeOptions.value = res
|
|
38
|
-
} catch (error) {
|
|
39
|
-
console.log(error)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const handleNotFoundApi = async () => {
|
|
44
|
-
try {
|
|
45
|
-
const res = await NotFoundApi()
|
|
46
|
-
console.log(res)
|
|
47
|
-
} catch (error) {
|
|
48
|
-
console.log(error)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const handleNoAuth = async (showErrorMsg = true) => {
|
|
53
|
-
try {
|
|
54
|
-
const res = await NoAuth(showErrorMsg)
|
|
55
|
-
console.log(res)
|
|
56
|
-
} catch (error) {
|
|
57
|
-
console.log(error)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const handleLogin = async () => {
|
|
62
|
-
try {
|
|
63
|
-
const res = await LoginApi(loginParams.value)
|
|
64
|
-
ElMessage.success('登录成功')
|
|
65
|
-
console.log(res)
|
|
66
|
-
} catch (error) {
|
|
67
|
-
console.log(error)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const handleRouteChange = () => {
|
|
72
|
-
handleRouter({
|
|
73
|
-
name: currentRoute.value
|
|
74
|
-
})
|
|
75
|
-
}
|
|
2
|
+
import { ref } from 'vue'
|
|
76
3
|
</script>
|
|
77
4
|
|
|
78
5
|
<template>
|
|
79
|
-
<div>
|
|
80
|
-
<h3>Playground - 功能测试</h3>
|
|
81
|
-
<p>权限测试(admin 账号拥有全部权限,请用非 admin 账号测试该功能)</p>
|
|
82
|
-
<ul>
|
|
83
|
-
<li>
|
|
84
|
-
<span>有权限:(期望:正常显示按钮)</span>
|
|
85
|
-
<el-button type="primary" size="small" v-permissions="['mine:view']">添加</el-button>
|
|
86
|
-
</li>
|
|
87
|
-
<li>
|
|
88
|
-
<span>无权限:(期望:按钮禁用 -> UI 组件:使用 UI 框架提供的禁用属性)</span>
|
|
89
|
-
<el-button type="primary" size="small" :disabled="!hasPermission(['test:del'])">删除</el-button>
|
|
90
|
-
</li>
|
|
91
|
-
<li>
|
|
92
|
-
<span>无权限:(期望:按钮禁用 -> 原生元素:添加 disabled 属性和类名)</span>
|
|
93
|
-
<button size="small" v-permissions.disabled="['test:del']">删除</button>
|
|
94
|
-
</li>
|
|
95
|
-
<li>
|
|
96
|
-
<span>无权限:(期望:按钮不可见 -> 添加样式 display:none)</span>
|
|
97
|
-
<button size="small" v-permissions.display="['test:del']">删除</button>
|
|
98
|
-
</li>
|
|
99
|
-
<li>
|
|
100
|
-
<span>无权限:(期望:按钮不可见 -> remove HTMLElement)</span>
|
|
101
|
-
<button size="small" v-permissions="['test:del']">删除</button>
|
|
102
|
-
</li>
|
|
103
|
-
</ul>
|
|
104
|
-
<p>网络请求测试</p>
|
|
105
|
-
<div>
|
|
106
|
-
<span>服务器类型:</span>
|
|
107
|
-
<el-switch v-model="isMock" active-text="Mock 服务器" inactive-text="后端服务器" />
|
|
108
|
-
</div>
|
|
109
|
-
<el-button-group>
|
|
110
|
-
<el-button type="primary" size="small" @click="handleMenuApi">获取完整菜单数据</el-button>
|
|
111
|
-
<el-button type="primary" size="small" @click="handleInfoApi">获取用户数据</el-button>
|
|
112
|
-
<el-button type="primary" size="small" @click="handleNotFoundApi">404</el-button>
|
|
113
|
-
<el-button type="primary" size="small" @click="handleNoAuth()">暂无权限</el-button>
|
|
114
|
-
<el-button type="primary" size="small" @click="handleNoAuth(false)">暂无权限(不显示 Message)</el-button>
|
|
115
|
-
</el-button-group>
|
|
116
|
-
<el-input v-model="loginParams.account" size="small" style="width: 200px">
|
|
117
|
-
<template #append>
|
|
118
|
-
<el-button size="small" @click="handleLogin">验证登录接口</el-button>
|
|
119
|
-
</template>
|
|
120
|
-
</el-input>
|
|
121
|
-
<p>完整路由测试(先点击按钮,获取完整菜单数据)</p>
|
|
122
|
-
<el-cascader
|
|
123
|
-
v-model="currentRoute"
|
|
124
|
-
:options="routeOptions"
|
|
125
|
-
:props="{
|
|
126
|
-
emitPath: false,
|
|
127
|
-
value: 'name',
|
|
128
|
-
label: 'name'
|
|
129
|
-
}"
|
|
130
|
-
:show-all-levels="false"
|
|
131
|
-
@change="handleRouteChange"
|
|
132
|
-
>
|
|
133
|
-
<template #default="{ data }">
|
|
134
|
-
<span>{{ data.meta.title }}</span>
|
|
135
|
-
</template>
|
|
136
|
-
</el-cascader>
|
|
137
|
-
<p>Element 组件测试</p>
|
|
138
|
-
<el-date-picker-panel v-model="datePicker" />
|
|
139
|
-
</div>
|
|
140
|
-
<router-view></router-view>
|
|
6
|
+
<div>欢迎使用</div>
|
|
141
7
|
</template>
|
|
142
8
|
|
|
143
|
-
<style
|
|
144
|
-
h3 {
|
|
145
|
-
color: var(--jnrs-color-primary);
|
|
146
|
-
}
|
|
147
|
-
p {
|
|
148
|
-
margin: 24px 0 8px;
|
|
149
|
-
color: var(--jnrs-background-primary);
|
|
150
|
-
background: var(--jnrs-font-primary);
|
|
151
|
-
}
|
|
152
|
-
</style>
|
|
9
|
+
<style lang="scss" scoped></style>
|
|
@@ -6,8 +6,15 @@ import { useAuthStore } from '@/stores'
|
|
|
6
6
|
import { handleRouter, useRoute } from '@jnrs/vue-core/router'
|
|
7
7
|
import { isWeakPwd } from '@jnrs/shared/validator'
|
|
8
8
|
import { formatDateTime, formatWeekday } from '@jnrs/shared'
|
|
9
|
+
import { GlobalSetting } from '@jnrs/vue-core/components'
|
|
9
10
|
|
|
10
11
|
const route = useRoute()
|
|
12
|
+
|
|
13
|
+
const globalSettingRef = ref()
|
|
14
|
+
const showGlobalSetting = () => {
|
|
15
|
+
globalSettingRef.value.handleShow()
|
|
16
|
+
}
|
|
17
|
+
|
|
11
18
|
const loading = ref(false)
|
|
12
19
|
const {
|
|
13
20
|
setUserInfo,
|
|
@@ -76,16 +83,21 @@ const submitForm = async () => {
|
|
|
76
83
|
|
|
77
84
|
<template>
|
|
78
85
|
<div class="main">
|
|
86
|
+
<div class="topFixed_right">
|
|
87
|
+
<el-icon class="topBarBtn" title="全局偏好设置" @click="showGlobalSetting()">
|
|
88
|
+
<el-icon><Setting /></el-icon>
|
|
89
|
+
</el-icon>
|
|
90
|
+
</div>
|
|
79
91
|
<div class="card">
|
|
80
92
|
<div class="card_left">
|
|
81
93
|
<div class="card_left_mid">
|
|
82
94
|
<img class="logo" src="@/assets/images/common/jnrs-white.svg" alt="JNRS" />
|
|
83
|
-
<h5 class="title"
|
|
95
|
+
<h5 class="title">{{ $t('login.title') }}</h5>
|
|
84
96
|
</div>
|
|
85
97
|
</div>
|
|
86
98
|
<div class="card_right">
|
|
87
99
|
<div class="card_right_mid">
|
|
88
|
-
<h1 class="title"
|
|
100
|
+
<h1 class="title">{{ $t('login.formTitle') }}</h1>
|
|
89
101
|
<el-form
|
|
90
102
|
class="form"
|
|
91
103
|
ref="ruleFormRef"
|
|
@@ -95,28 +107,36 @@ const submitForm = async () => {
|
|
|
95
107
|
@keyup.enter="submitForm()"
|
|
96
108
|
>
|
|
97
109
|
<el-form-item prop="account">
|
|
98
|
-
<el-input
|
|
110
|
+
<el-input
|
|
111
|
+
v-model="ruleForm.account"
|
|
112
|
+
:placeholder="$t('login.formAccount')"
|
|
113
|
+
prefix-icon="User"
|
|
114
|
+
clearable
|
|
115
|
+
/>
|
|
99
116
|
</el-form-item>
|
|
100
117
|
<el-form-item prop="password">
|
|
101
118
|
<el-input
|
|
102
119
|
v-model="ruleForm.password"
|
|
103
120
|
type="password"
|
|
104
121
|
autocomplete="off"
|
|
105
|
-
placeholder="
|
|
122
|
+
:placeholder="$t('login.formPassword')"
|
|
106
123
|
prefix-icon="Lock"
|
|
107
124
|
show-password
|
|
108
125
|
></el-input>
|
|
109
126
|
</el-form-item>
|
|
110
127
|
<el-form-item>
|
|
111
|
-
<el-button class="btn" type="primary" :loading="loading" @click="submitForm()"
|
|
128
|
+
<el-button class="btn" type="primary" :loading="loading" @click="submitForm()">
|
|
129
|
+
{{ $t('login.formBtn') }}
|
|
130
|
+
</el-button>
|
|
112
131
|
</el-form-item>
|
|
113
132
|
</el-form>
|
|
114
|
-
<div class="greeting"
|
|
133
|
+
<div class="greeting">{{ $t('login.greeting') }}</div>
|
|
115
134
|
</div>
|
|
116
135
|
<div class="card_right_copyright">Powered by JNRS TECH 2026</div>
|
|
117
136
|
</div>
|
|
118
137
|
</div>
|
|
119
138
|
</div>
|
|
139
|
+
<GlobalSetting ref="globalSettingRef" />
|
|
120
140
|
</template>
|
|
121
141
|
|
|
122
142
|
<style scoped lang="scss">
|
|
@@ -136,6 +156,23 @@ const submitForm = async () => {
|
|
|
136
156
|
}
|
|
137
157
|
}
|
|
138
158
|
|
|
159
|
+
.topBarBtn {
|
|
160
|
+
font-size: 22px;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.topFixed_right {
|
|
164
|
+
position: absolute;
|
|
165
|
+
top: 4px;
|
|
166
|
+
right: 4px;
|
|
167
|
+
z-index: 1;
|
|
168
|
+
display: flex;
|
|
169
|
+
align-items: center;
|
|
170
|
+
justify-content: space-around;
|
|
171
|
+
background: var(--jnrs-card-primary);
|
|
172
|
+
padding: 4px 16px;
|
|
173
|
+
border-radius: 10px;
|
|
174
|
+
}
|
|
175
|
+
|
|
139
176
|
.card {
|
|
140
177
|
display: flex;
|
|
141
178
|
align-items: center;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": {
|
|
3
|
+
"id": 1,
|
|
4
|
+
"name": "测试刀库20251216",
|
|
5
|
+
"code": "DK20251216",
|
|
6
|
+
"stationCount": 2,
|
|
7
|
+
"imageDocumentId": 1,
|
|
8
|
+
"imageDocument": {
|
|
9
|
+
"id": 1,
|
|
10
|
+
"description": null,
|
|
11
|
+
"attachments": [
|
|
12
|
+
{
|
|
13
|
+
"id": 1,
|
|
14
|
+
"documentId": 1,
|
|
15
|
+
"fileName": "成品.png",
|
|
16
|
+
"uniqueFileName": "20251216134412632-1376c8a7-1f31-451c-9eb4-944aaa03497b.png",
|
|
17
|
+
"fileType": "image/png",
|
|
18
|
+
"fileSize": 432866
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": 3,
|
|
22
|
+
"documentId": 1,
|
|
23
|
+
"fileName": "02.png",
|
|
24
|
+
"uniqueFileName": "20251216135111546-e33d678c-5099-4c4c-bc81-a97688f433af.png",
|
|
25
|
+
"fileType": "image/png",
|
|
26
|
+
"fileSize": 24306
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"attachmentDocumentId": 2,
|
|
31
|
+
"attachmentDocument": {
|
|
32
|
+
"id": 2,
|
|
33
|
+
"description": null,
|
|
34
|
+
"attachments": [
|
|
35
|
+
{
|
|
36
|
+
"id": 2,
|
|
37
|
+
"documentId": 2,
|
|
38
|
+
"fileName": "Law Policy for Alibaba Sans.pdf",
|
|
39
|
+
"uniqueFileName": "20251216134412671-e3f13c84-a24d-4718-930a-959cd2b41fb1.pdf",
|
|
40
|
+
"fileType": "application/pdf",
|
|
41
|
+
"fileSize": 63610
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": 4,
|
|
45
|
+
"documentId": 2,
|
|
46
|
+
"fileName": "信息化项目设计流程规定JND 024.01-2024.pdf",
|
|
47
|
+
"uniqueFileName": "20251216135247581-05eee726-a0fe-4a44-a890-ee64b106c4b7.pdf",
|
|
48
|
+
"fileType": "application/pdf",
|
|
49
|
+
"fileSize": 231295
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"code": 0,
|
|
55
|
+
"msg": "操作成功"
|
|
56
|
+
}
|
|
@@ -6,6 +6,7 @@ import loginRes_user from './loginRes_user.json'
|
|
|
6
6
|
import dictRes from './dictRes.json'
|
|
7
7
|
import dictItemRes from './dictItemRes.json'
|
|
8
8
|
import roleRes from './roleRes.json'
|
|
9
|
+
import detailsRes from './detailsRes.json'
|
|
9
10
|
|
|
10
11
|
export default [
|
|
11
12
|
...successMock,
|
|
@@ -63,5 +64,13 @@ export default [
|
|
|
63
64
|
response: () => {
|
|
64
65
|
return roleRes
|
|
65
66
|
}
|
|
67
|
+
},
|
|
68
|
+
// 获取数据详情
|
|
69
|
+
{
|
|
70
|
+
url: '/mock/details',
|
|
71
|
+
method: 'get',
|
|
72
|
+
response: () => {
|
|
73
|
+
return detailsRes
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
]
|
package/package.json
CHANGED
|
File without changes
|