create-jnrs-template-vue 1.2.1 → 1.2.3
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 +3 -3
- package/jnrs-template-vue/auto-imports.d.ts +4 -0
- package/jnrs-template-vue/components.d.ts +0 -1
- package/jnrs-template-vue/package.json +3 -4
- package/jnrs-template-vue/public/system/menu.json +1 -1
- 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 +84 -48
- package/jnrs-template-vue/src/api/system/index.ts +10 -10
- package/jnrs-template-vue/src/api/user/index.ts +2 -2
- package/jnrs-template-vue/src/assets/styles/animation.scss +0 -0
- package/jnrs-template-vue/src/assets/styles/common.scss +4 -0
- package/jnrs-template-vue/src/assets/styles/fonts.scss +4 -1
- package/jnrs-template-vue/src/assets/styles/{main.scss → index.scss} +1 -0
- package/jnrs-template-vue/src/assets/styles/init.scss +4 -13
- package/jnrs-template-vue/src/assets/styles/root.scss +0 -3
- package/jnrs-template-vue/src/components/common/{JnDictTag.vue → DictTag.vue} +1 -1
- package/jnrs-template-vue/src/components/{base → common}/PdfView.vue +2 -2
- package/jnrs-template-vue/src/components/select/SelectManager.vue +20 -0
- package/jnrs-template-vue/src/composables/common/usePagination.ts +4 -4
- package/jnrs-template-vue/src/composables/common/useTable.ts +4 -4
- package/jnrs-template-vue/src/composables/tools/useMouseSelection.ts +150 -0
- package/jnrs-template-vue/src/layout/SideMenu.vue +1 -0
- package/jnrs-template-vue/src/layout/TopHeader.vue +1 -1
- package/jnrs-template-vue/src/locales/en.ts +1 -1
- package/jnrs-template-vue/src/locales/index.ts +1 -1
- package/jnrs-template-vue/src/main.ts +1 -1
- package/jnrs-template-vue/src/types/index.ts +45 -3
- package/jnrs-template-vue/src/views/demos/crud/index.vue +140 -40
- package/jnrs-template-vue/src/views/demos/unitTest/RequestPage.vue +1 -1
- package/jnrs-template-vue/src/views/demos/unitTest/index.vue +26 -2
- package/jnrs-template-vue/src/views/login/index.vue +7 -2
- package/jnrs-template-vue/src/views/system/dict/index.vue +2 -2
- package/jnrs-template-vue/src/views/system/menu/index.vue +2 -2
- package/jnrs-template-vue/src/views/system/mine/baseInfo.vue +1 -1
- package/jnrs-template-vue/tsconfig.json +1 -9
- package/jnrs-template-vue/vite.config.ts +1 -3
- package/jnrs-template-vue/viteMockServe/fail.ts +12 -0
- package/jnrs-template-vue/viteMockServe/file.ts +2 -3
- package/jnrs-template-vue/viteMockServe/json/tableRes.json +384 -342
- package/package.json +1 -1
- 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/JnFileUpload.vue +0 -433
- package/jnrs-template-vue/src/components/common/JnDatetime.vue +0 -37
- package/jnrs-template-vue/src/components/common/JnEdit.vue +0 -68
- package/jnrs-template-vue/src/components/common/JnPagination.vue +0 -83
- package/jnrs-template-vue/src/components/common/JnTable.vue +0 -133
- package/jnrs-template-vue/src/composables/tools/useReactivityTableHeight.ts +0 -63
- /package/jnrs-template-vue/src/components/{base → common}/ImageView.vue +0 -0
- /package/jnrs-template-vue/viteMockServe/{fileSrc → file}/mock-pdf.pdf +0 -0
- /package/jnrs-template-vue/viteMockServe/{fileSrc → file}/mock-png-0.png +0 -0
- /package/jnrs-template-vue/viteMockServe/{fileSrc → file}/mock-png-1.png +0 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @Author : TanRui
|
|
3
|
+
* @WeChat : Tan578853789
|
|
4
|
+
* @File : useMouseSelection.ts
|
|
5
|
+
* @Date : 2025/04/14
|
|
6
|
+
* @Desc. : 鼠标框选表格进行多选、回车执行回调
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { onMounted, onUnmounted, onActivated, onDeactivated } from 'vue'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {*} containerClass 表格或容器类名,默认值 el-table,如果页面存在多个表格,则必须分别传入自定义类名
|
|
13
|
+
* @param {*} rowClass 表格或容器类名,默认值 el-table__row
|
|
14
|
+
* @param {*} callback 框选后的回调,默认处理的是 input[type='checkbox'] 元素
|
|
15
|
+
* @returns handleMouseDown
|
|
16
|
+
* @example <el-table @mousedown="handleMouseDown" @selection-change="handleSelectionChange">
|
|
17
|
+
*/
|
|
18
|
+
export function useMouseSelection({
|
|
19
|
+
containerClass = 'jn_table',
|
|
20
|
+
rowClass = 'el-table__row',
|
|
21
|
+
callback = handleSelection
|
|
22
|
+
} = {}) {
|
|
23
|
+
let isDragging = false
|
|
24
|
+
let startPoint = { x: 0, y: 0 }
|
|
25
|
+
let endPoint = { x: 0, y: 0 }
|
|
26
|
+
|
|
27
|
+
onMounted(() => {
|
|
28
|
+
window.addEventListener('mouseup', handleMouseUp)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
onUnmounted(() => {
|
|
32
|
+
window.removeEventListener('mouseup', handleMouseUp)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
onActivated(() => {
|
|
36
|
+
window.addEventListener('mouseup', handleMouseUp)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
onDeactivated(() => {
|
|
40
|
+
window.removeEventListener('mouseup', handleMouseUp)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// 鼠标按下事件
|
|
44
|
+
const handleMouseDown = (event: MouseEvent) => {
|
|
45
|
+
window.addEventListener('mousemove', handleMouseMove)
|
|
46
|
+
isDragging = false
|
|
47
|
+
startPoint = { x: event.clientX, y: event.clientY }
|
|
48
|
+
endPoint = { ...startPoint }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 鼠标移动事件
|
|
52
|
+
const handleMouseMove = (event: MouseEvent) => {
|
|
53
|
+
endPoint = { x: event.clientX, y: event.clientY }
|
|
54
|
+
// 判断是否为拖动
|
|
55
|
+
if (Math.abs(endPoint.x - startPoint.x) > 5 && Math.abs(endPoint.y - startPoint.y) > 25) {
|
|
56
|
+
isDragging = true
|
|
57
|
+
}
|
|
58
|
+
// 如果没有拖动,则认为是单击
|
|
59
|
+
if (isDragging) {
|
|
60
|
+
selectRows()
|
|
61
|
+
}
|
|
62
|
+
setFixedRectBoxStyle()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 鼠标抬起事件
|
|
66
|
+
const handleMouseUp = () => {
|
|
67
|
+
window.removeEventListener('mousemove', handleMouseMove)
|
|
68
|
+
// 如果没有拖动,则认为是单击
|
|
69
|
+
if (isDragging) {
|
|
70
|
+
isDragging = false
|
|
71
|
+
}
|
|
72
|
+
setFixedRectBoxStyle()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 判断选中的行
|
|
76
|
+
const selectRows = () => {
|
|
77
|
+
const container = document.querySelector(`.${containerClass}`) as HTMLElement
|
|
78
|
+
const rows = container?.querySelectorAll(`.${rowClass}`) as NodeListOf<HTMLElement>
|
|
79
|
+
if (!rows) {
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
rows.forEach((row) => {
|
|
83
|
+
const rect = row.getBoundingClientRect()
|
|
84
|
+
const isIntersecting =
|
|
85
|
+
rect.right > Math.min(startPoint.x, endPoint.x) &&
|
|
86
|
+
rect.left < Math.max(startPoint.x, endPoint.x) &&
|
|
87
|
+
rect.bottom > Math.min(startPoint.y, endPoint.y) &&
|
|
88
|
+
rect.top < Math.max(startPoint.y, endPoint.y)
|
|
89
|
+
if (isIntersecting && callback) {
|
|
90
|
+
callback(row)
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 设置框选框的位置
|
|
96
|
+
const setFixedRectBoxStyle = () => {
|
|
97
|
+
const selectionBox = document.querySelector('.useMouseSelection_fixedRectBox') as HTMLElement
|
|
98
|
+
if (selectionBox) {
|
|
99
|
+
const left = Math.min(startPoint.x, endPoint.x) + 'px'
|
|
100
|
+
const top = Math.min(startPoint.y, endPoint.y) + 'px'
|
|
101
|
+
const width = Math.abs(endPoint.x - startPoint.x) + 'px'
|
|
102
|
+
const height = Math.abs(endPoint.y - startPoint.y) + 'px'
|
|
103
|
+
Object.assign(selectionBox.style, {
|
|
104
|
+
display: isDragging ? 'block' : 'none',
|
|
105
|
+
left: left,
|
|
106
|
+
top: top,
|
|
107
|
+
width: width,
|
|
108
|
+
height: height
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const container = document.querySelector(`.${containerClass}`) as HTMLElement
|
|
112
|
+
Object.assign(container.style, {
|
|
113
|
+
'user-select': isDragging ? 'none' : 'auto'
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
checkAndAddElement()
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
handleMouseDown
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 回调选中逻辑
|
|
126
|
+
const handleSelection = (row: HTMLElement) => {
|
|
127
|
+
const checkbox = row.querySelector("input[type='checkbox']") as HTMLInputElement
|
|
128
|
+
if (checkbox && !checkbox.checked) {
|
|
129
|
+
checkbox.click()
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 往页面上添加框选框元素
|
|
134
|
+
const checkAndAddElement = () => {
|
|
135
|
+
const fixedRectBox = document.querySelector('.useMouseSelection_fixedRectBox')
|
|
136
|
+
if (!fixedRectBox) {
|
|
137
|
+
const newDiv = document.createElement('div')
|
|
138
|
+
newDiv.className = 'useMouseSelection_fixedRectBox'
|
|
139
|
+
Object.assign(newDiv.style, {
|
|
140
|
+
display: 'none',
|
|
141
|
+
position: 'fixed',
|
|
142
|
+
'z-index': 100,
|
|
143
|
+
border: '2px dashed #409eff',
|
|
144
|
+
'background-color': 'rgba(64, 158, 255, 0.2)',
|
|
145
|
+
'pointer-events': 'none',
|
|
146
|
+
'will-change': 'transform'
|
|
147
|
+
})
|
|
148
|
+
document.body.appendChild(newDiv)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -8,7 +8,7 @@ import { useSystemStore, useAuthStore, useMenuStore } from '@jnrs/vue-core/pinia
|
|
|
8
8
|
import { LogoutApi } from '@/api/system'
|
|
9
9
|
import { getDictLabel, getDictColor } from '@/utils/packages'
|
|
10
10
|
|
|
11
|
-
import ImageView from '@/components/
|
|
11
|
+
import ImageView from '@/components/common/ImageView.vue'
|
|
12
12
|
|
|
13
13
|
const { userInfo, clearAuth } = useAuthStore()
|
|
14
14
|
const { clearMenu } = useMenuStore()
|
|
@@ -4,7 +4,7 @@ import en from './en'
|
|
|
4
4
|
import { zhCn as vueCore_zhCn, en as vueCore_en } from '@jnrs/vue-core/locales'
|
|
5
5
|
|
|
6
6
|
const i18n = createI18n({
|
|
7
|
-
legacy: false, //
|
|
7
|
+
legacy: false, // legacy 为 false 则启用 Composition API 模式
|
|
8
8
|
globalInjection: true, // 允许在模板中使用 $t
|
|
9
9
|
locale: 'zhCn',
|
|
10
10
|
fallbackLocale: 'en',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import 'element-plus/dist/index.css'
|
|
2
2
|
import 'element-plus/theme-chalk/dark/css-vars.css'
|
|
3
3
|
import '@jnrs/shared/styles/theme.scss'
|
|
4
|
-
import '@/assets/styles/
|
|
4
|
+
import '@/assets/styles/index.scss'
|
|
5
5
|
|
|
6
6
|
import { createApp } from 'vue'
|
|
7
7
|
import { createPinia } from 'pinia'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 文件信息
|
|
3
3
|
*/
|
|
4
4
|
export interface Attachment {
|
|
5
5
|
/**
|
|
@@ -15,7 +15,7 @@ export interface Attachment {
|
|
|
15
15
|
*/
|
|
16
16
|
fileName: string
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* 文件名唯一标识(用于文件获取 API)
|
|
19
19
|
*/
|
|
20
20
|
uniqueFileName: string
|
|
21
21
|
/**
|
|
@@ -29,10 +29,52 @@ export interface Attachment {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
32
|
+
* 文件容器(用于图片或附件)
|
|
33
33
|
*/
|
|
34
34
|
export interface Document {
|
|
35
35
|
id: number
|
|
36
36
|
description: string | null
|
|
37
37
|
attachments: Attachment[]
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 图片 & 附件数据
|
|
42
|
+
*/
|
|
43
|
+
export interface FileContainer {
|
|
44
|
+
/**
|
|
45
|
+
* 图片
|
|
46
|
+
*/
|
|
47
|
+
imageDocument?: Document
|
|
48
|
+
/**
|
|
49
|
+
* 附件
|
|
50
|
+
*/
|
|
51
|
+
attachmentDocument?: Document
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 分页
|
|
56
|
+
*/
|
|
57
|
+
export interface Pagination {
|
|
58
|
+
/**
|
|
59
|
+
* 当前页码
|
|
60
|
+
*/
|
|
61
|
+
pageNo: number
|
|
62
|
+
/**
|
|
63
|
+
* 每页大小
|
|
64
|
+
*/
|
|
65
|
+
pageSize: number
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 分页列表数据
|
|
70
|
+
*/
|
|
71
|
+
export interface PageTableData<T> extends Pagination {
|
|
72
|
+
/**
|
|
73
|
+
* 数据列表
|
|
74
|
+
*/
|
|
75
|
+
list: T[]
|
|
76
|
+
/**
|
|
77
|
+
* 数据总数
|
|
78
|
+
*/
|
|
79
|
+
count: number
|
|
80
|
+
}
|
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { FormInstance, FormRules } from 'element-plus'
|
|
3
|
-
import type { Attachment } from '@/types'
|
|
3
|
+
import type { Attachment, Pagination } from '@/types'
|
|
4
4
|
import type { ProjectItem, AddProjectItem } from '@/api/demos/index'
|
|
5
5
|
import { ref, onActivated } from 'vue'
|
|
6
6
|
import { ElMessage } from 'element-plus'
|
|
7
7
|
import { Plus } from '@element-plus/icons-vue'
|
|
8
|
-
import { objectMatchAssign } from '@jnrs/shared'
|
|
8
|
+
import { objectMatchAssign, dateFormatsToObject } from '@jnrs/shared'
|
|
9
|
+
import { debounce } from '@jnrs/shared/lodash'
|
|
9
10
|
import { isNumberGtZero } from '@jnrs/shared/validator'
|
|
10
|
-
import { getDictList, objectToFormData } from '@/utils/packages'
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import JnFileUpload from '
|
|
11
|
+
import { getDictList, objectToFormData, downloadFile } from '@/utils/packages'
|
|
12
|
+
import {
|
|
13
|
+
DemosTableApi,
|
|
14
|
+
DemosFormApi,
|
|
15
|
+
DemosImportTemplateApi,
|
|
16
|
+
DemosImportDataApi,
|
|
17
|
+
DemosExportApi
|
|
18
|
+
} from '@/api/demos/index'
|
|
19
|
+
|
|
20
|
+
import { JnDialog, JnDatetime, JnPagination, JnFileUpload, JnTable, JnImportAndExport } from '@jnrs/vue-core/components'
|
|
21
|
+
import ImageView from '@/components/common/ImageView.vue'
|
|
22
|
+
import PdfView from '@/components/common/PdfView.vue'
|
|
23
|
+
import DictTag from '@/components/common/DictTag.vue'
|
|
24
|
+
import SelectManager from '@/components/select/SelectManager.vue'
|
|
20
25
|
|
|
21
26
|
interface ProcessedProjectItem extends ProjectItem {
|
|
22
27
|
newImageFiles?: Attachment[]
|
|
@@ -26,28 +31,30 @@ interface ProcessedProjectItem extends ProjectItem {
|
|
|
26
31
|
const loading = ref(false)
|
|
27
32
|
const tableData = ref<ProcessedProjectItem[]>([])
|
|
28
33
|
const total = ref(0)
|
|
29
|
-
const pagination = ref({
|
|
30
|
-
const jnEditRef = ref()
|
|
31
|
-
const ruleFormRef = ref<FormInstance>()
|
|
34
|
+
const pagination = ref<Pagination>({ pageNo: 1, pageSize: 10 })
|
|
32
35
|
|
|
36
|
+
// 编辑
|
|
37
|
+
const editDialogRef = ref()
|
|
38
|
+
const ruleFormRef = ref<FormInstance>()
|
|
33
39
|
const ruleForm = ref<AddProjectItem>({
|
|
34
40
|
id: '',
|
|
35
41
|
name: '',
|
|
36
42
|
program: '',
|
|
37
43
|
projectType: undefined,
|
|
44
|
+
managerId: undefined,
|
|
38
45
|
budget: 0,
|
|
39
46
|
plannedStartDate: '',
|
|
40
47
|
description: '',
|
|
41
48
|
newImageFiles: [],
|
|
42
49
|
newAttachmentFile: []
|
|
43
50
|
})
|
|
44
|
-
|
|
45
51
|
const rules = ref<FormRules>({
|
|
46
52
|
name: [{ required: true, message: '请输入', trigger: 'change' }],
|
|
47
53
|
program: [{ required: true, message: '请选择', trigger: 'change' }],
|
|
48
54
|
projectType: [{ required: true, message: '请选择', trigger: 'change' }],
|
|
49
55
|
plannedStartDate: [{ required: true, message: '请选择', trigger: 'change' }],
|
|
50
56
|
newImageFiles: [{ required: true, message: '请上传', trigger: 'change' }],
|
|
57
|
+
managerId: [{ required: true, message: '请选择', trigger: 'change' }],
|
|
51
58
|
budget: [
|
|
52
59
|
{ required: true, message: '请输入', trigger: 'change' },
|
|
53
60
|
{
|
|
@@ -57,35 +64,49 @@ const rules = ref<FormRules>({
|
|
|
57
64
|
]
|
|
58
65
|
})
|
|
59
66
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
// 查询
|
|
68
|
+
const queryForm = ref({
|
|
69
|
+
code: '',
|
|
70
|
+
projectType: undefined,
|
|
71
|
+
manager: '',
|
|
72
|
+
plannedStartDate: ''
|
|
73
|
+
})
|
|
63
74
|
|
|
64
75
|
const handleSelectionChange = (row: ProjectItem[]) => {
|
|
65
76
|
console.log(row)
|
|
66
77
|
}
|
|
67
78
|
|
|
68
|
-
const getDemosTable = async () => {
|
|
79
|
+
const getDemosTable = debounce(async () => {
|
|
69
80
|
try {
|
|
70
|
-
const res = await DemosTableApi(
|
|
71
|
-
|
|
81
|
+
const res = await DemosTableApi({
|
|
82
|
+
...pagination.value,
|
|
83
|
+
...queryForm.value
|
|
84
|
+
})
|
|
85
|
+
tableData.value = res.list.map((item) => ({
|
|
72
86
|
...item,
|
|
73
87
|
newImageFiles: item.imageDocument?.attachments ?? undefined,
|
|
74
88
|
newAttachmentFile: item.attachmentDocument?.attachments ?? undefined
|
|
75
89
|
}))
|
|
76
|
-
total.value = res.
|
|
90
|
+
total.value = res.count
|
|
77
91
|
} catch (error) {
|
|
78
92
|
console.error(error)
|
|
79
93
|
}
|
|
80
|
-
}
|
|
94
|
+
}, 300)
|
|
81
95
|
|
|
82
96
|
// 新增和修改
|
|
83
97
|
const handleEdit = (row?: ProjectItem) => {
|
|
84
|
-
|
|
98
|
+
editDialogRef.value.open()
|
|
85
99
|
queueMicrotask(() => {
|
|
86
100
|
ruleFormRef.value?.resetFields()
|
|
87
101
|
const matched = objectMatchAssign(ruleForm.value, row)
|
|
88
102
|
ruleForm.value = matched
|
|
103
|
+
// Select 组件数据回填
|
|
104
|
+
if (row && 'managerId' in row && 'manager' in row) {
|
|
105
|
+
ruleForm.value.managerId = {
|
|
106
|
+
managerId: row.managerId,
|
|
107
|
+
manager: row.manager
|
|
108
|
+
}
|
|
109
|
+
}
|
|
89
110
|
})
|
|
90
111
|
}
|
|
91
112
|
|
|
@@ -94,7 +115,10 @@ const submitForm = () => {
|
|
|
94
115
|
ruleFormRef.value?.validate(async (valid) => {
|
|
95
116
|
if (valid) {
|
|
96
117
|
loading.value = true
|
|
97
|
-
const formData = objectToFormData(
|
|
118
|
+
const formData = objectToFormData({
|
|
119
|
+
...ruleForm.value,
|
|
120
|
+
managerId: ruleForm.value.managerId?.managerId
|
|
121
|
+
})
|
|
98
122
|
try {
|
|
99
123
|
await DemosFormApi(formData)
|
|
100
124
|
ElMessage({
|
|
@@ -117,7 +141,8 @@ onActivated(() => {
|
|
|
117
141
|
</script>
|
|
118
142
|
|
|
119
143
|
<template>
|
|
120
|
-
|
|
144
|
+
<!-- 编辑弹窗 -->
|
|
145
|
+
<JnDialog ref="editDialogRef" title="项目管理" width="600px">
|
|
121
146
|
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" v-loading="loading">
|
|
122
147
|
<el-form-item prop="id"></el-form-item>
|
|
123
148
|
<el-form-item label="项目名称" prop="name">
|
|
@@ -133,6 +158,14 @@ onActivated(() => {
|
|
|
133
158
|
/>
|
|
134
159
|
</el-select>
|
|
135
160
|
</el-form-item>
|
|
161
|
+
<el-form-item label="项目经理" prop="managerId">
|
|
162
|
+
<SelectManager
|
|
163
|
+
v-model="ruleForm.managerId"
|
|
164
|
+
:formRef="ruleFormRef"
|
|
165
|
+
validateFieldName="managerId"
|
|
166
|
+
:simpleValue="false"
|
|
167
|
+
></SelectManager>
|
|
168
|
+
</el-form-item>
|
|
136
169
|
<el-form-item label="预算" prop="budget">
|
|
137
170
|
<el-input-number v-model="ruleForm.budget" :min="0" :precision="2" :step="10000" controls-position="right">
|
|
138
171
|
<template #prefix>
|
|
@@ -171,6 +204,7 @@ onActivated(() => {
|
|
|
171
204
|
:fileSizeMb="50"
|
|
172
205
|
:limit="3"
|
|
173
206
|
drag
|
|
207
|
+
:downloadFileFn="(file) => downloadFile(file.uniqueFileName, file.fileName)"
|
|
174
208
|
/>
|
|
175
209
|
</el-form-item>
|
|
176
210
|
<el-form-item label="上传文件" prop="newAttachmentFile">
|
|
@@ -180,20 +214,92 @@ onActivated(() => {
|
|
|
180
214
|
<template #footer>
|
|
181
215
|
<el-button type="success" icon="Select" :loading="loading" @click="submitForm()">提交</el-button>
|
|
182
216
|
</template>
|
|
183
|
-
</
|
|
217
|
+
</JnDialog>
|
|
184
218
|
|
|
185
219
|
<el-card>
|
|
186
220
|
<template #header>
|
|
187
|
-
<div
|
|
221
|
+
<div style="display: flex; justify-content: space-between; align-items: center">
|
|
188
222
|
<span>项目管理</span>
|
|
189
|
-
<
|
|
223
|
+
<div style="display: flex; justify-content: space-between; align-items: center">
|
|
224
|
+
<JnImportAndExport
|
|
225
|
+
:importTemplateApi="DemosImportTemplateApi"
|
|
226
|
+
importBtnName="导入项目"
|
|
227
|
+
:importApi="DemosImportDataApi"
|
|
228
|
+
exportBtnName="导出项目"
|
|
229
|
+
:exportApi="DemosExportApi"
|
|
230
|
+
:exportParams="{
|
|
231
|
+
...dateFormatsToObject(queryForm.plannedStartDate)
|
|
232
|
+
}"
|
|
233
|
+
:exportDynamicParamsConfig="{
|
|
234
|
+
label: '项目编号',
|
|
235
|
+
prop: 'code'
|
|
236
|
+
}"
|
|
237
|
+
:exportDisabled="tableData.length === 0"
|
|
238
|
+
size="small"
|
|
239
|
+
@change="getDemosTable()"
|
|
240
|
+
/>
|
|
241
|
+
<el-button type="primary" size="small" :icon="Plus" @click="handleEdit()" style="margin-left: 12px">
|
|
242
|
+
新增
|
|
243
|
+
</el-button>
|
|
244
|
+
</div>
|
|
190
245
|
</div>
|
|
191
246
|
</template>
|
|
247
|
+
|
|
248
|
+
<!-- 查询条件 -->
|
|
249
|
+
<el-form :model="queryForm" size="small" inline v-loading="loading">
|
|
250
|
+
<el-form-item label="项目编号" prop="code">
|
|
251
|
+
<el-input v-model="queryForm.code" clearable style="width: 150px">
|
|
252
|
+
<template #append>
|
|
253
|
+
<el-button icon="Search" @click="getDemosTable()" />
|
|
254
|
+
</template>
|
|
255
|
+
</el-input>
|
|
256
|
+
</el-form-item>
|
|
257
|
+
<el-form-item label="项目名称" prop="projectType">
|
|
258
|
+
<el-select
|
|
259
|
+
v-model="queryForm.projectType"
|
|
260
|
+
filterable
|
|
261
|
+
placeholder=""
|
|
262
|
+
clearable
|
|
263
|
+
style="width: 150px"
|
|
264
|
+
@change="getDemosTable()"
|
|
265
|
+
>
|
|
266
|
+
<el-option
|
|
267
|
+
:label="item.label"
|
|
268
|
+
:value="item.value"
|
|
269
|
+
v-for="item in getDictList('projectType')"
|
|
270
|
+
:key="item.value"
|
|
271
|
+
/>
|
|
272
|
+
</el-select>
|
|
273
|
+
</el-form-item>
|
|
274
|
+
<el-form-item label="项目经理" prop="manager">
|
|
275
|
+
<SelectManager
|
|
276
|
+
v-model="queryForm.manager"
|
|
277
|
+
:initialParams="{ role: 1 }"
|
|
278
|
+
size="small"
|
|
279
|
+
width="200px"
|
|
280
|
+
@change="getDemosTable()"
|
|
281
|
+
></SelectManager>
|
|
282
|
+
</el-form-item>
|
|
283
|
+
<el-form-item label="计划开始时间" prop="plannedStartDate">
|
|
284
|
+
<el-date-picker
|
|
285
|
+
v-model="queryForm.plannedStartDate"
|
|
286
|
+
value-format="YYYY-MM-DD"
|
|
287
|
+
size="small"
|
|
288
|
+
style="width: 150px"
|
|
289
|
+
@change="getDemosTable()"
|
|
290
|
+
/>
|
|
291
|
+
</el-form-item>
|
|
292
|
+
</el-form>
|
|
293
|
+
|
|
294
|
+
<!-- 数据列表 -->
|
|
192
295
|
<JnTable
|
|
193
296
|
:data="tableData"
|
|
194
297
|
:pagination="pagination"
|
|
298
|
+
:autoHeight="true"
|
|
299
|
+
:showScrollbar="true"
|
|
195
300
|
:showIndexColumn="true"
|
|
196
301
|
:showSelectionColumn="true"
|
|
302
|
+
:showMouseSelection="true"
|
|
197
303
|
@selection-change="handleSelectionChange"
|
|
198
304
|
>
|
|
199
305
|
<el-table-column prop="code" label="项目编号" min-width="200" sortable show-overflow-tooltip />
|
|
@@ -205,7 +311,7 @@ onActivated(() => {
|
|
|
205
311
|
<el-table-column prop="program" label="项目集名称" min-width="200" sortable show-overflow-tooltip />
|
|
206
312
|
<el-table-column prop="projectType" label="项目类型" width="100" align="center" sortable>
|
|
207
313
|
<template #default="{ row }">
|
|
208
|
-
<
|
|
314
|
+
<DictTag dictName="projectType" :value="row.projectType" />
|
|
209
315
|
</template>
|
|
210
316
|
</el-table-column>
|
|
211
317
|
<el-table-column prop="manager" label="项目经理" width="100" align="center" sortable />
|
|
@@ -231,7 +337,7 @@ onActivated(() => {
|
|
|
231
337
|
</el-table-column>
|
|
232
338
|
<el-table-column prop="status" label="状态" width="100" align="center" sortable>
|
|
233
339
|
<template #default="{ row }">
|
|
234
|
-
<
|
|
340
|
+
<DictTag dictName="status" :value="row.status" :showColor="false" />
|
|
235
341
|
</template>
|
|
236
342
|
</el-table-column>
|
|
237
343
|
<el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip />
|
|
@@ -252,13 +358,7 @@ onActivated(() => {
|
|
|
252
358
|
</el-table-column>
|
|
253
359
|
</JnTable>
|
|
254
360
|
|
|
255
|
-
|
|
361
|
+
<!-- 表格分页 -->
|
|
362
|
+
<JnPagination :total="total" v-model="pagination" @change="getDemosTable" />
|
|
256
363
|
</el-card>
|
|
257
364
|
</template>
|
|
258
|
-
|
|
259
|
-
<style lang="scss" scoped>
|
|
260
|
-
.card_header {
|
|
261
|
-
display: flex;
|
|
262
|
-
justify-content: space-between;
|
|
263
|
-
}
|
|
264
|
-
</style>
|
|
@@ -7,7 +7,7 @@ import { NotFoundApi, NoAuth, DetailsApi } from '@/api/demos'
|
|
|
7
7
|
import { getFileUrl } from '@/utils/file'
|
|
8
8
|
import { downloadFile } from '@/utils/packages'
|
|
9
9
|
|
|
10
|
-
import ImageView from '@/components/
|
|
10
|
+
import ImageView from '@/components/common/ImageView.vue'
|
|
11
11
|
|
|
12
12
|
const squareUrl = ref()
|
|
13
13
|
|
|
@@ -5,12 +5,16 @@ import { handleRouter } from '@jnrs/vue-core/router'
|
|
|
5
5
|
import type { MenuItem } from '@jnrs/vue-core'
|
|
6
6
|
import { hasPermission } from '@/utils/permissions'
|
|
7
7
|
import { MenuApi } from '@/api/system'
|
|
8
|
+
import { formatDateTime, formatWeekday } from '@jnrs/shared'
|
|
9
|
+
import { isFloatGtZero } from '@jnrs/shared/validator'
|
|
10
|
+
import { testI18n } from '@jnrs/shared/request'
|
|
8
11
|
|
|
9
12
|
const routeOptions = ref<MenuItem[]>([])
|
|
10
13
|
const currentRoute = ref('')
|
|
11
14
|
const datePicker = ref(new Date())
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
const datetime = ref(formatDateTime() + ' ' + formatWeekday())
|
|
16
|
+
const validator = ref()
|
|
17
|
+
const testI18nInCore = ref('')
|
|
14
18
|
|
|
15
19
|
const handleMenuApi = async () => {
|
|
16
20
|
try {
|
|
@@ -26,11 +30,31 @@ const handleRouteChange = () => {
|
|
|
26
30
|
name: currentRoute.value
|
|
27
31
|
})
|
|
28
32
|
}
|
|
33
|
+
|
|
34
|
+
const changeI18n = () => {
|
|
35
|
+
datetime.value = formatDateTime() + ' ' + formatWeekday()
|
|
36
|
+
isFloatGtZero({}, '0', (msg) => {
|
|
37
|
+
validator.value = msg
|
|
38
|
+
})
|
|
39
|
+
testI18nInCore.value = testI18n()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
onMounted(() => {
|
|
43
|
+
isFloatGtZero({}, '0', (msg) => {
|
|
44
|
+
validator.value = msg
|
|
45
|
+
})
|
|
46
|
+
testI18nInCore.value = testI18n()
|
|
47
|
+
})
|
|
29
48
|
</script>
|
|
30
49
|
|
|
31
50
|
<template>
|
|
32
51
|
<div>
|
|
33
52
|
<h3>Playground - 功能测试</h3>
|
|
53
|
+
<p>国际化测试</p>
|
|
54
|
+
<div>@jnrs/shared: {{ datetime }}</div>
|
|
55
|
+
<div>@jnrs/shared/validator: {{ validator }}</div>
|
|
56
|
+
<div>@jnrs/shared/request: {{ testI18nInCore }}</div>
|
|
57
|
+
<el-button type="primary" size="small" @click="changeI18n">切换语言后点击按钮更新国际化显示</el-button>
|
|
34
58
|
<p>权限测试(admin 账号拥有全部权限,请用非 admin 账号测试该功能)</p>
|
|
35
59
|
<ul>
|
|
36
60
|
<li>
|
|
@@ -191,8 +191,6 @@ const submitForm = async () => {
|
|
|
191
191
|
box-shadow: 5px 0 10px rgba(0, 0, 0, 0.5);
|
|
192
192
|
// background: url('@/assets/img/common/card_bg.png') no-repeat;
|
|
193
193
|
// background-size: 100% 100%;
|
|
194
|
-
text-align: center;
|
|
195
|
-
font-size: 22px;
|
|
196
194
|
|
|
197
195
|
.card_left_mid {
|
|
198
196
|
width: 50%;
|
|
@@ -204,7 +202,10 @@ const submitForm = async () => {
|
|
|
204
202
|
}
|
|
205
203
|
|
|
206
204
|
.title {
|
|
205
|
+
text-align: center;
|
|
207
206
|
font-size: 24px;
|
|
207
|
+
letter-spacing: 4px;
|
|
208
|
+
white-space: nowrap;
|
|
208
209
|
font-weight: normal;
|
|
209
210
|
font-family: AlimamaShuHeiTi-Bold;
|
|
210
211
|
color: rgba(255, 255, 255, 0.5);
|
|
@@ -238,6 +239,7 @@ const submitForm = async () => {
|
|
|
238
239
|
|
|
239
240
|
.title {
|
|
240
241
|
text-align: center;
|
|
242
|
+
text-transform: uppercase;
|
|
241
243
|
color: var(--jnrs-color-primary);
|
|
242
244
|
}
|
|
243
245
|
|
|
@@ -261,6 +263,7 @@ const submitForm = async () => {
|
|
|
261
263
|
color: var(--jnrs-color-primary-06);
|
|
262
264
|
font-size: 14px;
|
|
263
265
|
text-align: center;
|
|
266
|
+
text-transform: uppercase;
|
|
264
267
|
|
|
265
268
|
&::before,
|
|
266
269
|
&::after {
|
|
@@ -286,6 +289,8 @@ const submitForm = async () => {
|
|
|
286
289
|
position: absolute;
|
|
287
290
|
bottom: 5px;
|
|
288
291
|
font-size: 12px;
|
|
292
|
+
letter-spacing: 2px;
|
|
293
|
+
text-transform: uppercase;
|
|
289
294
|
color: rgba(0, 0, 0, 0.1);
|
|
290
295
|
}
|
|
291
296
|
}
|