create-jnrs-template-vue 1.1.14 → 1.1.15
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/bin/create.mjs +55 -32
- package/jnrs-template-vue/auto-imports.d.ts +2 -0
- package/jnrs-template-vue/components.d.ts +1 -1
- package/jnrs-template-vue/package.json +4 -4
- package/jnrs-template-vue/src/api/common/index.ts +7 -3
- package/jnrs-template-vue/src/api/demos/index.ts +40 -25
- package/jnrs-template-vue/src/api/system/index.ts +3 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconArchive.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconAudio.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconCode.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconExcel.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconFile.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconFlash.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconGif.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconImage.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconMac.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconOfd.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconPdf.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconPpt.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconText.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconUnknown.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconVideo.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconWindows.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconWord.png +0 -0
- package/jnrs-template-vue/src/assets/images/fileIcon/iconWps.png +0 -0
- package/jnrs-template-vue/src/components/base/ImageView.vue +117 -40
- package/jnrs-template-vue/src/components/base/JnFileUpload.vue +433 -0
- package/jnrs-template-vue/src/components/base/PdfView.vue +106 -0
- package/jnrs-template-vue/src/components/common/JnDatetime.vue +37 -0
- package/jnrs-template-vue/src/components/common/JnDictTag.vue +70 -0
- package/jnrs-template-vue/src/components/common/JnEdit.vue +68 -0
- package/jnrs-template-vue/src/layout/SideMenu.vue +1 -0
- package/jnrs-template-vue/src/layout/TopHeader.vue +17 -5
- package/jnrs-template-vue/src/types/index.ts +32 -8
- package/jnrs-template-vue/src/utils/packages.ts +12 -7
- package/jnrs-template-vue/src/views/demos/crud/index.vue +180 -24
- package/jnrs-template-vue/src/views/demos/unitTest/RequestPage.vue +12 -16
- package/jnrs-template-vue/src/views/login/index.vue +13 -18
- package/jnrs-template-vue/src/views/system/mine/baseInfo.vue +3 -8
- package/jnrs-template-vue/tsconfig.json +4 -1
- package/jnrs-template-vue/vite.config.ts +1 -1
- package/jnrs-template-vue/viteMockServe/file.ts +68 -0
- package/jnrs-template-vue/viteMockServe/fileSrc/mock-pdf.pdf +0 -0
- package/jnrs-template-vue/viteMockServe/fileSrc/mock-png-0.png +0 -0
- package/jnrs-template-vue/viteMockServe/fileSrc/mock-png-1.png +0 -0
- package/jnrs-template-vue/viteMockServe/index.ts +10 -8
- package/jnrs-template-vue/viteMockServe/json/dictRes.json +21 -0
- package/jnrs-template-vue/viteMockServe/json/loginRes_admin.json +157 -0
- package/jnrs-template-vue/viteMockServe/{loginRes_user.json → json/loginRes_user.json} +1 -1
- package/jnrs-template-vue/viteMockServe/{tableRes.json → json/tableRes.json} +143 -70
- package/jnrs-template-vue/viteMockServe/success.ts +8 -0
- package/package.json +1 -1
- package/jnrs-template-vue/viteMockServe/dictRes.json +0 -141
- package/jnrs-template-vue/viteMockServe/loginRes_admin.json +0 -713
- /package/jnrs-template-vue/viteMockServe/{detailsRes.json → json/detailsRes.json} +0 -0
- /package/jnrs-template-vue/viteMockServe/{dictItemRes.json → json/dictItemRes.json} +0 -0
- /package/jnrs-template-vue/viteMockServe/{roleRes.json → json/roleRes.json} +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { GlobalSetting } from '@jnrs/vue-core/components'
|
|
3
2
|
import { ref, computed } from 'vue'
|
|
4
3
|
import { storeToRefs } from 'pinia'
|
|
5
4
|
import { ElMessageBox } from 'element-plus'
|
|
6
5
|
import { handleRouter } from '@jnrs/vue-core/router'
|
|
6
|
+
import { GlobalSetting } from '@jnrs/vue-core/components'
|
|
7
7
|
import { useSystemStore, useAuthStore, useMenuStore } from '@jnrs/vue-core/pinia'
|
|
8
|
-
import { useAvatar } from '@/composables/base/useAvatar'
|
|
9
8
|
import { LogoutApi } from '@/api/system'
|
|
10
9
|
import { getDictLabel, getDictColor } from '@/utils/packages'
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
import ImageView from '@/components/base/ImageView.vue'
|
|
12
|
+
|
|
13
13
|
const { userInfo, clearAuth } = useAuthStore()
|
|
14
14
|
const { clearMenu } = useMenuStore()
|
|
15
15
|
|
|
@@ -66,14 +66,14 @@ const showGlobalSetting = () => {
|
|
|
66
66
|
<el-popover placement="bottom" trigger="click" :teleported="false" :width="260" :hide-after="0">
|
|
67
67
|
<template #reference>
|
|
68
68
|
<span class="userMenu_reference">
|
|
69
|
-
<
|
|
69
|
+
<ImageView class="userMenu_avatar" :loadKeys="userInfo?.avatarFileName" />
|
|
70
70
|
<span>{{ userInfo?.name }}</span>
|
|
71
71
|
<span class="userMenu_roleName" :style="{ color: roleColor }" v-if="userInfo?.role">[{{ roleLabel }}]</span>
|
|
72
72
|
<el-icon class="userMenu_icon"><arrow-down /></el-icon>
|
|
73
73
|
</span>
|
|
74
74
|
</template>
|
|
75
75
|
<div class="userMenu_dropdown">
|
|
76
|
-
<
|
|
76
|
+
<ImageView class="userMenu_dropdown_avatar" :loadKeys="userInfo?.avatarFileName" />
|
|
77
77
|
<b>
|
|
78
78
|
<span>{{ userInfo?.name }}</span>
|
|
79
79
|
<span class="userMenu_roleName" :style="{ color: roleColor }" v-if="userInfo?.role">[{{ roleLabel }}]</span>
|
|
@@ -147,6 +147,8 @@ $topHoverSize: 35px;
|
|
|
147
147
|
height: $topHoverSize;
|
|
148
148
|
border-radius: 50%;
|
|
149
149
|
margin-right: 4px;
|
|
150
|
+
overflow: hidden;
|
|
151
|
+
background: var(--jnrs-background-head);
|
|
150
152
|
}
|
|
151
153
|
.userMenu_icon {
|
|
152
154
|
margin-left: 4px;
|
|
@@ -155,10 +157,20 @@ $topHoverSize: 35px;
|
|
|
155
157
|
}
|
|
156
158
|
.userMenu_dropdown {
|
|
157
159
|
text-align: center;
|
|
160
|
+
|
|
161
|
+
.userMenu_dropdown_avatar {
|
|
162
|
+
width: 120px !important;
|
|
163
|
+
height: 120px !important;
|
|
164
|
+
margin: 0 auto 8px;
|
|
165
|
+
background: var(--jnrs-background-head);
|
|
166
|
+
border-radius: 5px;
|
|
167
|
+
}
|
|
158
168
|
img {
|
|
159
169
|
width: 80px;
|
|
160
170
|
height: 80px;
|
|
161
171
|
border-radius: 50%;
|
|
172
|
+
object-fit: none;
|
|
173
|
+
object-position: center;
|
|
162
174
|
}
|
|
163
175
|
b {
|
|
164
176
|
display: block;
|
|
@@ -1,14 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 附件(文件)信息
|
|
3
|
+
*/
|
|
1
4
|
export interface Attachment {
|
|
2
|
-
|
|
5
|
+
/**
|
|
6
|
+
* 数据 id
|
|
7
|
+
*/
|
|
8
|
+
id: number
|
|
9
|
+
/**
|
|
10
|
+
* 文件 id
|
|
11
|
+
*/
|
|
12
|
+
documentId: number
|
|
13
|
+
/**
|
|
14
|
+
* 文件名
|
|
15
|
+
*/
|
|
16
|
+
fileName: string
|
|
17
|
+
/**
|
|
18
|
+
* 文件名唯一标识
|
|
19
|
+
*/
|
|
3
20
|
uniqueFileName: string
|
|
21
|
+
/**
|
|
22
|
+
* MIME 类型
|
|
23
|
+
*/
|
|
24
|
+
fileType: string
|
|
25
|
+
/**
|
|
26
|
+
* 文件大小 单位:字节(Bytes)
|
|
27
|
+
*/
|
|
28
|
+
fileSize: number
|
|
4
29
|
}
|
|
5
30
|
|
|
6
|
-
|
|
31
|
+
/**
|
|
32
|
+
* 文档容器(用于图片或附件)
|
|
33
|
+
*/
|
|
34
|
+
export interface Document {
|
|
35
|
+
id: number
|
|
36
|
+
description: string | null
|
|
7
37
|
attachments: Attachment[]
|
|
8
38
|
}
|
|
9
|
-
|
|
10
|
-
export interface ApiResponse {
|
|
11
|
-
attachmentDocument?: AttachmentDocument
|
|
12
|
-
imageDocument?: AttachmentDocument
|
|
13
|
-
[key: string]: unknown
|
|
14
|
-
}
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
* @Desc. : 对 packages 的一些公用方法进行封装
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { ElMessage } from 'element-plus'
|
|
9
|
+
import { ElMessage, ElLoading } from 'element-plus'
|
|
10
10
|
import {
|
|
11
|
-
|
|
11
|
+
getDictList as _getDictList,
|
|
12
12
|
getDictLabel as _getDictLabel,
|
|
13
13
|
getDictValue as _getDictValue,
|
|
14
14
|
getDictColor as _getDictColor,
|
|
15
|
-
|
|
15
|
+
downloadByBlob as _downloadByBlob
|
|
16
16
|
} from '@jnrs/shared'
|
|
17
17
|
import { useAuthStore } from '@jnrs/vue-core/pinia'
|
|
18
18
|
import { objectToFormData as _objectToFormData } from '@jnrs/shared'
|
|
@@ -23,10 +23,10 @@ import { FileApi } from '@/api/common'
|
|
|
23
23
|
* @param name 字典名称
|
|
24
24
|
* @returns 某字典名称所对应的字典列表数据
|
|
25
25
|
*/
|
|
26
|
-
export const
|
|
26
|
+
export const getDictList = (name: string) => {
|
|
27
27
|
const { dict } = useAuthStore()
|
|
28
28
|
if (dict) {
|
|
29
|
-
return
|
|
29
|
+
return _getDictList(name, dict)
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -96,15 +96,20 @@ export const objectToFormData = (obj: Record<string, unknown>) => {
|
|
|
96
96
|
* @returns loading 下载状态
|
|
97
97
|
*/
|
|
98
98
|
export const downloadFile = async (uniqueFileName: string, filename?: string) => {
|
|
99
|
+
const elLoading = ElLoading.service({
|
|
100
|
+
lock: true,
|
|
101
|
+
text: '文件下载中...',
|
|
102
|
+
background: 'rgba(0, 0, 0, 0.5)'
|
|
103
|
+
})
|
|
99
104
|
let loading = true
|
|
100
|
-
ElMessage.info('文件下载中...')
|
|
101
105
|
try {
|
|
102
106
|
const blob = await FileApi(uniqueFileName)
|
|
103
|
-
|
|
107
|
+
_downloadByBlob(blob, filename || uniqueFileName)
|
|
104
108
|
} catch (error) {
|
|
105
109
|
console.error(error)
|
|
106
110
|
ElMessage.warning('文件下载失败')
|
|
107
111
|
} finally {
|
|
112
|
+
elLoading.close()
|
|
108
113
|
loading = false
|
|
109
114
|
}
|
|
110
115
|
return loading
|
|
@@ -1,34 +1,114 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { FormInstance, FormRules } from 'element-plus'
|
|
3
|
+
import type { Attachment } from '@/types'
|
|
4
|
+
import type { ProjectItem, AddProjectItem } from '@/api/demos/index'
|
|
2
5
|
import { ref, onActivated } from 'vue'
|
|
6
|
+
import { ElMessage } from 'element-plus'
|
|
7
|
+
import { Plus } from '@element-plus/icons-vue'
|
|
8
|
+
import { objectMatchAssign } from '@jnrs/shared'
|
|
9
|
+
import { isNumberGtZero } from '@jnrs/shared/validator'
|
|
10
|
+
import { getDictList, objectToFormData } from '@/utils/packages'
|
|
11
|
+
import { DemosTableApi, DemosFormApi } from '@/api/demos/index'
|
|
3
12
|
import JnTable from '@/components/common/JnTable.vue'
|
|
4
13
|
import JnPagination from '@/components/common/JnPagination.vue'
|
|
5
|
-
import
|
|
6
|
-
import
|
|
14
|
+
import ImageView from '@/components/base/ImageView.vue'
|
|
15
|
+
import PdfView from '@/components/base/PdfView.vue'
|
|
16
|
+
import JnEdit from '@/components/common/JnEdit.vue'
|
|
17
|
+
import JnDictTag from '@/components/common/JnDictTag.vue'
|
|
18
|
+
import JnDatetime from '@/components/common/JnDatetime.vue'
|
|
19
|
+
import JnFileUpload from '@/components/base/JnFileUpload.vue'
|
|
7
20
|
|
|
8
|
-
|
|
21
|
+
interface ProcessedProjectItem extends ProjectItem {
|
|
22
|
+
newImageFiles?: Attachment[]
|
|
23
|
+
newAttachmentFile?: Attachment[]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const loading = ref(false)
|
|
27
|
+
const tableData = ref<ProcessedProjectItem[]>([])
|
|
9
28
|
const total = ref(0)
|
|
10
29
|
const pagination = ref({ currentPage: 1, pageSize: 10 })
|
|
30
|
+
const jnEditRef = ref()
|
|
31
|
+
const ruleFormRef = ref<FormInstance>()
|
|
11
32
|
|
|
12
|
-
const
|
|
33
|
+
const ruleForm = ref<AddProjectItem>({
|
|
34
|
+
id: '',
|
|
35
|
+
name: '',
|
|
36
|
+
program: '',
|
|
37
|
+
projectType: undefined,
|
|
38
|
+
budget: 0,
|
|
39
|
+
plannedStartDate: '',
|
|
40
|
+
description: '',
|
|
41
|
+
newImageFiles: [],
|
|
42
|
+
newAttachmentFile: []
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const rules = ref<FormRules>({
|
|
46
|
+
name: [{ required: true, message: '请输入', trigger: 'change' }],
|
|
47
|
+
program: [{ required: true, message: '请选择', trigger: 'change' }],
|
|
48
|
+
projectType: [{ required: true, message: '请选择', trigger: 'change' }],
|
|
49
|
+
plannedStartDate: [{ required: true, message: '请选择', trigger: 'change' }],
|
|
50
|
+
newImageFiles: [{ required: true, message: '请上传', trigger: 'change' }],
|
|
51
|
+
budget: [
|
|
52
|
+
{ required: true, message: '请输入', trigger: 'change' },
|
|
53
|
+
{
|
|
54
|
+
validator: isNumberGtZero,
|
|
55
|
+
trigger: 'change'
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const handlePaginationChange = () => {
|
|
13
61
|
console.log(pagination.value)
|
|
14
62
|
}
|
|
15
63
|
|
|
64
|
+
const handleSelectionChange = (row: ProjectItem[]) => {
|
|
65
|
+
console.log(row)
|
|
66
|
+
}
|
|
67
|
+
|
|
16
68
|
const getDemosTable = async () => {
|
|
17
69
|
try {
|
|
18
70
|
const res = await DemosTableApi()
|
|
19
|
-
tableData.value = res
|
|
71
|
+
tableData.value = res.map((item) => ({
|
|
72
|
+
...item,
|
|
73
|
+
newImageFiles: item.imageDocument?.attachments ?? undefined,
|
|
74
|
+
newAttachmentFile: item.attachmentDocument?.attachments ?? undefined
|
|
75
|
+
}))
|
|
20
76
|
total.value = res.length
|
|
21
77
|
} catch (error) {
|
|
22
78
|
console.error(error)
|
|
23
79
|
}
|
|
24
80
|
}
|
|
25
81
|
|
|
26
|
-
|
|
27
|
-
|
|
82
|
+
// 新增和修改
|
|
83
|
+
const handleEdit = (row?: ProjectItem) => {
|
|
84
|
+
jnEditRef.value.open()
|
|
85
|
+
queueMicrotask(() => {
|
|
86
|
+
ruleFormRef.value?.resetFields()
|
|
87
|
+
const matched = objectMatchAssign(ruleForm.value, row)
|
|
88
|
+
ruleForm.value = matched
|
|
89
|
+
})
|
|
28
90
|
}
|
|
29
91
|
|
|
30
|
-
|
|
31
|
-
|
|
92
|
+
// 提交表单
|
|
93
|
+
const submitForm = () => {
|
|
94
|
+
ruleFormRef.value?.validate(async (valid) => {
|
|
95
|
+
if (valid) {
|
|
96
|
+
loading.value = true
|
|
97
|
+
const formData = objectToFormData(ruleForm.value)
|
|
98
|
+
try {
|
|
99
|
+
await DemosFormApi(formData)
|
|
100
|
+
ElMessage({
|
|
101
|
+
message: '数据已保存',
|
|
102
|
+
grouping: true,
|
|
103
|
+
type: 'success'
|
|
104
|
+
})
|
|
105
|
+
} catch (err) {
|
|
106
|
+
console.error(err)
|
|
107
|
+
} finally {
|
|
108
|
+
loading.value = false
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
})
|
|
32
112
|
}
|
|
33
113
|
|
|
34
114
|
onActivated(() => {
|
|
@@ -37,9 +117,77 @@ onActivated(() => {
|
|
|
37
117
|
</script>
|
|
38
118
|
|
|
39
119
|
<template>
|
|
120
|
+
<JnEdit ref="jnEditRef" title="项目管理" width="600px">
|
|
121
|
+
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" v-loading="loading">
|
|
122
|
+
<el-form-item prop="id"></el-form-item>
|
|
123
|
+
<el-form-item label="项目名称" prop="name">
|
|
124
|
+
<el-input v-model.trim="ruleForm.name" maxlength="20" show-word-limit />
|
|
125
|
+
</el-form-item>
|
|
126
|
+
<el-form-item label="类型" prop="projectType">
|
|
127
|
+
<el-select v-model="ruleForm.projectType" filterable placeholder="">
|
|
128
|
+
<el-option
|
|
129
|
+
:label="item.label"
|
|
130
|
+
:value="item.value"
|
|
131
|
+
v-for="item in getDictList('projectType')"
|
|
132
|
+
:key="item.value"
|
|
133
|
+
/>
|
|
134
|
+
</el-select>
|
|
135
|
+
</el-form-item>
|
|
136
|
+
<el-form-item label="预算" prop="budget">
|
|
137
|
+
<el-input-number v-model="ruleForm.budget" :min="0" :precision="2" :step="10000" controls-position="right">
|
|
138
|
+
<template #prefix>
|
|
139
|
+
<span>¥</span>
|
|
140
|
+
</template>
|
|
141
|
+
</el-input-number>
|
|
142
|
+
</el-form-item>
|
|
143
|
+
<el-form-item label="计划开始时间" prop="plannedStartDate">
|
|
144
|
+
<el-date-picker
|
|
145
|
+
v-model="ruleForm.plannedStartDate"
|
|
146
|
+
type="datetime"
|
|
147
|
+
format="YYYY-MM-DD HH:mm:ss"
|
|
148
|
+
value-format="YYYY-MM-DD HH:mm:ss"
|
|
149
|
+
:disabled-date="
|
|
150
|
+
(time: number) => {
|
|
151
|
+
return time < Date.now() - 86400000
|
|
152
|
+
}
|
|
153
|
+
"
|
|
154
|
+
/>
|
|
155
|
+
</el-form-item>
|
|
156
|
+
<el-form-item label="描述" prop="description">
|
|
157
|
+
<el-input
|
|
158
|
+
v-model="ruleForm.description"
|
|
159
|
+
:autosize="{ minRows: 2, maxRows: 4 }"
|
|
160
|
+
type="textarea"
|
|
161
|
+
maxlength="200"
|
|
162
|
+
show-word-limit
|
|
163
|
+
/>
|
|
164
|
+
</el-form-item>
|
|
165
|
+
<el-form-item label="上传图片" prop="newImageFiles">
|
|
166
|
+
<JnFileUpload
|
|
167
|
+
v-model="ruleForm.newImageFiles"
|
|
168
|
+
:formRef="ruleFormRef"
|
|
169
|
+
validateFieldName="newImageFiles"
|
|
170
|
+
accept=".png,.jpg,.bmp,.gif"
|
|
171
|
+
:fileSizeMb="50"
|
|
172
|
+
:limit="3"
|
|
173
|
+
drag
|
|
174
|
+
/>
|
|
175
|
+
</el-form-item>
|
|
176
|
+
<el-form-item label="上传文件" prop="newAttachmentFile">
|
|
177
|
+
<JnFileUpload v-model="ruleForm.newAttachmentFile" accept=".pdf" :limit="1" />
|
|
178
|
+
</el-form-item>
|
|
179
|
+
</el-form>
|
|
180
|
+
<template #footer>
|
|
181
|
+
<el-button type="success" icon="Select" :loading="loading" @click="submitForm()">提交</el-button>
|
|
182
|
+
</template>
|
|
183
|
+
</JnEdit>
|
|
184
|
+
|
|
40
185
|
<el-card>
|
|
41
186
|
<template #header>
|
|
42
|
-
<
|
|
187
|
+
<div class="card_header">
|
|
188
|
+
<span>项目管理</span>
|
|
189
|
+
<el-button type="primary" size="small" :icon="Plus" @click="handleEdit()">新增</el-button>
|
|
190
|
+
</div>
|
|
43
191
|
</template>
|
|
44
192
|
<JnTable
|
|
45
193
|
:data="tableData"
|
|
@@ -51,29 +199,29 @@ onActivated(() => {
|
|
|
51
199
|
<el-table-column prop="code" label="项目编号" min-width="200" sortable show-overflow-tooltip />
|
|
52
200
|
<el-table-column prop="name" label="项目名称" min-width="200" sortable show-overflow-tooltip>
|
|
53
201
|
<template #default="{ row }">
|
|
54
|
-
|
|
202
|
+
{{ row.name }}
|
|
55
203
|
</template>
|
|
56
204
|
</el-table-column>
|
|
57
205
|
<el-table-column prop="program" label="项目集名称" min-width="200" sortable show-overflow-tooltip />
|
|
58
|
-
<el-table-column prop="
|
|
206
|
+
<el-table-column prop="projectType" label="项目类型" width="100" align="center" sortable>
|
|
59
207
|
<template #default="{ row }">
|
|
60
|
-
<
|
|
208
|
+
<JnDictTag dictName="projectType" :value="row.projectType" />
|
|
61
209
|
</template>
|
|
62
210
|
</el-table-column>
|
|
63
211
|
<el-table-column prop="manager" label="项目经理" width="100" align="center" sortable />
|
|
64
|
-
<el-table-column prop="budget" label="预算" width="100" align="center" sortable>
|
|
212
|
+
<el-table-column prop="budget" label="预算(¥)" width="100" align="center" sortable>
|
|
65
213
|
<template #default="{ row }">
|
|
66
|
-
|
|
214
|
+
{{ row.budget }}
|
|
67
215
|
</template>
|
|
68
216
|
</el-table-column>
|
|
69
|
-
<el-table-column prop="plannedStartDate" label="
|
|
217
|
+
<el-table-column prop="plannedStartDate" label="计划开始时间" width="130" align="center" sortable>
|
|
70
218
|
<template #default="{ row }">
|
|
71
|
-
<
|
|
219
|
+
<JnDatetime :value="row.plannedStartDate" />
|
|
72
220
|
</template>
|
|
73
221
|
</el-table-column>
|
|
74
222
|
<el-table-column prop="plannedFinishDate" label="计划完成日期" width="130" align="center" sortable>
|
|
75
223
|
<template #default="{ row }">
|
|
76
|
-
|
|
224
|
+
{{ row.plannedFinishDate }}
|
|
77
225
|
</template>
|
|
78
226
|
</el-table-column>
|
|
79
227
|
<el-table-column prop="progress" label="进度" width="100" align="center" sortable>
|
|
@@ -83,26 +231,34 @@ onActivated(() => {
|
|
|
83
231
|
</el-table-column>
|
|
84
232
|
<el-table-column prop="status" label="状态" width="100" align="center" sortable>
|
|
85
233
|
<template #default="{ row }">
|
|
86
|
-
<
|
|
234
|
+
<JnDictTag dictName="status" :value="row.status" :showColor="false" />
|
|
87
235
|
</template>
|
|
88
236
|
</el-table-column>
|
|
237
|
+
<el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip />
|
|
89
238
|
<el-table-column prop="imageDocument" label="图片" width="100" align="center" sortable>
|
|
90
239
|
<template #default="{ row }">
|
|
91
|
-
<
|
|
240
|
+
<ImageView :loadKeys="row.newImageFiles" preview maxHeight="50px" />
|
|
92
241
|
</template>
|
|
93
242
|
</el-table-column>
|
|
94
243
|
<el-table-column prop="attachmentDocument" label="附件" width="100" align="center" sortable>
|
|
95
244
|
<template #default="{ row }">
|
|
96
|
-
<
|
|
245
|
+
<PdfView :loadKeys="row.newAttachmentFile" isPdf />
|
|
97
246
|
</template>
|
|
98
247
|
</el-table-column>
|
|
99
248
|
<el-table-column label="操作" width="100" align="center" fixed="right">
|
|
100
249
|
<template #default="{ row }">
|
|
101
|
-
<el-button link type="primary" @click.stop="
|
|
250
|
+
<el-button link type="primary" @click.stop="handleEdit(row)">编辑</el-button>
|
|
102
251
|
</template>
|
|
103
252
|
</el-table-column>
|
|
104
253
|
</JnTable>
|
|
105
|
-
|
|
254
|
+
|
|
255
|
+
<JnPagination :total="total" v-model="pagination" @change="handlePaginationChange" />
|
|
106
256
|
</el-card>
|
|
107
257
|
</template>
|
|
108
|
-
|
|
258
|
+
|
|
259
|
+
<style lang="scss" scoped>
|
|
260
|
+
.card_header {
|
|
261
|
+
display: flex;
|
|
262
|
+
justify-content: space-between;
|
|
263
|
+
}
|
|
264
|
+
</style>
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref } from 'vue'
|
|
3
|
-
import { storeToRefs } from 'pinia'
|
|
4
3
|
import { ElMessage } from 'element-plus'
|
|
5
4
|
import { objectToFormData } from '@/utils/packages'
|
|
6
|
-
import { useMockStore } from '@jnrs/vue-core/pinia'
|
|
7
5
|
import { LoginApi, UserInfoApi } from '@/api/system'
|
|
8
6
|
import { NotFoundApi, NoAuth, DetailsApi } from '@/api/demos'
|
|
9
7
|
import { getFileUrl } from '@/utils/file'
|
|
10
8
|
import { downloadFile } from '@/utils/packages'
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
import ImageView from '@/components/base/ImageView.vue'
|
|
11
|
+
|
|
13
12
|
const squareUrl = ref()
|
|
14
13
|
|
|
15
14
|
const loginParams = ref({
|
|
@@ -80,10 +79,10 @@ const handleDetailsApi = async () => {
|
|
|
80
79
|
}
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
//
|
|
82
|
+
// 获取后端服务器文件进行预览
|
|
84
83
|
const handleFileView = async () => {
|
|
85
84
|
try {
|
|
86
|
-
const url = await getFileUrl('
|
|
85
|
+
const url = await getFileUrl('mock-png-1.png')
|
|
87
86
|
squareUrl.value = url.value
|
|
88
87
|
} catch (error) {
|
|
89
88
|
console.log(error)
|
|
@@ -93,10 +92,6 @@ const handleFileView = async () => {
|
|
|
93
92
|
|
|
94
93
|
<template>
|
|
95
94
|
<p>网络请求测试</p>
|
|
96
|
-
<div>
|
|
97
|
-
<span>服务器类型:</span>
|
|
98
|
-
<el-switch v-model="isMock" active-text="Mock 服务器" inactive-text="后端服务器" />
|
|
99
|
-
</div>
|
|
100
95
|
<el-button-group>
|
|
101
96
|
<el-button type="success" size="small" @click="handleInfoApi">获取用户数据</el-button>
|
|
102
97
|
<el-button type="primary" size="small" @click="handleNotFoundApi">404</el-button>
|
|
@@ -111,20 +106,21 @@ const handleFileView = async () => {
|
|
|
111
106
|
<div>
|
|
112
107
|
<el-button-group>
|
|
113
108
|
<el-button type="primary" plain size="small" @click="handleDetailsApi">获取数据列表单个数据</el-button>
|
|
114
|
-
<el-button
|
|
115
|
-
type="primary"
|
|
116
|
-
plain
|
|
117
|
-
size="small"
|
|
118
|
-
@click="downloadFile('20251217171430919-34bcc1a9-a19d-4b91-9ab6-57cb31c3df28.jpg')"
|
|
119
|
-
>
|
|
109
|
+
<el-button type="primary" plain size="small" @click="downloadFile('mock-pdf.pdf')">
|
|
120
110
|
获取后端服务器文件进行下载
|
|
121
111
|
</el-button>
|
|
122
112
|
</el-button-group>
|
|
123
113
|
<div>
|
|
124
|
-
<
|
|
114
|
+
<span>通过 ImageView 组件显示的图片(可支持预览)</span>
|
|
115
|
+
<ImageView
|
|
116
|
+
loadKeys="mock-png-1.png"
|
|
117
|
+
preview
|
|
118
|
+
style="width: 300px; height: 50px; border: 1px solid var(--jnrs-color-primary)"
|
|
119
|
+
/>
|
|
125
120
|
</div>
|
|
126
121
|
<div>
|
|
127
122
|
<el-button type="primary" plain size="small" @click="handleFileView">获取后端服务器图片</el-button>
|
|
123
|
+
<el-avatar shape="circle" :src="squareUrl" />
|
|
128
124
|
</div>
|
|
129
125
|
</div>
|
|
130
126
|
</template>
|
|
@@ -16,12 +16,7 @@ const showGlobalSetting = () => {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
const loading = ref(false)
|
|
19
|
-
const {
|
|
20
|
-
setUserInfo,
|
|
21
|
-
setToken,
|
|
22
|
-
setDict
|
|
23
|
-
// setRole
|
|
24
|
-
} = useAuthStore()
|
|
19
|
+
const { setUserInfo, setToken, setDict, setRole } = useAuthStore()
|
|
25
20
|
|
|
26
21
|
// 表单 ref
|
|
27
22
|
const ruleFormRef = ref<FormInstance>()
|
|
@@ -51,21 +46,21 @@ const submitForm = async () => {
|
|
|
51
46
|
const loginDateTime = formatDateTime() + ' ' + formatWeekday()
|
|
52
47
|
|
|
53
48
|
// 获取角色列表,将登录人角色对应的权限叠加给当前登录人(一次性获取叠加)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
49
|
+
const roleRes = await RoleApi()
|
|
50
|
+
let permissionsMerger = restParameter.permissions
|
|
51
|
+
if (Array.isArray(restParameter.permissions)) {
|
|
52
|
+
permissionsMerger = [
|
|
53
|
+
...new Set([
|
|
54
|
+
...restParameter.permissions,
|
|
55
|
+
...(roleRes.find((r) => r.value === restParameter.role)?.permissions ?? []).flat()
|
|
56
|
+
])
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
setRole(roleRes) // 由于是一次性获取叠加,此处不需要保存角色列表到全局状态
|
|
65
60
|
|
|
66
61
|
setUserInfo({
|
|
67
62
|
...restParameter,
|
|
68
|
-
|
|
63
|
+
permissions: permissionsMerger,
|
|
69
64
|
account: ruleForm.value.account,
|
|
70
65
|
loginDateTime
|
|
71
66
|
})
|
|
@@ -5,7 +5,7 @@ import { ElMessage } from 'element-plus'
|
|
|
5
5
|
import type { UploadProps } from 'element-plus'
|
|
6
6
|
import { useAuthStore } from '@jnrs/vue-core/pinia'
|
|
7
7
|
import { useAvatar } from '@/composables/base/useAvatar'
|
|
8
|
-
import {
|
|
8
|
+
import { getDictList } from '@/utils/packages'
|
|
9
9
|
import type { User } from '@jnrs/shared'
|
|
10
10
|
|
|
11
11
|
const { userInfo, token } = storeToRefs(useAuthStore())
|
|
@@ -81,7 +81,7 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
|
|
81
81
|
<el-option
|
|
82
82
|
:label="item.label"
|
|
83
83
|
:value="item.value"
|
|
84
|
-
v-for="(item, index) in
|
|
84
|
+
v-for="(item, index) in getDictList('jobTitle')"
|
|
85
85
|
:key="index"
|
|
86
86
|
/>
|
|
87
87
|
</el-select>
|
|
@@ -91,12 +91,7 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
|
|
91
91
|
</el-form-item>
|
|
92
92
|
<el-form-item label="职位/账号权限" prop="role">
|
|
93
93
|
<el-select v-model="ruleForm.role" placeholder="" style="width: 200px">
|
|
94
|
-
<el-option
|
|
95
|
-
:label="item.label"
|
|
96
|
-
:value="item.value"
|
|
97
|
-
v-for="(item, index) in getOneDictList('role')"
|
|
98
|
-
:key="index"
|
|
99
|
-
/>
|
|
94
|
+
<el-option :label="item.label" :value="item.value" v-for="(item, index) in getDictList('role')" :key="index" />
|
|
100
95
|
</el-select>
|
|
101
96
|
</el-form-item>
|
|
102
97
|
<el-form-item label="头像" prop="avatarFileName" class="uploader_item">
|
|
@@ -24,7 +24,10 @@
|
|
|
24
24
|
"src/**/*",
|
|
25
25
|
"vite.config.ts",
|
|
26
26
|
"../../../packages/shared/src/validate.ts",
|
|
27
|
-
"../../../packages/shared/src/validator.ts"
|
|
27
|
+
"../../../packages/shared/src/validator.ts",
|
|
28
|
+
"../../../packages/vue-core/src/components/JnImageView.vue",
|
|
29
|
+
"../../../packages/vue-core/src/components/JnPdfView.vue",
|
|
30
|
+
"src/components/common/JnEdit.vue"
|
|
28
31
|
],
|
|
29
32
|
"exclude": ["node_modules", "dist"]
|
|
30
33
|
}
|