create-jnrs-template-vue 1.2.2 → 1.2.4
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 +1 -1
- package/jnrs-template-vue/index.html +1 -1
- package/jnrs-template-vue/package.json +3 -4
- package/jnrs-template-vue/public/system/menu.json +11 -2
- package/jnrs-template-vue/src/App.vue +1 -3
- package/jnrs-template-vue/src/api/common/index.ts +2 -2
- package/jnrs-template-vue/src/api/demos/index.ts +85 -43
- package/jnrs-template-vue/src/api/system/index.ts +20 -10
- package/jnrs-template-vue/src/api/user/index.ts +2 -2
- package/jnrs-template-vue/src/assets/styles/index.scss +0 -24
- package/jnrs-template-vue/src/assets/styles/init.scss +24 -0
- package/jnrs-template-vue/src/assets/styles/root.scss +4 -0
- package/jnrs-template-vue/src/components/common/CardTable.vue +89 -0
- package/jnrs-template-vue/src/components/common/DictTag.vue +8 -4
- package/jnrs-template-vue/src/components/common/ImageView.vue +16 -7
- package/jnrs-template-vue/src/components/common/PdfView.vue +14 -5
- package/jnrs-template-vue/src/components/select/SelectManager.vue +2 -2
- package/jnrs-template-vue/src/layout/SideMenu.vue +0 -1
- package/jnrs-template-vue/src/layout/TopHeader.vue +7 -14
- package/jnrs-template-vue/src/locales/index.ts +1 -1
- package/jnrs-template-vue/src/types/webSocket.ts +19 -0
- package/jnrs-template-vue/src/utils/file.ts +36 -1
- package/jnrs-template-vue/src/views/demos/crud/index.vue +57 -32
- package/jnrs-template-vue/src/views/demos/simpleTable/index.vue +41 -0
- package/jnrs-template-vue/src/views/demos/unitTest/RequestPage.vue +2 -2
- package/jnrs-template-vue/src/views/demos/unitTest/index.vue +26 -2
- package/jnrs-template-vue/src/views/login/index.vue +18 -15
- package/jnrs-template-vue/src/views/system/dict/index.vue +63 -76
- package/jnrs-template-vue/src/views/system/menu/index.vue +42 -54
- package/jnrs-template-vue/src/views/system/mine/baseInfo.vue +26 -59
- package/jnrs-template-vue/src/views/system/role/index.vue +20 -29
- package/jnrs-template-vue/src/views/visual/index.vue +130 -15
- package/jnrs-template-vue/vite.config.ts +0 -1
- package/jnrs-template-vue/viteMockServe/fail.ts +12 -0
- package/package.json +1 -1
- package/jnrs-template-vue/src/composables/base/useAvatar.ts +0 -36
- package/jnrs-template-vue/src/composables/tools/useMouseSelection.ts +0 -150
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { DictItem } from '@jnrs/shared'
|
|
2
3
|
import { ElMessage } from 'element-plus'
|
|
3
4
|
import { ref, onActivated } from 'vue'
|
|
4
5
|
import { DictApi, DictDetailApi, DictChangeApi } from '@/api/system'
|
|
5
|
-
import { useReactivityTableHeight } from '@jnrs/vue-core/composables'
|
|
6
|
-
import type { DictItem } from '@jnrs/shared'
|
|
7
6
|
import { hasPermission } from '@/utils/permissions'
|
|
7
|
+
import { JnTable } from '@jnrs/vue-core/components'
|
|
8
8
|
|
|
9
|
-
const { maxHeight } = useReactivityTableHeight({ className: 'el_table_dict', bottomGap: 0 })
|
|
10
9
|
const PERMISSION_EDIT = ['dict:edit']
|
|
11
10
|
const loading = ref(false)
|
|
12
11
|
const tableData = ref<DictItem[]>()
|
|
@@ -73,80 +72,68 @@ const editKeyValue = (row: DictItem) => {
|
|
|
73
72
|
</script>
|
|
74
73
|
|
|
75
74
|
<template>
|
|
76
|
-
<
|
|
77
|
-
<
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<el-table
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
v-loading="loading"
|
|
90
|
-
row-key="id"
|
|
91
|
-
@expand-change="handleExpandChange"
|
|
92
|
-
>
|
|
93
|
-
<el-table-column prop="dictName" label="字典名" />
|
|
94
|
-
<el-table-column prop="describe" label="说明" />
|
|
95
|
-
<el-table-column type="expand" fixed="right" label="字典值" width="100">
|
|
96
|
-
<template #default="scope">
|
|
97
|
-
<div class="table_expand animation15" style="animation-duration: 0.5s; animation-delay: 0s">
|
|
98
|
-
<div class="table_expand_top">
|
|
99
|
-
<h5>字典值列表</h5>
|
|
100
|
-
</div>
|
|
101
|
-
<el-table :data="scope.row.options" :border="true" size="small" row-key="value">
|
|
102
|
-
<el-table-column label="value" prop="value" width="100" align="center"></el-table-column>
|
|
103
|
-
<el-table-column label="label" prop="label">
|
|
104
|
-
<template #default="optionScope">
|
|
105
|
-
<el-input
|
|
106
|
-
v-model="optionScope.row.label"
|
|
107
|
-
maxlength="20"
|
|
108
|
-
:disabled="!hasPermission(PERMISSION_EDIT)"
|
|
109
|
-
/>
|
|
110
|
-
</template>
|
|
111
|
-
</el-table-column>
|
|
112
|
-
<el-table-column label="颜色" prop="displayColor">
|
|
113
|
-
<template #default="optionScope">
|
|
114
|
-
<el-color-picker
|
|
115
|
-
v-model="optionScope.row.displayColor"
|
|
116
|
-
:predefine="predefineColors"
|
|
117
|
-
:disabled="!hasPermission(PERMISSION_EDIT)"
|
|
118
|
-
/>
|
|
119
|
-
<span style="margin-left: 10px">
|
|
120
|
-
{{ optionScope.row.displayColor || '无' }}
|
|
121
|
-
</span>
|
|
122
|
-
</template>
|
|
123
|
-
</el-table-column>
|
|
124
|
-
<el-table-column prop="sequence" label="排序" width="180" align="center">
|
|
125
|
-
<template #default="optionScope">
|
|
126
|
-
<el-input-number
|
|
127
|
-
v-model="optionScope.row.sequence"
|
|
128
|
-
:min="1"
|
|
129
|
-
:max="999"
|
|
130
|
-
:step="1"
|
|
131
|
-
controls-position="right"
|
|
132
|
-
step-strictly
|
|
133
|
-
:disabled="!hasPermission(PERMISSION_EDIT)"
|
|
134
|
-
style="width: 140px"
|
|
135
|
-
/>
|
|
136
|
-
</template>
|
|
137
|
-
</el-table-column>
|
|
138
|
-
<el-table-column label="操作" width="100" align="center" fixed="right" v-permissions="PERMISSION_EDIT">
|
|
139
|
-
<template #default="optionScope">
|
|
140
|
-
<el-button type="success" size="small" @click="editKeyValue(optionScope.row)">确认修改</el-button>
|
|
141
|
-
</template>
|
|
142
|
-
</el-table-column>
|
|
143
|
-
</el-table>
|
|
75
|
+
<el-card v-loading="loading">
|
|
76
|
+
<template #header>
|
|
77
|
+
<span>字典管理</span>
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<JnTable :data="tableData" @expand-change="handleExpandChange">
|
|
81
|
+
<el-table-column prop="dictName" label="字典名" />
|
|
82
|
+
<el-table-column prop="describe" label="说明" />
|
|
83
|
+
<el-table-column type="expand" fixed="right" label="字典值" width="100">
|
|
84
|
+
<template #default="scope">
|
|
85
|
+
<div class="table_expand">
|
|
86
|
+
<div class="table_expand_top">
|
|
87
|
+
<h5>字典值列表</h5>
|
|
144
88
|
</div>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
89
|
+
<el-table :data="scope.row.options" :border="true" size="small" row-key="value">
|
|
90
|
+
<el-table-column label="value" prop="value" width="100" align="center"></el-table-column>
|
|
91
|
+
<el-table-column label="label" prop="label">
|
|
92
|
+
<template #default="optionScope">
|
|
93
|
+
<el-input
|
|
94
|
+
v-model="optionScope.row.label"
|
|
95
|
+
maxlength="20"
|
|
96
|
+
:disabled="!hasPermission(PERMISSION_EDIT)"
|
|
97
|
+
/>
|
|
98
|
+
</template>
|
|
99
|
+
</el-table-column>
|
|
100
|
+
<el-table-column label="颜色" prop="displayColor">
|
|
101
|
+
<template #default="optionScope">
|
|
102
|
+
<el-color-picker
|
|
103
|
+
v-model="optionScope.row.displayColor"
|
|
104
|
+
:predefine="predefineColors"
|
|
105
|
+
:disabled="!hasPermission(PERMISSION_EDIT)"
|
|
106
|
+
/>
|
|
107
|
+
<span style="margin-left: 10px">
|
|
108
|
+
{{ optionScope.row.displayColor || '无' }}
|
|
109
|
+
</span>
|
|
110
|
+
</template>
|
|
111
|
+
</el-table-column>
|
|
112
|
+
<el-table-column prop="sequence" label="排序" width="180" align="center">
|
|
113
|
+
<template #default="optionScope">
|
|
114
|
+
<el-input-number
|
|
115
|
+
v-model="optionScope.row.sequence"
|
|
116
|
+
:min="1"
|
|
117
|
+
:max="999"
|
|
118
|
+
:step="1"
|
|
119
|
+
controls-position="right"
|
|
120
|
+
step-strictly
|
|
121
|
+
:disabled="!hasPermission(PERMISSION_EDIT)"
|
|
122
|
+
style="width: 140px"
|
|
123
|
+
/>
|
|
124
|
+
</template>
|
|
125
|
+
</el-table-column>
|
|
126
|
+
<el-table-column label="操作" width="100" align="center" fixed="right" v-permissions="PERMISSION_EDIT">
|
|
127
|
+
<template #default="optionScope">
|
|
128
|
+
<el-button type="success" size="small" @click="editKeyValue(optionScope.row)">确认修改</el-button>
|
|
129
|
+
</template>
|
|
130
|
+
</el-table-column>
|
|
131
|
+
</el-table>
|
|
132
|
+
</div>
|
|
133
|
+
</template>
|
|
134
|
+
</el-table-column>
|
|
135
|
+
</JnTable>
|
|
136
|
+
</el-card>
|
|
150
137
|
</template>
|
|
151
138
|
|
|
152
139
|
<style scoped lang="scss">
|
|
@@ -1,65 +1,53 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref } from 'vue'
|
|
3
3
|
import { useMenuStore } from '@jnrs/vue-core/pinia'
|
|
4
|
-
import {
|
|
4
|
+
import { JnTable } from '@jnrs/vue-core/components'
|
|
5
5
|
|
|
6
|
-
const { maxHeight } = useReactivityTableHeight({ className: 'el_table_menu', bottomGap: 0 })
|
|
7
6
|
const loading = ref(false)
|
|
8
7
|
|
|
9
8
|
const { menus } = useMenuStore()
|
|
10
9
|
</script>
|
|
11
10
|
|
|
12
11
|
<template>
|
|
13
|
-
<
|
|
14
|
-
<
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<el-table
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
>
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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>
|
|
60
|
-
</template>
|
|
61
|
-
</el-table-column>
|
|
62
|
-
</el-table>
|
|
63
|
-
</el-card>
|
|
64
|
-
</div>
|
|
12
|
+
<el-card v-loading="loading">
|
|
13
|
+
<template #header>
|
|
14
|
+
<span>菜单管理</span>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<JnTable :data="menus" row-key="meta.uuid" :showScrollbar="true">
|
|
18
|
+
<el-table-column prop="meta.title" label="标题" min-width="120" header-align="center" />
|
|
19
|
+
<el-table-column prop="icon" label="图标" width="60" align="center">
|
|
20
|
+
<template #default="{ row }">
|
|
21
|
+
<el-icon v-if="row.meta.icon"><component :is="row.meta.icon" /></el-icon>
|
|
22
|
+
</template>
|
|
23
|
+
</el-table-column>
|
|
24
|
+
<el-table-column prop="path" label="路由地址" min-width="120" header-align="center" />
|
|
25
|
+
<el-table-column prop="component" label="component path" min-width="120" header-align="center" />
|
|
26
|
+
<el-table-column prop="redirect" label="redirect" min-width="120" header-align="center" />
|
|
27
|
+
<el-table-column prop="editRole" label="权限标识" min-width="120" header-align="center">
|
|
28
|
+
<template #default="{ row }">
|
|
29
|
+
<span v-if="!row.meta.permissions" style="color: #999">auto</span>
|
|
30
|
+
<span v-else>{{ row.meta.permissions }}</span>
|
|
31
|
+
</template>
|
|
32
|
+
</el-table-column>
|
|
33
|
+
<el-table-column prop="type" label="类型" width="80" align="center">
|
|
34
|
+
<template #default="{ row }">
|
|
35
|
+
<el-tag type="primary" v-if="row.path">菜单</el-tag>
|
|
36
|
+
<el-tag type="success" v-else>目录</el-tag>
|
|
37
|
+
</template>
|
|
38
|
+
</el-table-column>
|
|
39
|
+
<el-table-column prop="type" label="NoAuthApi" width="80" align="center">
|
|
40
|
+
<template #default="{ row }">
|
|
41
|
+
<el-tag type="danger" v-if="row.meta.noAuth">否</el-tag>
|
|
42
|
+
<el-tag type="success" v-else>是</el-tag>
|
|
43
|
+
</template>
|
|
44
|
+
</el-table-column>
|
|
45
|
+
<el-table-column prop="type" label="Global" width="80" align="center">
|
|
46
|
+
<template #default="{ row }">
|
|
47
|
+
<el-tag type="success" v-if="row.meta.global">是</el-tag>
|
|
48
|
+
<el-tag type="primary" v-else>否</el-tag>
|
|
49
|
+
</template>
|
|
50
|
+
</el-table-column>
|
|
51
|
+
</JnTable>
|
|
52
|
+
</el-card>
|
|
65
53
|
</template>
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { FormInstance } from 'element-plus'
|
|
2
3
|
import { ref, onMounted } from 'vue'
|
|
3
|
-
import { storeToRefs } from 'pinia'
|
|
4
|
-
import { ElMessage } from 'element-plus'
|
|
5
|
-
import type { UploadProps } from 'element-plus'
|
|
6
4
|
import { useAuthStore } from '@jnrs/vue-core/pinia'
|
|
7
|
-
import { useAvatar } from '@/composables/base/useAvatar'
|
|
8
5
|
import { getDictList } from '@/utils/packages'
|
|
9
|
-
import
|
|
6
|
+
import { JnFileUpload } from '@jnrs/vue-core/components'
|
|
7
|
+
import { AvatarChangeApi } from '@/api/system'
|
|
8
|
+
import { objectMatchAssign } from '@jnrs/shared'
|
|
10
9
|
|
|
11
|
-
const { userInfo
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const ruleForm = ref<User>({
|
|
10
|
+
const { userInfo } = useAuthStore()
|
|
11
|
+
// const loading = ref(false)
|
|
12
|
+
const ruleFormRef = ref<FormInstance>()
|
|
13
|
+
const ruleForm = ref({
|
|
16
14
|
id: 0,
|
|
17
15
|
account: '',
|
|
18
16
|
name: '',
|
|
@@ -20,7 +18,8 @@ const ruleForm = ref<User>({
|
|
|
20
18
|
jobTitle: 0,
|
|
21
19
|
workgroup: '',
|
|
22
20
|
role: 0,
|
|
23
|
-
avatarFileName: ''
|
|
21
|
+
avatarFileName: '',
|
|
22
|
+
file: []
|
|
24
23
|
})
|
|
25
24
|
const rules = ref({
|
|
26
25
|
// account: { required: true, message: '请输入', trigger: 'change' },
|
|
@@ -29,44 +28,14 @@ const rules = ref({
|
|
|
29
28
|
// workNo: { required: true, message: '请输入', trigger: 'change' },
|
|
30
29
|
})
|
|
31
30
|
|
|
32
|
-
interface ApiResponse {
|
|
33
|
-
code: number
|
|
34
|
-
message: string
|
|
35
|
-
data: string
|
|
36
|
-
}
|
|
37
|
-
|
|
38
31
|
onMounted(() => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
32
|
+
const matched = objectMatchAssign(ruleForm.value, userInfo)
|
|
33
|
+
ruleForm.value = matched
|
|
42
34
|
})
|
|
43
|
-
|
|
44
|
-
const handleAvatarSuccess: UploadProps['onSuccess'] = (response: ApiResponse) => {
|
|
45
|
-
loading.value = false
|
|
46
|
-
if (userInfo.value && response.code === 0) {
|
|
47
|
-
userInfo.value.avatarFileName = response.data
|
|
48
|
-
ElMessage.success({ message: '头像上传成功' })
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const handleProgress = () => {
|
|
53
|
-
loading.value = true
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
|
57
|
-
if (rawFile.type.indexOf('image/') < 0) {
|
|
58
|
-
ElMessage.error('上传头像只能是图片格式!')
|
|
59
|
-
return false
|
|
60
|
-
} else if (rawFile.size / 1024 / 1024 > 10) {
|
|
61
|
-
ElMessage.error('上传头像图片大小不能超过10MB!')
|
|
62
|
-
return false
|
|
63
|
-
}
|
|
64
|
-
return true
|
|
65
|
-
}
|
|
66
35
|
</script>
|
|
67
36
|
|
|
68
37
|
<template>
|
|
69
|
-
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" disabled>
|
|
38
|
+
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" :disabled="true">
|
|
70
39
|
<el-form-item label="登录账号" prop="account">
|
|
71
40
|
<el-input v-model.trim="ruleForm.account" style="width: 200px" />
|
|
72
41
|
</el-form-item>
|
|
@@ -94,23 +63,21 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
|
|
94
63
|
<el-option :label="item.label" :value="item.value" v-for="(item, index) in getDictList('role')" :key="index" />
|
|
95
64
|
</el-select>
|
|
96
65
|
</el-form-item>
|
|
97
|
-
<el-form-item label="头像" prop="
|
|
98
|
-
<
|
|
99
|
-
|
|
100
|
-
:
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
:
|
|
104
|
-
:
|
|
105
|
-
:
|
|
106
|
-
:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
<el-icon v-else class="uploader_icon"><Plus /></el-icon>
|
|
110
|
-
</el-upload>
|
|
66
|
+
<el-form-item label="头像" prop="file" class="uploader_item">
|
|
67
|
+
<JnFileUpload
|
|
68
|
+
v-model="ruleForm.file"
|
|
69
|
+
:formRef="ruleFormRef"
|
|
70
|
+
validateFieldName="newImageFiles"
|
|
71
|
+
accept=".png,.jpg,.bmp,.gif"
|
|
72
|
+
:fileSizeMb="50"
|
|
73
|
+
:limit="1"
|
|
74
|
+
:showFileList="false"
|
|
75
|
+
:autoUploadApi="AvatarChangeApi"
|
|
76
|
+
style="width: 500px"
|
|
77
|
+
/>
|
|
111
78
|
</el-form-item>
|
|
112
79
|
<!-- <el-form-item>
|
|
113
|
-
<el-button class="form_submit" :loading="loading" type="primary" @click="submitForm
|
|
80
|
+
<el-button class="form_submit" :loading="loading" type="primary" @click="submitForm">
|
|
114
81
|
保存修改
|
|
115
82
|
</el-button>
|
|
116
83
|
</el-form-item> -->
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, onMounted } from 'vue'
|
|
3
3
|
import { RoleApi } from '@/api/system'
|
|
4
|
+
import { JnTable } from '@jnrs/vue-core/components'
|
|
4
5
|
|
|
5
6
|
const loading = ref(false)
|
|
6
7
|
const tableData = ref()
|
|
@@ -18,33 +19,23 @@ onMounted(() => {
|
|
|
18
19
|
</script>
|
|
19
20
|
|
|
20
21
|
<template>
|
|
21
|
-
<
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<el-table
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
</template>
|
|
41
|
-
</el-table-column>
|
|
42
|
-
<el-table-column prop="permissions" label="可用权限" header-align="center">
|
|
43
|
-
<template #default="{ row }">
|
|
44
|
-
{{ row.permissions }}
|
|
45
|
-
</template>
|
|
46
|
-
</el-table-column>
|
|
47
|
-
</el-table>
|
|
48
|
-
</el-card>
|
|
49
|
-
</div>
|
|
22
|
+
<el-card v-loading="loading">
|
|
23
|
+
<template #header>
|
|
24
|
+
<span>角色管理</span>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<JnTable :data="tableData">
|
|
28
|
+
<el-table-column prop="label" label="角色名称" width="200" align="center" />
|
|
29
|
+
<el-table-column prop="value" label="值" width="200" align="center">
|
|
30
|
+
<template #default="{ row }">
|
|
31
|
+
{{ row.value + ' [' + typeof row.value + ']' }}
|
|
32
|
+
</template>
|
|
33
|
+
</el-table-column>
|
|
34
|
+
<el-table-column prop="permissions" label="可用权限" header-align="center">
|
|
35
|
+
<template #default="{ row }">
|
|
36
|
+
{{ row.permissions }}
|
|
37
|
+
</template>
|
|
38
|
+
</el-table-column>
|
|
39
|
+
</JnTable>
|
|
40
|
+
</el-card>
|
|
50
41
|
</template>
|
|
@@ -1,22 +1,59 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
}
|
|
2
|
+
import type { MsgIdMessage, TypeDataMessage } from '@/types/webSocket'
|
|
3
|
+
import { isMsgIdMessage, isTypeDataMessage } from '@/types/webSocket'
|
|
4
|
+
import { storeToRefs } from 'pinia'
|
|
5
|
+
import { useWebSocket } from '@jnrs/vue-core/composables'
|
|
6
|
+
import { useRouter } from '@jnrs/vue-core/router'
|
|
7
|
+
import { useSystemStore } from '@jnrs/vue-core/pinia'
|
|
8
|
+
|
|
9
|
+
const router = useRouter()
|
|
10
|
+
const systemStore = useSystemStore()
|
|
11
|
+
const { documentFullscreen } = storeToRefs(systemStore)
|
|
12
|
+
const { toggleFullScreen } = systemStore
|
|
13
|
+
|
|
14
|
+
const { isLoading, wsStateInfo } = useWebSocket({
|
|
15
|
+
url: '/ws/monitor',
|
|
16
|
+
connectionTimeoutDuration: 3_000, // 修改仅为测试
|
|
17
|
+
onMessage: (rawMessage: unknown) => {
|
|
18
|
+
if (isMsgIdMessage(rawMessage)) {
|
|
19
|
+
const msg = rawMessage as MsgIdMessage
|
|
20
|
+
if (msg.msgId && msg.d && typeof msg.d === 'object') {
|
|
21
|
+
// console.log('接收 msgId 数据:', msg)
|
|
22
|
+
}
|
|
23
|
+
} else if (isTypeDataMessage(rawMessage)) {
|
|
24
|
+
const msg = rawMessage as TypeDataMessage
|
|
25
|
+
if (msg.type && msg.data && typeof msg.data === 'object') {
|
|
26
|
+
// console.log('接收 type 数据:', msg)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
})
|
|
12
31
|
</script>
|
|
13
32
|
|
|
14
33
|
<template>
|
|
15
|
-
<div
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
34
|
+
<div
|
|
35
|
+
class="visual"
|
|
36
|
+
v-loading="isLoading"
|
|
37
|
+
element-loading-background="rgba(0,0,0,.5)"
|
|
38
|
+
element-loading-text="网络加载中..."
|
|
39
|
+
>
|
|
40
|
+
<div class="visual_head">
|
|
41
|
+
<div class="visual_head_left">
|
|
42
|
+
<div class="visual_title">
|
|
43
|
+
<b>数字孪生看板</b>
|
|
44
|
+
<span>{{ wsStateInfo }}</span>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="visual_head_right">
|
|
48
|
+
<span class="btn" @click="toggleFullScreen">
|
|
49
|
+
{{ !documentFullscreen ? '启用全屏' : '退出全屏' }}
|
|
50
|
+
</span>
|
|
51
|
+
<span class="btn" @click="router.push('/')">返回首页</span>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="visual_canvas">
|
|
55
|
+
<i>canvas</i>
|
|
56
|
+
</div>
|
|
20
57
|
</div>
|
|
21
58
|
</template>
|
|
22
59
|
|
|
@@ -25,4 +62,82 @@ const goBack = () => {
|
|
|
25
62
|
@function px2vw($px) {
|
|
26
63
|
@return math.div($px, 1920) * 100vw;
|
|
27
64
|
}
|
|
65
|
+
|
|
66
|
+
.visual {
|
|
67
|
+
position: relative;
|
|
68
|
+
width: 100%;
|
|
69
|
+
height: 100%;
|
|
70
|
+
font-size: px2vw(18);
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
user-select: none;
|
|
73
|
+
|
|
74
|
+
.visual_head {
|
|
75
|
+
position: absolute;
|
|
76
|
+
z-index: 10;
|
|
77
|
+
display: flex;
|
|
78
|
+
justify-content: space-between;
|
|
79
|
+
align-items: top;
|
|
80
|
+
width: 100%;
|
|
81
|
+
padding: px2vw(10);
|
|
82
|
+
color: #fff;
|
|
83
|
+
|
|
84
|
+
.visual_title {
|
|
85
|
+
display: inline-flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
font-size: px2vw(24);
|
|
88
|
+
height: px2vw(30);
|
|
89
|
+
background: #000;
|
|
90
|
+
border: px2vw(2) solid #f2f2f2;
|
|
91
|
+
margin: 0 0 px2vw(5) 0;
|
|
92
|
+
overflow: hidden;
|
|
93
|
+
|
|
94
|
+
b {
|
|
95
|
+
display: inline-block;
|
|
96
|
+
padding: 0 px2vw(5);
|
|
97
|
+
font-size: px2vw(24);
|
|
98
|
+
background: #f2f2f2;
|
|
99
|
+
color: #000;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
span {
|
|
103
|
+
padding: 0 px2vw(8);
|
|
104
|
+
color: #f2f2f2;
|
|
105
|
+
box-sizing: border-box;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.visual_head_right {
|
|
110
|
+
.btn {
|
|
111
|
+
align-items: center;
|
|
112
|
+
padding: 0 px2vw(8);
|
|
113
|
+
color: #f2f2f2;
|
|
114
|
+
background: var(--jnrs-color-primary);
|
|
115
|
+
border-radius: px2vw(2);
|
|
116
|
+
margin: 0 px2vw(2);
|
|
117
|
+
transition: all 0.25s ease;
|
|
118
|
+
cursor: pointer;
|
|
119
|
+
|
|
120
|
+
&:hover {
|
|
121
|
+
filter: brightness(1.3);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.visual_canvas {
|
|
128
|
+
position: relative;
|
|
129
|
+
width: 100%;
|
|
130
|
+
height: 100%;
|
|
131
|
+
|
|
132
|
+
i {
|
|
133
|
+
position: absolute;
|
|
134
|
+
top: 50%;
|
|
135
|
+
left: 50%;
|
|
136
|
+
transform: translate(-50%, -50%);
|
|
137
|
+
font-size: px2vw(100);
|
|
138
|
+
color: #fff;
|
|
139
|
+
opacity: 0.5;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
28
143
|
</style>
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'http'
|
|
2
|
+
|
|
1
3
|
const res_fail = {
|
|
2
4
|
code: 1,
|
|
3
5
|
msg: '操作失败'
|
|
4
6
|
}
|
|
5
7
|
|
|
6
8
|
export default [
|
|
9
|
+
// 404
|
|
10
|
+
{
|
|
11
|
+
url: '/mock/notFound',
|
|
12
|
+
method: 'get',
|
|
13
|
+
rawResponse: async (req: IncomingMessage, res: ServerResponse) => {
|
|
14
|
+
res.statusCode = 404
|
|
15
|
+
res.end('File not found')
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
},
|
|
7
19
|
// 权限不足
|
|
8
20
|
{
|
|
9
21
|
url: '/mock/auth/no',
|