Compare commits
309 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b69abfc9b | ||
|
|
6af7bf9d2f | ||
|
|
604fad9009 | ||
|
|
9013d54add | ||
|
|
fd722b5c82 | ||
|
|
a8e56fe985 | ||
|
|
4953e96415 | ||
| 5b85abd219 | |||
| 7156e34fde | |||
| e903dd2994 | |||
| 549e307b3e | |||
| 390474ea24 | |||
| 43c9cb03d3 | |||
|
|
5eb7e34571 | ||
|
|
d12fb8a12b | ||
| 1991d7eada | |||
| 31a12e566a | |||
| 5c8679d5f9 | |||
| 7e70c9271f | |||
| 6748685712 | |||
| cd7f94e8f2 | |||
|
|
db8a96a664 | ||
|
|
17207b2c87 | ||
| d6de4d5854 | |||
| bcdafbc7cd | |||
|
|
e9e5a0c785 | ||
|
|
21f90e438c | ||
| e1b9f3f220 | |||
| 96d46e6480 | |||
| 6ab0c206c4 | |||
| a4255c3157 | |||
| 39b1690c0a | |||
| 9f4fe95e4d | |||
| 1635482e09 | |||
| 3270aeef06 | |||
|
|
6c80652416 | ||
|
|
c97091db4f | ||
| 1c57cb277b | |||
| e648faba69 | |||
| a663b84fab | |||
| f83ae8df51 | |||
| 1d772e1414 | |||
| 92e9468cb9 | |||
| 5c93eae4ce | |||
| 5d7b6bc59f | |||
| 1825b6c871 | |||
| dee7fdacf2 | |||
| dc7d90c349 | |||
| 9661cdbb2b | |||
|
|
3a4f9927c9 | ||
| 1f4389eb5e | |||
|
|
4a90f4bc1e | ||
|
|
8155a4d160 | ||
| 771a844552 | |||
| 08a609e2a8 | |||
| d16045a1b2 | |||
| 1fc0ae6ac0 | |||
| 08f20bb171 | |||
| 5421145583 | |||
| b7a0dc2545 | |||
| 3bd6df74cc | |||
|
|
190a1d6477 | ||
|
|
cb7f6e9919 | ||
| 5ea20654cc | |||
| 670c8a5653 | |||
| 206a024f4b | |||
| 89d5c86d8b | |||
| 397d5f0182 | |||
| 10bc019866 | |||
| 62620b1dc5 | |||
| ff68ce96af | |||
| 65d933c027 | |||
| 726c746a87 | |||
| c498a3de62 | |||
| d432e54bc8 | |||
| 5b68ee6846 | |||
| 96e7ca1a67 | |||
| 9368ea24ab | |||
| c96cbf8415 | |||
| bab0421b6d | |||
| fccce985b6 | |||
| c675b1ec48 | |||
| 02bda3c71f | |||
| b7ebd66729 | |||
| 76c759c088 | |||
| e4e7444aff | |||
| a8f5f84b20 | |||
| 716d18122f | |||
| 2f19bb7bdc | |||
| 8f8d954bb6 | |||
| 0732acf8c7 | |||
| 6540ac8991 | |||
| 6009885c09 | |||
| 83a8fac0fb | |||
| 0c070154e1 | |||
| 32a3ab3001 | |||
| d0fe340f9d | |||
| 92d2278dfd | |||
| f5c6680c66 | |||
| b5e5a3f12a | |||
| 7869ff4e6a | |||
| 95f4610714 | |||
| 9754b62038 | |||
| 573fff84e4 | |||
|
|
1f1ff3a466 | ||
| 79f2032fde | |||
|
|
f820c25892 | ||
|
|
a4cb59ff9a | ||
| a7b6b44a42 | |||
| 1f126592e1 | |||
| 0f914237bf | |||
| 9a0f5b0e12 | |||
| 9f7e3778ad | |||
| 01540a3144 | |||
| 5e4e8d6389 | |||
| 08579c8aad | |||
| 5ae971e0ac | |||
| 9ae0b7547c | |||
| b2369d1702 | |||
| 8b6c9a7d1e | |||
| 6097e74a9b | |||
| 11b794bf96 | |||
| 2a72de08a4 | |||
| 77fcdc240b | |||
| 6d8dbaa8c4 | |||
| d7b004ae80 | |||
| 1f9a3603d8 | |||
| b8b165c205 | |||
| de2f566bd0 | |||
| 38182da467 | |||
| de0e0be953 | |||
| ef1acd65b7 | |||
| 27dcca6617 | |||
| 2ad94511d0 | |||
| bfdf2cf4a2 | |||
| 4f4ef2cfde | |||
| 222ab1bec7 | |||
| bead5edc86 | |||
| 18caa0ee58 | |||
| 96d8f1e48a | |||
| 3bc24219ed | |||
| 07d5380818 | |||
| cd91dd3cad | |||
| edb235ff0d | |||
| 9ade24768e | |||
| e753c27455 | |||
| 1684e49662 | |||
| 42ea1dde8b | |||
|
|
bb2a0ce177 | ||
|
|
9da6e82763 | ||
|
|
31a88c232f | ||
| 1c00a040f0 | |||
|
|
f46f95c4ad | ||
| 9e8e3e4705 | |||
| f55059eed7 | |||
|
|
3bec5a6620 | ||
|
|
ad3fa0e688 | ||
|
|
0041bbbfa8 | ||
|
|
bdc9c244a4 | ||
|
|
acc38adae1 | ||
|
|
5911d0f6d2 | ||
|
|
66454b2023 | ||
|
|
8d51d68df1 | ||
| 84a3981df3 | |||
| 64981433bf | |||
| e5dfadb8c0 | |||
| 888c01efbf | |||
| c206844e24 | |||
| 4070e15e63 | |||
| 92b9dd5e03 | |||
| 2d73580195 | |||
| 3538813100 | |||
| 71d78d9cca | |||
|
|
14fa25b509 | ||
|
|
bd220ad5b1 | ||
| 4a7cffde2e | |||
| b170d42263 | |||
| d0e517e7d9 | |||
| 55e0f28ebc | |||
| 250f6344f1 | |||
| abbb4551ad | |||
| 6ae58eefaf | |||
| 9d63b64c91 | |||
| 324cc268b5 | |||
| d5c7da1328 | |||
| 13774dada9 | |||
| 68cc3e7a12 | |||
| 72a8572910 | |||
| 86ddbf2ffb | |||
| d139b016a2 | |||
| 8bdafdd087 | |||
| b4c91f3daf | |||
|
|
aaedb362b5 | ||
| 548cab4cde | |||
| 876bd1f9f9 | |||
| eeab66d8fb | |||
|
|
416fa2ed53 | ||
| 72210306b6 | |||
| 6fbcdc82ca | |||
| 8e671e959c | |||
| 48e5d82acb | |||
|
|
ce2752af9b | ||
| 01021b640e | |||
| 5e08db55fb | |||
| 7810de1327 | |||
| b58dfcb566 | |||
|
|
44ed106775 | ||
| a077e38fdc | |||
| 9c6c494b80 | |||
| 77301e09e4 | |||
| a7d9391e9a | |||
| af2667502a | |||
| eb061dd1a6 | |||
|
|
f0212046f3 | ||
| 5498337d3e | |||
| 6c27a5f954 | |||
| 615e0f85c7 | |||
| 04d0e9a7d2 | |||
| 0cf56d875e | |||
| 779ebf093a | |||
| 0d31b47a56 | |||
|
|
f7fddab0bd | ||
|
|
9da9b763be | ||
| e935c870bf | |||
| c008aab0d3 | |||
| d9dce9e8e5 | |||
| e6a515f673 | |||
| 5ce118a149 | |||
| 452e2479e0 | |||
|
|
5c0e962626 | ||
| cf367951a5 | |||
| dde77b1425 | |||
|
|
3ba7845893 | ||
|
|
a5822ca276 | ||
| 332d843dc2 | |||
| fdca87d870 | |||
| 1a211fec21 | |||
| 5710597454 | |||
|
|
81d0987a9a | ||
| 1ee39bfa0c | |||
| 371a55cfe1 | |||
| 90de57698b | |||
| 858289ec0e | |||
| bf6a683261 | |||
| 460dd793cf | |||
| be5150c7c4 | |||
| 233f44990d | |||
|
|
3403ca7ecb | ||
|
|
28b4637e01 | ||
|
|
639caadc46 | ||
|
|
6557b5d2c8 | ||
| 4f6b2dcc27 | |||
| dcc6866211 | |||
|
|
0e0e1f9bb9 | ||
|
|
0e0d206cc7 | ||
|
|
bfe24e1207 | ||
|
|
2bb86ced15 | ||
|
|
929228974a | ||
|
|
eee3c3852e | ||
|
|
57bfb6f4a0 | ||
|
|
5d3ab890f3 | ||
|
|
3eecc3f4b9 | ||
|
|
9217f019e5 | ||
|
|
26b50d6103 | ||
|
|
12053b81b9 | ||
|
|
360f0dd92d | ||
|
|
68c4ca5dc9 | ||
|
|
8f922a8815 | ||
|
|
508e391823 | ||
|
|
2560ed701f | ||
|
|
c3e582ad33 | ||
|
|
fde73bd7b0 | ||
|
|
ef46911a5b | ||
|
|
3b0637e1b3 | ||
|
|
a3c4a79fd0 | ||
|
|
450d483f39 | ||
|
|
699c7ecc7d | ||
|
|
0ffbdbbcc7 | ||
| d784928d05 | |||
| a005409d92 | |||
| 7b500e7ea1 | |||
| e9acf99ccb | |||
|
|
e950d9e687 | ||
|
|
dd659cf135 | ||
|
|
736798b540 | ||
|
|
0c56e6a161 | ||
|
|
190c77d71d | ||
|
|
bba369abaa | ||
|
|
6df354ec1b | ||
|
|
fcff8c9cc4 | ||
|
|
13d3428d7a | ||
|
|
99cf83a563 | ||
|
|
f98103c61f | ||
|
|
5986ab1eb4 | ||
|
|
ecf3fecd40 | ||
|
|
658f7de3c0 | ||
|
|
46a6745f17 | ||
|
|
d6ce782681 | ||
|
|
aa3194dcc1 | ||
|
|
fa56d63dbb | ||
|
|
2ad0dbf8ab | ||
|
|
89b42dba2a | ||
|
|
c28b0e306d | ||
|
|
c88be616fc | ||
|
|
38b5e2d2af | ||
|
|
b1b039a897 | ||
|
|
1e23fe08e3 | ||
|
|
5fc036d12d | ||
|
|
610b1a66b6 |
@@ -5,8 +5,8 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
type: NodePort
|
type: NodePort
|
||||||
ports:
|
ports:
|
||||||
- name: damdsdha
|
- name: $PORTS_NAME
|
||||||
nodePort: 8081
|
nodePort: $PORTS_PORT
|
||||||
port: 80
|
port: 80
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
targetPort: 80
|
targetPort: 80
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="icon" href="/favicon.ico">
|
<link rel="icon" href="/favicon.ico">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>科研管理平台</title>
|
<!-- <title>科研管理平台</title>-->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ http {
|
|||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
|
|
||||||
location /api {
|
location /api {
|
||||||
proxy_pass http://gateway.mosr.svc.cluster.local:8080;
|
proxy_pass http://gateway.$PROFILES.svc.cluster.local:8080;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_set_header X-Forwarded-Port $server_port;
|
proxy_set_header X-Forwarded-Port $server_port;
|
||||||
|
|||||||
8
src/api/home/index.js
Normal file
8
src/api/home/index.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import request from '@/utils/request.js'
|
||||||
|
|
||||||
|
export const getHomeInfo = () => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/process/task',
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
84
src/api/project-demand/index.js
Normal file
84
src/api/project-demand/index.js
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import request from '@/utils/request.js'
|
||||||
|
//需求征集
|
||||||
|
export const getDemandInfo = (param) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/requirement',
|
||||||
|
method: "get",
|
||||||
|
params: param
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const getWorkflowInfo = () => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/requirement/process',
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const getInfo = (requirementId) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/mosr/requirement/info/${requirementId}`,
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const getFormInfo = (requirementId) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/mosr/requirement/form/${requirementId}`,
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const agreeTask = (data) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/mosr/process/task/agree`,
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const rejectTask = (data) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/mosr/process/task/reject`,
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addRequirement = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/requirement',
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const resubmit = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/requirement/resubmit',
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const deleteFile = (fileId) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/process/file/delete/${fileId}`,
|
||||||
|
method: "delete"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const downloadFile = (fileId) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/process/file/download',
|
||||||
|
method: "get",
|
||||||
|
responseType:'blob',
|
||||||
|
params:{
|
||||||
|
fileId:fileId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const getCompanyOption = () => {
|
||||||
|
return request({
|
||||||
|
url: '/admin/mosr/sub/company/companyOption',
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const deleteDemand = (id) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/mosr/requirement/${id}`,
|
||||||
|
method: "delete"
|
||||||
|
});
|
||||||
|
};
|
||||||
86
src/api/project-manage/index.js
Normal file
86
src/api/project-manage/index.js
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import request from '@/utils/request.js'
|
||||||
|
//项目立项
|
||||||
|
export const getApplyProcess = (projectId) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/mosr/project/approval/initiation/process/${projectId}`,
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const projectApply = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/project/approval/initiation/apply',
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const getApplyDetail = (ProjectId) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/mosr/project/approval/info/${ProjectId}`,
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const resubmitApply = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/project/approval/initiation/resubmit',
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
//项目实施
|
||||||
|
export const getCheckDetail = (projectId) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/mosr/project/implementation/info/${projectId}`,
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const resubmitCheck = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/project/implementation/resubmit',
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const projectCheck = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/project/implementation/initiation/check',
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const getProjectCheckProcess = (projectId) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/mosr/project/implementation/process/${projectId}`,
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
//项目归档
|
||||||
|
export const getConclusionDetail = (ProjectId) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/mosr/project/filing/info/${ProjectId}`,
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const resubmitConclusion = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/project/filing/resubmit',
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const projectConclusion = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/project/filing/project/entry',
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const getProjectConclusionProcess = () => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/project/filing/process',
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -46,6 +46,15 @@ export const getUserDetail = (userId) => {
|
|||||||
method: "get"
|
method: "get"
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 操作
|
||||||
|
export const operate = (data, type) => {
|
||||||
|
console.log(type ,'type');
|
||||||
|
if(data.userId && type !== '0') return editUser(data)
|
||||||
|
else if(type == '0') return editUserOA(data)
|
||||||
|
return addUser(data)
|
||||||
|
}
|
||||||
|
|
||||||
// 新增用户
|
// 新增用户
|
||||||
export const addUser = (data) => {
|
export const addUser = (data) => {
|
||||||
return request({
|
return request({
|
||||||
@@ -63,6 +72,15 @@ export const editUser = (data) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改OA用户
|
||||||
|
export const editUserOA = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/admin/mosr/user/oa',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
//删除用户信息
|
//删除用户信息
|
||||||
export const deleteUser = (userId) => {
|
export const deleteUser = (userId) => {
|
||||||
return request({
|
return request({
|
||||||
|
|||||||
@@ -60,3 +60,12 @@ export function addProcessDefinition(param) {
|
|||||||
data: param
|
data: param
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getTypeOption() {
|
||||||
|
return request({
|
||||||
|
url: "/workflow/process/definition/type/option",
|
||||||
|
method: "get",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,3 +22,10 @@ export function getDepartmentTree() {
|
|||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
export function getMosrDept(params) {
|
||||||
|
return request({
|
||||||
|
url: '/admin/mosr/user/choose',
|
||||||
|
method: 'get',
|
||||||
|
params:params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.el-main {
|
.el-main {
|
||||||
background: #F4F6F8;
|
background: #EFEFEF;
|
||||||
padding: 0 0 0 18px;
|
padding: 0 0 0 18px;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 200px;
|
left: 200px;
|
||||||
@@ -27,6 +27,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
|||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
transition: margin-left .15s;
|
transition: margin-left .15s;
|
||||||
width: calc(100vw - 200px);
|
width: calc(100vw - 200px);
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
}
|
}
|
||||||
@@ -83,9 +84,11 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-dialog__body {
|
.el-dialog__body {
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stateIcon {
|
.stateIcon {
|
||||||
margin-top: 9px;
|
margin-top: 9px;
|
||||||
margin-right: 7px;
|
margin-right: 7px;
|
||||||
@@ -248,6 +251,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.el-icon {
|
.el-icon {
|
||||||
width: 1.4em;
|
width: 1.4em;
|
||||||
height: 1.4em;
|
height: 1.4em;
|
||||||
@@ -287,6 +291,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
|||||||
.layout {
|
.layout {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
|
|
||||||
.scrollbar-user {
|
.scrollbar-user {
|
||||||
height: calc(100vh - 250px) !important;
|
height: calc(100vh - 250px) !important;
|
||||||
overflow: auto !important;
|
overflow: auto !important;
|
||||||
@@ -373,7 +378,8 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
|||||||
.scale {
|
.scale {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
z-index: 666;
|
z-index: 666;
|
||||||
position: absolute;
|
position: static;
|
||||||
|
//top: -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-overlay-dialog {
|
.el-overlay-dialog {
|
||||||
@@ -401,6 +407,15 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//SvgIcon组件的样式
|
//SvgIcon组件的样式
|
||||||
|
.home-icon {
|
||||||
|
width: 4em;
|
||||||
|
height: 4em;
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
fill: currentColor;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
width: 1.2em;
|
width: 1.2em;
|
||||||
height: 1.2em;
|
height: 1.2em;
|
||||||
@@ -445,10 +460,12 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fen-icon {
|
.fen-icon {
|
||||||
width: 1.8em;
|
width: 1.8em;
|
||||||
height: 1.7em;
|
height: 1.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.middle-icon {
|
.middle-icon {
|
||||||
width: 1.4em;
|
width: 1.4em;
|
||||||
height: 1.4em;
|
height: 1.4em;
|
||||||
@@ -530,4 +547,5 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 15px;
|
bottom: 15px;
|
||||||
right: 15px;
|
right: 15px;
|
||||||
|
z-index: 5;
|
||||||
}
|
}
|
||||||
|
|||||||
6
src/assets/svg/home1.svg
Normal file
6
src/assets/svg/home1.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="71" height="68" viewBox="0 0 71 68" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="Group 229">
|
||||||
|
<ellipse id="Ellipse 12" cx="35.3747" cy="33.663" rx="35.3747" ry="33.663" fill="#87C3ED"/>
|
||||||
|
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M23.3174 21.8325C23.3174 20.7279 24.2128 19.8325 25.3174 19.8325H28.485V23.3688C28.485 23.9211 28.9327 24.3688 29.485 24.3688H32.7358C33.288 24.3688 33.7358 23.9211 33.7358 23.3688V19.8325H45.4049C46.5094 19.8325 47.4049 20.7279 47.4049 21.8325V44.741C47.4049 45.8456 46.5094 46.741 45.4049 46.741H25.3174C24.2128 46.741 23.3174 45.8456 23.3174 44.741V21.8325ZM32.7358 19.8325H29.485V23.3688L32.7358 23.3688V19.8325ZM28.876 29.1297H39.9933V28.1297H28.876V29.1297ZM41.8462 34.4079H28.876V33.4079H41.8462V34.4079ZM41.8462 39.6862H28.876V38.6862H41.8462V39.6862Z" fill="#0043C5"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 860 B |
6
src/assets/svg/home2.svg
Normal file
6
src/assets/svg/home2.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="71" height="68" viewBox="0 0 71 68" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="Group 230">
|
||||||
|
<ellipse id="Ellipse 13" cx="35.3747" cy="33.663" rx="35.3747" ry="33.663" fill="#B487ED"/>
|
||||||
|
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M41.1045 20.8325C41.1045 20.2802 40.6568 19.8325 40.1045 19.8325H26.1016C24.997 19.8325 24.1016 20.7279 24.1016 21.8325V44.741C24.1016 45.8456 24.997 46.741 26.1016 46.741H46.189C47.2936 46.741 48.189 45.8456 48.189 44.741V27.5596C48.189 27.0073 47.7413 26.5596 47.189 26.5596H42.1045C41.5522 26.5596 41.1045 26.1118 41.1045 25.5596V20.8325ZM43.9383 31.0958H31.1861V30.0958H43.9383V31.0958ZM35.4369 23.0234H39.6876V22.0234H35.4369V23.0234ZM43.9383 36.4777H31.1861V35.4777H43.9383V36.4777ZM31.1861 41.8593H43.9383V40.8593H31.1861V41.8593Z" fill="#8600C5"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 838 B |
6
src/assets/svg/home3.svg
Normal file
6
src/assets/svg/home3.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="71" height="68" viewBox="0 0 71 68" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="Group 231">
|
||||||
|
<ellipse id="Ellipse 14" cx="35.3747" cy="33.663" rx="35.3747" ry="33.663" fill="#FDCB9D"/>
|
||||||
|
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M54.4044 32.614C54.4044 40.4161 46.1575 46.741 35.9845 46.741C32.9189 46.741 30.0281 46.1666 27.4852 45.1505C27.3501 45.3211 27.1528 45.4524 26.9047 45.5078L19.6131 47.1386C18.844 47.3106 18.1654 46.6256 18.393 45.9072L20.2692 39.9868C18.5537 37.8406 17.5647 35.3159 17.5647 32.614C17.5647 24.8119 25.8115 18.4871 35.9845 18.4871C46.1575 18.4871 54.4044 24.8119 54.4044 32.614ZM28.1916 34.6321C29.3654 34.6321 30.317 33.7286 30.317 32.614C30.317 31.4994 29.3654 30.5958 28.1916 30.5958C27.0178 30.5958 26.0662 31.4994 26.0662 32.614C26.0662 33.7286 27.0178 34.6321 28.1916 34.6321ZM38.8184 32.614C38.8184 33.7286 37.8669 34.6321 36.6931 34.6321C35.5193 34.6321 34.5677 33.7286 34.5677 32.614C34.5677 31.4994 35.5193 30.5958 36.6931 30.5958C37.8669 30.5958 38.8184 31.4994 38.8184 32.614ZM45.1945 34.6321C46.3683 34.6321 47.3198 33.7286 47.3198 32.614C47.3198 31.4994 46.3683 30.5958 45.1945 30.5958C44.0207 30.5958 43.0691 31.4994 43.0691 32.614C43.0691 33.7286 44.0207 34.6321 45.1945 34.6321Z" fill="#F47D0E"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
6
src/assets/svg/home4.svg
Normal file
6
src/assets/svg/home4.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="71" height="68" viewBox="0 0 71 68" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="Group 232">
|
||||||
|
<ellipse id="Ellipse 19" cx="35.3747" cy="33.663" rx="35.3747" ry="33.663" fill="#87EDBC"/>
|
||||||
|
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M18.7023 20.134C18.1358 20.4872 17.7588 21.1158 17.7588 21.8325V42.0502C17.7588 43.1547 18.6542 44.0502 19.7588 44.0502H48.3477C49.4523 44.0502 50.3477 43.1547 50.3477 42.0502V21.8325C50.3477 21.1082 49.9627 20.4738 49.3861 20.1229L49.9153 20.9221L35.7553 30.2976C34.9339 30.8415 33.8697 30.8523 33.0374 30.3252L18.1997 20.9276L18.7023 20.134ZM18.7605 20.0991L33.5725 29.4804C34.0718 29.7966 34.7104 29.7902 35.2032 29.4638L49.3465 20.0993C49.0526 19.9296 48.7115 19.8325 48.3477 19.8325H19.7588C19.3952 19.8325 19.0543 19.9295 18.7605 20.0991Z" fill="#01A054"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 845 B |
1
src/assets/svg/sso.svg
Normal file
1
src/assets/svg/sso.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.4 KiB |
192
src/components/AttachmentUpload.vue
Normal file
192
src/components/AttachmentUpload.vue
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
<template>
|
||||||
|
<el-form :model="formData" ref="applyForm" label-width="auto" :rules="rules">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item :label="label" prop="attachment">
|
||||||
|
<template v-if="preview&&JSON.stringify(singleFile) !== '{}'&&JSON.stringify(singleFile)!=='null'">
|
||||||
|
<el-button type="primary" link @click="handleDownload(singleFile)" style="font-size: 18px">
|
||||||
|
{{ singleFile?.originalFileName }}
|
||||||
|
</el-button>
|
||||||
|
<el-button type="danger" link @click="deleteOtherFile(singleFile,1)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="!preview||JSON.stringify(singleFile) === '{}'||singleFile==null">
|
||||||
|
<file-upload @getFile="getAttachment" :showFileList="showFileList" :maxSize="0" @delete="deleteAttachment"/>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="其他文件">
|
||||||
|
<el-card style="width: 100%">
|
||||||
|
<file-upload @getFile="getOtherFile"/>
|
||||||
|
<fvTable style="width: 100%;max-height: 250px;height: 250px" v-if="showTable" :tableConfig="tableConfig"
|
||||||
|
:data="allFileList" :isSettingCol="false" :pagination="false">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</el-card>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import FileUpload from '@/components/FileUpload.vue'
|
||||||
|
import {deleteFile, downloadFile} from "../api/project-demand";
|
||||||
|
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
|
||||||
|
|
||||||
|
const emit = defineEmits(["getAttachment", "getOtherFile"])
|
||||||
|
const formData = ref({})
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'index',
|
||||||
|
type: 'index',
|
||||||
|
label: '序号',
|
||||||
|
align: 'center',
|
||||||
|
width: '80',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'originalFileName',
|
||||||
|
label: '文件名',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'tag',
|
||||||
|
label: '标签',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'size',
|
||||||
|
label: '文件大小',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// prop: 'oper',
|
||||||
|
// label: '操作',
|
||||||
|
// align: 'center',
|
||||||
|
// showOverflowTooltip: false,
|
||||||
|
// currentRender: ({row, index}) => {
|
||||||
|
// return (
|
||||||
|
// <div>
|
||||||
|
// <el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||||
|
// <el-button type="primary" size="large" link onClick={() => deleteOtherFile(row)}>删除</el-button>
|
||||||
|
// </div>
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const rules = reactive({
|
||||||
|
attachment: [{required: true, message: '请上传附件', trigger: ['blur', 'change']}],
|
||||||
|
})
|
||||||
|
const applyForm = ref()
|
||||||
|
const singleFile = ref()
|
||||||
|
const allFileList = ref([])
|
||||||
|
const props = defineProps({
|
||||||
|
showFileList: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}, label: {
|
||||||
|
type: String,
|
||||||
|
default: '项目附件'
|
||||||
|
}, showTable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}, preview: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}, otherFileList: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
}, formData: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
watch(() => props.showTable, (newVal) => {
|
||||||
|
props.showTable = newVal
|
||||||
|
}, {deep: true})
|
||||||
|
watch(() => props.otherFileList, (newVal) => {
|
||||||
|
newVal.forEach(item => {
|
||||||
|
allFileList.value.push(item)
|
||||||
|
})
|
||||||
|
}, {deep: true})
|
||||||
|
watch(() => props.formData.fileList, (newVal) => {
|
||||||
|
if (props.preview) {
|
||||||
|
newVal.forEach(item => {
|
||||||
|
allFileList.value.push(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, {deep: true})
|
||||||
|
watch(() => props.formData.singleFile, (newVal) => {
|
||||||
|
// singleFile.value = {}
|
||||||
|
singleFile.value = newVal
|
||||||
|
}, {deep: true})
|
||||||
|
const getAttachment = (val) => {
|
||||||
|
emit('getAttachment', val)
|
||||||
|
}
|
||||||
|
const getOtherFile = (val) => {
|
||||||
|
emit('getOtherFile', val)
|
||||||
|
}
|
||||||
|
const deleteAttachment = (val) => {
|
||||||
|
deleteFile(val).then(res => {
|
||||||
|
if (res.code === 1000) {
|
||||||
|
ElMessage.success("删除成功");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const deleteOtherFile = (row, type) => {
|
||||||
|
ElMessageBox.confirm(`确认删除名称为${row.originalFileName}的表格吗?`, '系统提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
deleteFile(row.fileId).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
if (type === 1) {
|
||||||
|
singleFile.value = {}
|
||||||
|
} else {
|
||||||
|
props.otherFileList.splice(props.otherFileList.findIndex((item) => item.id === row.fileId), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(() => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: "用户取消删除! ",
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleDownload = (row) => {
|
||||||
|
downloadFile(row.fileId).then(res => {
|
||||||
|
const blob = new Blob([res])
|
||||||
|
let a = document.createElement('a')
|
||||||
|
a.href = URL.createObjectURL(blob)
|
||||||
|
a.download = row.originalFileName
|
||||||
|
a.click()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
defineExpose({
|
||||||
|
validate() {
|
||||||
|
return applyForm.value.validate()
|
||||||
|
},
|
||||||
|
clearValidate() {
|
||||||
|
return applyForm.value.clearValidate()
|
||||||
|
},
|
||||||
|
allFileList,
|
||||||
|
singleFile
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
193
src/components/DetailComponent/ApprovalDetail.vue
Normal file
193
src/components/DetailComponent/ApprovalDetail.vue
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
<template>
|
||||||
|
<div v-loading="loading">
|
||||||
|
<fvForm :schema="schema" @getInstance="(e)=>form = e"></fvForm>
|
||||||
|
<!-- <AttachmentUpload></AttachmentUpload> -->
|
||||||
|
<el-form :model="formData" label-width="auto">
|
||||||
|
<el-form-item label="其他文件">
|
||||||
|
<el-table :data="formData.fileList" style="width: 100%">
|
||||||
|
<el-table-column label="序号" type="index" width="80"></el-table-column>
|
||||||
|
<el-table-column label="文件名称" prop="originalFileName"></el-table-column>
|
||||||
|
<el-table-column label="标签" prop="tag"></el-table-column>
|
||||||
|
<el-table-column label="文件大小" prop="size">
|
||||||
|
<template #default="{row}">
|
||||||
|
{{ parseInt(row.size / 1024) + 'KB' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div class="approval-record">
|
||||||
|
<baseTitle title="审批记录"></baseTitle>
|
||||||
|
<div class="process">
|
||||||
|
<operation-render v-if="processViewer" :operation-list="data.operationList"
|
||||||
|
:state="data.state"/>
|
||||||
|
<process-diagram-viewer v-if="processViewer" :id-name="type"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <Opinion: v-if="data.taskId" :formData="formData" :taskId="formData.taskId"></Opinion:>-->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import { computed, markRaw, reactive, ref, watchEffect } from 'vue';
|
||||||
|
import AttachmentUpload from '../AttachmentUpload.vue';
|
||||||
|
import OperationRender from '@/views/workflow/common/OperationRender.vue'
|
||||||
|
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
|
||||||
|
import Opinion from './Opinion.vue';
|
||||||
|
import fvTable from '@/fvcomponents/fvTable/index.vue'
|
||||||
|
import { ElLoading } from 'element-plus';
|
||||||
|
import {deleteFile, downloadFile} from "@/api/project-demand";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
formData: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
processViewer: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
companyOption: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
|
||||||
|
// approval 立项, execute 实施, 归档 archivist
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'approval'
|
||||||
|
}, loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
watch(() => props.loading, (newVal) => {
|
||||||
|
props.loading = newVal
|
||||||
|
}, {deep: true})
|
||||||
|
const form = ref()
|
||||||
|
|
||||||
|
const localData = reactive({
|
||||||
|
fileList: props.formData.fileList,
|
||||||
|
singleFile: props.formData.singleFile
|
||||||
|
})
|
||||||
|
|
||||||
|
const schema = computed(()=>{
|
||||||
|
let arr
|
||||||
|
|
||||||
|
if(props.type == 'approval') {
|
||||||
|
arr = [
|
||||||
|
{
|
||||||
|
label: '前置流程',
|
||||||
|
prop: 'preProcess',
|
||||||
|
colProps: {
|
||||||
|
span: 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目立项附件',
|
||||||
|
prop: 'singleFile',
|
||||||
|
colProps: {
|
||||||
|
span: 24
|
||||||
|
},
|
||||||
|
component: ()=>(
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
props.formData.singleFile?.originalFileName ?
|
||||||
|
<span
|
||||||
|
style={{color: '#409EFF', cursor: 'pointer'}}
|
||||||
|
onClick={()=>handleDownload(props.formData.singleFile)}
|
||||||
|
>
|
||||||
|
{props.formData.singleFile?.originalFileName}
|
||||||
|
</span> :
|
||||||
|
<span>{'--'}</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
},
|
||||||
|
]
|
||||||
|
} else if(props.type == 'execute') {
|
||||||
|
arr = [
|
||||||
|
{
|
||||||
|
label: '前置流程',
|
||||||
|
prop: 'preProcess',
|
||||||
|
colProps: {
|
||||||
|
span: 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目验收附件',
|
||||||
|
prop: 'singleFile',
|
||||||
|
colProps: {
|
||||||
|
span: 24
|
||||||
|
},
|
||||||
|
component: ()=>(
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
props.formData.singleFile?.originalFileName ?
|
||||||
|
<span
|
||||||
|
style={{color: '#409EFF', cursor: 'pointer'}}
|
||||||
|
onClick={()=>handleDownload(props.formData.singleFile)}
|
||||||
|
>
|
||||||
|
{props.formData.singleFile?.originalFileName}
|
||||||
|
</span> :
|
||||||
|
<span>{'--'}</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
},
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
arr = [
|
||||||
|
{
|
||||||
|
label: '项目归档附件',
|
||||||
|
prop: 'singleFile',
|
||||||
|
colProps: {
|
||||||
|
span: 24
|
||||||
|
},
|
||||||
|
component: ()=>(
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
props.formData.singleFile?.originalFileName ?
|
||||||
|
<span
|
||||||
|
style={{color: '#409EFF', cursor: 'pointer'}}
|
||||||
|
onClick={()=>handleDownload(props.formData.singleFile)}
|
||||||
|
>
|
||||||
|
{props.formData.singleFile?.originalFileName}
|
||||||
|
</span> :
|
||||||
|
<span>{'--'}</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleDownload = (row) => {
|
||||||
|
const loading = ElLoading.service({fullscreen: true})
|
||||||
|
downloadFile(row.fileId).then(res => {
|
||||||
|
const blob = new Blob([res])
|
||||||
|
let a = document.createElement('a')
|
||||||
|
a.href = URL.createObjectURL(blob)
|
||||||
|
a.download = row.originalFileName
|
||||||
|
a.click()
|
||||||
|
loading.close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watchEffect(()=>{
|
||||||
|
Object.keys(props.formData).length && (form.value.setValues(props.formData))
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
178
src/components/DetailComponent/CollectionDetail.vue
Normal file
178
src/components/DetailComponent/CollectionDetail.vue
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
<template>
|
||||||
|
<div v-loading="loading">
|
||||||
|
<el-form :model="formData" ref="form" label-width="auto">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="名称">
|
||||||
|
<span>{{ formData.requirementName }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="所属公司">
|
||||||
|
<span>{{ formData.companyIds }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="征集类型">
|
||||||
|
<span>{{ formData.collectType }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="截止时间">
|
||||||
|
<span>{{ formData.deadline }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<baseTitle title="征集说明"></baseTitle>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item>
|
||||||
|
<el-card style="width: 100%">
|
||||||
|
<div v-html="formData.collectExplain">
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<baseTitle title="附件列表"></baseTitle>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item>
|
||||||
|
<fvTable style="width: 100%;max-height: 200px" v-if="processViewer" :tableConfig="tableConfig"
|
||||||
|
:data="formData.fileList" :isSettingCol="false" :pagination="false">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<div v-if="formData.taskId">
|
||||||
|
<baseTitle title="审核意见"></baseTitle>
|
||||||
|
<el-form-item prop="auditOpinion">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.auditOpinion"
|
||||||
|
:rows="3"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请输入审核意见"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div class="approval-record">
|
||||||
|
<baseTitle title="审批记录"></baseTitle>
|
||||||
|
<div class="process">
|
||||||
|
<operation-render v-if="processViewer" :operation-list="data.operationList"
|
||||||
|
:state="data.state"/>
|
||||||
|
<process-diagram-viewer v-if="processViewer" id-name="collectionProcess"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import OperationRender from '@/views/workflow/common/OperationRender.vue'
|
||||||
|
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
|
||||||
|
import {matterTree} from '@/utils/matterTree.js';
|
||||||
|
import {downloadFile} from "@/api/project-demand";
|
||||||
|
|
||||||
|
const emit = defineEmits(['getInfo',"update:formData"])
|
||||||
|
const form = ref()
|
||||||
|
const showTable = ref(false)
|
||||||
|
const companyNameArray = ref([])
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
formData: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
processViewer: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
companyOption: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
}, loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'index',
|
||||||
|
type: 'index',
|
||||||
|
label: '序号',
|
||||||
|
align: 'center',
|
||||||
|
width: '80',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'originalFileName',
|
||||||
|
label: '文件名',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'tag',
|
||||||
|
label: '标签',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'size',
|
||||||
|
label: '文件大小',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
return (
|
||||||
|
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const handleDownload = (row) => {
|
||||||
|
downloadFile(row.fileId).then(res => {
|
||||||
|
const blob = new Blob([res])
|
||||||
|
let a = document.createElement('a')
|
||||||
|
a.href = URL.createObjectURL(blob)
|
||||||
|
a.download = row.originalFileName
|
||||||
|
a.click()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getDataSourceOptionItem = (val) => {
|
||||||
|
if (val instanceof Array) {
|
||||||
|
val.forEach(item => {
|
||||||
|
matterTree(companyNameArray.value, props.companyOption, item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let uniqueArr = Array.from(new Set(companyNameArray.value));
|
||||||
|
return uniqueArr.join(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => props.loading, (newVal) => {
|
||||||
|
props.loading = newVal
|
||||||
|
}, {deep: true})
|
||||||
|
|
||||||
|
watch(() => props.companyOption, (newVal) => {
|
||||||
|
props.companyOption = newVal
|
||||||
|
}, {deep: true})
|
||||||
|
watch(() => props.formData, (newVal) => {
|
||||||
|
if(newVal!=null){
|
||||||
|
props.formData.companyIds = getDataSourceOptionItem(newVal.companyIds)
|
||||||
|
}
|
||||||
|
}, {deep: true})
|
||||||
|
watch(() => props.processViewer, (newVal) => {
|
||||||
|
props.processViewer = newVal
|
||||||
|
}, {deep: true})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
108
src/components/DetailComponent/Opinion.vue
Normal file
108
src/components/DetailComponent/Opinion.vue
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<baseTitle title="审核意见"></baseTitle>
|
||||||
|
<fvForm :schema="schema" @getInstance="(e)=>form = e"></fvForm>
|
||||||
|
<div class="oper-page-btn">
|
||||||
|
<el-button type="danger" @click="handleReject">驳回</el-button>
|
||||||
|
<el-button color="#DED0B2" @click="handleAgree">同意</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {ElNotification} from 'element-plus';
|
||||||
|
import {agreeTask, rejectTask} from "@/api/project-demand/index.js";
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const props = defineProps({
|
||||||
|
taskId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
formData: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const form = ref()
|
||||||
|
const schema = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
prop: 'auditOpinion',
|
||||||
|
component: 'el-input',
|
||||||
|
colProps: {
|
||||||
|
span: 24
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入审核意见',
|
||||||
|
type: 'textarea',
|
||||||
|
maxlength: 140
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const back = () => {
|
||||||
|
switch (route.name) {
|
||||||
|
case 'Initiation/detail':
|
||||||
|
router.push({name: 'Initiation'})
|
||||||
|
break;
|
||||||
|
case 'Filing/detail':
|
||||||
|
router.push({name: 'Filing'})
|
||||||
|
break;
|
||||||
|
case 'Implementation/detail':
|
||||||
|
router.push({name: 'Implementation'})
|
||||||
|
break;
|
||||||
|
case 'Summary/detail':
|
||||||
|
router.push({name: 'Summary'})
|
||||||
|
break;
|
||||||
|
case 'Requirement/detail':
|
||||||
|
router.push({name: 'Requirement'})
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 驳回
|
||||||
|
const handleReject = async () => {
|
||||||
|
const values = form.value.getValues()
|
||||||
|
if (!values.auditOpinion) {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: '请填写审核意见',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log('values', values)
|
||||||
|
const params = {
|
||||||
|
taskId: props.taskId,
|
||||||
|
...values
|
||||||
|
}
|
||||||
|
const res = await rejectTask(params)
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
back()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAgree = async () => {
|
||||||
|
const values = form.value.getValues()
|
||||||
|
const params = {
|
||||||
|
taskId: props.taskId,
|
||||||
|
formData: props.formData,
|
||||||
|
...values
|
||||||
|
}
|
||||||
|
const res = await agreeTask(params)
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
back()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
322
src/components/DetailComponent/SummaryDetail.vue
Normal file
322
src/components/DetailComponent/SummaryDetail.vue
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
<template>
|
||||||
|
<div class="detail-block" v-loading="loading">
|
||||||
|
<el-form :model="localFormData" ref="summaryForm" :rules="rules">
|
||||||
|
<el-row gutter="50">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="名称" prop="projectName">
|
||||||
|
<span>{{ localFormData.projectName }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="专项资金" prop="specialFund">
|
||||||
|
<span>{{ localFormData.specialFund }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="开始时间" prop="startTime">
|
||||||
|
<span>{{ localFormData.startTime }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="结束时间" prop="endTime">
|
||||||
|
<span>{{ formData.endTime }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="所属公司" prop="affiliatedCompanyId">
|
||||||
|
<span>{{ localFormData.affiliatedCompanyId }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="项目类型" prop="projectType">
|
||||||
|
<span>{{ localFormData.projectType }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="研发主体" prop="rdSubject">
|
||||||
|
<span>{{ localFormData.rdSubject }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="出资类型" prop="investmentType">
|
||||||
|
<span>{{ localFormData.investmentType }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="项目影响" prop="projectImpact">
|
||||||
|
<span>{{ localFormData.projectImpact }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="所属业务板块" prop="businessSegment">
|
||||||
|
<span>{{ localFormData.businessSegment }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="预期成果形式" prop="resultForm">
|
||||||
|
<span>{{ localFormData.resultForm }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="预期技术标准制定" prop="technicalStandard">
|
||||||
|
<span>{{ localFormData.technicalStandard }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="产学研联合" prop="industryUniversityResearch">
|
||||||
|
<span>{{ localFormData.industryUniversityResearch }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="开展政府申报" prop="governmentDeclaration">
|
||||||
|
<span>{{ localFormData.governmentDeclaration }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="知识产权状况" prop="intellectualProperty">
|
||||||
|
<span>{{ localFormData.intellectualProperty }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="发明专利(项)" prop="inventionPatent">
|
||||||
|
<span>{{ localFormData.inventionPatent }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="实用性新型专利(项)" prop="newPatent">
|
||||||
|
<span>{{ localFormData.newPatent }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="软件著作权(项)" prop="softwareCopyright">
|
||||||
|
<span>{{ localFormData.softwareCopyright }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="著作权(项)" prop="copyright">
|
||||||
|
<span>{{ localFormData.copyright }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="其他(项)" prop="other">
|
||||||
|
<span>{{ localFormData.other }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="经济概算(万元)" prop="economicEstimate">
|
||||||
|
<span>{{ localFormData.economicEstimate }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="其中申请公司总部科技创新专项资金(万元)" prop="specialFundAmount">
|
||||||
|
<span>{{ localFormData.specialFundAmount }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="现有业务描述" prop="serviceDescription">
|
||||||
|
<span>{{ localFormData.serviceDescription }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="研发项目关键内容描述" prop="contentDescription">
|
||||||
|
<span>{{ localFormData.contentDescription }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="需求上报申请书">
|
||||||
|
<el-button type="primary" link @click="handleDownload(localFormData.singleFile)">
|
||||||
|
{{ localFormData.singleFile?.originalFileName }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="需求上报附件">
|
||||||
|
<fvTable style="width: 100%;max-height: 400px;" v-if="processViewer" :tableConfig="tableConfig"
|
||||||
|
:data="localFormData.fileList" :isSettingCol="false" :pagination="false">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<div v-if="data.taskId">
|
||||||
|
<baseTitle title="审核意见"></baseTitle>
|
||||||
|
<el-form-item prop="auditOpinion">
|
||||||
|
<el-input
|
||||||
|
v-model="localFormData.auditOpinion"
|
||||||
|
:rows="3"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请输入审核意见"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div class="approval-record">
|
||||||
|
<baseTitle title="审批记录"></baseTitle>
|
||||||
|
<div class="process">
|
||||||
|
<operation-render v-if="processViewer" :operation-list="data.operationList"
|
||||||
|
:state="data.state"/>
|
||||||
|
<process-diagram-viewer v-if="processViewer" id-name="summaryProcess"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="oper-page-btn" v-if="data.state === '1' && data.taskId">-->
|
||||||
|
<!-- <el-button @click="handleReject(summaryForm)">驳回</el-button>-->
|
||||||
|
<!-- <el-button color="#DED0B2" @click="handleAgree">同意</el-button>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {downloadFile} from "@/api/project-demand";
|
||||||
|
import OperationRender from '@/views/workflow/common/OperationRender.vue'
|
||||||
|
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
|
||||||
|
import {ElMessage, ElNotification} from "element-plus";
|
||||||
|
import {agreeTask, rejectTask} from "@/api/project-demand";
|
||||||
|
import {useTagsView} from '@/stores/tagsview.js'
|
||||||
|
|
||||||
|
const tagsViewStore = useTagsView()
|
||||||
|
const props = defineProps({
|
||||||
|
formData: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
processViewer: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}, loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const localFormData = ref({})
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'index',
|
||||||
|
type: 'index',
|
||||||
|
label: '序号',
|
||||||
|
align: 'center',
|
||||||
|
width: '80',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'originalFileName',
|
||||||
|
label: '文件名',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'tag',
|
||||||
|
label: '标签',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'size',
|
||||||
|
label: '文件大小',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
return (
|
||||||
|
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const router = useRouter()
|
||||||
|
const summaryForm = ref()
|
||||||
|
const rules = reactive({
|
||||||
|
auditOpinion: [{required: true, message: '请输入审核意见', trigger: 'blur'}],
|
||||||
|
})
|
||||||
|
const handleReject = (instance) => {
|
||||||
|
if (!instance) return
|
||||||
|
instance.validate(async (valid) => {
|
||||||
|
if (!valid) return
|
||||||
|
let approve = {
|
||||||
|
taskId: props.data.taskId,
|
||||||
|
auditOpinion: localFormData.value.auditOpinion,
|
||||||
|
}
|
||||||
|
rejectTask(approve).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
router.push({
|
||||||
|
name: 'Summary'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleAgree = () => {
|
||||||
|
let approve = {
|
||||||
|
taskId: props.data.taskId,
|
||||||
|
auditOpinion: localFormData.value.auditOpinion,
|
||||||
|
formData: localFormData.value
|
||||||
|
}
|
||||||
|
agreeTask(approve).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
router.push({
|
||||||
|
name: 'Summary'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleDownload = (row) => {
|
||||||
|
downloadFile(row.fileId).then(res => {
|
||||||
|
const blob = new Blob([res])
|
||||||
|
let a = document.createElement('a')
|
||||||
|
a.href = URL.createObjectURL(blob)
|
||||||
|
a.download = row.originalFileName
|
||||||
|
a.click()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.formData,
|
||||||
|
(val) => {
|
||||||
|
}
|
||||||
|
)
|
||||||
|
watch(() => props.processViewer, (newVal) => {
|
||||||
|
props.processViewer = newVal
|
||||||
|
}, {deep: true})
|
||||||
|
watch(() => props.loading, (newVal) => {
|
||||||
|
props.loading = newVal
|
||||||
|
}, {deep: true})
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
Object.keys(props.formData).length && (localFormData.value = props.formData)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
:deep(.el-table--fit) {
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-block {
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
112
src/components/FileUpload.vue
Normal file
112
src/components/FileUpload.vue
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<template>
|
||||||
|
<el-upload :file-list="_value"
|
||||||
|
:action="uploadFileUrl"
|
||||||
|
:headers="headers"
|
||||||
|
:limit="maxSize"
|
||||||
|
with-credentials
|
||||||
|
:multiple="maxSize > 0"
|
||||||
|
:data="uploadParams"
|
||||||
|
:show-file-list="showFileList"
|
||||||
|
:auto-upload="true"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
:on-success="handleUploadSuccess"
|
||||||
|
:on-error="uploadError"
|
||||||
|
:before-remove="beforeRemove"
|
||||||
|
:on-remove="handleRemove"
|
||||||
|
>
|
||||||
|
<el-button color="#DED0B2" :loading="loading">上传文件</el-button>
|
||||||
|
</el-upload>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ElMessage,ElMessageBox} from "element-plus";
|
||||||
|
import {getToken} from '@/utils/auth'
|
||||||
|
const baseURL = import.meta.env.VITE_BASE_URL
|
||||||
|
const uploadFileUrl = ref(baseURL + "/workflow/process/file/upload")
|
||||||
|
const headers = reactive({
|
||||||
|
authorization: getToken()
|
||||||
|
})
|
||||||
|
const disabled = ref(false)
|
||||||
|
const loading = ref(false)
|
||||||
|
const showTable = ref(false)
|
||||||
|
const uploadParams = ref({})
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 30
|
||||||
|
},
|
||||||
|
showFileList: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(["input", "getFile","delete"])
|
||||||
|
const fileList = ref([])
|
||||||
|
const _value = computed({
|
||||||
|
get() {
|
||||||
|
return props.value;
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
emit("input", val);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const beforeRemove = (file, fileList) => {
|
||||||
|
return ElMessageBox.confirm(`确认删除名称为${file.name}的文件吗?`, '系统提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRemove = (file, fileList) => {
|
||||||
|
emit("delete",file.response.data.id)
|
||||||
|
}
|
||||||
|
const beforeUpload = (file) => {
|
||||||
|
// const FileExt = file.name.replace(/.+\./, "");
|
||||||
|
// if (['zip', 'rar', 'pdf', 'doc', 'docx', 'xlsx'].indexOf(FileExt.toLowerCase()) === -1) {
|
||||||
|
// ElMessage.warning('请上传后缀名为pdf、doc、docx、xlsx、zip或rar的文件!');
|
||||||
|
// return false;
|
||||||
|
// } else
|
||||||
|
// if (props.maxSize > 0 && file.size / 1024 / 1024 > props.maxSize) {
|
||||||
|
// ElMessage.warning(`每个文件最大不超过 ${props.maxSize}MB`)
|
||||||
|
// } else {
|
||||||
|
loading.value = true
|
||||||
|
return true
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
const handleUploadSuccess = (res, file) => {
|
||||||
|
if (res.code !== 1000) {
|
||||||
|
loading.value = false
|
||||||
|
ElMessage.error("上传失败")
|
||||||
|
} else {
|
||||||
|
loading.value = false
|
||||||
|
ElMessage.success("上传成功")
|
||||||
|
}
|
||||||
|
showTable.value = true
|
||||||
|
let data = res.data
|
||||||
|
fileList.value.push(data)
|
||||||
|
emit("getFile", res.data)
|
||||||
|
}
|
||||||
|
const uploadError=(err)=>{
|
||||||
|
loading.value = false
|
||||||
|
ElMessage.error("上传失败,请稍后再试!")
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
a {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #2a99ff;
|
||||||
|
}
|
||||||
|
:deep(.el-upload-list) {
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
126
src/components/NameCircle.vue
Normal file
126
src/components/NameCircle.vue
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<slot name="pre"></slot>
|
||||||
|
<div class="user-audit">
|
||||||
|
<div class="circle-user">
|
||||||
|
<Tooltip :content="user.name" placement="bottom-start" width="45"/>
|
||||||
|
<div v-if="user.icon"
|
||||||
|
class="el-timeline-item__node" :style="{
|
||||||
|
backgroundColor: user.color
|
||||||
|
}">
|
||||||
|
<el-icon v-if="user.icon" size="15" :class="user.class">
|
||||||
|
<component :is="user.icon"/>
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="username" v-if="user.auditOpinion">
|
||||||
|
<div style="margin-bottom: 10px;color: #909399">{{user.operationTime}}</div>
|
||||||
|
<Tooltip :content="user.auditOpinion" placement="bottom-start" width="140" :lines="true"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {Loading, Close, CircleCheckFilled, MoreFilled} from '@element-plus/icons-vue'
|
||||||
|
import {defineProps} from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
row: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
hoverTip: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'design'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
// for (let user of props.userInfo) {
|
||||||
|
initUser(props.user)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
const initUser = (user) => {
|
||||||
|
let state = user.state
|
||||||
|
//创建节点
|
||||||
|
if (state === 'CREATE') {
|
||||||
|
user["icon"] = CircleCheckFilled
|
||||||
|
user["color"] = "#0bbd87"
|
||||||
|
}
|
||||||
|
//审批通过
|
||||||
|
if (state === 'AGREE' || state === 'AUTO_PASS') {
|
||||||
|
user["icon"] = CircleCheckFilled
|
||||||
|
user["color"] = "#0bbd87"
|
||||||
|
}
|
||||||
|
//审批处理中
|
||||||
|
if (state === 'RUNNING') {
|
||||||
|
user["icon"] = Loading
|
||||||
|
user["color"] = "#f78f5f"
|
||||||
|
user["class"] = 'is-loading'
|
||||||
|
}
|
||||||
|
//拒绝后评论
|
||||||
|
if (state === 'REFUSE') {
|
||||||
|
user["icon"] = Close
|
||||||
|
user["color"] = "#f56c6c"
|
||||||
|
}
|
||||||
|
if (state === 'PASS') {
|
||||||
|
user["icon"] = MoreFilled
|
||||||
|
user["color"] = "#c0c4cc"
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
init()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.user-audit {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.circle-user {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #ACACAC;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.el-timeline-item__node {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
//width: 90px;
|
||||||
|
margin-top: 10px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
.el-tooltip__trigger {
|
||||||
|
width: 90px;
|
||||||
|
text-align: center;
|
||||||
|
//padding-top: 2px;
|
||||||
|
//text-align: center;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
>
|
>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button :type="btnType" size="mini" v-perm="perm" :disabled="isDisabled" :icon="btnIcon" :plain="isPlain">
|
<el-button v-perm="perm" :type="btnType" size="mini" :disabled="isDisabled" :icon="btnIcon" :plain="isPlain" :link="link">
|
||||||
{{ btnText }}
|
{{ btnText }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -24,12 +24,16 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
btnType: {
|
btnType: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'text'
|
default: 'danger'
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
|
link: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
btnIcon: {
|
btnIcon: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
@@ -61,6 +65,7 @@ const handleCancel = () => {
|
|||||||
visible.value = false
|
visible.value = false
|
||||||
}
|
}
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
|
console.log('确认')
|
||||||
emit("delete")
|
emit("delete")
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -60,13 +60,21 @@ const props = defineProps({
|
|||||||
toolbar: {
|
toolbar: {
|
||||||
type: [String, Array],
|
type: [String, Array],
|
||||||
default: [
|
default: [
|
||||||
"fullscreen undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link anchor | alignleft aligncenter alignright alignjustify outdent indent | bullist numlist | blockquote subscript superscript removeformat ",
|
"fullscreen undo redo | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link anchor | alignleft aligncenter alignright alignjustify outdent indent | bullist numlist | blockquote subscript superscript removeformat ",
|
||||||
"styleselect formatselect fontselect fontsizeselect | table image axupimgs media pagebreak insertdatetime selectall visualblocks searchreplace | code preview | indent2em lineheight formatpainter",
|
"styleselect formatselect fontselect fontsizeselect | table image axupimgs media pagebreak insertdatetime selectall visualblocks searchreplace | code preview | indent2em lineheight formatpainter",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
fontFormats: {
|
fontFormats: {
|
||||||
type: [String, Array],
|
type: [String, Array],
|
||||||
default: "微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;"
|
default: "微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;"
|
||||||
|
},
|
||||||
|
width:{
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
height:{
|
||||||
|
type: Number,
|
||||||
|
default: 450
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const content = ref(props.value);
|
const content = ref(props.value);
|
||||||
@@ -78,9 +86,10 @@ const init = reactive({
|
|||||||
content_css: '/skins/content/default/content.css',
|
content_css: '/skins/content/default/content.css',
|
||||||
language: 'zh_CN',
|
language: 'zh_CN',
|
||||||
placeholder: "在这里输入文字", //textarea中的提示信息
|
placeholder: "在这里输入文字", //textarea中的提示信息
|
||||||
min_width: 320,
|
min_width: 300,
|
||||||
min_height: 220,
|
min_height: 200,
|
||||||
height: 500, //注:引入autoresize插件时,此属性失效
|
width:props.width,
|
||||||
|
height: props.height, //注:引入autoresize插件时,此属性失效
|
||||||
resize: "both", //编辑器宽高是否可变,false-否,true-高可变,'both'-宽高均可,注意引号
|
resize: "both", //编辑器宽高是否可变,false-否,true-高可变,'both'-宽高均可,注意引号
|
||||||
promotion: false,
|
promotion: false,
|
||||||
branding: false, //tiny技术支持信息是否显示
|
branding: false, //tiny技术支持信息是否显示
|
||||||
|
|||||||
49
src/components/Tooltip.vue
Normal file
49
src/components/Tooltip.vue
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<el-tooltip
|
||||||
|
effect="dark"
|
||||||
|
:content="props.content"
|
||||||
|
placement="bottom-start"
|
||||||
|
:disabled="isShow"
|
||||||
|
>
|
||||||
|
<div :class="lines?'content-lines':'content'" :style="{width: props.width+'px'}" @mouseover="isShowTooltip">
|
||||||
|
<span ref="contentRef">
|
||||||
|
<slot name="content">{{ props.content }}</slot>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}, width: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}, lines: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const contentRef = ref()
|
||||||
|
const isShow = ref(false)
|
||||||
|
const isShowTooltip = () => {
|
||||||
|
isShow.value = props.width > contentRef.value.offsetWidth;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.content {
|
||||||
|
width: 45px;
|
||||||
|
text-align: center;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.content-lines{
|
||||||
|
overflow:hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
15
src/components/steps/api/index.js
Normal file
15
src/components/steps/api/index.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export const getBaseInfoApi = (projectId) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/details/info/'+projectId,
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getMapProjectStateInfo = (projectId, state) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/details/${projectId}/${state}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
256
src/components/steps/index.vue
Normal file
256
src/components/steps/index.vue
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
<template>
|
||||||
|
<baseTitle title="基础信息"></baseTitle>
|
||||||
|
<fvForm :schema="schema" @getInstance="(e)=>baseForm = e"></fvForm>
|
||||||
|
<baseTitle title="各流程信息"></baseTitle>
|
||||||
|
<div class="steps-box">
|
||||||
|
<el-steps :active="localActive" finish-status="success">
|
||||||
|
<el-step
|
||||||
|
v-for="(item, index) in localSteps"
|
||||||
|
:key="item.key"
|
||||||
|
:title="item.title"
|
||||||
|
:class="stepClass(index)"
|
||||||
|
@click="handleStep(item.key, index)"
|
||||||
|
|
||||||
|
/>
|
||||||
|
</el-steps>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 步骤内容 -->
|
||||||
|
<div>
|
||||||
|
<slot name="content" :localActive="localActive"></slot>
|
||||||
|
<!-- <template v-for="(item, index) in stepList" :key="item.key">
|
||||||
|
<component v-if="localActive == index" v-bind="item.props || {}" :is="item.component" />
|
||||||
|
</template> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import { ElLoading, ElNotification } from 'element-plus';
|
||||||
|
import { computed, reactive, ref, watchEffect } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { getBaseInfoApi } from './api';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
// 步骤对应内容list
|
||||||
|
stepList: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
// 当前显示步骤
|
||||||
|
active: {
|
||||||
|
type: Number,
|
||||||
|
default: '0'
|
||||||
|
},
|
||||||
|
// 已完成的工作流步骤
|
||||||
|
stepSuccess: {
|
||||||
|
type: Array,
|
||||||
|
default: ['00']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const emits = defineEmits(['stepChange', 'setDetail'])
|
||||||
|
|
||||||
|
const localData = reactive({
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
const localActive = ref(0) // 当前激活步骤
|
||||||
|
|
||||||
|
const localSteps = ref([
|
||||||
|
{
|
||||||
|
title: '需求征集',
|
||||||
|
key: 'collect',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '需求上报',
|
||||||
|
key: 'report',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '项目立项',
|
||||||
|
key: 'approve',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '项目实施',
|
||||||
|
key: 'execute',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '项目归档',
|
||||||
|
key: 'archivist',
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// title: '项目结项',
|
||||||
|
// key: 'end',
|
||||||
|
// },
|
||||||
|
])
|
||||||
|
|
||||||
|
const baseForm = ref()
|
||||||
|
|
||||||
|
const schema = computed(()=>{
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: '所属公司',
|
||||||
|
prop: 'affiliatedCompany',
|
||||||
|
colProps: {
|
||||||
|
span: 12
|
||||||
|
}
|
||||||
|
// component:
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '征集类型',
|
||||||
|
prop: 'collectType',
|
||||||
|
colProps: {
|
||||||
|
span: 12
|
||||||
|
}
|
||||||
|
// component:
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '截止时间',
|
||||||
|
prop: 'deadline',
|
||||||
|
colProps: {
|
||||||
|
span: 12
|
||||||
|
}
|
||||||
|
// component:
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '需求名称',
|
||||||
|
prop: 'requirementName',
|
||||||
|
colProps: {
|
||||||
|
span: 12
|
||||||
|
}
|
||||||
|
// component:
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const localStepSuccess = ref([])
|
||||||
|
|
||||||
|
// 格式化详情步骤条
|
||||||
|
const formatProcedure = (data) => {
|
||||||
|
let arr = []
|
||||||
|
if(data instanceof Array) {
|
||||||
|
data.forEach(item=>{
|
||||||
|
switch (item) {
|
||||||
|
case '00': arr.push(0)
|
||||||
|
break
|
||||||
|
case '10': arr.push(1)
|
||||||
|
break
|
||||||
|
case '20': arr.push(2)
|
||||||
|
break
|
||||||
|
// case '30': arr.push(3)
|
||||||
|
// break
|
||||||
|
case '40': arr.push(3)
|
||||||
|
break
|
||||||
|
case '50': arr.push(4)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// 反向格式化
|
||||||
|
const formatReProcedure = (data) => {
|
||||||
|
let arr = []
|
||||||
|
if(data instanceof Array) {
|
||||||
|
data.forEach(item=>{
|
||||||
|
switch (item) {
|
||||||
|
case 0: arr.push('00')
|
||||||
|
break
|
||||||
|
case 1: arr.push('10')
|
||||||
|
break
|
||||||
|
case 2: arr.push('20')
|
||||||
|
break
|
||||||
|
// case 3: arr.push('30')
|
||||||
|
// break
|
||||||
|
case 3: arr.push('40')
|
||||||
|
break
|
||||||
|
case 4: arr.push('50')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatActive = (val) => {
|
||||||
|
let active = ''
|
||||||
|
val == 0 && (active = '00')
|
||||||
|
val == 1 && (active = '10')
|
||||||
|
val == 2 && (active = '20')
|
||||||
|
// val == 3 && (active = '30')
|
||||||
|
val == 3 && (active = '40')
|
||||||
|
val == 4 && (active = '50')
|
||||||
|
return active
|
||||||
|
}
|
||||||
|
|
||||||
|
const stepClass = (val) => {
|
||||||
|
if (localStepSuccess.value.includes(val)) {
|
||||||
|
return 'step-success'
|
||||||
|
}
|
||||||
|
return 'step-error'
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleStep = (key, index) => {
|
||||||
|
if (localStepSuccess.value.includes(index)) {
|
||||||
|
let active = ''
|
||||||
|
localActive.value = index
|
||||||
|
switch(index) {
|
||||||
|
case 0: active = '00'
|
||||||
|
break
|
||||||
|
case 1: active = '10'
|
||||||
|
break
|
||||||
|
case 2: active = '20'
|
||||||
|
break
|
||||||
|
// case 3: active = '30'
|
||||||
|
// break
|
||||||
|
case 3: active = '40'
|
||||||
|
break
|
||||||
|
case 4: active = '50'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
emits('stepChange', { key, active })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: '不能查看未完成的工作流信息',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBaseInfo = async () => {
|
||||||
|
const loading = ElLoading.service({fullscreen: true})
|
||||||
|
try {
|
||||||
|
const { code, data } = await getBaseInfoApi(route.query.projectId)
|
||||||
|
localStepSuccess.value = formatProcedure(data.procedure)
|
||||||
|
baseForm.value.setValues(data)
|
||||||
|
console.log(formatActive(localActive.value), 'formatActive(localActive.value)');
|
||||||
|
emits('setDetail', formatActive(localActive.value))
|
||||||
|
loading.close()
|
||||||
|
} catch {
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getBaseInfo()
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
console.log(props.active, 'props.active');
|
||||||
|
localActive.value = props.active
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.steps-box {
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-success {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-error {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -8,7 +8,7 @@ export const hasPerm = (el, binding, vnode) => {
|
|||||||
if (value && value instanceof Array && value.length > 0) {
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
const permissiosFlag = value
|
const permissiosFlag = value
|
||||||
const hasPermission = permisstions.some(permission => {
|
const hasPermission = permisstions.some(permission => {
|
||||||
return allPermission === permission || permissiosFlag.includes(permission)
|
return permission === allPermission || permissiosFlag.includes(permission) || permissiosFlag.includes(allPermission)
|
||||||
})
|
})
|
||||||
if (!hasPermission) {
|
if (!hasPermission) {
|
||||||
el.parentNode && el.parentNode.removeChild(el)
|
el.parentNode && el.parentNode.removeChild(el)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
<el-button v-if="searchConfig.length>=4" link type="primary" @click="showMore = !showMore">
|
<el-button v-if="searchConfig.length>=4" link type="primary" @click="showMore = !showMore">
|
||||||
{{ showMore ? '收起' : '展开' }}
|
{{ showMore ? '收起' : '展开' }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" @click="getValues" :icon="Search">搜索</el-button>
|
<el-button @click="getValues" color="#DED0B2" :icon="Search">搜索</el-button>
|
||||||
<el-button @click="handleReset" :icon="Refresh">重置</el-button>
|
<el-button @click="handleReset" :icon="Refresh">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -68,7 +68,7 @@ const filterConfig = computed(()=>{
|
|||||||
// 搜索功能表单元素默认值
|
// 搜索功能表单元素默认值
|
||||||
const setDefaultFormValues = () => {
|
const setDefaultFormValues = () => {
|
||||||
filterConfig.value.forEach(item => {
|
filterConfig.value.forEach(item => {
|
||||||
form.value[item.prop] = item.props.defaultValue || null
|
form.value[item.prop] = item.props?.defaultValue || null
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,6 +103,7 @@ onMounted(()=>{
|
|||||||
.search-form {
|
.search-form {
|
||||||
padding-top: 18px;
|
padding-top: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-col {
|
.btn-col {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
|
|||||||
@@ -2,16 +2,50 @@
|
|||||||
<div class="fv-table-container">
|
<div class="fv-table-container">
|
||||||
<!-- 表格头部按钮 -->
|
<!-- 表格头部按钮 -->
|
||||||
<div class="fv-table-btn" v-if="tableConfig.btns">
|
<div class="fv-table-btn" v-if="tableConfig.btns">
|
||||||
|
<div class="table-head-btn">
|
||||||
<el-button
|
<el-button
|
||||||
v-for="btn in tableConfig.btns"
|
v-for="btn in tableConfig.btns"
|
||||||
:key="btn.key"
|
:key="btn.key"
|
||||||
:type="btn.type || ''"
|
:type="btn.type || ''"
|
||||||
|
:color="btn.color || ''"
|
||||||
v-perm="btn.auth || ['*:*:*']"
|
v-perm="btn.auth || ['*:*:*']"
|
||||||
@click="handleClickBtns(btn.key)"
|
@click="handleClickBtns(btn.key)"
|
||||||
>
|
>
|
||||||
{{ btn.name }}
|
{{ btn.name }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 列显示配置 -->
|
||||||
|
<div v-if="isSettingCol">
|
||||||
|
<el-tooltip effect="dark" content="列配置" placement="bottom">
|
||||||
|
<el-button ref="buttonRef" link>
|
||||||
|
<el-icon size="18"><Setting /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-popover
|
||||||
|
placement="bottom"
|
||||||
|
:width="200"
|
||||||
|
ref="popoverRef"
|
||||||
|
:virtual-ref="buttonRef"
|
||||||
|
virtual-triggering
|
||||||
|
trigger="click">
|
||||||
|
<div class="col-setting-checkall">
|
||||||
|
<el-checkbox label="列展示" v-model="localData.allColShow" :indeterminate="localData.indeterminate" @change="changeIsShowAll"></el-checkbox>
|
||||||
|
</div>
|
||||||
|
<div class="col-setting-list">
|
||||||
|
<el-checkbox-group v-model="localData.checkGroup" @change="changeColShow">
|
||||||
|
<el-space direction="vertical" alignment="flex-start" :size="0">
|
||||||
|
<el-checkbox
|
||||||
|
v-for="item in tableConfig.columns"
|
||||||
|
:key="item.prop"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.prop"
|
||||||
|
/>
|
||||||
|
</el-space>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 表格部分 -->
|
<!-- 表格部分 -->
|
||||||
<div class="fv-table">
|
<div class="fv-table">
|
||||||
<el-table
|
<el-table
|
||||||
@@ -30,7 +64,7 @@
|
|||||||
ref="tableInstance"
|
ref="tableInstance"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<fvTableColumn v-for="column in tableConfig.columns" :key="column.prop" :columns="column">
|
<fvTableColumn v-for="column in localData.columns" :key="column.prop" :columns="column">
|
||||||
<template v-if="column?.slots?.header" #[column?.slots?.header]="params">
|
<template v-if="column?.slots?.header" #[column?.slots?.header]="params">
|
||||||
<slot :name="column?.slots?.header" v-bind="params || {}"></slot>
|
<slot :name="column?.slots?.header" v-bind="params || {}"></slot>
|
||||||
</template>
|
</template>
|
||||||
@@ -80,10 +114,17 @@ const props = defineProps({
|
|||||||
pagination: {
|
pagination: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示列配置
|
||||||
|
isSettingCol: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableInstance = ref()
|
const tableInstance = ref()
|
||||||
|
const buttonRef = ref()
|
||||||
|
const popoverRef = ref()
|
||||||
|
|
||||||
const localData = reactive({
|
const localData = reactive({
|
||||||
list: [], // 表格数据
|
list: [], // 表格数据
|
||||||
@@ -92,7 +133,12 @@ const localData = reactive({
|
|||||||
pageNum: 1
|
pageNum: 1
|
||||||
},
|
},
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false
|
loading: false,
|
||||||
|
// 列展示设置
|
||||||
|
columns: [],
|
||||||
|
allColShow: true, // 默认全部列都展示
|
||||||
|
indeterminate: false,
|
||||||
|
checkGroup: []
|
||||||
})
|
})
|
||||||
|
|
||||||
const emits = defineEmits(['headBtnClick', 'selectionChange', 'rowClick', 'rowDblclick', 'getBaseQuery', 'cellClick'])
|
const emits = defineEmits(['headBtnClick', 'selectionChange', 'rowClick', 'rowDblclick', 'getBaseQuery', 'cellClick'])
|
||||||
@@ -101,6 +147,52 @@ const handleClickBtns = (key) => {
|
|||||||
emits('headBtnClick', key)
|
emits('headBtnClick', key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filterColumns = () => {
|
||||||
|
localData.columns = props.tableConfig.columns.map(item=>{
|
||||||
|
if(item.prop) {
|
||||||
|
return {
|
||||||
|
...item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeIsShowAll = (val) => {
|
||||||
|
if(val) {
|
||||||
|
filterColumns()
|
||||||
|
localData.indeterminate = false
|
||||||
|
localData.checkGroup = props.tableConfig.columns.map(item=>item.prop)
|
||||||
|
} else {
|
||||||
|
localData.columns.length = 0
|
||||||
|
localData.checkGroup.length = 0
|
||||||
|
localData.indeterminate = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeColShow = (val) => {
|
||||||
|
if(val.length == props.tableConfig.columns.length) {
|
||||||
|
localData.indeterminate = false
|
||||||
|
localData.allColShow = true
|
||||||
|
} else if(val.length !== props.tableConfig.columns.length && val.length != 0) {
|
||||||
|
localData.allColShow = false
|
||||||
|
localData.indeterminate = true
|
||||||
|
} else {
|
||||||
|
localData.indeterminate = false
|
||||||
|
localData.allColShow = false
|
||||||
|
}
|
||||||
|
const template = []
|
||||||
|
props.tableConfig.columns.forEach(item=>{
|
||||||
|
val.forEach(v=>{
|
||||||
|
if(item.prop == v) {
|
||||||
|
template.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
localData.columns = template
|
||||||
|
}
|
||||||
|
|
||||||
|
filterColumns()
|
||||||
|
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
const { api, params } = props.tableConfig
|
const { api, params } = props.tableConfig
|
||||||
const queryParmas = {...localData.query, ...params}
|
const queryParmas = {...localData.query, ...params}
|
||||||
@@ -154,13 +246,11 @@ const handleCurrentChange = (val) => {
|
|||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// watchEffect(()=>{
|
watchEffect(()=>{
|
||||||
// if(!props.tableConfig.api) {
|
if(localData.allColShow) {
|
||||||
// localData.list = props.data
|
localData.checkGroup = props.tableConfig.columns.map(item=>item.prop)
|
||||||
// }else {
|
}
|
||||||
// getList()
|
})
|
||||||
// }
|
|
||||||
// })
|
|
||||||
//刷新
|
//刷新
|
||||||
const refresh = ({resetPage=false}={}) => {
|
const refresh = ({resetPage=false}={}) => {
|
||||||
resetPage ? localData.query.pageNum = 1 : null
|
resetPage ? localData.query.pageNum = 1 : null
|
||||||
@@ -184,5 +274,26 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.col-setting-checkall {
|
||||||
|
border-bottom: 1px solid rgb(210, 210, 213);
|
||||||
|
}
|
||||||
|
.col-setting-list {
|
||||||
|
max-height: 45vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.table-head-btn {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.fv-table-btn {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
.fv-table {
|
||||||
|
:deep(.el-tooltip) {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,37 +1,37 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-popover
|
<!-- <el-popover-->
|
||||||
:width="300"
|
<!-- :width="300"-->
|
||||||
trigger="click"
|
<!-- trigger="click"-->
|
||||||
placement="bottom"
|
<!-- placement="bottom"-->
|
||||||
popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 10px;"
|
<!-- popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 10px;"-->
|
||||||
>
|
<!-- >-->
|
||||||
<template #reference>
|
<!-- <template #reference>-->
|
||||||
<el-badge :hidden="total===0" :value="total" class="item">
|
<!-- <el-badge :hidden="total===0" :value="total" class="item">-->
|
||||||
<el-icon size="22px" style="cursor: pointer">
|
<!-- <el-icon size="22px" style="cursor: pointer">-->
|
||||||
<Bell/>
|
<!-- <Bell/>-->
|
||||||
</el-icon>
|
<!-- </el-icon>-->
|
||||||
</el-badge>
|
<!-- </el-badge>-->
|
||||||
</template>
|
<!-- </template>-->
|
||||||
<template #default>
|
<!-- <template #default>-->
|
||||||
<div v-if="total===0" style="height: 100px;display: flex;align-items: center;justify-content: center">
|
<!-- <div v-if="total===0" style="height: 100px;display: flex;align-items: center;justify-content: center">-->
|
||||||
暂无数据~
|
<!-- 暂无数据~-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<ul v-else>
|
<!-- <ul v-else>-->
|
||||||
<li v-for="(notice,index) in noticeList" :key="index">
|
<!-- <li v-for="(notice,index) in noticeList" :key="index">-->
|
||||||
<span @click="handleToNotifyDetail(notice,index)">{{ notice.noticeTitle }}</span>
|
<!-- <span @click="handleToNotifyDetail(notice,index)">{{ notice.noticeTitle }}</span>-->
|
||||||
<span v-if="notice.state==='0'" @click="handleRead(notice)">已读</span>
|
<!-- <span v-if="notice.state==='0'" @click="handleRead(notice)">已读</span>-->
|
||||||
</li>
|
<!-- </li>-->
|
||||||
</ul>
|
<!-- </ul>-->
|
||||||
|
|
||||||
<div class="notify-btn">
|
<!-- <div class="notify-btn">-->
|
||||||
<el-button type="primary" @click="handlePrevious" :disabled="pageInfo.pageNum===1" link>上一页</el-button>
|
<!-- <el-button type="primary" @click="handlePrevious" :disabled="pageInfo.pageNum===1" link>上一页</el-button>-->
|
||||||
<span @click="handleMoreRead">本页已读</span>
|
<!-- <span @click="handleMoreRead">本页已读</span>-->
|
||||||
<el-button type="primary" @click="handleNext" :disabled="pageInfo.pageNum*pageInfo.pageSize>total" link>下一页
|
<!-- <el-button type="primary" @click="handleNext" :disabled="pageInfo.pageNum*pageInfo.pageSize>total" link>下一页-->
|
||||||
</el-button>
|
<!-- </el-button>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</template>
|
<!-- </template>-->
|
||||||
</el-popover>
|
<!-- </el-popover>-->
|
||||||
<el-dialog width="1200px" title="通知公告详情" v-model="visible" @close="visible=false">
|
<el-dialog width="1200px" title="通知公告详情" v-model="visible" @close="visible=false">
|
||||||
<el-form :model="viewForm" label-width="100px">
|
<el-form :model="viewForm" label-width="100px">
|
||||||
<el-row>
|
<el-row>
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
<Hamburger></Hamburger>
|
<Hamburger></Hamburger>
|
||||||
<Breadcrumb></Breadcrumb>
|
<Breadcrumb></Breadcrumb>
|
||||||
<div class="right-bar">
|
<div class="right-bar">
|
||||||
<bell-socket/>
|
<!-- <bell-socket/>-->
|
||||||
<div class="user-box">
|
<div class="user-box">
|
||||||
<div>
|
<div>
|
||||||
<img :src="userInfo.avatar" alt="" @click.stop="handleVisitedP">
|
<!-- <img :src="userInfo.avatar" alt="" @click.stop="handleVisitedP">-->
|
||||||
<span>{{userInfo.userName}}</span>
|
<span @click.stop="handleVisitedP">欢迎回来,{{userInfo.userName}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="person" v-if="visitedP">
|
<div class="person" v-if="visitedP">
|
||||||
<ul>
|
<ul>
|
||||||
@@ -81,6 +81,7 @@ const handleLogout = () => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.user-box{
|
.user-box{
|
||||||
|
cursor: pointer;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
position: relative;
|
position: relative;
|
||||||
>div:first-child{
|
>div:first-child{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 有子菜单 -->
|
<!-- 有子菜单 -->
|
||||||
<template v-for="item in menuItem" :key="item.path">
|
<template v-for="item in menuItem" :key="item.path">
|
||||||
<el-sub-menu v-if="item?.children?.length>0 && !item.hidden" :index="item.path">
|
<el-sub-menu v-if="checkMenuItem(item)" :index="item.path">
|
||||||
<template #title>
|
<template #title>
|
||||||
<svg-icon :name="item.icon"/>
|
<svg-icon :name="item.icon"/>
|
||||||
<span>{{ item.title }}</span>
|
<span>{{ item.title }}</span>
|
||||||
@@ -44,5 +44,19 @@ const handleGo = (path) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const checkMenuItem = (item) => {
|
||||||
|
let children = item.children
|
||||||
|
let childState = false;
|
||||||
|
if (children){
|
||||||
|
for (let child of children) {
|
||||||
|
if (!child.hidden) {
|
||||||
|
childState = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item?.children?.length>0 && !item.hidden && childState
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="logo" ref="logo">
|
<div class="logo" ref="logo">
|
||||||
<span v-if="!siderbarStore.isCollapse">科研管理平台</span>
|
<!-- <span v-if="!siderbarStore.isCollapse">科研管理平台</span>-->
|
||||||
|
<span v-if="!siderbarStore.isCollapse"></span>
|
||||||
</div>
|
</div>
|
||||||
<el-scrollbar :height="`calc(100vh - ${logoHeight}px)`" style="background-color: #ffffff">
|
<el-scrollbar :height="`calc(100vh - ${logoHeight}px)`" style="background-color: #ffffff">
|
||||||
<el-menu
|
<el-menu
|
||||||
|
|||||||
@@ -188,8 +188,14 @@ router.beforeEach(async (to, form, next) => {
|
|||||||
next()
|
next()
|
||||||
NProgress.done()
|
NProgress.done()
|
||||||
} else {
|
} else {
|
||||||
sessionStorage.setItem('toView', JSON.stringify(to))
|
let path = window.location.pathname;
|
||||||
next({path: '/cas/login'})
|
let query = window.location.search
|
||||||
|
sessionStorage.setItem('toView', JSON.stringify({
|
||||||
|
path: path,
|
||||||
|
query: query
|
||||||
|
}))
|
||||||
|
window.location.href = `${window.location.origin}/api/auth/cas/login`
|
||||||
|
// next({path: '/api/auth/cas/login'})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (to.path === '/login' || to.path === '/cas/login') {
|
if (to.path === '/login' || to.path === '/cas/login') {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { defineAsyncComponent, ref } from "vue";
|
import { defineAsyncComponent, ref, toRaw } from "vue";
|
||||||
import { getRouters } from "@/api/system/menu";
|
import { getRouters } from "@/api/system/menu";
|
||||||
import Layout from '@/layout/index.vue'
|
import Layout from '@/layout/index.vue'
|
||||||
import ParentView from '@/components/ParentView.vue'
|
import ParentView from '@/components/ParentView.vue'
|
||||||
@@ -21,6 +21,8 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
// 二级页面路由list
|
||||||
|
const slRouters = ref([])
|
||||||
|
|
||||||
const setIsLoadRoutes = (status) => {
|
const setIsLoadRoutes = (status) => {
|
||||||
return isLoadRoutes.value = status
|
return isLoadRoutes.value = status
|
||||||
@@ -30,7 +32,9 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
|
|||||||
if (res.code === 1000) {
|
if (res.code === 1000) {
|
||||||
const sRouter = JSON.parse(JSON.stringify(res.data))
|
const sRouter = JSON.parse(JSON.stringify(res.data))
|
||||||
const mData = JSON.parse(JSON.stringify(res.data))
|
const mData = JSON.parse(JSON.stringify(res.data))
|
||||||
asyncRouters.value = formatAsyncRouters(sRouter)
|
console.log(JSON.parse(JSON.stringify(sRouter)), 'sRouter');
|
||||||
|
const firstFormat = setRouterLevel(JSON.parse(JSON.stringify(sRouter)))
|
||||||
|
asyncRouters.value = formatAsyncRouters(JSON.parse(JSON.stringify(firstFormat)))
|
||||||
menuList.value = [...menuList.value, ...generateMenu(mData)]
|
menuList.value = [...menuList.value, ...generateMenu(mData)]
|
||||||
addAsyncRouters(asyncRouters.value)
|
addAsyncRouters(asyncRouters.value)
|
||||||
isLoadRoutes.value = false
|
isLoadRoutes.value = false
|
||||||
@@ -41,6 +45,23 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setRouterLevel = (routers) => {
|
||||||
|
return routers.filter(item=>{
|
||||||
|
if(item.component === 'Layout') {
|
||||||
|
if(item.children) {
|
||||||
|
item.children.forEach(v=>{
|
||||||
|
if(v.children) {
|
||||||
|
slRouters.value = [...toRaw(slRouters.value), ...v.children]
|
||||||
|
delete v.children
|
||||||
|
}
|
||||||
|
})
|
||||||
|
item.children = [...item.children, ...toRaw(slRouters.value)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const formatAsyncRouters = (routers) => {
|
const formatAsyncRouters = (routers) => {
|
||||||
return routers.filter(route => {
|
return routers.filter(route => {
|
||||||
if (route.component) {
|
if (route.component) {
|
||||||
@@ -48,8 +69,7 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
|
|||||||
route.component = Layout
|
route.component = Layout
|
||||||
} else if (route.component === 'ParentView') {
|
} else if (route.component === 'ParentView') {
|
||||||
route.component = ParentView
|
route.component = ParentView
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
route.component = loadView(route.component)
|
route.component = loadView(route.component)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,7 +127,17 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const removeMenu = () => {
|
const removeMenu = () => {
|
||||||
menuList.value.length = 0
|
menuList.value = [
|
||||||
|
{
|
||||||
|
name: 'home',
|
||||||
|
path: '/home',
|
||||||
|
icon: 'home',
|
||||||
|
title: '首页',
|
||||||
|
meta: {
|
||||||
|
breadcrumb: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
asyncRouters.value.length = 0
|
asyncRouters.value.length = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
src/utils/matterTree.js
Normal file
13
src/utils/matterTree.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export const matterTree = (array,data, id) => {
|
||||||
|
if (id) {
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
if (data[i].value == id) {
|
||||||
|
array.push(data[i].label);
|
||||||
|
}
|
||||||
|
if (data[i].children && data[i].children.length > 0) {
|
||||||
|
matterTree(data[i].children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,13 @@ serveice.interceptors.response.use(response=>{
|
|||||||
closeOnClickModal: false
|
closeOnClickModal: false
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
removeToken()
|
removeToken()
|
||||||
window.location = '/login'
|
let path = window.location.pathname;
|
||||||
|
let query = window.location.search
|
||||||
|
sessionStorage.setItem('toView', JSON.stringify({
|
||||||
|
path: path,
|
||||||
|
query: query
|
||||||
|
}))
|
||||||
|
window.location.href = `${window.location.origin}/api/auth/cas/login`
|
||||||
})
|
})
|
||||||
return Promise.reject('会话已过期,请重新登录')
|
return Promise.reject('会话已过期,请重新登录')
|
||||||
case 402:
|
case 402:
|
||||||
|
|||||||
@@ -15,9 +15,16 @@ const init = () => {
|
|||||||
})
|
})
|
||||||
if (authStore.casToken(tokenValue)) {
|
if (authStore.casToken(tokenValue)) {
|
||||||
loading.close()
|
loading.close()
|
||||||
|
const toView = sessionStorage.getItem('toView')
|
||||||
|
console.log(toView, 'toView');
|
||||||
|
if (toView) {
|
||||||
|
let parse = JSON.parse(toView);
|
||||||
|
window.location.href = window.location.origin + parse.path + parse.query
|
||||||
|
} else {
|
||||||
router.push('/')
|
router.push('/')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
init()
|
init()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,263 +1,323 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="home-container">
|
<div class="home-bg">
|
||||||
<div class="home-top">
|
<el-row gutter="20">
|
||||||
<el-image :src="homeImage" style="width: 380px"/>
|
<el-col :xs="24" :sm="24" :md="18" :lg="18" :xl="18">
|
||||||
<div class="top-right">
|
<div class="left">
|
||||||
<div>Admin,欢迎回来!</div>
|
<h3>我的科创工作</h3>
|
||||||
|
<el-row :gutter="20" class="statistics">
|
||||||
|
<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-for="(item,index) in list" :key="index">
|
||||||
|
<div class="block" :style="{background: item.color}">
|
||||||
|
<svg-icon :name="item.icon" :class-name="'home-icon'"/>
|
||||||
|
<div class="block-right">
|
||||||
|
<span>{{ item.title }}</span>
|
||||||
|
<span :style="{color: item.textColor}">{{ item.num }}<span>个</span></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="home-top-right">
|
</el-col>
|
||||||
<el-image :src="coffee" style="height: 100px"/>
|
|
||||||
<span>科研管理平台</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- <el-row :gutter="10" type="flex">-->
|
|
||||||
<!-- <el-col :span="6" :xs="8" :sm="16" :md="18" :lg="20" :xl="24" >-->
|
|
||||||
<!-- <div v-for="(item,index) in list" :key="index" class="block">-->
|
|
||||||
<!-- <div>{{item.title}}</div>-->
|
|
||||||
<!-- <div>-->
|
|
||||||
<!-- <el-icon><User/></el-icon>-->
|
|
||||||
<!-- <span>{{item.num}}</span>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </el-col>-->
|
|
||||||
<!-- </el-row>-->
|
|
||||||
<el-row :gutter="10">
|
|
||||||
<el-col :span="6" v-for="item in 4">1</el-col>
|
|
||||||
<!-- <el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11"-->
|
|
||||||
<!-- >2<div class="grid-content ep-bg-purple-light"-->
|
|
||||||
<!-- /></el-col>-->
|
|
||||||
<!-- <el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11"-->
|
|
||||||
<!-- >3<div class="grid-content ep-bg-purple"-->
|
|
||||||
<!-- /></el-col>-->
|
|
||||||
<!-- <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1"-->
|
|
||||||
<!-- >4<div class="grid-content ep-bg-purple-light"-->
|
|
||||||
<!-- /></el-col>-->
|
|
||||||
</el-row>
|
</el-row>
|
||||||
<div class="container">
|
<h4>待办 ({{ todoNum }})</h4>
|
||||||
<div id="bar1" ref="bar1"></div>
|
<fvTable ref="tableIns" class="home-table" :tableConfig="tableConfig">
|
||||||
<div id="bar2" ref="bar2"></div>
|
<template #empty>
|
||||||
<div id="bar3" ref="bar3"></div>
|
<el-empty description="暂无待办"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
</el-col>
|
||||||
<div id="pie1" ref="pie1"></div>
|
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
|
||||||
<div id="pie2" ref="pie2"></div>
|
<div class="right">
|
||||||
<div id="pie3" ref="pie3"></div>
|
<div class="right-top ">
|
||||||
|
<div>
|
||||||
|
<h3>帮助文档</h3>
|
||||||
|
<span>查看更多</span>
|
||||||
|
</div>
|
||||||
|
<el-divider/>
|
||||||
|
<div v-for="item in helpDocList" class="help">
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right-top">
|
||||||
|
<div>
|
||||||
|
<h3>工具下载</h3>
|
||||||
|
<span>常用网站</span>
|
||||||
|
</div>
|
||||||
|
<el-divider/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup lang="jsx">
|
||||||
import * as echarts from 'echarts'
|
import 'element-plus/theme-chalk/display.css'
|
||||||
import homeImage from "@/assets/home/home.png"
|
|
||||||
import coffee from "@/assets/home/coffee.png"
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const list = ref([
|
const list = ref([
|
||||||
{
|
{
|
||||||
title: '在线用户量',
|
title: '待立项',
|
||||||
num:2142
|
color: '#CEE8FA',
|
||||||
|
textColor: '#0043C5',
|
||||||
|
icon: 'home1',
|
||||||
|
num: 21
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '在线用户量',
|
title: '待评审',
|
||||||
num:2142
|
color: '#DCCEFA',
|
||||||
|
textColor: '#8600C5',
|
||||||
|
icon: 'home2',
|
||||||
|
num: 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '在线用户量',
|
title: '待验收',
|
||||||
num:2142
|
color: '#FAE6CE',
|
||||||
|
textColor: '#F47D0E',
|
||||||
|
icon: 'home3',
|
||||||
|
num: 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '在线用户量',
|
title: '待归档',
|
||||||
num:2142
|
color: '#CEFAD8',
|
||||||
|
textColor: '#01A089',
|
||||||
|
icon: 'home4',
|
||||||
|
num: 1
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
const barOption = {
|
const helpDocList = ref([
|
||||||
title: {
|
|
||||||
text: 'World Population'
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'axis',
|
|
||||||
axisPointer: {
|
|
||||||
type: 'shadow'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
legend: {},
|
|
||||||
grid: {
|
|
||||||
left: '3%',
|
|
||||||
right: '4%',
|
|
||||||
bottom: '3%',
|
|
||||||
containLabel: true
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'value',
|
|
||||||
boundaryGap: [0, 0.01]
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
type: 'category',
|
|
||||||
data: ['Brazil', 'Indonesia', 'USA', 'India', 'China', 'World']
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
{
|
||||||
name: '2011',
|
title: '业务流程'
|
||||||
type: 'bar',
|
|
||||||
data: [18203, 23489, 29034, 104970, 131744, 630230]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '2012',
|
title: '业务流程'
|
||||||
type: 'bar',
|
|
||||||
data: [19325, 23438, 31000, 121594, 134141, 681807]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
const pieOption = {
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'item'
|
|
||||||
},
|
},
|
||||||
legend: {
|
|
||||||
top: '5%',
|
|
||||||
left: 'center'
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
{
|
||||||
name: 'Access From',
|
title: '业务流程'
|
||||||
type: 'pie',
|
|
||||||
radius: ['40%', '70%'],
|
|
||||||
avoidLabelOverlap: false,
|
|
||||||
itemStyle: {
|
|
||||||
borderRadius: 10,
|
|
||||||
borderColor: '#fff',
|
|
||||||
borderWidth: 2
|
|
||||||
},
|
},
|
||||||
label: {
|
{
|
||||||
show: false,
|
title: '业务流程'
|
||||||
position: 'center'
|
}
|
||||||
|
])
|
||||||
|
const todoNum = ref(20)
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'processName',
|
||||||
|
label: '流程名称',
|
||||||
|
align: 'center',
|
||||||
},
|
},
|
||||||
emphasis: {
|
{
|
||||||
label: {
|
prop: 'initiatorName',
|
||||||
show: true,
|
label: '发起人',
|
||||||
fontSize: 40,
|
align: 'center',
|
||||||
fontWeight: 'bold'
|
},
|
||||||
|
{
|
||||||
|
prop: 'targetState',
|
||||||
|
label: '类型',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
if(row.targetState!==null){
|
||||||
|
return (<Tag dictType={'todo_type'} value={row.targetState}/>)
|
||||||
|
}else {
|
||||||
|
return '--'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
labelLine: {
|
{
|
||||||
show: false
|
prop: 'submitTime',
|
||||||
|
label: '提交时间',
|
||||||
|
align: 'center',
|
||||||
},
|
},
|
||||||
data: [
|
{
|
||||||
{value: 1048, name: 'Search Engine'},
|
prop: 'taskName',
|
||||||
{value: 735, name: 'Direct'},
|
label: '当前节点',
|
||||||
{value: 580, name: 'Email'},
|
align: 'center',
|
||||||
{value: 484, name: 'Union Ads'},
|
},
|
||||||
{value: 300, name: 'Video Ads'}
|
{
|
||||||
]
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
fixed: 'right',
|
||||||
|
width: '150',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" link onClick={() => handleView(row)}>查看</el-button>
|
||||||
|
<el-button type="primary" link onClick={() => handleEdit(row)}>已读</el-button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
};
|
],
|
||||||
|
api: '/workflow/mosr/process/task',
|
||||||
const data = reactive({
|
params: {},
|
||||||
barCharts: null,
|
|
||||||
pieCharts: null,
|
|
||||||
bar1: null,
|
|
||||||
bar2: null,
|
|
||||||
bar3: null,
|
|
||||||
pie1: null,
|
|
||||||
pie2: null,
|
|
||||||
pie3: null,
|
|
||||||
})
|
})
|
||||||
|
const handleView = (row) => {
|
||||||
const init = () => {
|
console.log('row', row)
|
||||||
data.barCharts = echarts.init(document.getElementById('bar1')).setOption(barOption)
|
if(row.targetState=='00'&&row.targetId){
|
||||||
data.barCharts = echarts.init(document.getElementById('bar2')).setOption(barOption)
|
|
||||||
data.barCharts = echarts.init(document.getElementById('bar3')).setOption(barOption)
|
|
||||||
data.pieCharts = echarts.init(document.getElementById('pie1')).setOption(pieOption)
|
|
||||||
data.pieCharts = echarts.init(document.getElementById('pie2')).setOption(pieOption)
|
|
||||||
data.pieCharts = echarts.init(document.getElementById('pie3')).setOption(pieOption)
|
|
||||||
}
|
|
||||||
|
|
||||||
const redirectView = () => {
|
|
||||||
const toView = sessionStorage.getItem('toView')
|
|
||||||
console.log(toView, 'toView');
|
|
||||||
toView ?
|
|
||||||
router.push({
|
router.push({
|
||||||
path: JSON.parse(toView).path,
|
name: 'Collection/detail',
|
||||||
query: {
|
query: {
|
||||||
...JSON.parse(toView).query
|
id: row.targetId
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}) :
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
init()
|
|
||||||
redirectView()
|
|
||||||
})
|
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
data.bar1 = null
|
|
||||||
data.bar2 = null
|
|
||||||
data.bar3 = null
|
|
||||||
data.pie1 = null
|
|
||||||
data.pie2 = null
|
|
||||||
data.pie3 = null
|
|
||||||
data.barCharts = null
|
|
||||||
data.pieCharts = null
|
|
||||||
init()
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.home-container {
|
@media only screen and (max-width: 767px) {
|
||||||
|
.right {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
:deep(.el-table) {
|
||||||
|
height: 300px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1000px) {
|
||||||
|
.right {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
:deep(.el-table) {
|
||||||
|
height: 300px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-bg {
|
||||||
|
height: calc(100vh - 130px);
|
||||||
|
max-height: calc(100vh - 96px);
|
||||||
|
background-color: #EFEFEF;
|
||||||
|
position: absolute;
|
||||||
|
left: 18px;
|
||||||
|
right: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动条轨道
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: rgb(239, 239, 239);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小滑块
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(80, 81, 82, 0.29);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
//flex: 0.8;
|
||||||
|
padding: 15px;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
|
||||||
|
|
||||||
|
.el-table__empty-block {
|
||||||
|
.el-empty {
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics {
|
||||||
|
width: 99%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.block {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
background-color: #e9edf2;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 25px;
|
||||||
|
margin-top: 15px;
|
||||||
|
|
||||||
.home-top {
|
.block-right {
|
||||||
width: 1000px;
|
margin-left: 15%;
|
||||||
height: 150px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
padding: 10px;
|
justify-content: center;
|
||||||
background-color: #e1eaf9;
|
color: #92969a;
|
||||||
|
font-size: 17px;
|
||||||
|
|
||||||
.top-right {
|
> span:first-child {
|
||||||
font-size: 16px;
|
white-space: nowrap;
|
||||||
margin-left: 10px;
|
color: #000000;
|
||||||
letter-spacing: 1.5px;
|
|
||||||
|
|
||||||
> div:first-child {
|
|
||||||
color: #557ad2;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 20px;
|
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> span:last-child {
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-top-right {
|
}
|
||||||
flex: 1;
|
|
||||||
|
.right {
|
||||||
|
height: calc(100vh - 130px);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
justify-content: space-between;
|
||||||
}
|
|
||||||
.statistics{
|
|
||||||
//display: flex;
|
|
||||||
.block{
|
|
||||||
|
|
||||||
|
.right-top {
|
||||||
|
flex: 0.5;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.container {
|
.right-top {
|
||||||
height: calc((100vh / 2) - 150px);
|
flex: 0.48;
|
||||||
|
|
||||||
|
> div:first-child {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
> div {
|
h3 {
|
||||||
height: 300px;
|
white-space: nowrap;
|
||||||
flex: 0.9;
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> span {
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #927648;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-divider--horizontal {
|
||||||
|
height: 3px;
|
||||||
|
background: #D9D9D9;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help {
|
||||||
|
height: 61px;
|
||||||
|
line-height: 61px;
|
||||||
|
padding-left: 15px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #FBFBF7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -4,14 +4,14 @@
|
|||||||
:model="loginForm"
|
:model="loginForm"
|
||||||
ref="formInstance"
|
ref="formInstance"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
label-width="65px"
|
label-width="70px"
|
||||||
>
|
>
|
||||||
<h3>科研管理平台</h3>
|
<!-- <h2>科研管理平台</h2>-->
|
||||||
<el-form-item prop="username" label="账号">
|
<el-form-item prop="username" label="账号">
|
||||||
<el-input v-model="loginForm.username" :prefix-icon="User"></el-input>
|
<el-input v-model="loginForm.username" :prefix-icon="User"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="password" label="密码">
|
<el-form-item prop="password" label="密码">
|
||||||
<el-input v-model="loginForm.password" type="password" :prefix-icon="Lock"></el-input>
|
<el-input v-model="loginForm.password" type="password" :prefix-icon="Lock" :show-password="true"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="code" label="验证码">
|
<el-form-item prop="code" label="验证码">
|
||||||
<div class="code">
|
<div class="code">
|
||||||
@@ -20,6 +20,12 @@
|
|||||||
<img :src="codeImg" alt="" @click="getCode">
|
<img :src="codeImg" alt="" @click="getCode">
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<div class="sso">
|
||||||
|
<a href="/api/auth/cas/login">
|
||||||
|
<svg-icon name="sso"/>
|
||||||
|
<span>统一身份认证</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button @click="handleLogin(formInstance)" type="primary">登录</el-button>
|
<el-button @click="handleLogin(formInstance)" type="primary">登录</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -98,26 +104,77 @@ onBeforeUnmount(() => {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.login-box {
|
.login-box {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #4158D0;
|
background-color: #F3F3F3;
|
||||||
background-image: linear-gradient(43deg, #4158D0 0%, #C850C0 46%, #FFCC70 100%);
|
//background-image: linear-gradient(43deg, #4158D0 0%, #C850C0 46%, #FFCC70 100%);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
.sso {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: -5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #BEA266;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.el-form {
|
.el-form {
|
||||||
padding: 12px 15px;
|
padding: 12px 15px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
width: 25%;
|
width: 560px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
|
||||||
h3 {
|
.el-form-item {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
|
||||||
|
:deep(.el-form-item__label) {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
|
:deep(.el-input__inner) {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-input__suffix) {
|
||||||
|
.el-input__password {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-input__prefix ) {
|
||||||
|
.el-input__prefix-inner {
|
||||||
|
.el-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-button {
|
.el-button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
background-color: #BEA266;
|
||||||
|
border-color: #BEA266;
|
||||||
|
font-size: 17px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +191,7 @@ onBeforeUnmount(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 32px;
|
height: 40px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
348
src/views/project-demand/collection/add.vue
Normal file
348
src/views/project-demand/collection/add.vue
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
<template>
|
||||||
|
<div v-loading="loading" class="add-block">
|
||||||
|
<baseTitle title="需求征集信息录入"></baseTitle>
|
||||||
|
<el-form :model="formData" inline class="query-form" ref="demandForm" :rules="rules">
|
||||||
|
<div class="left-info">
|
||||||
|
<el-form-item v-if="checkFormPrem('requirementName')" label="名称" prop="requirementName">
|
||||||
|
<el-input v-model="formData.requirementName" placeholder="请输入名称" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="checkFormPrem('companyIds')" label="所属公司" prop="companyIds">
|
||||||
|
<el-tree-select v-model="formData.companyIds" :data="companyOption" style="width: 100%;"
|
||||||
|
filterable clearable :check-strictly="true" multiple/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="checkFormPrem('collectType')" label="征集类型" prop="collectType">
|
||||||
|
<el-select v-model="formData.collectType" placeholder="征集类型" clearable filterable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in typeOption"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="checkFormPrem('deadline')" label="截止时间" prop="deadline">
|
||||||
|
<el-config-provider>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="formData.deadline"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="截止时间"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
/>
|
||||||
|
</el-config-provider>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
<baseTitle title="征集说明"></baseTitle>
|
||||||
|
<Tinymce v-if="checkFormPrem('collectExplain') && showTinymce" image-url="/notice/file" file-url="/notice/file"
|
||||||
|
v-model:value="formData.collectExplain" height="300" />
|
||||||
|
<baseTitle title="申请文件"></baseTitle>
|
||||||
|
<file-upload v-if="checkFormPrem('fileList')" @getFile="getFile"/>
|
||||||
|
<fvTable style="width: 100%;max-height: 200px" v-if="showTable"
|
||||||
|
:tableConfig="tableConfig" :data="formData.fileList"
|
||||||
|
:isSettingCol="false" :pagination="false">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
<div class="approval-record">
|
||||||
|
<baseTitle title="流程"></baseTitle>
|
||||||
|
<process-diagram-viewer mode="view" v-if="processDiagramViewer"/>
|
||||||
|
<!-- <div class="process" id="approvalRecord">-->
|
||||||
|
<!-- <process-tree ref="processTree" mode="view" id-name="approvalRecord"/>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
</div>
|
||||||
|
<div class="oper-page-btn">
|
||||||
|
<el-button color="#DED0B2" @click="handleSubmit(demandForm)">提交</el-button>
|
||||||
|
<el-button color="#DED0B2" @click="handleResubmit">重新提交</el-button>
|
||||||
|
<el-button @click="handleBack">返回</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {useAuthStore} from '@/stores/userstore.js'
|
||||||
|
import {useProcessStore} from '@/stores/processStore.js';
|
||||||
|
import {
|
||||||
|
getWorkflowInfo,
|
||||||
|
addRequirement,
|
||||||
|
getFormInfo,
|
||||||
|
resubmit,
|
||||||
|
deleteFile,
|
||||||
|
downloadFile
|
||||||
|
} from "@/api/project-demand/index.js";
|
||||||
|
import FileUpload from "@/components/FileUpload.vue";
|
||||||
|
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
|
||||||
|
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
|
||||||
|
import {useRoute, useRouter} from 'vue-router'
|
||||||
|
import {getSubCompOpt} from '@/api/user/user.js'
|
||||||
|
import {useTagsView} from '@/stores/tagsview.js'
|
||||||
|
|
||||||
|
const tagsViewStore = useTagsView()
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const demandForm = ref()
|
||||||
|
const dateValue = ref()
|
||||||
|
const formData = ref({
|
||||||
|
requirementName: '',
|
||||||
|
companyIds: '',
|
||||||
|
collectType: '',
|
||||||
|
deadline: '',
|
||||||
|
collectExplain: '',
|
||||||
|
fileList: []
|
||||||
|
})
|
||||||
|
const showTinymce = ref(true)
|
||||||
|
const processDiagramViewer = ref(false)
|
||||||
|
const typeOption = ref([
|
||||||
|
{
|
||||||
|
label: "需求征集",
|
||||||
|
value: '需求征集'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const companyOption = ref([])
|
||||||
|
const form = ref(null)
|
||||||
|
const fileList = ref([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const showTable = ref(true)
|
||||||
|
const processStore = useProcessStore()
|
||||||
|
const processInstanceData = ref()
|
||||||
|
const formPermMap = ref(new Map());
|
||||||
|
const rules = reactive({
|
||||||
|
requirementName: [{required: true, message: '请输入名称', trigger: 'blur'}],
|
||||||
|
companyIds: [{required: true, message: '请选择所属公司', trigger: 'blur'}],
|
||||||
|
collectType: [{required: true, message: '请选择征集类型', trigger: 'blur'}],
|
||||||
|
deadline: [{required: true, message: '请选择截止时间', trigger: 'blur'}],
|
||||||
|
})
|
||||||
|
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'index',
|
||||||
|
type: 'index',
|
||||||
|
label: '序号',
|
||||||
|
align: 'center',
|
||||||
|
width: '80',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'originalFileName',
|
||||||
|
label: '文件名',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'tag',
|
||||||
|
label: '标签',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'size',
|
||||||
|
label: '文件大小',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||||
|
<el-button type="primary" size="large" link onClick={() => handleDelete(row)}>删除</el-button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const checkFormPrem = (formKey) => {
|
||||||
|
if (formPermMap.value.hasOwnProperty(formKey)) {
|
||||||
|
let formItem = formPermMap.value[formKey];
|
||||||
|
return formItem.perm === 'EDIT'
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDownload = (row) => {
|
||||||
|
downloadFile(row.fileId).then(res => {
|
||||||
|
const blob = new Blob([res])
|
||||||
|
let a = document.createElement('a')
|
||||||
|
a.href = URL.createObjectURL(blob)
|
||||||
|
a.download = row.originalFileName
|
||||||
|
a.click()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const compositeParam = (item) => {
|
||||||
|
let tag = ''
|
||||||
|
if (!formData.value.collectType && router.currentRoute.value.name === 'Collection/add') {
|
||||||
|
tag = '需求征集'
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
fileId: item.id,
|
||||||
|
size: item.size,
|
||||||
|
originalFileName: item.originalFilename,
|
||||||
|
fileType: item.fileType,
|
||||||
|
url: item.url,
|
||||||
|
processNodeTag: null,
|
||||||
|
tag: tag,
|
||||||
|
userId: authStore.userinfo.userId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getFile = (val) => {
|
||||||
|
console.log('上传文件', val)
|
||||||
|
showTable.value = false
|
||||||
|
let fileObj = compositeParam(val)
|
||||||
|
formData.value.fileList.push(fileObj)
|
||||||
|
nextTick(() => {
|
||||||
|
showTable.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const init = async () => {
|
||||||
|
const res = await getSubCompOpt()
|
||||||
|
companyOption.value = res.data
|
||||||
|
getWorkflowInfo().then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
let data = res.data
|
||||||
|
processInstanceData.value = data
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
formPermMap.value = data.formPermMap
|
||||||
|
// const entriesArray = Object.entries(data.formPermMap);// 使用Map构造函数将键值对数组转换为Map对象
|
||||||
|
// formPermMap.value = new Map(entriesArray);
|
||||||
|
nextTick(() => {
|
||||||
|
processDiagramViewer.value = true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const submitParam = (item) => {
|
||||||
|
let files = []
|
||||||
|
item.fileList.forEach(item => {
|
||||||
|
let obj = {
|
||||||
|
fileId: item.fileId,
|
||||||
|
}
|
||||||
|
files.push(obj)
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
collectExplain: item.collectExplain,
|
||||||
|
collectType: item.collectType,
|
||||||
|
companyIds: item.companyIds,
|
||||||
|
deadline: item.deadline,
|
||||||
|
requirementId: item.requirementId ? item.requirementId : 0,
|
||||||
|
requirementName: item.requirementName,
|
||||||
|
fileList: files,
|
||||||
|
deploymentId: processInstanceData.value.deploymentId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleSubmit = async (instance) => {
|
||||||
|
if (!instance) return
|
||||||
|
instance.validate(async (valid) => {
|
||||||
|
if (!valid) return
|
||||||
|
let res = await addRequirement(submitParam(formData.value))
|
||||||
|
if (res.code === 1000) {
|
||||||
|
ElMessage.success(res.msg)
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
await router.push({
|
||||||
|
name: 'Collection'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleResubmit = () => {
|
||||||
|
resubmit(submitParam(formData.value)).then(res => {
|
||||||
|
if (res.code === 1000) {
|
||||||
|
ElMessage.success(res.msg)
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
router.push({
|
||||||
|
name: 'Collection'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getDetailInfo = async () => {
|
||||||
|
getFormInfo(route.query.id).then(res => {
|
||||||
|
if (res.code === 1000) {
|
||||||
|
ElMessage.success(res.msg)
|
||||||
|
formData.value = res.data
|
||||||
|
showTinymce.value = false
|
||||||
|
showTable.value = false
|
||||||
|
nextTick(() => {
|
||||||
|
showTinymce.value = true
|
||||||
|
showTable.value = true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
history.back()
|
||||||
|
}
|
||||||
|
const handleDelete = (row) => {
|
||||||
|
ElMessageBox.confirm(`确认删除名称为${row.originalFileName}的表格吗?`, '系统提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
deleteFile(row.fileId).then(res => {
|
||||||
|
if (res.code === 1000) {
|
||||||
|
ElMessage.success("删除成功");
|
||||||
|
formData.value.fileList.splice(formData.value.fileList.findIndex((item) => item.id === row.fileId), 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(() => {
|
||||||
|
ElMessage.warning("用户取消删除! ");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
loading.value = true
|
||||||
|
await init()
|
||||||
|
if (route.query.id) {
|
||||||
|
await getDetailInfo()
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-empty__description) {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-block {
|
||||||
|
//display: flex;
|
||||||
|
//justify-content: space-between;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
a {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #2a99ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.approval-record {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
281
src/views/project-demand/collection/detail.vue
Normal file
281
src/views/project-demand/collection/detail.vue
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
<template>
|
||||||
|
<div class="detail-block" v-loading="loading">
|
||||||
|
<el-form :model="formData" ref="demandForm" label-width="auto" :rules="rules">
|
||||||
|
<baseTitle title="需求征集详情"></baseTitle>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12" v-if="checkFormPrem('requirementName')">
|
||||||
|
<el-form-item label="名称">
|
||||||
|
<span>{{ formData.requirementName }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="checkFormPrem('companyIds')">
|
||||||
|
<el-form-item label="所属公司">
|
||||||
|
<span>{{ formData.companyIds }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="checkFormPrem('collectType')">
|
||||||
|
<el-form-item label="征集类型">
|
||||||
|
<span>{{ formData.collectType }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="checkFormPrem('deadline')">
|
||||||
|
<el-form-item label="截止时间">
|
||||||
|
<span>{{ formData.deadline }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<baseTitle title="征集说明"></baseTitle>
|
||||||
|
<el-col :span="24" v-if="checkFormPrem('collectExplain')">
|
||||||
|
<el-form-item>
|
||||||
|
<el-card style="width: 100%">
|
||||||
|
<div v-html="formData.collectExplain">
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<baseTitle title="附件列表"></baseTitle>
|
||||||
|
<el-col :span="24" v-if="checkFormPrem('collectExplain')">
|
||||||
|
<el-form-item>
|
||||||
|
<fvTable style="width: 100%;max-height: 200px" v-if="showTable" :tableConfig="tableConfig"
|
||||||
|
:data="formData.fileList" :isSettingCol="false" :pagination="false">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<div v-if="processInstanceData.taskId">
|
||||||
|
<baseTitle title="审核意见"></baseTitle>
|
||||||
|
<el-form-item prop="auditOpinion">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.auditOpinion"
|
||||||
|
:rows="3"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请输入审核意见"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div class="approval-record">
|
||||||
|
<baseTitle title="审批记录"></baseTitle>
|
||||||
|
<div class="process">
|
||||||
|
<operation-render v-if="processDiagramViewer" :operation-list="processInstanceData.operationList"
|
||||||
|
:state="processInstanceData.state"/>
|
||||||
|
<process-diagram-viewer v-if="processDiagramViewer"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
<div class="oper-page-btn" v-if="processInstanceData.state === '1' && processInstanceData.taskId">
|
||||||
|
<el-button @click="handleReject(demandForm)">驳回</el-button>
|
||||||
|
<el-button color="#DED0B2" @click="handleSubmit">同意</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import OperationRender from '@/views/workflow/common/OperationRender.vue'
|
||||||
|
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
|
||||||
|
import {useProcessStore} from '@/stores/processStore.js';
|
||||||
|
import {getInfo, agreeTask, rejectTask, downloadFile} from "@/api/project-demand/index.js";
|
||||||
|
import {getSubCompOpt} from '@/api/user/user.js'
|
||||||
|
import {ElMessage} from "element-plus";
|
||||||
|
import {useTagsView} from '@/stores/tagsview.js'
|
||||||
|
import {matterTree} from '@/utils/matterTree.js';
|
||||||
|
|
||||||
|
const tagsViewStore = useTagsView()
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const form = ref();
|
||||||
|
const loading = ref(false)
|
||||||
|
const demandForm = ref()
|
||||||
|
const processStore = useProcessStore()
|
||||||
|
const companyOption = ref([])
|
||||||
|
const formPermMap = ref(new Map());
|
||||||
|
const processInstanceData = ref({})
|
||||||
|
const showTable = ref(false)
|
||||||
|
const processDiagramViewer = ref(false)
|
||||||
|
const processTree = ref()
|
||||||
|
const companyNameArray = ref([])
|
||||||
|
const formData = ref({})
|
||||||
|
const rules = reactive({
|
||||||
|
auditOpinion: [{required: true, message: '请输入审核意见', trigger: 'blur'}],
|
||||||
|
})
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'index',
|
||||||
|
type: 'index',
|
||||||
|
label: '序号',
|
||||||
|
align: 'center',
|
||||||
|
width: '80',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'originalFileName',
|
||||||
|
label: '文件名',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'tag',
|
||||||
|
label: '标签',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'size',
|
||||||
|
label: '文件大小',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
return (
|
||||||
|
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const checkFormPrem = (formKey) => {
|
||||||
|
if (formPermMap.value.hasOwnProperty(formKey)) {
|
||||||
|
let formItem = formPermMap.value[formKey];
|
||||||
|
return formItem.perm === 'READ'
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const fromPrem = (formKey) => {
|
||||||
|
let formItem = formPermMap.value[formKey];
|
||||||
|
return formItem.perm
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
let approve = {
|
||||||
|
taskId: processInstanceData.value.taskId,
|
||||||
|
auditOpinion: formData.value.auditOpinion,
|
||||||
|
formData: formData.value
|
||||||
|
}
|
||||||
|
agreeTask(approve).then(res => {
|
||||||
|
if (res.code === 1000) {
|
||||||
|
ElMessage.success(res.msg)
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
router.push({
|
||||||
|
name: 'Collection'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleReject = (instance) => {
|
||||||
|
if (!instance) return
|
||||||
|
instance.validate(async (valid) => {
|
||||||
|
if (!valid) return
|
||||||
|
let approve = {
|
||||||
|
taskId: processInstanceData.value.taskId,
|
||||||
|
auditOpinion: formData.value.auditOpinion,
|
||||||
|
}
|
||||||
|
rejectTask(approve).then(res => {
|
||||||
|
if (res.code === 1000) {
|
||||||
|
ElMessage.success(res.msg)
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
router.push({
|
||||||
|
name: 'Collection'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getCompanyOption = async () => {
|
||||||
|
const res = await getSubCompOpt()
|
||||||
|
companyOption.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDataSourceOptionItem = (val) => {
|
||||||
|
if (val !== undefined) {
|
||||||
|
val.forEach(item => {
|
||||||
|
matterTree(companyNameArray.value, companyOption.value, item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return companyNameArray.value.join(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDownload = (row) => {
|
||||||
|
downloadFile(row.fileId).then(res => {
|
||||||
|
const blob = new Blob([res])
|
||||||
|
let a = document.createElement('a')
|
||||||
|
a.href = URL.createObjectURL(blob)
|
||||||
|
a.download = row.originalFileName
|
||||||
|
a.click()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const init = async () => {
|
||||||
|
if (!route.query.id) return;
|
||||||
|
await getCompanyOption()
|
||||||
|
getInfo(route.query.id).then(res => {
|
||||||
|
loading.value = false
|
||||||
|
let data = res.data
|
||||||
|
formData.value = data.formData;
|
||||||
|
data.formData.companyIds = getDataSourceOptionItem(data.formData.companyIds)
|
||||||
|
processInstanceData.value = data
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
nextTick(() => {
|
||||||
|
processDiagramViewer.value = true
|
||||||
|
showTable.value = true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(async () => {
|
||||||
|
loading.value = true
|
||||||
|
await init()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-empty__description) {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-block {
|
||||||
|
overflow: hidden;
|
||||||
|
padding-right: 10px;
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
width: 350px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
margin-right: 10px;
|
||||||
|
|
||||||
|
> span:first-child {
|
||||||
|
color: black;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.approval-record {
|
||||||
|
padding-bottom: 30px;
|
||||||
|
|
||||||
|
.process {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
202
src/views/project-demand/collection/index.vue
Normal file
202
src/views/project-demand/collection/index.vue
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
<template>
|
||||||
|
<fvSearchForm :searchConfig="searchConfig" @search="search"></fvSearchForm>
|
||||||
|
<fvTable ref="tableIns" :tableConfig="tableConfig" @headBtnClick="headBtnClick">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty description="暂无数据"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {useAuthStore} from '@/stores/userstore.js'
|
||||||
|
import Tag from '@/components/Tag.vue'
|
||||||
|
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
|
||||||
|
import {ElMessage} from "element-plus";
|
||||||
|
import {deleteDemand} from "@/api/project-demand";
|
||||||
|
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
const router = useRouter()
|
||||||
|
const searchConfig = reactive([
|
||||||
|
{
|
||||||
|
label: '需求名称',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入名称查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '征集类型',
|
||||||
|
prop: 'collectType',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择征集类型',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
cacheKey: 'todo_type'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const tableIns = ref()
|
||||||
|
const userInfo = ref(authStore.userinfo)
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'selection',
|
||||||
|
prop: 'selection'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'requirementName',
|
||||||
|
label: '需求名称',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'collectType',
|
||||||
|
label: '征集类型',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'companyName',
|
||||||
|
label: '所属公司',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => (
|
||||||
|
<div style={{width: '300px', textOverflow: 'ellipsis'}}>{row.companyName}</div>)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'approveName',
|
||||||
|
label: '审批人',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'deadline',
|
||||||
|
label: '截止时间',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'taskNode',
|
||||||
|
label: '当前节点',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'state',
|
||||||
|
label: '状态',
|
||||||
|
align: 'center',
|
||||||
|
width: 200,
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) => (<Tag dictType={'demand_collection'} value={row.state}/>)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
let btn = []
|
||||||
|
let buttons = new Set(Array.from(row.buttons))
|
||||||
|
if (buttons.has("details")) {
|
||||||
|
btn.push({label: '详情', prem: ['mosr:requirement:info'], func: () => handleDetail(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("edit")) {
|
||||||
|
btn.push({label: '编辑', prem: ['mosr:requirement:resubmit'], func: () => handleEdit(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
// if (buttons.has("delete")) {
|
||||||
|
// btn.push({label: '删除',prem: ['mosr:requirement:del'], func: () => handleDelete(row), type: 'primary'})
|
||||||
|
// }
|
||||||
|
if (buttons.has("report")) {
|
||||||
|
btn.push({label: '需求上报',prem: ['mosr:requirement:info'], func: () => handleReport(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div style={{width: '100%'}}>
|
||||||
|
{
|
||||||
|
btn.map(item => (
|
||||||
|
<el-button
|
||||||
|
type={item.type}
|
||||||
|
v-perm={item.prem}
|
||||||
|
onClick={() => item.func()}
|
||||||
|
link
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</el-button>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
{
|
||||||
|
buttons.has("delete") ?
|
||||||
|
<popover-delete name={row.requirementName} type={'需求征集'} btnType={'danger'} perm={['mosr:requirement:del']}
|
||||||
|
onDelete={() => handleDelete(row)}/> : ''
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
api: '/workflow/mosr/requirement',
|
||||||
|
btns: [
|
||||||
|
{name: '新增', key: 'add', color: '#DED0B2'},
|
||||||
|
{name: '导出', key: 'export', type: ''},
|
||||||
|
],
|
||||||
|
params: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('userInfo', userInfo.value.userName)
|
||||||
|
|
||||||
|
const search = (val) => {
|
||||||
|
tableConfig.params = {...val}
|
||||||
|
tableIns.value.refresh()
|
||||||
|
}
|
||||||
|
const handleAdd = () => {
|
||||||
|
//新增
|
||||||
|
router.push({
|
||||||
|
name: 'Requirement/edit',
|
||||||
|
query: {
|
||||||
|
isAdd: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleEdit = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Requirement/edit',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleDelete = (row) => {
|
||||||
|
deleteDemand(row.requirementId).then(res => {
|
||||||
|
if (res.code === 1000) {
|
||||||
|
ElMessage.success(res.msg)
|
||||||
|
tableIns.value.refresh()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleDetail = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Requirement/detail',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleReport = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Summary/add',
|
||||||
|
query: {
|
||||||
|
id:row.requirementId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const headBtnClick = (key) => {
|
||||||
|
switch (key) {
|
||||||
|
case 'add':
|
||||||
|
handleAdd()
|
||||||
|
break;
|
||||||
|
case 'export':
|
||||||
|
handleExport()
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
492
src/views/project-demand/summary/add.vue
Normal file
492
src/views/project-demand/summary/add.vue
Normal file
@@ -0,0 +1,492 @@
|
|||||||
|
<template>
|
||||||
|
<div class="detail-block" v-loading="loading">
|
||||||
|
<baseTitle title="需求上报"></baseTitle>
|
||||||
|
<el-form :model="formData" ref="summaryForm" :rules="rules">
|
||||||
|
<el-row gutter="50">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="名称" prop="projectName">
|
||||||
|
<el-input v-model="formData.projectName" placeholder="请输入名称" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="专项资金" prop="specialFund">
|
||||||
|
<el-select v-model="formData.specialFund" placeholder="请选择专项资金" clearable filterable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in cacheStore.getDict('todo_type')"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="开始时间" prop="startTime">
|
||||||
|
<el-config-provider>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="formData.startTime"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="开始时间"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-config-provider>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="结束时间" prop="endTime">
|
||||||
|
<el-config-provider>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="formData.endTime"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="结束时间"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-config-provider>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<!-- <el-form-item label="所属公司" prop="affiliatedCompanyId">-->
|
||||||
|
<!-- <el-tree-select v-model="formData.affiliatedCompanyId" :data="companyOption" style="width: 100%;"-->
|
||||||
|
<!-- filterable clearable :check-strictly="true"/>-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- </el-col> <el-col :span="12">-->
|
||||||
|
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="项目类型" prop="projectType">
|
||||||
|
<el-select v-model="formData.projectType" placeholder="请选择项目类型" clearable filterable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in cacheStore.getDict('todo_type')"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="研发主体" prop="rdSubject">
|
||||||
|
<el-input v-model="formData.rdSubject" placeholder="请输入研发主体" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="出资类型" prop="investmentType">
|
||||||
|
<el-select v-model="formData.investmentType" placeholder="请选择出资类型" clearable filterable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in cacheStore.getDict('todo_type')"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="项目影响" prop="projectImpact">
|
||||||
|
<el-select v-model="formData.projectImpact" placeholder="请选择项目影响" clearable filterable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in cacheStore.getDict('todo_type')"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="所属业务板块" prop="businessSegment">
|
||||||
|
<el-select v-model="formData.businessSegment" placeholder="请选择所属业务板块" clearable filterable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in cacheStore.getDict('todo_type')"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="预期成果形式" prop="resultForm">
|
||||||
|
<el-select v-model="formData.resultForm" placeholder="请选择预期成果形式" clearable filterable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in cacheStore.getDict('todo_type')"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="预期技术标准制定" prop="technicalStandard">
|
||||||
|
<el-select v-model="formData.technicalStandard" placeholder="请选择预期技术标准制定" clearable filterable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in cacheStore.getDict('todo_type')"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="产学研联合" prop="industryUniversityResearch">
|
||||||
|
<el-select v-model="formData.industryUniversityResearch" placeholder="请选择产学研联合" clearable filterable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in cacheStore.getDict('todo_type')"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="开展政府申报" prop="governmentDeclaration">
|
||||||
|
<el-select v-model="formData.governmentDeclaration" placeholder="请选择开展政府申报" clearable filterable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in cacheStore.getDict('todo_type')"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="知识产权状况" prop="intellectualProperty">
|
||||||
|
<el-select v-model="formData.intellectualProperty" placeholder="请选择知识产权状况" clearable filterable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in cacheStore.getDict('todo_type')"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="发明专利(项)" prop="inventionPatent">
|
||||||
|
<el-input v-model="formData.inventionPatent" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="实用性新型专利(项)" prop="newPatent">
|
||||||
|
<el-input v-model="formData.newPatent" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="软件著作权(项)" prop="softwareCopyright">
|
||||||
|
<el-input v-model="formData.softwareCopyright" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="著作权(项)" prop="copyright">
|
||||||
|
<el-input v-model="formData.copyright" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="其他(项)" prop="other">
|
||||||
|
<el-input v-model="formData.other" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="经济概算(万元)" prop="economicEstimate">
|
||||||
|
<el-input v-model="formData.economicEstimate" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="其中申请公司总部科技创新专项资金(万元)" prop="specialFundAmount">
|
||||||
|
<el-input v-model="formData.specialFundAmount" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="现有业务描述" prop="serviceDescription">
|
||||||
|
<el-input v-model="formData.serviceDescription" type="textarea" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="研发项目关键内容描述" prop="contentDescription">
|
||||||
|
<el-input v-model="formData.contentDescription" type="textarea" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<AttachmentUpload ref="attachment" label="需求申请书附件" :showTable="showTable" :otherFileList="otherFileList"
|
||||||
|
@getAttachment="getAttachment"
|
||||||
|
@getOtherFile="getOtherFile" :showFileList="true" :formData="formData"
|
||||||
|
:preview="name === 'Summary/edit'"/>
|
||||||
|
<!-- <fvForm :schema="schame" @getInstance="getInstance"></fvForm>-->
|
||||||
|
<div class="approval-record">
|
||||||
|
<baseTitle title="流程"></baseTitle>
|
||||||
|
<process-diagram-viewer mode="view" v-if="processDiagramViewer"/>
|
||||||
|
<!-- <div class="process" id="approvalRecord">-->
|
||||||
|
<!-- <process-tree ref="processTree" mode="view" id-name="approvalRecord"/>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
</div>
|
||||||
|
<div class="oper-page-btn">
|
||||||
|
<el-button type="primary" @click="staging">存为草稿</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit(summaryForm)">发布</el-button>
|
||||||
|
<el-button color="#DED0B2" @click="handleResubmit">重新发布</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {getDetail, getProcessInfo, requirementReported, resubmitReported} from "./api";
|
||||||
|
import {ElMessage, ElNotification} from "element-plus";
|
||||||
|
import {useTagsView} from '@/stores/tagsview.js'
|
||||||
|
import {useCacheStore} from '@/stores/cache.js'
|
||||||
|
import {useProcessStore} from '@/stores/processStore.js';
|
||||||
|
import {getSubCompOpt} from "@/api/user/user";
|
||||||
|
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
|
||||||
|
|
||||||
|
const cacheStore = useCacheStore()
|
||||||
|
const processStore = useProcessStore()
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const attachment = ref()
|
||||||
|
const name = ref(router.currentRoute.value.name)
|
||||||
|
const loading = ref(false)
|
||||||
|
const processDiagramViewer = ref(false)
|
||||||
|
const tagsViewStore = useTagsView()
|
||||||
|
const companyOption = ref([])
|
||||||
|
const summaryForm = ref()
|
||||||
|
const deploymentId = ref()
|
||||||
|
const showTable = ref(true)
|
||||||
|
const otherFileList = ref([])
|
||||||
|
const file = ref({})
|
||||||
|
const formData = ref({})
|
||||||
|
const rules = reactive({
|
||||||
|
projectName: [{required: true, message: '请输入名称', trigger: 'blur'}],
|
||||||
|
specialFund: [{required: true, message: '请选择专项资金', trigger: 'blur'}],
|
||||||
|
startTime: [{required: true, message: '请选择开始时间', trigger: 'blur'}],
|
||||||
|
rdSubject: [{required: true, message: '请输入研发主体', trigger: 'blur'}],
|
||||||
|
// affiliatedCompanyId: [{required: true, message: '请输入所属公司', trigger: 'blur'}],
|
||||||
|
projectType: [{required: true, message: '请选择项目类型', trigger: 'blur'}],
|
||||||
|
endTime: [{required: true, message: '请选择结束时间', trigger: 'blur'}],
|
||||||
|
investmentType: [{required: true, message: '请选择出资类型', trigger: 'blur'}],
|
||||||
|
projectImpact: [{required: true, message: '请选择项目影响', trigger: 'blur'}],
|
||||||
|
businessSegment: [{required: true, message: '请选择所属业务板块', trigger: 'blur'}],
|
||||||
|
resultForm: [{required: true, message: '请选择预期成果形式', trigger: 'blur'}],
|
||||||
|
technicalStandard: [{required: true, message: '请选择预期技术标准制定', trigger: 'blur'}],
|
||||||
|
industryUniversityResearch: [{required: true, message: '请选择产学研联合', trigger: 'blur'}],
|
||||||
|
governmentDeclaration: [{required: true, message: '请选择开展政府申报', trigger: 'blur'}],
|
||||||
|
intellectualProperty: [{required: true, message: '请选择知识产权状况', trigger: 'blur'}],
|
||||||
|
inventionPatent: [{required: true, message: '请输入发明专利', trigger: 'blur'}],
|
||||||
|
newPatent: [{required: true, message: '请输入实用性新型专利', trigger: 'blur'}],
|
||||||
|
softwareCopyright: [{required: true, message: '请输入软件著作权', trigger: 'blur'}],
|
||||||
|
copyright: [{required: true, message: '请输入著作权', trigger: 'blur'}],
|
||||||
|
other: [{required: true, message: '请输入其他', trigger: 'blur'}],
|
||||||
|
economicEstimate: [{required: true, message: '请输入经济概算', trigger: 'blur'}],
|
||||||
|
specialFundAmount: [{required: true, message: '请输入专项资金', trigger: 'blur'}],
|
||||||
|
serviceDescription: [{required: true, message: '请输入现有业务描述', trigger: 'blur'}],
|
||||||
|
contentDescription: [{required: true, message: '请输入研发项目关键内容描述', trigger: 'blur'}]
|
||||||
|
})
|
||||||
|
const compositeParam = (item, type) => {
|
||||||
|
let tag = ''
|
||||||
|
if (name.value === 'Summary/add' || name.value === 'Summary/edit') {
|
||||||
|
tag = '需求上报'
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
fileId: item.id,
|
||||||
|
size: item.size,
|
||||||
|
originalFileName: item.originalFilename,
|
||||||
|
fileType: item.fileType,
|
||||||
|
url: item.url,
|
||||||
|
tag: tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getEditOtherFile = (val) => {
|
||||||
|
console.log('getEditOtherFile', val)
|
||||||
|
}
|
||||||
|
const getAttachment = (val) => {
|
||||||
|
console.log('上传文件getAttachment', val)
|
||||||
|
file.value = compositeParam(val)
|
||||||
|
}
|
||||||
|
const getOtherFile = (val) => {
|
||||||
|
console.log('上传文件getOtherFile', val)
|
||||||
|
showTable.value = false
|
||||||
|
let fileObj = compositeParam(val)
|
||||||
|
otherFileList.value.push(fileObj)
|
||||||
|
nextTick(() => {
|
||||||
|
showTable.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getFileParam = (item) => {
|
||||||
|
return {
|
||||||
|
fileId: item.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleSubmit = async (instance) => {
|
||||||
|
// if (!instance) return
|
||||||
|
// instance.validate(async (valid, fields) => {
|
||||||
|
// if(JSON.stringify(file.value) == "{}"){
|
||||||
|
// attachment.value.validate()
|
||||||
|
// } else {
|
||||||
|
// attachment.value.clearValidate()
|
||||||
|
// }
|
||||||
|
// if (!valid) return
|
||||||
|
let singleFile = {}
|
||||||
|
if (file.value.fileId !== undefined) {
|
||||||
|
singleFile = {
|
||||||
|
fileId: file.value.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let otherFiles = []
|
||||||
|
otherFileList.value.forEach(item => {
|
||||||
|
otherFiles.push(getFileParam(item))
|
||||||
|
})
|
||||||
|
let params = {
|
||||||
|
"specialFund": "2",
|
||||||
|
"projectName": "重新提交全流程测试2024520",
|
||||||
|
"startTime": "2024-05-24 00:00:00",
|
||||||
|
"endTime": "2024-05-29 00:00:00",
|
||||||
|
"projectType": "3",
|
||||||
|
"investmentType": "3",
|
||||||
|
"businessSegment": "2",
|
||||||
|
"technicalStandard": "2",
|
||||||
|
"governmentDeclaration": "2",
|
||||||
|
"inventionPatent": "3",
|
||||||
|
"newPatent": "3",
|
||||||
|
"economicEstimate": "3",
|
||||||
|
"other": "3",
|
||||||
|
"copyright": "3",
|
||||||
|
"softwareCopyright": "3",
|
||||||
|
"industryUniversityResearch": "2",
|
||||||
|
"intellectualProperty": "00",
|
||||||
|
"resultForm": "3",
|
||||||
|
"projectImpact": "3",
|
||||||
|
"rdSubject": "3",
|
||||||
|
// "affiliatedCompanyId": formData.value.affiliatedCompanyId,
|
||||||
|
"serviceDescription": "3",
|
||||||
|
"contentDescription": "3",
|
||||||
|
"specialFundAmount": "3",
|
||||||
|
deploymentId: deploymentId.value,
|
||||||
|
"singleFile": singleFile,
|
||||||
|
"fileList": otherFiles,
|
||||||
|
"requirementId":route.query.id
|
||||||
|
}
|
||||||
|
// let params = {
|
||||||
|
// ...formData.value,
|
||||||
|
// deploymentId: deploymentId.value,
|
||||||
|
// fileList: otherFiles,
|
||||||
|
// singleFile: singleFile,
|
||||||
|
// requirementId: route.query.id
|
||||||
|
// }
|
||||||
|
let res = await requirementReported(params)
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
await router.push({
|
||||||
|
name: 'Summary'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
const handleResubmit = () => {
|
||||||
|
let singleFile = {}
|
||||||
|
let otherFiles = []
|
||||||
|
let fileArray
|
||||||
|
if (name.value === 'Summary/edit') {
|
||||||
|
singleFile = {
|
||||||
|
fileId: attachment.value.singleFile.fileId
|
||||||
|
}
|
||||||
|
fileArray = attachment.value.allFileList
|
||||||
|
} else {
|
||||||
|
if (file.value.fileId !== undefined) {
|
||||||
|
singleFile = {
|
||||||
|
fileId: file.value.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileArray = otherFileList.value
|
||||||
|
}
|
||||||
|
fileArray.forEach(item => {
|
||||||
|
otherFiles.push(getFileParam(item))
|
||||||
|
})
|
||||||
|
//todo requirementId
|
||||||
|
let params = {
|
||||||
|
...formData.value,
|
||||||
|
deploymentId: deploymentId.value,
|
||||||
|
fileList: otherFiles,
|
||||||
|
singleFile: singleFile,
|
||||||
|
requirementId: route.query.id
|
||||||
|
}
|
||||||
|
console.log('重新提交params', params)
|
||||||
|
resubmitReported(params).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
router.push({
|
||||||
|
name: 'Summary'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getDetailInfo = async () => {
|
||||||
|
getDetail(route.query.projectId).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
formData.value = res.data.formData
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const init = async () => {
|
||||||
|
const res = await getSubCompOpt()
|
||||||
|
companyOption.value = res.data
|
||||||
|
getProcessInfo().then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
let data = res.data
|
||||||
|
deploymentId.value = data.deploymentId
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
nextTick(() => {
|
||||||
|
processDiagramViewer.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(async () => {
|
||||||
|
await init()
|
||||||
|
if (route.query.projectId) {
|
||||||
|
loading.value = true
|
||||||
|
await getDetailInfo()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const staging = async () => {
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.detail-block {
|
||||||
|
overflow: hidden;
|
||||||
|
padding-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table--fit) {
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
40
src/views/project-demand/summary/api/index.js
Normal file
40
src/views/project-demand/summary/api/index.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export const fileUp = (url, data) => {
|
||||||
|
return request({
|
||||||
|
url,
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const requirementReported = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/requirement/reported',
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const getProcessInfo = () => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/requirement/collect/process',
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const getDetail = (projectId) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/mosr/requirement/collect/info/${projectId}`,
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const resubmitReported = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/mosr/requirement/collect/resubmit',
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
75
src/views/project-demand/summary/components/FileUpload.vue
Normal file
75
src/views/project-demand/summary/components/FileUpload.vue
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<el-upload
|
||||||
|
ref="uploadRef"
|
||||||
|
class="upload-demo"
|
||||||
|
v-bind="$attrs"
|
||||||
|
drag
|
||||||
|
:action="url"
|
||||||
|
multiple
|
||||||
|
:on-change="change"
|
||||||
|
:on-progress="progress"
|
||||||
|
:on-remove="remove"
|
||||||
|
:before-remove="beforeRemove"
|
||||||
|
v-model:file-list="fileList"
|
||||||
|
:http-request="uploadRequest"
|
||||||
|
style="width: 50%;"
|
||||||
|
>
|
||||||
|
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||||
|
<div class="el-upload__text">
|
||||||
|
拖拽上传/<em>点击上传</em>
|
||||||
|
</div>
|
||||||
|
<template #tip>
|
||||||
|
<div class="el-upload__tip">
|
||||||
|
{{ tip }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-upload>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
import { fileUp } from '../api';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
tip: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const fileList = ref([])
|
||||||
|
const uploadRef = ref()
|
||||||
|
|
||||||
|
const localData = reactive({
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
const change = (file, files) => {
|
||||||
|
console.log(file, 'file');
|
||||||
|
}
|
||||||
|
|
||||||
|
const progress = (UploadProgressEvent, UploadFile, UploadFiles) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const remove = (file, files) => {}
|
||||||
|
|
||||||
|
const beforeRemove = (file, files) => {}
|
||||||
|
|
||||||
|
const uploadRequest = (UploadRequestOptions) => {
|
||||||
|
console.log(UploadRequestOptions, 'UploadRequestOptions');
|
||||||
|
// UploadRequestOptions.data = {}
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', UploadRequestOptions.file)
|
||||||
|
// formData.append('params', UploadRequestOptions.data)
|
||||||
|
fileUp(url, formData)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
</style>
|
||||||
96
src/views/project-demand/summary/detail.vue
Normal file
96
src/views/project-demand/summary/detail.vue
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<template>
|
||||||
|
<steps :active="'1'" @setDetail="setDetail" @stepChange="stepChange">
|
||||||
|
<template #content>
|
||||||
|
<collection-detail v-show="showActive == '00'" :formData="summaryData.formData" :data="summaryData"
|
||||||
|
:processViewer="summaryProcessViewer" :companyOption="companyOption" :loading="loading"/>
|
||||||
|
<summary-detail v-show="showActive == '10'" :formData="summaryData.formData" :data="summaryData"
|
||||||
|
:processViewer="summaryProcessViewer" :loading="loading"/>
|
||||||
|
<ApprovalDetail v-show="showActive == '20'" :formData="summaryData.formData" :data="summaryData" :processViewer="summaryProcessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
<ApprovalDetail type="execute" v-show="showActive == '40'" :formData="summaryData.formData" :data="summaryData"
|
||||||
|
:processViewer="summaryProcessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
<ApprovalDetail type="archivist" v-show="showActive == '50'" :formData="summaryData.formData" :data="summaryData"
|
||||||
|
:processViewer="summaryProcessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</steps>
|
||||||
|
<opinion v-if="summaryData.taskId" :formData="summaryData.formData" :taskId="summaryData.taskId"></opinion>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import SummaryDetail from '@/components/DetailComponent/SummaryDetail.vue';
|
||||||
|
import {useProcessStore} from '@/stores/processStore.js';
|
||||||
|
import {getMapProjectStateInfo} from '@/components/steps/api';
|
||||||
|
import CollectionDetail from "@/components/DetailComponent/CollectionDetail.vue";
|
||||||
|
import {getSubCompOpt} from "@/api/user/user";
|
||||||
|
import {ElNotification} from "element-plus";
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const companyOption = ref([])
|
||||||
|
const summaryData = ref({})
|
||||||
|
const summaryProcessViewer = ref(true)
|
||||||
|
const loading = ref(false)
|
||||||
|
const processStore = useProcessStore()
|
||||||
|
const active = ref(route.query.state)
|
||||||
|
const showActive = ref()
|
||||||
|
const getCompanyOption = async () => {
|
||||||
|
const res = await getSubCompOpt()
|
||||||
|
companyOption.value = res.data
|
||||||
|
}
|
||||||
|
const getInfo = async (state) => {
|
||||||
|
const projectId = route.query.projectId
|
||||||
|
if(showActive == '00'){
|
||||||
|
await getCompanyOption()
|
||||||
|
}
|
||||||
|
summaryProcessViewer.value = false
|
||||||
|
loading.value = true
|
||||||
|
const {code, data,msg} = await getMapProjectStateInfo(projectId, state)
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: msg,
|
||||||
|
type: code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if(code===1000){
|
||||||
|
summaryData.value = data;
|
||||||
|
loading.value = false
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
nextTick(() => {
|
||||||
|
summaryProcessViewer.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// const back = () => {
|
||||||
|
// switch (route.name) {
|
||||||
|
// case 'Summary/detail':
|
||||||
|
// setDetail('1')
|
||||||
|
// break;
|
||||||
|
// case 'Initiation/detail':
|
||||||
|
// setDetail('2')
|
||||||
|
// break;
|
||||||
|
// case 'Implementation/detail':
|
||||||
|
// setDetail('3')
|
||||||
|
// break;
|
||||||
|
// case 'Filing/detail':
|
||||||
|
// setDetail('4')
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
const setDetail = (active) => {
|
||||||
|
showActive.value = active
|
||||||
|
getInfo(active)
|
||||||
|
}
|
||||||
|
|
||||||
|
const stepChange = (data) => {
|
||||||
|
showActive.value = data.active
|
||||||
|
getInfo(data.active)
|
||||||
|
}
|
||||||
|
// back()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
207
src/views/project-demand/summary/index.vue
Normal file
207
src/views/project-demand/summary/index.vue
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
<template>
|
||||||
|
<fvSearchForm :searchConfig="searchConfig" @search="search"></fvSearchForm>
|
||||||
|
<fvTable ref="tableIns" :tableConfig="tableConfig" @headBtnClick="headBtnClick"></fvTable>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {reactive, ref, shallowRef} from 'vue';
|
||||||
|
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
|
||||||
|
import {useRouter} from 'vue-router';
|
||||||
|
|
||||||
|
const localData = reactive({})
|
||||||
|
|
||||||
|
const tableIns = ref()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
|
||||||
|
const searchConfig = reactive([
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
prop: 'requirementName',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入'
|
||||||
|
},
|
||||||
|
component: 'el-input',
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目类型',
|
||||||
|
prop: 'projectType',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {},
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '研发主体',
|
||||||
|
prop: 'productMainBody',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {},
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目影响',
|
||||||
|
prop: 'projectEffect',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {},
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '起止时间',
|
||||||
|
prop: 'startTime',
|
||||||
|
component: 'el-date-picker',
|
||||||
|
props: {},
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '最小金额',
|
||||||
|
prop: 'minMoney',
|
||||||
|
component: 'el-input',
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '最大金额',
|
||||||
|
prop: 'maxMoney',
|
||||||
|
component: 'el-input',
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'selection',
|
||||||
|
prop: 'selection'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'requirementName',
|
||||||
|
label: '名称',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'undertaker',
|
||||||
|
label: '承办单位',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectType',
|
||||||
|
label: '项目类型',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'rdSubject',
|
||||||
|
label: '研发主体',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectImpact',
|
||||||
|
label: '项目影响',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'startTime',
|
||||||
|
label: '起止时间',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'state',
|
||||||
|
label: '状态',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
if (row.state !== null&&row.state != 0) {
|
||||||
|
return (<Tag dictType={'demand_summary'} value={row.state}/>)
|
||||||
|
} else {
|
||||||
|
return '--'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
let btn = []
|
||||||
|
let buttons = new Set(Array.from(row.buttons))
|
||||||
|
if (buttons.has("details")) {
|
||||||
|
btn.push({label: '详情', prem: ['mosr:collect:info'], func: () => handleDetail(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("edit")) {
|
||||||
|
btn.push({label: '编辑',prem: ['mosr:collect:resubmit'], func: () => handleEdit(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
// if (buttons.has("delete")) {
|
||||||
|
// btn.push({label: '删除',prem: ['mosr:requirement:del'], func: () => handleEdit(row), type: 'primary'})
|
||||||
|
// }
|
||||||
|
if (buttons.has("report")) {
|
||||||
|
btn.push({label: '上报',prem: ['mosr:collect:reported'], func: () => handleAdd(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div style={{width: '100%'}}>
|
||||||
|
{
|
||||||
|
btn.map(item => (
|
||||||
|
<el-button
|
||||||
|
type={item.type}
|
||||||
|
v-perm={item.prem}
|
||||||
|
onClick={() => item.func()}
|
||||||
|
link
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</el-button>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
api: '/workflow/mosr/requirement/collect',
|
||||||
|
params: {},
|
||||||
|
btns: [
|
||||||
|
{name: '年度计划导出', key: '_export', color: '#DED0B2', auth: ''},
|
||||||
|
{name: '经费预算生成', key: 'preMonty', color: '#DED0B2', auth: ''},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const search = (val) => {
|
||||||
|
let obj = {...val}
|
||||||
|
if (obj.time) {
|
||||||
|
obj.startTime = obj.time[0]
|
||||||
|
obj.endTime = obj.time[1]
|
||||||
|
delete obj.dateValue
|
||||||
|
}
|
||||||
|
tableConfig.params = obj
|
||||||
|
tableIns.value.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAdd = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Summary/add',
|
||||||
|
query: {
|
||||||
|
id:row.requirementId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleEdit = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Summary/edit',
|
||||||
|
query: {
|
||||||
|
id:row.requirementId,
|
||||||
|
projectId:row.projectId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleDetail = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Summary/detail',
|
||||||
|
query: {
|
||||||
|
id:row.requirementId,
|
||||||
|
projectId: row.projectId,
|
||||||
|
state: row.state
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
83
src/views/project-management/filing/attachment.vue
Normal file
83
src/views/project-management/filing/attachment.vue
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<fvSearchForm :searchConfig="searchConfig" @search="search"></fvSearchForm>
|
||||||
|
<el-card style="width: 100%">
|
||||||
|
<file-upload @getFile="getOtherFile" :showFileList="true"/>
|
||||||
|
<fvTable style="width: 100%;max-height: 250px" v-if="showTable" :tableConfig="tableConfig"
|
||||||
|
:data="otherFileList" :isSettingCol="false" :pagination="false">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {downloadFile} from "@/api/project-demand";
|
||||||
|
|
||||||
|
const searchConfig = reactive([
|
||||||
|
{
|
||||||
|
label: '关键词',
|
||||||
|
prop: 'collectType',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'originalFileName',
|
||||||
|
label: '附件名称',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'tag',
|
||||||
|
label: '自定义标签',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'tag',
|
||||||
|
label: '内置标签',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'tag',
|
||||||
|
label: '上传时间',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const showTable=ref(true)
|
||||||
|
const otherFileList = ref([])
|
||||||
|
const getOtherFile = () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
const handleDownload = (row) => {
|
||||||
|
downloadFile(row.fileId).then(res => {
|
||||||
|
const blob = new Blob([res])
|
||||||
|
let a = document.createElement('a')
|
||||||
|
a.href=URL.createObjectURL(blob)
|
||||||
|
a.download = row.originalFileName
|
||||||
|
a.click()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
265
src/views/project-management/filing/conclusion.vue
Normal file
265
src/views/project-management/filing/conclusion.vue
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
<template>
|
||||||
|
<div class="apply-block">
|
||||||
|
<el-form :model="formData" ref="applyForm" label-width="auto" :rules="rules">
|
||||||
|
<baseTitle title="项目结项"></baseTitle>
|
||||||
|
<AttachmentUpload ref="attachment" label="项目结项附件" :showTable="showTable" :otherFileList="otherFileList"
|
||||||
|
@getAttachment="getAttachment"
|
||||||
|
@getOtherFile="getOtherFile" :showFileList="true" :formData="formData" :preview="name === 'Filing/edit'"/>
|
||||||
|
<div class="approval-record">
|
||||||
|
<baseTitle title="流程"></baseTitle>
|
||||||
|
<process-diagram-viewer mode="view" v-if="processDiagramViewer"/>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
<div class="oper-page-btn">
|
||||||
|
<el-button color="#DED0B2" @click="handleSubmit(applyForm)">提交</el-button>
|
||||||
|
<el-button color="#DED0B2" @click="handleResubmit">重新提交</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {useTagsView} from '@/stores/tagsview.js'
|
||||||
|
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
|
||||||
|
import {downloadFile} from "@/api/project-demand";
|
||||||
|
import {ElNotification} from "element-plus";
|
||||||
|
import {useProcessStore} from '@/stores/processStore.js';
|
||||||
|
import {getProjectConclusionProcess, projectConclusion,getConclusionDetail, resubmitConclusion} from "@/api/project-manage";
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const tagsViewStore = useTagsView()
|
||||||
|
const formData = ref({})
|
||||||
|
const rules = reactive({
|
||||||
|
attachment: [{required: true, message: '请上传项目结项附件', trigger: 'blur'}],
|
||||||
|
})
|
||||||
|
const attachment = ref()
|
||||||
|
const name=ref(router.currentRoute.value.name)
|
||||||
|
const loading = ref(false)
|
||||||
|
const file = ref({})
|
||||||
|
const applyForm = ref()
|
||||||
|
const deploymentId = ref()
|
||||||
|
const showTable = ref(true)
|
||||||
|
const otherFileList = ref([])
|
||||||
|
const processInstanceData = ref()
|
||||||
|
const processDiagramViewer = ref(true)
|
||||||
|
const processStore = useProcessStore()
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'index',
|
||||||
|
type: 'index',
|
||||||
|
label: '序号',
|
||||||
|
align: 'center',
|
||||||
|
width: '80',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'originalFileName',
|
||||||
|
label: '文件名',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'tag',
|
||||||
|
label: '标签',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'size',
|
||||||
|
label: '文件大小',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// prop: 'oper',
|
||||||
|
// label: '操作',
|
||||||
|
// align: 'center',
|
||||||
|
// currentRender: ({row, index}) => {
|
||||||
|
// return (
|
||||||
|
// <div>
|
||||||
|
// <el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||||
|
// <el-button type="primary" size="large" link onClick={() => beforeRemove(row)}>删除</el-button>
|
||||||
|
// </div>
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const handleDownload = (row) => {
|
||||||
|
downloadFile(row.fileId).then(res => {
|
||||||
|
const blob = new Blob([res])
|
||||||
|
let a = document.createElement('a')
|
||||||
|
a.href = URL.createObjectURL(blob)
|
||||||
|
a.download = row.originalFileName
|
||||||
|
a.click()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const compositeParam = (item) => {
|
||||||
|
let tag = ''
|
||||||
|
if (name.value === 'Filing/conclusion'||name.value === 'Filing/edit') {
|
||||||
|
tag = '项目结项'
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
fileId: item.id,
|
||||||
|
size: item.size,
|
||||||
|
originalFileName: item.originalFilename,
|
||||||
|
fileType: item.fileType,
|
||||||
|
url: item.url,
|
||||||
|
tag: tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getAttachment = (val) => {
|
||||||
|
console.log('上传文件getAttachment', val)
|
||||||
|
file.value=compositeParam(val)
|
||||||
|
}
|
||||||
|
const getOtherFile = (val) => {
|
||||||
|
console.log('上传文件getOtherFile', val)
|
||||||
|
showTable.value = false
|
||||||
|
let fileObj = compositeParam(val)
|
||||||
|
otherFileList.value.push(fileObj)
|
||||||
|
nextTick(() => {
|
||||||
|
showTable.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFileParam = (item) => {
|
||||||
|
return {
|
||||||
|
fileId: item.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleSubmit = (instance) => {
|
||||||
|
if (!instance) return
|
||||||
|
instance.validate(async (valid) => {
|
||||||
|
if (!valid) return
|
||||||
|
if(JSON.stringify(file.value) === "{}"){
|
||||||
|
attachment.value.validate()
|
||||||
|
} else {
|
||||||
|
attachment.value.clearValidate()
|
||||||
|
}
|
||||||
|
if (!valid) return
|
||||||
|
let files = []
|
||||||
|
let singleFile={}
|
||||||
|
if(file.value.fileId!==undefined){
|
||||||
|
singleFile = {
|
||||||
|
fileId: file.value.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
otherFileList.value.forEach(item => {
|
||||||
|
files.push(getFileParam(item))
|
||||||
|
})
|
||||||
|
let params = {
|
||||||
|
deploymentId: deploymentId.value,
|
||||||
|
requirementId: route.query.id,
|
||||||
|
fileList: files,
|
||||||
|
singleFile: singleFile,
|
||||||
|
projectId:route.query.projectId,
|
||||||
|
}
|
||||||
|
console.log('params', params)
|
||||||
|
let res = await projectConclusion(params)
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
await router.push({
|
||||||
|
name: 'Filing'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleResubmit = () => {
|
||||||
|
let singleFile = {}
|
||||||
|
let otherFiles = []
|
||||||
|
let fileArray
|
||||||
|
if (JSON.stringify(file.value) === "{}"||attachment.value.singleFile===null) {
|
||||||
|
attachment.value.validate()
|
||||||
|
} else {
|
||||||
|
attachment.value.clearValidate()
|
||||||
|
}
|
||||||
|
if(attachment.value.singleFile!==null&&name.value === 'Filing/edit'){
|
||||||
|
singleFile = {
|
||||||
|
fileId: attachment.value.singleFile.fileId
|
||||||
|
}
|
||||||
|
fileArray=attachment.value.allFileList
|
||||||
|
}else {
|
||||||
|
if (file.value.fileId !== undefined) {
|
||||||
|
singleFile = {
|
||||||
|
fileId: file.value.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileArray=otherFileList.value
|
||||||
|
}
|
||||||
|
fileArray.forEach(item => {
|
||||||
|
otherFiles.push(getFileParam(item))
|
||||||
|
})
|
||||||
|
//todo requirementId
|
||||||
|
let params={
|
||||||
|
deploymentId: deploymentId.value,
|
||||||
|
requirementId: route.query.id,
|
||||||
|
fileList: otherFiles,
|
||||||
|
singleFile: singleFile,
|
||||||
|
projectId:route.query.projectId,
|
||||||
|
}
|
||||||
|
console.log('重新提交params',params)
|
||||||
|
resubmitConclusion(params).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
router.push({
|
||||||
|
name: 'Filing'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getDetailInfo = async () => {
|
||||||
|
getConclusionDetail(route.query.projectId).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
formData.value = res.data.formData
|
||||||
|
loading.value=false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const init = () => {
|
||||||
|
getProjectConclusionProcess().then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
processDiagramViewer.value = false
|
||||||
|
if (res.code === 1000) {
|
||||||
|
let data = res.data
|
||||||
|
deploymentId.value=data.deploymentId
|
||||||
|
processInstanceData.value = data
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
nextTick(() => {
|
||||||
|
processDiagramViewer.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(async () => {
|
||||||
|
await init()
|
||||||
|
if (name.value === 'Filing/edit') {
|
||||||
|
loading.value=true
|
||||||
|
await getDetailInfo()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
129
src/views/project-management/filing/detail.vue
Normal file
129
src/views/project-management/filing/detail.vue
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<template>
|
||||||
|
<steps :active="'4'" @setDetail="setDetail" @stepChange="stepChange">
|
||||||
|
<template #content>
|
||||||
|
<collection-detail
|
||||||
|
:formData="commonForm.formData"
|
||||||
|
:data="commonForm"
|
||||||
|
:processViewer="commonProvessViewer"
|
||||||
|
:companyOption="companyOption"
|
||||||
|
v-show="showActive == '00'"
|
||||||
|
:loading="loading"
|
||||||
|
/>
|
||||||
|
<summary-detail v-show="showActive == '10'" :formData="commonForm.formData" :data="commonForm"
|
||||||
|
:processViewer="commonProvessViewer" :loading="loading"/>
|
||||||
|
<ApprovalDetail type="approval" v-show="showActive == '20'" :formData="commonForm.formData" :data="commonForm"
|
||||||
|
:processViewer="commonProvessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
<ApprovalDetail type="execute" v-show="showActive == '40'" :formData="commonForm.formData" :data="commonForm"
|
||||||
|
:processViewer="commonProvessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
<ApprovalDetail type="archivist" v-show="showActive == '50'" :formData="commonForm.formData" :data="commonForm"
|
||||||
|
:processViewer="commonProvessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
</template>
|
||||||
|
</steps>
|
||||||
|
<opinion v-if="commonForm.taskId" :formData="commonForm.formData" :taskId="commonForm.taskId"/>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {getInfo} from "@/api/project-demand/index.js";
|
||||||
|
import {getSubCompOpt} from '@/api/user/user.js'
|
||||||
|
import {useProcessStore} from '@/stores/processStore.js';
|
||||||
|
import CollectionDetail from "@/components/DetailComponent/CollectionDetail.vue";
|
||||||
|
import SummaryDetail from "@/components/DetailComponent/SummaryDetail.vue";
|
||||||
|
import ApprovalDetail from "@/components/DetailComponent/ApprovalDetail.vue";
|
||||||
|
import {getMapProjectStateInfo} from '@/components/steps/api';
|
||||||
|
import {ElLoading} from "element-plus";
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const companyOption = ref([])
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
const processStore = useProcessStore()
|
||||||
|
const activeName = ref('first')
|
||||||
|
const handleClick = (tab, event) => {
|
||||||
|
console.log(tab, event)
|
||||||
|
if (tab.index.value === 0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const getCompanyOption = async () => {
|
||||||
|
const res = await getSubCompOpt()
|
||||||
|
companyOption.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const commonForm = ref({})
|
||||||
|
const commonProvessViewer = ref(true)
|
||||||
|
|
||||||
|
const getAllInfo = async (state) => {
|
||||||
|
const loading = ElLoading.service({fullscreen: true})
|
||||||
|
try {
|
||||||
|
state == '00' && (await getCompanyOption())
|
||||||
|
commonProvessViewer.value = false
|
||||||
|
loading.value = true
|
||||||
|
const {data, code} = await getMapProjectStateInfo(route.query.projectId, state)
|
||||||
|
// if(state == '00') {
|
||||||
|
// collectionData.value = data;
|
||||||
|
// } else if(state == '10') {
|
||||||
|
// summaryData.value = data;
|
||||||
|
// }
|
||||||
|
if(code===1000){
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
commonForm.value = data
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
nextTick(() => {
|
||||||
|
// summaryProcessViewer.value = true
|
||||||
|
commonProvessViewer.value = true
|
||||||
|
})
|
||||||
|
loading.close()
|
||||||
|
} catch {
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const showActive = ref()
|
||||||
|
|
||||||
|
const setDetail = (active) => {
|
||||||
|
showActive.value = active
|
||||||
|
getAllInfo(active)
|
||||||
|
}
|
||||||
|
|
||||||
|
const stepChange = (data) => {
|
||||||
|
showActive.value = data.active
|
||||||
|
getAllInfo(data.active)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.detail-block {
|
||||||
|
padding-top: 15px;
|
||||||
|
|
||||||
|
:deep(.el-tabs__nav-scroll) {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.el-tabs__nav {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.el-tabs__item {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-active {
|
||||||
|
color: black;
|
||||||
|
background-color: #DED0B2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
238
src/views/project-management/filing/index.vue
Normal file
238
src/views/project-management/filing/index.vue
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
<template>
|
||||||
|
<fvSearchForm :searchConfig="searchConfig" @search="search"></fvSearchForm>
|
||||||
|
<fvTable ref="tableIns" :tableConfig="tableConfig">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty description="暂无数据"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
|
||||||
|
import {reactive, shallowRef} from "vue";
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const searchConfig = reactive([
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入名称查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目类型',
|
||||||
|
prop: 'collectType',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择项目类型',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目影响',
|
||||||
|
prop: 'projectEffect',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择项目影响',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '研发主体',
|
||||||
|
prop: 'collectType',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择研发主体',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: '起始时间',
|
||||||
|
prop: 'time',
|
||||||
|
component: 'el-date-picker',
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择起止时间',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '最小金额',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入金额查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '最大金额',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入金额查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const tableIns = ref()
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'projectName',
|
||||||
|
label: '名称',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'affiliatedCompany',
|
||||||
|
label: '所属公司',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'approveName',
|
||||||
|
label: '审批人',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectType',
|
||||||
|
label: '项目类型',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'rdSubject',
|
||||||
|
label: '研发主体',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectImpact',
|
||||||
|
label: '项目影响',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'economicEstimate',
|
||||||
|
label: '经济概况',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'startTime',
|
||||||
|
label: '起止时间',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'taskNode',
|
||||||
|
label: '当前节点',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'state',
|
||||||
|
label: '状态',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) =>{
|
||||||
|
if (row.state !== null) {
|
||||||
|
return (<Tag dictType={'project_initiation'} value={row.state}/>)
|
||||||
|
} else {
|
||||||
|
return '--'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
let btn = []
|
||||||
|
let buttons = new Set(Array.from(row.buttons))
|
||||||
|
if (buttons.has("details")) {
|
||||||
|
btn.push({label: '详情', prem: ['mosr:requirement:info'], func: () => handleDetail(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("attachments")) {
|
||||||
|
btn.push({label: '附件',prem: ['mosr:requirement:resubmit'], func: () => handleAttachment(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("entry")) {
|
||||||
|
btn.push({label: '结项',prem: ['mosr:requirement:del'], func: () => handleConclusion(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("edit")) {
|
||||||
|
btn.push({label: '编辑',prem: ['mosr:requirement:info'], func: () => handleEdit(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div style={{width: '100%'}}>
|
||||||
|
{
|
||||||
|
btn.map(item => (
|
||||||
|
<el-button
|
||||||
|
type={item.type}
|
||||||
|
v-perm={item.prem}
|
||||||
|
onClick={() => item.func()}
|
||||||
|
link
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</el-button>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
api: '/workflow/mosr/project/filing',
|
||||||
|
params: {},
|
||||||
|
})
|
||||||
|
|
||||||
|
const search = (val) => {
|
||||||
|
tableConfig.params = {...val}
|
||||||
|
tableIns.value.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDetail = (row) => {
|
||||||
|
router.push({
|
||||||
|
name:'Filing/detail',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId,
|
||||||
|
projectId: row.projectId,
|
||||||
|
state: row.state
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleAttachment = (row) => {
|
||||||
|
router.push({
|
||||||
|
name:'Filing/attachment',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId,
|
||||||
|
projectId: row.projectId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleConclusion = (row) => {
|
||||||
|
router.push({
|
||||||
|
name:'Filing/conclusion',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId,
|
||||||
|
projectId: row.projectId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleEdit = (row) => {
|
||||||
|
router.push({
|
||||||
|
name:'Filing/edit',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId,
|
||||||
|
projectId: row.projectId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
103
src/views/project-management/implementation/account.vue
Normal file
103
src/views/project-management/implementation/account.vue
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
<template>
|
||||||
|
<fvSearchForm :searchConfig="searchConfig" @search="search"></fvSearchForm>
|
||||||
|
<fvTable ref="tableIns" :tableConfig="tableConfig" @headBtnClick="headBtnClick">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty description="暂无数据"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
const searchConfig = reactive([
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入名称查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目费用',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入项目费用查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '起始时间',
|
||||||
|
prop: 'datetime',
|
||||||
|
component: 'el-date-picker',
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择起始时间',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
colProps: {}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'name',
|
||||||
|
type: 'index',
|
||||||
|
label: '序号',
|
||||||
|
width:'80'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'name',
|
||||||
|
label: '时间',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectType',
|
||||||
|
label: '项目费用',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'productMainBody',
|
||||||
|
label: '研发阶段',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectEffect',
|
||||||
|
label: '摘要',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'survey',
|
||||||
|
label: '税后余额(元)',
|
||||||
|
align: 'center'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
api: '',
|
||||||
|
params: {},
|
||||||
|
btns: [
|
||||||
|
{name: '上传费用', key: 'add', color: '#DED0B2',auth: ''}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const router = useRouter()
|
||||||
|
const headBtnClick = (key) => {
|
||||||
|
switch (key) {
|
||||||
|
case 'add':
|
||||||
|
handleUploadFee()
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleUploadFee = () => {
|
||||||
|
router.push({
|
||||||
|
name: 'Implementation/uploadFee',
|
||||||
|
query: {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
89
src/views/project-management/implementation/attachment.vue
Normal file
89
src/views/project-management/implementation/attachment.vue
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<template>
|
||||||
|
<fvSearchForm :searchConfig="searchConfig" @search="search"></fvSearchForm>
|
||||||
|
<el-card style="width: 100%">
|
||||||
|
<file-upload @getFile="getOtherFile" :showFileList="true"/>
|
||||||
|
<fvTable style="width: 100%;max-height: 250px" v-if="showTable" :tableConfig="tableConfig"
|
||||||
|
:data="otherFileList" :isSettingCol="false" :pagination="false">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
|
||||||
|
import {shallowRef} from "vue";
|
||||||
|
import {downloadFile} from "@/api/project-demand";
|
||||||
|
|
||||||
|
const searchConfig = reactive([
|
||||||
|
{
|
||||||
|
label: '标签',
|
||||||
|
prop: 'collectType',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择标签',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'index',
|
||||||
|
type: 'index',
|
||||||
|
label: '序号',
|
||||||
|
align: 'center',
|
||||||
|
width: '80',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'originalFileName',
|
||||||
|
label: '文件名',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'tag',
|
||||||
|
label: '标签',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'size',
|
||||||
|
label: '文件大小',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||||
|
<el-button type="primary" size="large" link onClick={() => beforeRemove(row)}>删除</el-button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const showTable=ref(true)
|
||||||
|
const otherFileList = ref([])
|
||||||
|
const getOtherFile = () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
const handleDownload = (row) => {
|
||||||
|
downloadFile(row.fileId).then(res => {
|
||||||
|
const blob = new Blob([res])
|
||||||
|
let a = document.createElement('a')
|
||||||
|
a.href=URL.createObjectURL(blob)
|
||||||
|
a.download = row.originalFileName
|
||||||
|
a.click()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
232
src/views/project-management/implementation/check.vue
Normal file
232
src/views/project-management/implementation/check.vue
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
<template>
|
||||||
|
<div class="apply-block">
|
||||||
|
<el-form :model="formData" ref="applyForm" label-width="auto" :rules="rules">
|
||||||
|
<baseTitle title="项目验收"></baseTitle>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="前置流程">
|
||||||
|
<el-input v-model="formData.requirementName" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<AttachmentUpload ref="attachment" label="项目验收附件" :showTable="showTable" :otherFileList="otherFileList"
|
||||||
|
@getAttachment="getAttachment"
|
||||||
|
@getOtherFile="getOtherFile" :showFileList="true" :formData="formData" :preview="name === 'Implementation/edit'"/>
|
||||||
|
<div class="approval-record">
|
||||||
|
<baseTitle title="流程"></baseTitle>
|
||||||
|
<process-diagram-viewer mode="view" v-if="processDiagramViewer"/>
|
||||||
|
</div>
|
||||||
|
<div class="oper-page-btn">
|
||||||
|
<el-button color="#DED0B2" @click="handleSubmit(applyForm)">提交</el-button>
|
||||||
|
<el-button color="#DED0B2" @click="handleResubmit(applyForm)">重新提交</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
|
||||||
|
import {getProjectCheckProcess, projectCheck,getCheckDetail,resubmitCheck} from "@/api/project-manage";
|
||||||
|
import {ElNotification} from "element-plus";
|
||||||
|
import {useProcessStore} from '@/stores/processStore.js';
|
||||||
|
import {useTagsView} from '@/stores/tagsview.js'
|
||||||
|
const tagsViewStore = useTagsView()
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const attachment = ref()
|
||||||
|
const name=ref(router.currentRoute.value.name)
|
||||||
|
const loading = ref(false)
|
||||||
|
const formData = ref({})
|
||||||
|
const file = ref({})
|
||||||
|
const applyForm = ref()
|
||||||
|
const deploymentId = ref()
|
||||||
|
const showTable = ref(true)
|
||||||
|
const otherFileList = ref([])
|
||||||
|
const processInstanceData = ref()
|
||||||
|
const processDiagramViewer = ref(true)
|
||||||
|
const processStore = useProcessStore()
|
||||||
|
const compositeParam = (item) => {
|
||||||
|
let tag=''
|
||||||
|
if(name.value==='Implementation/check'||name.value === 'Implementation/edit'){
|
||||||
|
tag='项目验收'
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
fileId: item.id,
|
||||||
|
size: item.size,
|
||||||
|
originalFileName: item.originalFilename,
|
||||||
|
fileType: item.fileType,
|
||||||
|
url: item.url,
|
||||||
|
tag: tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getAttachment = (val) => {
|
||||||
|
console.log('上传文件getAttachment', val)
|
||||||
|
file.value=compositeParam(val)
|
||||||
|
}
|
||||||
|
const getOtherFile = (val) => {
|
||||||
|
console.log('上传文件getOtherFile', val)
|
||||||
|
showTable.value = false
|
||||||
|
let fileObj = compositeParam(val)
|
||||||
|
otherFileList.value.push(fileObj)
|
||||||
|
nextTick(() => {
|
||||||
|
showTable.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFileParam = (item) => {
|
||||||
|
return {
|
||||||
|
fileId: item.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleSubmit = (instance) => {
|
||||||
|
if (!instance) return
|
||||||
|
instance.validate(async (valid) => {
|
||||||
|
if (!valid) return
|
||||||
|
if(JSON.stringify(file.value) === "{}"){
|
||||||
|
attachment.value.validate()
|
||||||
|
}else {
|
||||||
|
attachment.value.clearValidate()
|
||||||
|
}
|
||||||
|
if (!valid) return
|
||||||
|
let files = []
|
||||||
|
let singleFile={}
|
||||||
|
let fileArray
|
||||||
|
if(name.value === 'Implementation/edit'){
|
||||||
|
singleFile = {
|
||||||
|
fileId: attachment.value.singleFile.fileId
|
||||||
|
}
|
||||||
|
fileArray=attachment.value.allFileList
|
||||||
|
}else {
|
||||||
|
if (file.value.fileId !== undefined) {
|
||||||
|
singleFile = {
|
||||||
|
fileId: file.value.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileArray=otherFileList.value
|
||||||
|
}
|
||||||
|
fileArray.forEach(item => {
|
||||||
|
files.push(getFileParam(item))
|
||||||
|
})
|
||||||
|
let params = {
|
||||||
|
deploymentId: deploymentId.value,
|
||||||
|
requirementId: route.query.id,
|
||||||
|
fileList: files,
|
||||||
|
singleFile: singleFile,
|
||||||
|
projectId:route.query.projectId,
|
||||||
|
}
|
||||||
|
console.log('params-提交',params)
|
||||||
|
let res = await projectCheck(params)
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
await router.push({
|
||||||
|
name: 'Implementation'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleResubmit = (instance) => {
|
||||||
|
if (!instance) return
|
||||||
|
instance.validate(async (valid) => {
|
||||||
|
if (!valid) return
|
||||||
|
let singleFile = {}
|
||||||
|
let otherFiles = []
|
||||||
|
let fileArray
|
||||||
|
if (JSON.stringify(file.value) === "{}"||attachment.value.singleFile===null) {
|
||||||
|
attachment.value.validate()
|
||||||
|
} else {
|
||||||
|
attachment.value.clearValidate()
|
||||||
|
}
|
||||||
|
if (attachment.value.singleFile!==null&&name.value === 'Implementation/edit') {
|
||||||
|
singleFile = {
|
||||||
|
fileId: attachment.value.singleFile.fileId
|
||||||
|
}
|
||||||
|
fileArray = attachment.value.allFileList
|
||||||
|
} else {
|
||||||
|
if (file.value.fileId !== undefined) {
|
||||||
|
singleFile = {
|
||||||
|
fileId: file.value.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileArray = otherFileList.value
|
||||||
|
}
|
||||||
|
fileArray.forEach(item => {
|
||||||
|
otherFiles.push(getFileParam(item))
|
||||||
|
})
|
||||||
|
//todo requirementId
|
||||||
|
let params = {
|
||||||
|
deploymentId: deploymentId.value,
|
||||||
|
requirementId: route.query.id,
|
||||||
|
fileList: otherFiles,
|
||||||
|
singleFile: singleFile,
|
||||||
|
projectId: route.query.projectId,
|
||||||
|
}
|
||||||
|
console.log('重新提交params', params)
|
||||||
|
resubmitCheck(params).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
router.push({
|
||||||
|
name: 'Implementation'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getDetailInfo = async () => {
|
||||||
|
getCheckDetail(route.query.projectId).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
formData.value = res.data.formData
|
||||||
|
loading.value=false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const init = () => {
|
||||||
|
getProjectCheckProcess(route.query.projectId).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
processDiagramViewer.value = false
|
||||||
|
if (res.code === 1000) {
|
||||||
|
let data = res.data
|
||||||
|
deploymentId.value=data.deploymentId
|
||||||
|
processInstanceData.value = data
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
nextTick(() => {
|
||||||
|
processDiagramViewer.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(async () => {
|
||||||
|
await init()
|
||||||
|
if (name.value === 'Implementation/edit'){
|
||||||
|
loading.value=true
|
||||||
|
await getDetailInfo()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
130
src/views/project-management/implementation/detail.vue
Normal file
130
src/views/project-management/implementation/detail.vue
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<template>
|
||||||
|
<steps :active="'3'" @setDetail="setDetail" @stepChange="stepChange">
|
||||||
|
<template #content>
|
||||||
|
<collection-detail
|
||||||
|
:formData="commonForm.formData"
|
||||||
|
:data="commonForm"
|
||||||
|
:processViewer="commonProvessViewer"
|
||||||
|
:companyOption="companyOption"
|
||||||
|
v-show="showActive == '00'"
|
||||||
|
:loading="loading"
|
||||||
|
/>
|
||||||
|
<summary-detail v-show="showActive == '10'" :formData="commonForm.formData" :data="commonForm" :processViewer="commonProvessViewer" :loading="loading"/>
|
||||||
|
<ApprovalDetail type="approval" v-show="showActive == '20'" :formData="commonForm.formData" :data="commonForm" :processViewer="commonProvessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
<ApprovalDetail type="execute" v-show="showActive == '40'" :formData="commonForm.formData" :data="commonForm" :processViewer="commonProvessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
<ApprovalDetail type="archivist" v-show="showActive == '50'" :formData="commonForm.formData" :data="commonForm"
|
||||||
|
:processViewer="commonProvessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</steps>
|
||||||
|
<opinion v-if="commonForm.taskId" :formData="commonForm.formData" :taskId="commonForm.taskId"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {getInfo} from "@/api/project-demand/index.js";
|
||||||
|
import {getSubCompOpt} from '@/api/user/user.js'
|
||||||
|
import {useProcessStore} from '@/stores/processStore.js';
|
||||||
|
import CollectionDetail from "@/components/DetailComponent/CollectionDetail.vue";
|
||||||
|
import SummaryDetail from "@/components/DetailComponent/SummaryDetail.vue";
|
||||||
|
import ApprovalDetail from "@/components/DetailComponent/ApprovalDetail.vue";
|
||||||
|
import { getMapProjectStateInfo } from '@/components/steps/api';
|
||||||
|
import { ElLoading } from "element-plus";
|
||||||
|
import Opinion from "@/components/DetailComponent/Opinion.vue";
|
||||||
|
|
||||||
|
// const activeName = ref('first')
|
||||||
|
const handleClick = (tab, event) => {
|
||||||
|
console.log(tab, event)
|
||||||
|
if(tab.index.value === 0){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const activeName = ref('first')
|
||||||
|
const collectionData = ref({})
|
||||||
|
const summaryData = ref({})
|
||||||
|
const loading = ref(false)
|
||||||
|
const collectionProcessViewer = ref(true)
|
||||||
|
const summaryProcessViewer = ref(true)
|
||||||
|
const processStore = useProcessStore()
|
||||||
|
const companyOption = ref([])
|
||||||
|
const rules = reactive({
|
||||||
|
auditOpinion: [{required: true, message: '请输入审核意见', trigger: 'blur'}],
|
||||||
|
})
|
||||||
|
const getCompanyOption = async () => {
|
||||||
|
const res = await getSubCompOpt()
|
||||||
|
companyOption.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const commonForm = ref({})
|
||||||
|
const commonProvessViewer = ref(true)
|
||||||
|
|
||||||
|
const getAllInfo = async (state) => {
|
||||||
|
const loading = ElLoading.service({fullscreen: true})
|
||||||
|
try {
|
||||||
|
state == '00' && ( await getCompanyOption() )
|
||||||
|
commonProvessViewer.value = false
|
||||||
|
loading.value = true
|
||||||
|
const { data, code } = await getMapProjectStateInfo(route.query.projectId, state)
|
||||||
|
if(state == '00') {
|
||||||
|
collectionData.value = data;
|
||||||
|
} else if(state == '10') {
|
||||||
|
summaryData.value = data;
|
||||||
|
}
|
||||||
|
if(code===1000){
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
commonForm.value = data
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
nextTick(() => {
|
||||||
|
// summaryProcessViewer.value = true
|
||||||
|
commonProvessViewer.value = true
|
||||||
|
})
|
||||||
|
loading.close()
|
||||||
|
} catch {
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const showActive = ref()
|
||||||
|
|
||||||
|
const setDetail = (active) => {
|
||||||
|
showActive.value = active
|
||||||
|
getAllInfo(active)
|
||||||
|
}
|
||||||
|
|
||||||
|
const stepChange = (data) => {
|
||||||
|
showActive.value = data.active
|
||||||
|
getAllInfo(data.active)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.detail-block{
|
||||||
|
padding-top: 15px;
|
||||||
|
:deep(.el-tabs__nav-scroll){
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
.el-tabs__nav{
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
.el-tabs__item{
|
||||||
|
flex: 1;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.is-active{
|
||||||
|
color: black;
|
||||||
|
background-color: #DED0B2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
269
src/views/project-management/implementation/index.vue
Normal file
269
src/views/project-management/implementation/index.vue
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
<template>
|
||||||
|
<fvSearchForm :searchConfig="searchConfig" @search="search"></fvSearchForm>
|
||||||
|
<fvTable ref="tableIns" :tableConfig="tableConfig">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty description="暂无数据"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
|
||||||
|
import {reactive, shallowRef} from "vue";
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const searchConfig = reactive([
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
prop: 'projectName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入名称查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目类型',
|
||||||
|
prop: 'projectType',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择项目类型',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目影响',
|
||||||
|
prop: 'projectImpact',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择项目影响',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '研发主体',
|
||||||
|
prop: 'rdSubject',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择研发主体',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: '起止时间',
|
||||||
|
prop: 'startTime',
|
||||||
|
component: 'el-date-picker',
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择起止时间',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '最小金额',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入金额查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '最大金额',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入金额查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const tableIns = ref()
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'selection',
|
||||||
|
prop: 'selection'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectName',
|
||||||
|
label: '名称',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'affiliatedCompany',
|
||||||
|
label: '所属公司',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'approveName',
|
||||||
|
label: '审批人',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectType',
|
||||||
|
label: '项目类型',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'rdSubject',
|
||||||
|
label: '研发主体',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectImpact',
|
||||||
|
label: '项目影响',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'economicEstimate',
|
||||||
|
label: '经济概况',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'startTime',
|
||||||
|
label: '起止时间',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'taskNode',
|
||||||
|
label: '当前节点',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'state',
|
||||||
|
label: '状态',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) =>{
|
||||||
|
if (row.state !== null) {
|
||||||
|
return (<Tag dictType={'project_initiation'} value={row.state}/>)
|
||||||
|
} else {
|
||||||
|
return '--'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
let btn = []
|
||||||
|
let buttons = new Set(Array.from(row.buttons))
|
||||||
|
if (buttons.has("details")) {
|
||||||
|
btn.push({label: '详情', prem: ['mosr:requirement:info'], func: () => handleDetail(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("check")) {
|
||||||
|
btn.push({label: '验收',prem: ['mosr:requirement:resubmit'], func: () => handleCheck(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("edit")) {
|
||||||
|
btn.push({label: '编辑',prem: ['mosr:requirement:del'], func: () => handleEdit(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("standing")) {
|
||||||
|
btn.push({label: '台账',prem: ['mosr:requirement:info'], func: () => handleStandingBook(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("attachments")) {
|
||||||
|
btn.push({label: '附件',prem: ['mosr:requirement:info'], func: () => handleAttachment(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("viewAllocation")) {
|
||||||
|
btn.push({label: '查看分摊',prem: ['mosr:requirement:info'], func: () => handleShare(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("phaseChange")) {
|
||||||
|
btn.push({label: '阶段变更',prem: ['mosr:requirement:info'], func: () => handleChange(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div style={{width: '100%'}}>
|
||||||
|
{
|
||||||
|
btn.map(item => (
|
||||||
|
<el-button
|
||||||
|
type={item.type}
|
||||||
|
v-perm={item.prem}
|
||||||
|
onClick={() => item.func()}
|
||||||
|
link
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</el-button>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
api: '/workflow/mosr/project/implementation',
|
||||||
|
params: {},
|
||||||
|
btns: [
|
||||||
|
{name: '生成分摊报表', key: '_export', color: '#DED0B2', auth: ''}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const search = (val) => {
|
||||||
|
tableConfig.params = {...val}
|
||||||
|
tableIns.value.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDetail = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Implementation/detail',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId,
|
||||||
|
projectId: row.projectId,
|
||||||
|
state: row.state
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleCheck = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Implementation/check',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId,
|
||||||
|
projectId: row.projectId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleEdit = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Implementation/edit',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId,
|
||||||
|
projectId: row.projectId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleStandingBook = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Implementation/account',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleAttachment = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Implementation/attachment',
|
||||||
|
query: {
|
||||||
|
id: row.projectId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleShare = (row) => {
|
||||||
|
router.push({
|
||||||
|
name: 'Implementation/share',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
113
src/views/project-management/implementation/share.vue
Normal file
113
src/views/project-management/implementation/share.vue
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
<template>
|
||||||
|
<fvSearchForm :searchConfig="searchConfig" @search="search"></fvSearchForm>
|
||||||
|
<fvTable ref="tableIns" :tableConfig="tableConfig">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty description="暂无数据"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {reactive} from "vue";
|
||||||
|
|
||||||
|
const searchConfig = reactive([
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入名称查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目费用',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入项目费用查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '起始时间',
|
||||||
|
prop: 'datetime',
|
||||||
|
component: 'el-date-picker',
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择起始时间',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
colProps: {}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const tableIns = ref()
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'name',
|
||||||
|
type: 'index',
|
||||||
|
label: '序号',
|
||||||
|
width:'80'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'name',
|
||||||
|
label: '时间',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectType',
|
||||||
|
label: '研发人员',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'productMainBody',
|
||||||
|
label: '应发工资',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectEffect',
|
||||||
|
label: '绩效',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'survey',
|
||||||
|
label: '公积金',
|
||||||
|
align: 'center'
|
||||||
|
},{
|
||||||
|
prop: 'survey',
|
||||||
|
label: '社保',
|
||||||
|
align: 'center'
|
||||||
|
},{
|
||||||
|
prop: 'survey',
|
||||||
|
label: '年金',
|
||||||
|
align: 'center'
|
||||||
|
},{
|
||||||
|
prop: 'survey',
|
||||||
|
label: '工作日(天)',
|
||||||
|
align: 'center'
|
||||||
|
},{
|
||||||
|
prop: 'survey',
|
||||||
|
label: '研发工时(天)',
|
||||||
|
align: 'center'
|
||||||
|
},{
|
||||||
|
prop: 'survey',
|
||||||
|
label: '小计',
|
||||||
|
align: 'center'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
api: '',
|
||||||
|
params: {},
|
||||||
|
btns: [
|
||||||
|
{name: '上传分摊', key: '_export', color: '#DED0B2',auth: ''}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
84
src/views/project-management/implementation/uploadFee.vue
Normal file
84
src/views/project-management/implementation/uploadFee.vue
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<template>
|
||||||
|
<el-form :model="formData" ref="demandForm" label-width="auto">
|
||||||
|
<baseTitle title="上传费用"></baseTitle>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="项目名称">
|
||||||
|
<span>{{ formData.requirementName }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="项目负责人">
|
||||||
|
<span>{{ formData.companyIds }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="项目开始时间">
|
||||||
|
<span>{{ formData.collectType }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="项目预计持续时间">
|
||||||
|
<span>{{ formData.deadline }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="项目开展方式">
|
||||||
|
<span>{{ formData.deadline }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="项目预算">
|
||||||
|
<span>{{ formData.deadline }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<el-table :data="tableData" style="width: 100%">
|
||||||
|
<el-table-column prop="date" label="时间" width="180" >
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row.uqName" placeholder="请输入时间" clearable>
|
||||||
|
</el-input>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="name" label="项目费用" width="180" />
|
||||||
|
<el-table-column prop="address" label="研发阶段" />
|
||||||
|
<el-table-column prop="address" label="摘要" />
|
||||||
|
<el-table-column prop="address" label="税后余额(元)" />
|
||||||
|
<el-table-column prop="address" label="操作" >
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button type="primary" size="mini" @click="handleDelete(scope.row)" link>删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
const formData = ref({})
|
||||||
|
const tableData = [
|
||||||
|
{
|
||||||
|
date: '2016-05-03',
|
||||||
|
name: 'Tom',
|
||||||
|
address: 'No. 189, Grove St, Los Angeles',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2016-05-02',
|
||||||
|
name: 'Tom',
|
||||||
|
address: 'No. 189, Grove St, Los Angeles',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2016-05-04',
|
||||||
|
name: 'Tom',
|
||||||
|
address: 'No. 189, Grove St, Los Angeles',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2016-05-01',
|
||||||
|
name: 'Tom',
|
||||||
|
address: 'No. 189, Grove St, Los Angeles',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
260
src/views/project-management/initiation/apply.vue
Normal file
260
src/views/project-management/initiation/apply.vue
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
<template>
|
||||||
|
<div class="apply-block">
|
||||||
|
<el-form :model="formData" ref="applyForm" label-width="auto" :rules="rules">
|
||||||
|
<baseTitle title="项目立项申请"></baseTitle>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="前置流程">
|
||||||
|
<el-input v-model="formData.requirementName" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<AttachmentUpload ref="attachment" label="需求申请书附件" :showTable="showTable" :otherFileList="otherFileList"
|
||||||
|
@getAttachment="getAttachment"
|
||||||
|
@getOtherFile="getOtherFile" :showFileList="true" :formData="formData" :preview="name === 'Initiation/edit'"/>
|
||||||
|
<div class="approval-record">
|
||||||
|
<baseTitle title="流程"></baseTitle>
|
||||||
|
<process-diagram-viewer mode="view" v-if="processDiagramViewer"/>
|
||||||
|
</div>
|
||||||
|
<div class="oper-page-btn">
|
||||||
|
<el-button color="#DED0B2" @click="handleSubmit(applyForm)">提交</el-button>
|
||||||
|
<el-button color="#DED0B2" @click="handleResubmit">重新提交</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {useTagsView} from '@/stores/tagsview.js'
|
||||||
|
import {ElMessage, ElNotification} from "element-plus";
|
||||||
|
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
|
||||||
|
import {getApplyProcess, projectApply,resubmitApply,getApplyDetail} from "@/api/project-manage";
|
||||||
|
import {useProcessStore} from '@/stores/processStore.js';
|
||||||
|
|
||||||
|
const tagsViewStore = useTagsView()
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const formData = ref({})
|
||||||
|
const rules = reactive({
|
||||||
|
attachment: [{required: true, message: '请上传项目立项附件', trigger: 'blur'}],
|
||||||
|
})
|
||||||
|
const processStore = useProcessStore()
|
||||||
|
const deploymentId = ref()
|
||||||
|
const attachment = ref()
|
||||||
|
const file = ref({})
|
||||||
|
const applyForm = ref()
|
||||||
|
const showTable = ref(true)
|
||||||
|
const otherFileList = ref([])
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'index',
|
||||||
|
type: 'index',
|
||||||
|
label: '序号',
|
||||||
|
align: 'center',
|
||||||
|
width: '80',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'originalFileName',
|
||||||
|
label: '文件名',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'tag',
|
||||||
|
label: '标签',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'size',
|
||||||
|
label: '文件大小',
|
||||||
|
align: 'center',
|
||||||
|
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// prop: 'oper',
|
||||||
|
// label: '操作',
|
||||||
|
// align: 'center',
|
||||||
|
// currentRender: ({row, index}) => {
|
||||||
|
// return (
|
||||||
|
// <div>
|
||||||
|
// <a style="cursor: pointer;font-size: 14px;color: #2a99ff;" href={row.url}>下载</a>
|
||||||
|
// <el-button type="primary" size="large" link onClick={() => beforeRemove(row)}>删除</el-button>
|
||||||
|
// </div>
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const loading = ref(false)
|
||||||
|
const processInstanceData = ref()
|
||||||
|
const processDiagramViewer = ref(true)
|
||||||
|
const name=ref(router.currentRoute.value.name)
|
||||||
|
const compositeParam = (item) => {
|
||||||
|
let tag = ''
|
||||||
|
if (name.value === 'Initiation/apply'||name.value === 'Initiation/edit') {
|
||||||
|
tag = '项目立项申请'
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
fileId: item.id,
|
||||||
|
size: item.size,
|
||||||
|
originalFileName: item.originalFilename,
|
||||||
|
fileType: item.fileType,
|
||||||
|
url: item.url,
|
||||||
|
tag:tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getAttachment = (val) => {
|
||||||
|
console.log('上传文件getAttachment', val)
|
||||||
|
file.value=compositeParam(val)
|
||||||
|
}
|
||||||
|
const getOtherFile = (val) => {
|
||||||
|
console.log('上传文件getOtherFile', val)
|
||||||
|
showTable.value = false
|
||||||
|
let fileObj = compositeParam(val)
|
||||||
|
otherFileList.value.push(fileObj)
|
||||||
|
nextTick(() => {
|
||||||
|
showTable.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getFileParam = (item) => {
|
||||||
|
return {
|
||||||
|
fileId: item.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleSubmit = (instance) => {
|
||||||
|
if (!instance) return
|
||||||
|
instance.validate(async (valid) => {
|
||||||
|
if(JSON.stringify(file.value) === "{}"){
|
||||||
|
attachment.value.validate()
|
||||||
|
}else {
|
||||||
|
attachment.value.clearValidate()
|
||||||
|
}
|
||||||
|
if (!valid) return
|
||||||
|
let files = []
|
||||||
|
let singleFile={}
|
||||||
|
if(file.value.fileId!==undefined){
|
||||||
|
singleFile = {
|
||||||
|
fileId: file.value.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
otherFileList.value.forEach(item => {
|
||||||
|
files.push(getFileParam(item))
|
||||||
|
})
|
||||||
|
let params = {
|
||||||
|
deploymentId: deploymentId.value,
|
||||||
|
requirementId: route.query.id,
|
||||||
|
fileList: files,
|
||||||
|
singleFile: singleFile,
|
||||||
|
projectId:route.query.projectId,
|
||||||
|
}
|
||||||
|
console.log('params',params)
|
||||||
|
let res = await projectApply(params)
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
await router.push({
|
||||||
|
name: 'Initiation'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleResubmit =async () => {
|
||||||
|
let files = []
|
||||||
|
let singleFile={}
|
||||||
|
let fileArray
|
||||||
|
if (JSON.stringify(file.value) === "{}"||attachment.value.singleFile===null) {
|
||||||
|
attachment.value.validate()
|
||||||
|
} else {
|
||||||
|
attachment.value.clearValidate()
|
||||||
|
}
|
||||||
|
if(attachment.value.singleFile!==null&&name.value === 'Initiation/edit'){
|
||||||
|
singleFile = {
|
||||||
|
fileId: attachment.value.singleFile.fileId
|
||||||
|
}
|
||||||
|
fileArray=attachment.value.allFileList
|
||||||
|
}else {
|
||||||
|
if (file.value.fileId !== undefined) {
|
||||||
|
singleFile = {
|
||||||
|
fileId: file.value.fileId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileArray=otherFileList.value
|
||||||
|
}
|
||||||
|
fileArray.forEach(item => {
|
||||||
|
files.push(getFileParam(item))
|
||||||
|
})
|
||||||
|
let params = {
|
||||||
|
deploymentId: deploymentId.value,
|
||||||
|
requirementId: route.query.id,
|
||||||
|
fileList: files,
|
||||||
|
singleFile: singleFile,
|
||||||
|
projectId:route.query.projectId,
|
||||||
|
}
|
||||||
|
console.log('params',params)
|
||||||
|
let res = await resubmitApply(params)
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||||
|
await router.push({
|
||||||
|
name: 'Initiation'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getDetailInfo = async () => {
|
||||||
|
getApplyDetail(route.query.projectId).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
if (res.code === 1000) {
|
||||||
|
formData.value = res.data.formData
|
||||||
|
loading.value=false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const init = () => {
|
||||||
|
getApplyProcess(route.query.projectId).then(res => {
|
||||||
|
ElNotification({
|
||||||
|
title: '提示',
|
||||||
|
message: res.msg,
|
||||||
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
|
})
|
||||||
|
processDiagramViewer.value = false
|
||||||
|
if (res.code === 1000) {
|
||||||
|
let data = res.data
|
||||||
|
deploymentId.value=data.deploymentId
|
||||||
|
processInstanceData.value = data
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
nextTick(() => {
|
||||||
|
processDiagramViewer.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
init()
|
||||||
|
onMounted(async () => {
|
||||||
|
await init()
|
||||||
|
if (name.value === 'Initiation/edit') {
|
||||||
|
loading.value=true
|
||||||
|
await getDetailInfo()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
183
src/views/project-management/initiation/detail.vue
Normal file
183
src/views/project-management/initiation/detail.vue
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
<template>
|
||||||
|
<steps :active="'2'" @setDetail="setDetail" @stepChange="stepChange">
|
||||||
|
<template #content>
|
||||||
|
<collection-detail
|
||||||
|
:formData="commonForm.formData"
|
||||||
|
:data="commonForm"
|
||||||
|
:processViewer="commonProvessViewer"
|
||||||
|
:companyOption="companyOption"
|
||||||
|
v-show="showActive == '00'"
|
||||||
|
:loading="loading"
|
||||||
|
/>
|
||||||
|
<summary-detail v-show="showActive == '10'" :formData="commonForm.formData" :data="commonForm" :processViewer="commonProvessViewer" :loading="loading"/>
|
||||||
|
<ApprovalDetail v-show="showActive == '20'" :formData="commonForm.formData" :data="commonForm" :processViewer="commonProvessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
<ApprovalDetail type="execute" v-show="showActive == '40'" :formData="commonForm.formData" :data="commonForm"
|
||||||
|
:processViewer="commonProvessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
<ApprovalDetail type="archivist" v-show="showActive == '50'" :formData="commonForm.formData" :data="commonForm"
|
||||||
|
:processViewer="commonProvessViewer" :loading="loading"></ApprovalDetail>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</steps>
|
||||||
|
<opinion v-if="commonForm.taskId" :formData="commonForm.formData" :taskId="commonForm.taskId"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import {getInfo} from "@/api/project-demand/index.js";
|
||||||
|
import {getSubCompOpt} from '@/api/user/user.js'
|
||||||
|
import {useProcessStore} from '@/stores/processStore.js';
|
||||||
|
import CollectionDetail from "@/components/DetailComponent/CollectionDetail.vue";
|
||||||
|
import {downloadFile} from "@/api/project-demand";
|
||||||
|
import SummaryDetail from "@/components/DetailComponent/SummaryDetail.vue";
|
||||||
|
import ApprovalDetail from "@/components/DetailComponent/ApprovalDetail.vue";
|
||||||
|
import { getMapProjectStateInfo } from '@/components/steps/api';
|
||||||
|
import { ElLoading } from "element-plus";
|
||||||
|
import Opinion from "@/components/DetailComponent/Opinion.vue";
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const activeName = ref('first')
|
||||||
|
const collectionData = ref({})
|
||||||
|
const summaryData = ref({})
|
||||||
|
const collectionProcessViewer = ref(true)
|
||||||
|
const loading = ref(false)
|
||||||
|
const active = ref(route.query.state)
|
||||||
|
const summaryProcessViewer = ref(true)
|
||||||
|
const processStore = useProcessStore()
|
||||||
|
const companyOption = ref([])
|
||||||
|
const rules = reactive({
|
||||||
|
auditOpinion: [{required: true, message: '请输入审核意见', trigger: 'blur'}],
|
||||||
|
})
|
||||||
|
const getCompanyOption = async () => {
|
||||||
|
const res = await getSubCompOpt()
|
||||||
|
companyOption.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDemandCollectionInfo = async () => {
|
||||||
|
if (!route.query.id) return
|
||||||
|
await getCompanyOption()
|
||||||
|
collectionProcessViewer.value = false
|
||||||
|
getInfo(route.query.id).then(res => {
|
||||||
|
let data = res.data
|
||||||
|
collectionData.value = data;
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
nextTick(() => {
|
||||||
|
collectionProcessViewer.value = true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getDemandSummaryInfo = async () => {
|
||||||
|
if (!route.query.id) return
|
||||||
|
// await getCompanyOption()
|
||||||
|
summaryProcessViewer.value = false
|
||||||
|
getInfo(route.query.id).then(res => {
|
||||||
|
let data = res.data
|
||||||
|
summaryData.value = data;
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
nextTick(() => {
|
||||||
|
summaryProcessViewer.value = true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClick = (tab, event) => {
|
||||||
|
console.log(tab, event)
|
||||||
|
if (tab.props.name === 'first') {
|
||||||
|
getDemandCollectionInfo()
|
||||||
|
} else if (tab.props.name === 'second') {
|
||||||
|
getDemandSummaryInfo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// getDemandCollectionInfo()
|
||||||
|
|
||||||
|
const commonForm = ref({})
|
||||||
|
const commonProvessViewer = ref(true)
|
||||||
|
|
||||||
|
const getAllInfo = async (state) => {
|
||||||
|
const loading = ElLoading.service({fullscreen: true})
|
||||||
|
try {
|
||||||
|
state == '00' && ( await getCompanyOption() )
|
||||||
|
commonProvessViewer.value = false
|
||||||
|
loading.value = true
|
||||||
|
const { data, code } = await getMapProjectStateInfo(route.query.projectId, state)
|
||||||
|
if(state == '00') {
|
||||||
|
collectionData.value = data;
|
||||||
|
} else if(state == '10') {
|
||||||
|
summaryData.value = data;
|
||||||
|
}
|
||||||
|
if(code===1000){
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
console.log(data, 'data--22');
|
||||||
|
commonForm.value = data
|
||||||
|
processStore.setDesign(data)
|
||||||
|
processStore.runningList.value = data.runningList;
|
||||||
|
processStore.endList.value = data.endList;
|
||||||
|
processStore.noTakeList.value = data.noTakeList;
|
||||||
|
processStore.refuseList.value = data.refuseList;
|
||||||
|
processStore.passList.value = data.passList;
|
||||||
|
nextTick(() => {
|
||||||
|
// summaryProcessViewer.value = true
|
||||||
|
commonProvessViewer.value = true
|
||||||
|
})
|
||||||
|
loading.close()
|
||||||
|
} catch {
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const showActive = ref()
|
||||||
|
|
||||||
|
const setDetail = (active) => {
|
||||||
|
showActive.value = active
|
||||||
|
getAllInfo(active)
|
||||||
|
}
|
||||||
|
|
||||||
|
const stepChange = (data) => {
|
||||||
|
showActive.value = data.active
|
||||||
|
getAllInfo(data.active)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.detail-block {
|
||||||
|
padding-top: 15px;
|
||||||
|
|
||||||
|
:deep(.el-tabs__nav-scroll) {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.el-tabs__nav {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.el-tabs__item {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-active {
|
||||||
|
color: black;
|
||||||
|
background-color: #DED0B2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.approval-record {
|
||||||
|
padding-bottom: 30px;
|
||||||
|
|
||||||
|
.process {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
230
src/views/project-management/initiation/index.vue
Normal file
230
src/views/project-management/initiation/index.vue
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
<template>
|
||||||
|
<fvSearchForm :searchConfig="searchConfig" @search="search"></fvSearchForm>
|
||||||
|
<fvTable ref="tableIns" :tableConfig="tableConfig">
|
||||||
|
<template #empty>
|
||||||
|
<el-empty description="暂无数据"/>
|
||||||
|
</template>
|
||||||
|
</fvTable>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
|
||||||
|
import {reactive, shallowRef} from "vue";
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const searchConfig = reactive([
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入名称查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目类型',
|
||||||
|
prop: 'collectType',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择项目类型',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目影响',
|
||||||
|
prop: 'projectEffect',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择项目影响',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '研发主体',
|
||||||
|
prop: 'collectType',
|
||||||
|
component: shallowRef(fvSelect),
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择研发主体',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: '起止时间',
|
||||||
|
prop: 'time',
|
||||||
|
component: 'el-date-picker',
|
||||||
|
props: {
|
||||||
|
placeholder: '请选择起止时间',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
colProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '最小金额',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入金额查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '最大金额',
|
||||||
|
prop: 'requirementName',
|
||||||
|
component: 'el-input',
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入金额查询',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
checkStrictly: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const tableIns = ref()
|
||||||
|
const tableConfig = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
prop: 'projectName',
|
||||||
|
label: '名称',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'affiliatedCompany',
|
||||||
|
label: '所属公司',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'approveName',
|
||||||
|
label: '审批人',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectType',
|
||||||
|
label: '项目类型',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'rdSubject',
|
||||||
|
label: '研发主体',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'projectImpact',
|
||||||
|
label: '项目影响',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'economicEstimate',
|
||||||
|
label: '经济概况',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'startTime',
|
||||||
|
label: '起止时间',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'taskNode',
|
||||||
|
label: '当前节点',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'state',
|
||||||
|
label: '状态',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) =>{
|
||||||
|
if (row.state !== null) {
|
||||||
|
return (<Tag dictType={'project_initiation'} value={row.state}/>)
|
||||||
|
} else {
|
||||||
|
return '--'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'oper',
|
||||||
|
label: '操作',
|
||||||
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
|
currentRender: ({row, index}) => {
|
||||||
|
let btn = []
|
||||||
|
let buttons = new Set(Array.from(row.buttons))
|
||||||
|
if (buttons.has("details")) {
|
||||||
|
btn.push({label: '详情', prem: ['mosr:requirement:info'], func: () => handleDetail(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
if (buttons.has("edit")) {
|
||||||
|
btn.push({label: '编辑',prem: ['mosr:requirement:resubmit'], func: () => handleEdit(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
// if (buttons.has("delete")) {
|
||||||
|
// btn.push({label: '删除',prem: ['mosr:requirement:del'], func: () => handleDelete(row), type: 'primary'})
|
||||||
|
// }
|
||||||
|
if (buttons.has("apply")) {
|
||||||
|
btn.push({label: '申请',prem: ['mosr:requirement:info'], func: () => handleApply(row), type: 'primary'})
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div style={{width: '100%'}}>
|
||||||
|
{
|
||||||
|
btn.map(item => (
|
||||||
|
<el-button
|
||||||
|
type={item.type}
|
||||||
|
v-perm={item.prem}
|
||||||
|
onClick={() => item.func()}
|
||||||
|
link
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</el-button>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
api: '/workflow/mosr/project/approval',
|
||||||
|
params: {},
|
||||||
|
})
|
||||||
|
|
||||||
|
const search = (val) => {
|
||||||
|
tableConfig.params = {...val}
|
||||||
|
tableIns.value.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDetail = (row) => {
|
||||||
|
router.push({
|
||||||
|
name:'Initiation/detail',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId,
|
||||||
|
projectId: row.projectId,
|
||||||
|
state: row.state
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleEdit = (row) => {
|
||||||
|
router.push({
|
||||||
|
name:'Initiation/edit',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId,
|
||||||
|
projectId: row.projectId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleApply = (row) => {
|
||||||
|
router.push({
|
||||||
|
name:'Initiation/apply',
|
||||||
|
query: {
|
||||||
|
id: row.requirementId,
|
||||||
|
projectId: row.projectId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
17
src/views/steps/step/Step1.vue
Normal file
17
src/views/steps/step/Step1.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
步骤1
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
console.log('步骤一挂载');
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
17
src/views/steps/step/Step2.vue
Normal file
17
src/views/steps/step/Step2.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
步骤2
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
console.log('步骤一挂载');
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
17
src/views/steps/step/Step3.vue
Normal file
17
src/views/steps/step/Step3.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
步骤1
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
console.log('步骤一挂载');
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
17
src/views/steps/step/Step4.vue
Normal file
17
src/views/steps/step/Step4.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
步骤1
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
console.log('步骤一挂载');
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
17
src/views/steps/step/Step5.vue
Normal file
17
src/views/steps/step/Step5.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
步骤1
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
console.log('步骤1-5挂载');
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
39
src/views/steps/step/index.vue
Normal file
39
src/views/steps/step/index.vue
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<template>
|
||||||
|
<steps :stepList="stepList" :stepSuccess="[0,1]"></steps>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import { reactive, shallowRef } from 'vue';
|
||||||
|
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
|
||||||
|
import Step1 from './Step1.vue'
|
||||||
|
import Step2 from './Step2.vue'
|
||||||
|
import Step3 from './Step3.vue'
|
||||||
|
import Step4 from './Step4.vue'
|
||||||
|
import Step5 from './Step5.vue'
|
||||||
|
const stepList = reactive([
|
||||||
|
{
|
||||||
|
key: 'collect',
|
||||||
|
component: markRaw(Step1)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'report',
|
||||||
|
component: markRaw(Step2)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'approve',
|
||||||
|
component: markRaw(Step3)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'execute',
|
||||||
|
component: markRaw(Step4)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'archivist',
|
||||||
|
component: markRaw(Step5)
|
||||||
|
},
|
||||||
|
])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -90,7 +90,7 @@ const schame = computed(()=>{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '角色权限',
|
label: '角色标识',
|
||||||
prop: 'roleKey',
|
prop: 'roleKey',
|
||||||
component: 'el-input',
|
component: 'el-input',
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ const tableConfig = reactive({
|
|||||||
prop: 'template',
|
prop: 'template',
|
||||||
label: '是否为模版角色',
|
label: '是否为模版角色',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
showOverflowTooltip: false,
|
||||||
currentRender: ({row, index}) => (<Tag dictType={'yes_no'} value={row.template ? '1' : '0'} />)
|
currentRender: ({row, index}) => (<Tag dictType={'yes_no'} value={row.template ? '1' : '0'} />)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -122,6 +123,7 @@ const tableConfig = reactive({
|
|||||||
{
|
{
|
||||||
prop: 'state',
|
prop: 'state',
|
||||||
label: '状态',
|
label: '状态',
|
||||||
|
showOverflowTooltip: false,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
currentRender: ({row, index}) => (<Tag dictType={'normal_disable'} value={row.state} />)
|
currentRender: ({row, index}) => (<Tag dictType={'normal_disable'} value={row.state} />)
|
||||||
},
|
},
|
||||||
@@ -147,7 +149,7 @@ const tableConfig = reactive({
|
|||||||
btn.push({label: '删除', auth: auths.edit, func: ()=>handleDel(row) , type: 'danger'})
|
btn.push({label: '删除', auth: auths.edit, func: ()=>handleDel(row) , type: 'danger'})
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div style={{width: '100%'}}>
|
<div>
|
||||||
{
|
{
|
||||||
btn.map(item=>(
|
btn.map(item=>(
|
||||||
<el-button
|
<el-button
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="jsx">
|
<script setup lang="jsx">
|
||||||
import { addUser, editUser } from '@/api/user/user.js'
|
import { operate } from '@/api/user/user.js'
|
||||||
import { ElLoading, ElNotification } from 'element-plus';
|
import { ElLoading, ElNotification } from 'element-plus';
|
||||||
import { useTagsView } from '@/stores/tagsview.js'
|
import { useTagsView } from '@/stores/tagsview.js'
|
||||||
import { useAuthStore } from '@/stores/userstore.js'
|
import { useAuthStore } from '@/stores/userstore.js'
|
||||||
@@ -43,7 +43,8 @@ const schame = computed(()=>{
|
|||||||
clearable: true,
|
clearable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
checkStrictly: true,
|
checkStrictly: true,
|
||||||
data: localData.subCompanyIdOpt
|
data: localData.subCompanyIdOpt,
|
||||||
|
disabled: route.query.userType == 0 ? true : false
|
||||||
},
|
},
|
||||||
on: {
|
on: {
|
||||||
change: async (val) => {
|
change: async (val) => {
|
||||||
@@ -61,7 +62,8 @@ const schame = computed(()=>{
|
|||||||
clearable: true,
|
clearable: true,
|
||||||
data: localData.departmentIdOpt,
|
data: localData.departmentIdOpt,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
checkStrictly: true
|
checkStrictly: true,
|
||||||
|
disabled: route.query.userType == 0 ? true : false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -69,7 +71,8 @@ const schame = computed(()=>{
|
|||||||
prop: 'userName',
|
prop: 'userName',
|
||||||
component: 'el-input',
|
component: 'el-input',
|
||||||
props: {
|
props: {
|
||||||
placeholder: '请输入'
|
placeholder: '请输入',
|
||||||
|
disabled: route.query.userType == 0 ? true : false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -77,7 +80,8 @@ const schame = computed(()=>{
|
|||||||
prop: 'nickName',
|
prop: 'nickName',
|
||||||
component: 'el-input',
|
component: 'el-input',
|
||||||
props: {
|
props: {
|
||||||
placeholder: '请输入'
|
placeholder: '请输入',
|
||||||
|
disabled: route.query.userType == 0 ? true : false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -86,7 +90,7 @@ const schame = computed(()=>{
|
|||||||
component: 'el-input',
|
component: 'el-input',
|
||||||
props: {
|
props: {
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
type: 'password'
|
type: 'password',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -97,7 +101,8 @@ const schame = computed(()=>{
|
|||||||
placeholder: '请选择',
|
placeholder: '请选择',
|
||||||
filterable: true,
|
filterable: true,
|
||||||
checkStrictly: true,
|
checkStrictly: true,
|
||||||
data: localData.jobOpt
|
data: localData.jobOpt,
|
||||||
|
disabled: route.query.userType == 0 ? true : false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -116,7 +121,8 @@ const schame = computed(()=>{
|
|||||||
component: 'el-tree-select',
|
component: 'el-tree-select',
|
||||||
props: {
|
props: {
|
||||||
placeholder: '请选择',
|
placeholder: '请选择',
|
||||||
data: cacheStore.getDict('user_sex')
|
data: cacheStore.getDict('user_sex'),
|
||||||
|
disabled: route.query.userType == 0 ? true : false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -125,7 +131,8 @@ const schame = computed(()=>{
|
|||||||
component: 'el-tree-select',
|
component: 'el-tree-select',
|
||||||
props: {
|
props: {
|
||||||
placeholder: '请选择',
|
placeholder: '请选择',
|
||||||
data: cacheStore.getDict('normal_disable')
|
data: cacheStore.getDict('normal_disable'),
|
||||||
|
disabled: route.query.userType == 0 ? true : false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -133,7 +140,8 @@ const schame = computed(()=>{
|
|||||||
prop: 'mobile',
|
prop: 'mobile',
|
||||||
component: 'el-input',
|
component: 'el-input',
|
||||||
props: {
|
props: {
|
||||||
placeholder: '请输入'
|
placeholder: '请输入',
|
||||||
|
disabled: route.query.userType == 0 ? true : false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -141,7 +149,8 @@ const schame = computed(()=>{
|
|||||||
prop: 'email',
|
prop: 'email',
|
||||||
component: 'el-input',
|
component: 'el-input',
|
||||||
props: {
|
props: {
|
||||||
placeholder: '请输入'
|
placeholder: '请输入',
|
||||||
|
disabled: route.query.userType == 0 ? true : false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -198,30 +207,20 @@ const getInfo = async () => {
|
|||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
const loading = ElLoading.service({fullscreen: true})
|
const loading = ElLoading.service({fullscreen: true})
|
||||||
try {
|
|
||||||
const { isValidate } = await form.value.validate()
|
const { isValidate } = await form.value.validate()
|
||||||
if(!isValidate) return Promise.reject()
|
if(!isValidate) return Promise.reject()
|
||||||
const values = form.value.getValues()
|
const values = form.value.getValues()
|
||||||
let message
|
operate(values, route.query.userType).then(res=>{
|
||||||
if(route.query.isAdd) {
|
|
||||||
const { code, msg } = await addUser(values)
|
|
||||||
code === 1000 ? message = msg : null
|
|
||||||
} else {
|
|
||||||
const { code, msg } = await editUser(values)
|
|
||||||
code === 1000 ? message = msg : null
|
|
||||||
}
|
|
||||||
ElNotification({
|
ElNotification({
|
||||||
title: route.query.isAdd ? '新增' : '编辑',
|
title: route.query.isAdd ? '新增' : '编辑',
|
||||||
message: message,
|
message: res.msg,
|
||||||
type: 'success'
|
type: res.code === 1000 ? 'success' : 'error'
|
||||||
})
|
})
|
||||||
loading.close()
|
loading.close()
|
||||||
tagsViewStore.delViewAndGoView('/system/user')
|
res.code === 1000 ? tagsViewStore.delViewAndGoView('/system/user') : null
|
||||||
} catch {
|
}).finally(()=>{
|
||||||
loading.close()
|
loading.close()
|
||||||
return Promise.reject()
|
})
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
|
|||||||
@@ -118,15 +118,14 @@ const tableConfig = reactive({
|
|||||||
align: 'center',
|
align: 'center',
|
||||||
currentRender: ({row, index}) => {
|
currentRender: ({row, index}) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
|
||||||
{
|
|
||||||
row.userType == 0 ?
|
|
||||||
'--' :
|
|
||||||
<div>
|
<div>
|
||||||
<el-button type="primary" link onClick={()=>handleEdit(row)}>编辑</el-button>
|
<el-button type="primary" link onClick={()=>handleEdit(row)}>编辑</el-button>
|
||||||
<el-button type="danger" link onClick={()=>handleDel(row)}>删除</el-button>
|
{
|
||||||
</div>
|
row.userType != 0 ?
|
||||||
|
<el-button type="danger" link onClick={()=>handleDel(row)}>删除</el-button> :
|
||||||
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -171,7 +170,8 @@ const handleEdit = (row) => {
|
|||||||
router.push({
|
router.push({
|
||||||
path: '/system/useredit',
|
path: '/system/useredit',
|
||||||
query: {
|
query: {
|
||||||
id: row.userId
|
id: row.userId,
|
||||||
|
userType: row.userType
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
<div v-loading="loading" class="initiate_process">
|
<div v-loading="loading" class="initiate_process">
|
||||||
<div v-if="!loading" style="min-width:30%">
|
<div v-if="!loading" style="min-width:30%">
|
||||||
<!--渲染表单-->
|
<!--渲染表单-->
|
||||||
<form-render class="process-form" ref="initiateForm" :form-items="processDefinition.formItems"
|
<!-- todo 关闭以前的表单渲染 , 此处需要根据参数来定制当前需要展示的页面信息 -->
|
||||||
v-model:value="formData" mode="E"/>
|
<!-- <form-render class="process-form" ref="initiateForm" :form-items="processDefinition.formItems"-->
|
||||||
|
<!-- v-model:value="formData" mode="E"/>-->
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!loading" id="approveTree"
|
<div v-if="!loading" id="approveTree"
|
||||||
style="display: flex;justify-content: center;flex-direction: column;min-width:60%">
|
style="display: flex;justify-content: center;flex-direction: column;min-width:60%">
|
||||||
@@ -18,6 +19,7 @@ import {getInitiateInfo} from "@/api/workflow/process-definition.js";
|
|||||||
import ProcessTree from '@/views/workflow/process/ProcessTree.vue'
|
import ProcessTree from '@/views/workflow/process/ProcessTree.vue'
|
||||||
import FormRender from '@/views/workflow/form/FormRender.vue'
|
import FormRender from '@/views/workflow/form/FormRender.vue'
|
||||||
import {useProcessStore} from '@/stores/processStore.js'
|
import {useProcessStore} from '@/stores/processStore.js'
|
||||||
|
|
||||||
const processStore = useProcessStore()
|
const processStore = useProcessStore()
|
||||||
import {defineProps, defineExpose} from 'vue'
|
import {defineProps, defineExpose} from 'vue'
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
|
|||||||
@@ -40,10 +40,10 @@
|
|||||||
<el-table-column prop="updateTime" label="更新时间" align="center"/>
|
<el-table-column prop="updateTime" label="更新时间" align="center"/>
|
||||||
<el-table-column label="操作" align="center">
|
<el-table-column label="操作" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="primary" size="mini" v-perm="['rapid:regular:edit']"
|
<el-button type="primary" size="mini"
|
||||||
@click="handleApprove(scope.row)" link>发起流程
|
@click="handleApprove(scope.row)" link>发起流程
|
||||||
</el-button>
|
</el-button>
|
||||||
<popover-delete :name="scope.row.deploymentName" :type="'流程'" :perm="['rapid:regular:del']"
|
<popover-delete :name="scope.row.deploymentName" :type="'流程'"
|
||||||
@delete="handleDelete(scope.row.id)"/>
|
@delete="handleDelete(scope.row.id)"/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -101,6 +101,7 @@ const handleReset = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
|
// todo 重新编写表单数据, 不适用当前的动态表单
|
||||||
let formData = processInstance.value.formData
|
let formData = processInstance.value.formData
|
||||||
let paramsData = {
|
let paramsData = {
|
||||||
processDefinitionId: selectItem.value.processDefinitionId,
|
processDefinitionId: selectItem.value.processDefinitionId,
|
||||||
|
|||||||
@@ -29,8 +29,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="height: 15px;background:#f5f5f5;"></div>
|
<div style="height: 15px;background:#f5f5f5;"></div>
|
||||||
<form-render ref="taskViewForm" :form-items="processInstanceData.formItems"
|
<!-- <form-render ref="taskViewForm" :form-items="processInstanceData.formItems"-->
|
||||||
v-model:value="processInstanceData.formData"/>
|
<!-- v-model:value="processInstanceData.formData"/>-->
|
||||||
<div style="height: 15px;background:#f5f5f5;"></div>
|
<div style="height: 15px;background:#f5f5f5;"></div>
|
||||||
<operation-render :operation-list="processInstanceData.operationList"
|
<operation-render :operation-list="processInstanceData.operationList"
|
||||||
:state="instance.state"/>
|
:state="instance.state"/>
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import Tag from '@/components/Tag.vue'
|
import Tag from '@/components/Tag.vue'
|
||||||
import FormRender from '@/views/workflow/form/FormRender.vue'
|
// import FormRender from '@/views/workflow/form/FormRender.vue'
|
||||||
import OperationRender from '@/views/workflow/common/OperationRender.vue'
|
import OperationRender from '@/views/workflow/common/OperationRender.vue'
|
||||||
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
|
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
|
||||||
import {getInitiatedInstanceInfo} from "@/api/workflow/process-instance.js";
|
import {getInitiatedInstanceInfo} from "@/api/workflow/process-instance.js";
|
||||||
|
|||||||
@@ -7,46 +7,18 @@
|
|||||||
:color="operation.color"
|
:color="operation.color"
|
||||||
size="large"
|
size="large"
|
||||||
placement="top">
|
placement="top">
|
||||||
|
|
||||||
<el-card>
|
<el-card>
|
||||||
<div style="display: flex;">
|
<div style="display: flex;">
|
||||||
|
<!-- <avatar-ellipsis :row="3" v-if="operation.userInfo.length > 0" :user-info="operation.userInfo"/>-->
|
||||||
<div v-for="(user,index) in operation.userInfo" :key="index" class="avatar_name">
|
<div v-for="(user,index) in operation.userInfo" :key="index" class="avatar_name">
|
||||||
<el-avatar size="large" :src="user.avatar"></el-avatar>
|
<name-circle :user="user"/>
|
||||||
<div v-if="!$slots.dot && operation.userInfo.length > 1"
|
|
||||||
class="el-timeline-item__node" :style="{
|
|
||||||
backgroundColor: user.color
|
|
||||||
}">
|
|
||||||
<el-icon v-if="user.icon" :class="user.class">
|
|
||||||
<component :is="user.icon"/>
|
|
||||||
</el-icon>
|
|
||||||
</div>
|
|
||||||
<el-tooltip effect="dark" :content="user.name" placement="bottom-start">
|
|
||||||
<span class="username">{{ user.name }}</span>
|
|
||||||
</el-tooltip>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-left: 10px;">
|
<div style="margin-left: 10px;">
|
||||||
<div style="color: #c0bebe">{{ operation.operationName }}</div>
|
<div style="color: #c0bebe">{{ operation.operationName }}</div>
|
||||||
<div style="font-size: 14px; font-weight: bold;">{{ operation.remark }}</div>
|
<div style="font-size: 14px; font-weight: bold;">{{ operation.remark }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="operation.comment">
|
|
||||||
<div style="margin-top: 10px;background:#f5f5f5;padding: 10px;">
|
|
||||||
<div>
|
|
||||||
{{ operation.comment.context }}
|
|
||||||
</div>
|
|
||||||
<div style="margin-top: 10px;" v-if="operation.comment.attachments && operation.comment.attachments.length > 0">
|
|
||||||
<template v-for="(item) in getAttachmentList(operation.comment.attachments,true)">
|
|
||||||
<el-image
|
|
||||||
style="width: 100px; height: 100px"
|
|
||||||
:src="item.url"
|
|
||||||
:preview-src-list="[item.url]">
|
|
||||||
</el-image>
|
|
||||||
</template>
|
|
||||||
<div v-for="(file) in getAttachmentList(operation.comment.attachments,false)">
|
|
||||||
<el-link style="color: #2a99ff" :href="file.url" icon="el-icon-document">{{ file.name }}</el-link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-timeline-item>
|
</el-timeline-item>
|
||||||
<el-timeline-item :color="timeline.color" :icon="timeline.icon" size="large">
|
<el-timeline-item :color="timeline.color" :icon="timeline.icon" size="large">
|
||||||
@@ -60,7 +32,8 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {CircleCheckFilled, Close, Loading, MoreFilled} from "@element-plus/icons-vue";
|
import {CircleCheckFilled, Close, Loading, MoreFilled} from "@element-plus/icons-vue";
|
||||||
import {ref,defineProps} from 'vue'
|
import AvatarEllipsis from '../process/common/AvatarEllipsis.vue'
|
||||||
|
import NameCircle from "@/components/NameCircle.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
operationList: {
|
operationList: {
|
||||||
@@ -113,7 +86,7 @@ const init = () => {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
// let operationListNew = []
|
// let operationListNew = []
|
||||||
for (let i = 0;i<props.operationList.length;i++) {
|
for (let i = 0; i < props.operationList?.length; i++) {
|
||||||
let operationNew = initOperationFun(props.operationList[i])
|
let operationNew = initOperationFun(props.operationList[i])
|
||||||
let userList = []
|
let userList = []
|
||||||
if (operationNew.userInfo) {
|
if (operationNew.userInfo) {
|
||||||
@@ -270,25 +243,19 @@ init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
.avatar_name {
|
.avatar_name {
|
||||||
width: 45px;
|
//width: 45px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-timeline-item__node {
|
.el-timeline-item__node {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
right: 1px;
|
right: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.username {
|
|
||||||
width: 45px;
|
|
||||||
padding-top: 2px;
|
|
||||||
text-align: center;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 40px">
|
<div style="margin-top: 40px">
|
||||||
<div :style="'transform: scale('+ scale / 100 +');'">
|
<div :style="'transform: scale('+ scale / 100 +');'">
|
||||||
<div id="previewProcess">
|
<div :id="idName">
|
||||||
<process-tree mode="preview" ref="processTreePreview" id-name="previewProcess"/>
|
<process-tree :mode="mode" ref="processTreePreview" :id-name="idName"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -20,6 +20,15 @@ import ProcessTree from '@/views/workflow/process/ProcessTree.vue'
|
|||||||
|
|
||||||
const processTreePreview = ref()
|
const processTreePreview = ref()
|
||||||
const scale = ref(100)
|
const scale = ref(100)
|
||||||
|
const props = defineProps({
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'preview'
|
||||||
|
},idName:{
|
||||||
|
type:String,
|
||||||
|
default:'previewProcess'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
nextTick(()=>{
|
nextTick(()=>{
|
||||||
processTreePreview.value.init()
|
processTreePreview.value.init()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="margin-top: 15px">
|
<div style="margin-top: 15px">
|
||||||
<el-button @click="changPan('processSetting')">流程设置</el-button>
|
<el-button @click="changPan('processSetting')">流程设置</el-button>
|
||||||
<el-button @click="changPan('formDesign')">表单</el-button>
|
<!-- <el-button @click="changPan('formDesign')">表单</el-button>-->
|
||||||
<el-button @click="changPan('processDesign')">流程</el-button>
|
<el-button @click="changPan('processDesign')">流程</el-button>
|
||||||
<el-button @click="publishProcess">发布</el-button>
|
<el-button @click="publishProcess">发布</el-button>
|
||||||
<div class="layout-body" v-if="visible">
|
<div class="layout-body" v-if="visible">
|
||||||
@@ -11,9 +11,9 @@
|
|||||||
<div v-show="activeSelect === 'processDesign'">
|
<div v-show="activeSelect === 'processDesign'">
|
||||||
<process-design ref="processDesign"/>
|
<process-design ref="processDesign"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="activeSelect === 'formDesign'">
|
<!-- <div v-show="activeSelect === 'formDesign'">-->
|
||||||
<form-design ref="formDesign"/>
|
<!-- <form-design ref="formDesign"/>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -72,7 +72,8 @@ import {ElMessage, ElMessageBox} from "element-plus";
|
|||||||
const processDesign = ref()
|
const processDesign = ref()
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const timer = ref(null)
|
const timer = ref(null)
|
||||||
const validComponents = ref(['processSetting', 'formDesign', 'processDesign'])
|
// const validComponents = ref(['processSetting', 'formDesign', 'processDesign'])
|
||||||
|
const validComponents = ref(['processSetting', 'processDesign'])
|
||||||
// const activeSelect = ref('formDesign')
|
// const activeSelect = ref('formDesign')
|
||||||
// const activeSelect = ref('processSetting')
|
// const activeSelect = ref('processSetting')
|
||||||
const activeSelect = ref('processDesign')
|
const activeSelect = ref('processDesign')
|
||||||
@@ -81,7 +82,7 @@ const validStep = ref(0)
|
|||||||
const validResult = ref({})
|
const validResult = ref({})
|
||||||
const validOptions = ref([
|
const validOptions = ref([
|
||||||
{title: '基础信息', description: '', icon: '', status: ''},
|
{title: '基础信息', description: '', icon: '', status: ''},
|
||||||
{title: '审批表单', description: '', icon: '', status: ''},
|
// {title: '审批表单', description: '', icon: '', status: ''},
|
||||||
{title: '审批流程', description: '', icon: '', status: ''},
|
{title: '审批流程', description: '', icon: '', status: ''},
|
||||||
// {title: '扩展设置', description: '', icon: '', status: ''}
|
// {title: '扩展设置', description: '', icon: '', status: ''}
|
||||||
])
|
])
|
||||||
@@ -118,21 +119,22 @@ const loadInitFrom = () => {
|
|||||||
let design = {
|
let design = {
|
||||||
processDefinitionKey: 'pro' + getRandomId(),
|
processDefinitionKey: 'pro' + getRandomId(),
|
||||||
deploymentName: "未命名表单",
|
deploymentName: "未命名表单",
|
||||||
logo: {
|
processKey: '',
|
||||||
icon: "el-icon-eleme",
|
// logo: {
|
||||||
background: "#1e90ff"
|
// icon: "el-icon-eleme",
|
||||||
},
|
// background: "#1e90ff"
|
||||||
settings: {
|
// },
|
||||||
commiter: [],
|
// settings: {
|
||||||
admin: [],
|
// commiter: [],
|
||||||
sign: false,
|
// admin: [],
|
||||||
notify: {
|
// sign: false,
|
||||||
types: ["APP"],
|
// notify: {
|
||||||
title: "消息通知标题"
|
// types: ["APP"],
|
||||||
}
|
// title: "消息通知标题"
|
||||||
},
|
// }
|
||||||
|
// },
|
||||||
groupId: 1,
|
groupId: 1,
|
||||||
formItems: [],
|
// formItems: [],
|
||||||
process: [
|
process: [
|
||||||
{
|
{
|
||||||
id: "root",
|
id: "root",
|
||||||
@@ -151,6 +153,27 @@ const loadInitFrom = () => {
|
|||||||
type: "END",
|
type: "END",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
processFromPerms: [{
|
||||||
|
id: "projectName",
|
||||||
|
title: "项目名称",
|
||||||
|
required: true,
|
||||||
|
perm: "R"
|
||||||
|
}, {
|
||||||
|
id: "projectType",
|
||||||
|
title: "项目类型",
|
||||||
|
required: true,
|
||||||
|
perm: "R"
|
||||||
|
}, {
|
||||||
|
id: "projectDesc",
|
||||||
|
title: "项目描述",
|
||||||
|
required: true,
|
||||||
|
perm: "R"
|
||||||
|
}, {
|
||||||
|
id: "projectManager",
|
||||||
|
title: "项目经理",
|
||||||
|
required: true,
|
||||||
|
perm: "R"
|
||||||
|
}],
|
||||||
remark: "备注说明"
|
remark: "备注说明"
|
||||||
}
|
}
|
||||||
processStore.setDesign(design)
|
processStore.setDesign(design)
|
||||||
@@ -168,7 +191,7 @@ const getRandomId = () => {
|
|||||||
d = Math.floor(d / 16)
|
d = Math.floor(d / 16)
|
||||||
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
|
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
|
||||||
})
|
})
|
||||||
return 'node_' + id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
const getProcessInfo = async () => {
|
const getProcessInfo = async () => {
|
||||||
|
|||||||
@@ -1,13 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-input v-model="processData.deploymentName" placeholder="请输入流程名称"/>
|
<el-input v-model="processData.deploymentName" placeholder="请输入流程名称"/>
|
||||||
|
<!-- <div v-if="!processData.processDefinitionKey">-->
|
||||||
|
<el-select v-model="processData.processKey" placeholder="请选择流程环节">
|
||||||
|
<el-option v-for="item in optionList" :label="item.label" :value="item.value"/>
|
||||||
|
</el-select>
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div v-else>-->
|
||||||
|
<!-- {{processData.processName}}-->
|
||||||
|
<!-- </div>-->
|
||||||
|
|
||||||
流程设置{{ processData.deploymentName }}
|
流程设置{{ processData.deploymentName }}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {useProcessStore} from '@/stores/processStore.js'
|
import {useProcessStore} from '@/stores/processStore.js'
|
||||||
import {computed, defineExpose} from "vue";
|
import {computed, defineExpose} from "vue";
|
||||||
|
import {getTypeOption} from "@/api/workflow/process-definition";
|
||||||
|
|
||||||
const processStore = useProcessStore()
|
const processStore = useProcessStore()
|
||||||
|
|
||||||
|
const optionList = ref([])
|
||||||
|
|
||||||
const processData = computed(() => {
|
const processData = computed(() => {
|
||||||
return processStore.getDesign()
|
return processStore.getDesign()
|
||||||
})
|
})
|
||||||
@@ -18,9 +31,17 @@ const validate = () => {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
getTypeOption().then(res => {
|
||||||
|
console.log(res)
|
||||||
|
optionList.value = res.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
validate
|
validate
|
||||||
})
|
})
|
||||||
|
init()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const valid = ref(true)
|
|||||||
let vNode = {}
|
let vNode = {}
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
|
// console.log("sdsdsdsdsdsdsd",processStore.getProcess())
|
||||||
processStore.init()
|
processStore.init()
|
||||||
initMapping(processStore.getProcess())
|
initMapping(processStore.getProcess())
|
||||||
// 定义类名(可忽略)
|
// 定义类名(可忽略)
|
||||||
@@ -48,7 +49,7 @@ const init = () => {
|
|||||||
|
|
||||||
// 初始化map集合,以便数据整理
|
// 初始化map集合,以便数据整理
|
||||||
const initMapping = (node) => {
|
const initMapping = (node) => {
|
||||||
node.forEach(nodeItem => {
|
node?.forEach(nodeItem => {
|
||||||
processStore.nodeMap.set(nodeItem.id, nodeItem)
|
processStore.nodeMap.set(nodeItem.id, nodeItem)
|
||||||
processStore.parentMap.set(nodeItem.parentId, nodeItem)
|
processStore.parentMap.set(nodeItem.parentId, nodeItem)
|
||||||
})
|
})
|
||||||
@@ -57,15 +58,15 @@ const initMapping = (node) => {
|
|||||||
const initHeaderBgc = (node) => {
|
const initHeaderBgc = (node) => {
|
||||||
if (node.props && props.mode === 'preview') {
|
if (node.props && props.mode === 'preview') {
|
||||||
let headerBgc = '#ff943e'
|
let headerBgc = '#ff943e'
|
||||||
if (processStore.runningList.value.includes(node.id)) {
|
if (processStore.runningList.value?.includes(node.id)) {
|
||||||
headerBgc = '#1e90ff'
|
headerBgc = '#1e90ff'
|
||||||
} else if (processStore.endList.value.includes(node.id)) {
|
} else if (processStore.endList.value?.includes(node.id)) {
|
||||||
headerBgc = '#20b2aa'
|
headerBgc = '#20b2aa'
|
||||||
} else if (processStore.noTakeList.value.includes(node.id)) {
|
} else if (processStore.noTakeList.value?.includes(node.id)) {
|
||||||
headerBgc = '#909399'
|
headerBgc = '#909399'
|
||||||
} else if (processStore.refuseList.value.includes(node.id)) {
|
} else if (processStore.refuseList.value?.includes(node.id)) {
|
||||||
headerBgc = '#f56c6c'
|
headerBgc = '#f56c6c'
|
||||||
} else if (processStore.passList.value.includes(node.id)) {
|
} else if (processStore.passList.value?.includes(node.id)) {
|
||||||
headerBgc = '#ff943e'
|
headerBgc = '#ff943e'
|
||||||
}
|
}
|
||||||
node.props.headerBgc = headerBgc
|
node.props.headerBgc = headerBgc
|
||||||
@@ -309,9 +310,9 @@ const insertNode = debounce((type, parentNode) => {
|
|||||||
case 'DELAY':
|
case 'DELAY':
|
||||||
insertDelayNode(children);
|
insertDelayNode(children);
|
||||||
break;
|
break;
|
||||||
case 'TRIGGER':
|
// case 'TRIGGER':
|
||||||
insertTriggerNode(children);
|
// insertTriggerNode(children);
|
||||||
break;
|
// break;
|
||||||
case 'CONDITIONS':
|
case 'CONDITIONS':
|
||||||
insertConditionsNode(children);
|
insertConditionsNode(children);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
<slot name="pre"></slot>
|
<slot name="pre"></slot>
|
||||||
<div style="display: flex;flex-wrap: wrap;">
|
<div style="display: flex;flex-wrap: wrap;">
|
||||||
<div v-for="(user,index) in userInfo" :key="index" class="avatar_name">
|
<div v-for="(user,index) in userInfo" :key="index" class="avatar_name">
|
||||||
<el-avatar size="large"
|
<div class="circle-user">
|
||||||
:src="user.avatar"></el-avatar>
|
<Tooltip :content="user.name" placement="bottom-start" width="45">
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
<div v-if="user.icon"
|
<div v-if="user.icon"
|
||||||
class="el-timeline-item__node" :style="{
|
class="el-timeline-item__node" :style="{
|
||||||
backgroundColor: user.color
|
backgroundColor: user.color
|
||||||
@@ -15,9 +17,6 @@
|
|||||||
<component :is="user.icon"/>
|
<component :is="user.icon"/>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
<el-tooltip class="item" effect="dark" :content="user.name" placement="bottom-start">
|
|
||||||
<span class="item_name">{{ user.name }}</span>
|
|
||||||
</el-tooltip>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -26,6 +25,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {Loading, Close, CircleCheckFilled, MoreFilled} from '@element-plus/icons-vue'
|
import {Loading, Close, CircleCheckFilled, MoreFilled} from '@element-plus/icons-vue'
|
||||||
import {defineProps} from "vue";
|
import {defineProps} from "vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
row: {
|
row: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -38,6 +38,10 @@ const props = defineProps({
|
|||||||
userInfo: {
|
userInfo: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: []
|
default: []
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'design'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -80,7 +84,27 @@ const initUser = (user) => {
|
|||||||
init()
|
init()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped lang="scss">
|
||||||
|
.circle-user {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #ACACAC;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.circle-icon {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
position: absolute;
|
||||||
|
top: auto !important;
|
||||||
|
bottom: -9px;
|
||||||
|
right: 15px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.avatar_name {
|
.avatar_name {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -92,16 +116,8 @@ init()
|
|||||||
|
|
||||||
.el-timeline-item__node {
|
.el-timeline-item__node {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 20px;
|
bottom: 0;
|
||||||
right: 1px;
|
right: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item_name {
|
|
||||||
width: 45px;
|
|
||||||
text-align: center;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
padding-top: 3px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -31,12 +31,12 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
<span>延迟等待</span>
|
<span>延迟等待</span>
|
||||||
</div>
|
</div>
|
||||||
<div @click="addTriggerNode">
|
<!-- <div @click="addTriggerNode">-->
|
||||||
<el-icon style="color:#15BC83;">
|
<!-- <el-icon style="color:#15BC83;">-->
|
||||||
<SetUp/>
|
<!-- <SetUp/>-->
|
||||||
</el-icon>
|
<!-- </el-icon>-->
|
||||||
<span>触发器</span>
|
<!-- <span>触发器</span>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
</div>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<!-- <el-button :icon="Plus" slot="reference" type="primary" @click="visible = !visible" size="small"-->
|
<!-- <el-button :icon="Plus" slot="reference" type="primary" @click="visible = !visible" size="small"-->
|
||||||
|
|||||||
@@ -5,19 +5,15 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="picker">
|
<div class="picker">
|
||||||
<div class="candidate" v-loading="loading">
|
<div class="candidate" v-loading="loading">
|
||||||
<div style="padding: 5px 8px;">
|
<el-input v-model="filterText" @change="getList(1)"
|
||||||
<el-input v-model="filterText" style="width: 100%;" size="small"
|
clearable placeholder="输入部门/昵称进行搜索">
|
||||||
clearable placeholder="输入关键字进行过滤" prefix-icon="el-icon-search"/>
|
<template #append>
|
||||||
<div style="margin-top: 5px">
|
<el-button @click="getList(1)">搜索</el-button>
|
||||||
<el-radio-group v-model="radio" size="mini" @change="radioChange">
|
</template>
|
||||||
<el-radio-button :label="0">角色</el-radio-button>
|
</el-input>
|
||||||
<el-radio-button :label="1">部门</el-radio-button>
|
|
||||||
</el-radio-group>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 人员选择 -->
|
<!-- 人员选择 -->
|
||||||
<el-empty :image-size="100" description="似乎没有数据" v-show="dataList.length === 0"/>
|
<el-empty :image-size="100" description="似乎没有数据" v-show="dataList.length === 0"/>
|
||||||
<el-scrollbar style="height:317px">
|
<el-scrollbar style="height:340px">
|
||||||
<div class="tree">
|
<div class="tree">
|
||||||
<el-tree :data="dataList" ref="tree" :props="defaultProps" empty-text="" node-key="value"
|
<el-tree :data="dataList" ref="tree" :props="defaultProps" empty-text="" node-key="value"
|
||||||
:default-expanded-keys="expandedKeys" lazy accordion
|
:default-expanded-keys="expandedKeys" lazy accordion
|
||||||
@@ -26,7 +22,9 @@
|
|||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<div class="tree-node">
|
<div class="tree-node">
|
||||||
<div v-if="data.type === 0" style="display: flex;align-items: center;padding: 3px 0">
|
<div v-if="data.type === 0" style="display: flex;align-items: center;padding: 3px 0">
|
||||||
<!-- <el-avatar :src="data.avatar"></el-avatar>-->
|
<el-icon>
|
||||||
|
<UserFilled/>
|
||||||
|
</el-icon>
|
||||||
{{ node.label }}
|
{{ node.label }}
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="data.type ===1">
|
<div v-else-if="data.type ===1">
|
||||||
@@ -71,9 +69,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {getUserTree} from "@/api/workflow/process-user";
|
|
||||||
import {computed, defineProps, defineExpose} from "vue";
|
import {computed, defineProps, defineExpose} from "vue";
|
||||||
import {ElMessageBox} from "element-plus";
|
import {ElMessageBox} from "element-plus";
|
||||||
|
import {getMosrDept} from "@/api/workflow/process-user";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: {
|
value: {
|
||||||
@@ -105,16 +103,19 @@ const selectList = ref([]);
|
|||||||
const filterText = ref("");
|
const filterText = ref("");
|
||||||
const dataList = ref([]);
|
const dataList = ref([]);
|
||||||
const tree = ref([]);
|
const tree = ref([]);
|
||||||
|
const isSearch = ref(false);
|
||||||
const expandedKeys = ref([]);
|
const expandedKeys = ref([]);
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
value: "value",
|
value: "value",
|
||||||
label: "name",
|
label: "name",
|
||||||
children: "children",
|
children: "children",
|
||||||
isLeaf:(data, node) => {
|
// isLeaf:(data, node) =>
|
||||||
if (node.level === 2) {
|
// {
|
||||||
return true
|
// console.log('data, node',data, node)
|
||||||
}
|
// if (node.level === 2) {
|
||||||
}
|
// return true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
};
|
};
|
||||||
const emit = defineEmits();
|
const emit = defineEmits();
|
||||||
@@ -128,27 +129,38 @@ const _value = computed({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => filterText, (newVal, oldVal) => {
|
watch(() => filterText.value, (newVal) => {
|
||||||
tree.value.filter(newVal);
|
console.log('filterText.value', newVal)
|
||||||
|
filterText.value = newVal
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getList = (flag) => {
|
||||||
const radioChange = (e) => {
|
let params = {}
|
||||||
selectItem.type = -2;
|
if (flag === 1) {
|
||||||
chooseId.value = 0;
|
isSearch.value = true;
|
||||||
radio.value = e;
|
params = {
|
||||||
expandedKeys.value = [];
|
chooseId: 0,
|
||||||
getList();
|
chooseName: filterText.value
|
||||||
|
}
|
||||||
|
selectItem = {
|
||||||
|
type: -1,
|
||||||
|
value: "0"
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
|
||||||
const getList = () => {
|
params = {
|
||||||
getUserTree(radio.value, chooseId.value).then(res => {
|
chooseId: radio.value,
|
||||||
|
chooseName: filterText.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getMosrDept(params).then(res => {
|
||||||
|
console.log('selectItem.type', selectItem.type)
|
||||||
// if (res.data) {
|
// if (res.data) {
|
||||||
if (selectItem.type === -1 || selectItem.type === -2) {//角色/部门
|
if (selectItem.type === -1) {
|
||||||
dataList.value = res.data;
|
dataList.value = res.data;
|
||||||
} else if (selectItem.type === 1) {
|
} else if (selectItem.type === 1) {
|
||||||
selectItem.children = res.data;
|
selectItem.children = res.data;
|
||||||
if(chooseId.value!==0&&res.data.length===0){
|
if (res.data.length === 0) {
|
||||||
selectItem.children = [{
|
selectItem.children = [{
|
||||||
type: 1,
|
type: 1,
|
||||||
name: '暂无数据'
|
name: '暂无数据'
|
||||||
@@ -187,19 +199,27 @@ const showUserPicker = () => {
|
|||||||
expandedKeys.value = [];
|
expandedKeys.value = [];
|
||||||
getList();
|
getList();
|
||||||
};
|
};
|
||||||
const handleChange = (item, data, node) => {
|
const handleChange = (item, data) => {
|
||||||
//渲染子节点用户或部门及用户数据
|
console.log('item', item, data)
|
||||||
selectItem = item;
|
selectItem = item;
|
||||||
|
if (isSearch.value && item.type !== 0) {
|
||||||
|
filterText.value = ""
|
||||||
|
radio.value = item.id;
|
||||||
|
getList();
|
||||||
|
return;
|
||||||
|
} else if (!isSearch.value) {
|
||||||
|
//渲染子节点用户或部门及用户数据
|
||||||
if (data.expanded) {
|
if (data.expanded) {
|
||||||
if (expandedKeys.value.indexOf(item.value) === -1) {
|
if (expandedKeys.value.indexOf(item.value) === -1) {
|
||||||
expandedKeys.value.push(item.value);
|
expandedKeys.value.push(item.value);
|
||||||
if (item.type !== 0) {
|
if (item.type !== 0) {
|
||||||
chooseId.value = item.id;
|
radio.value = item.id;
|
||||||
getList();
|
getList();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if(expandedKeys.value.indexOf(item.value)==-1){
|
// if(expandedKeys.value.indexOf(item.value)==-1){
|
||||||
// expandedKeys.value.push(item.value);
|
// expandedKeys.value.push(item.value);
|
||||||
@@ -271,7 +291,6 @@ $containWidth: 264px;
|
|||||||
.el-tree-node {
|
.el-tree-node {
|
||||||
.el-tree-node__content {
|
.el-tree-node__content {
|
||||||
//height: 45px !important;
|
//height: 45px !important;
|
||||||
|
|
||||||
.tree-node {
|
.tree-node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
<el-input-number :min="1" :max="20" :step="1" size="mini"
|
<el-input-number :min="1" :max="20" :step="1" size="mini"
|
||||||
v-model="nodeProps.leader.level"></el-input-number>
|
v-model="nodeProps.leader.level"></el-input-number>
|
||||||
<span> 级主管</span>
|
<span> 级主管</span>
|
||||||
<div style="color: #409EFF; font-size: small;">👉 直接主管为 第 1 级主管</div>
|
<div style="color: #409EFF; font-size: small;">直接主管为 第 1 级主管</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="nodeProps.assignedType === 'ROLE'">
|
<div v-else-if="nodeProps.assignedType === 'ROLE'">
|
||||||
@@ -56,12 +56,12 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<!-- <div v-else>-->
|
||||||
<span class="item-desc">发起人自己作为审批人进行审批</span>
|
<!-- <span class="item-desc">发起人自己作为审批人进行审批</span>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-divider></el-divider>
|
<el-divider></el-divider>
|
||||||
<el-form-item label="👤 审批人为空时" prop="text" class="line-mode">
|
<el-form-item label="审批人为空时" prop="text" class="line-mode">
|
||||||
<el-radio-group v-model="nodeProps.nobody.handler">
|
<el-radio-group v-model="nodeProps.nobody.handler">
|
||||||
<el-radio label="TO_PASS">自动通过</el-radio>
|
<el-radio label="TO_PASS">自动通过</el-radio>
|
||||||
<el-radio label="TO_REFUSE">自动驳回</el-radio>
|
<el-radio label="TO_REFUSE">自动驳回</el-radio>
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
|
|
||||||
<div v-if="showMode">
|
<div v-if="showMode">
|
||||||
<el-divider/>
|
<el-divider/>
|
||||||
<el-form-item label="👩👦👦 多人审批时审批方式" prop="text" class="approve-mode">
|
<el-form-item label="多人审批时审批方式" prop="text" class="approve-mode">
|
||||||
<el-radio-group v-model="nodeProps.mode">
|
<el-radio-group v-model="nodeProps.mode">
|
||||||
<el-radio label="NEXT">会签 (按选择顺序审批,每个人必须同意)</el-radio>
|
<el-radio label="NEXT">会签 (按选择顺序审批,每个人必须同意)</el-radio>
|
||||||
<el-radio label="AND">会签(可同时审批,每个人必须同意)</el-radio>
|
<el-radio label="AND">会签(可同时审批,每个人必须同意)</el-radio>
|
||||||
@@ -90,13 +90,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-divider>高级设置</el-divider>
|
<el-divider>高级设置</el-divider>
|
||||||
<el-form-item label="✍ 审批同意时是否需要签字" prop="text">
|
<!-- <el-form-item label="✍ 审批同意时是否需要签字" prop="text">-->
|
||||||
<el-switch inactive-text="不用" active-text="需要" v-model="nodeProps.sign"></el-switch>
|
<!-- <el-switch inactive-text="不用" active-text="需要" v-model="nodeProps.sign"></el-switch>-->
|
||||||
<el-tooltip class="item" effect="dark" content="如果全局设置了需要签字,则此处不生效" placement="top-start">
|
<!-- <el-tooltip class="item" effect="dark" content="如果全局设置了需要签字,则此处不生效" placement="top-start">-->
|
||||||
<i class="el-icon-question" style="margin-left: 10px; font-size: medium; color: #b0b0b1"></i>
|
<!-- <i class="el-icon-question" style="margin-left: 10px; font-size: medium; color: #b0b0b1"></i>-->
|
||||||
</el-tooltip>
|
<!-- </el-tooltip>-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<el-form-item label="是否使用矩阵审批" prop="text">
|
||||||
|
<el-switch inactive-text="不用" active-text="使用" v-model="nodeProps.matrixApproval"></el-switch>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="⏱ 审批期限(为 0 则不生效)" prop="timeLimit">
|
<el-form-item label="审批期限(为 0 则不生效)" prop="timeLimit">
|
||||||
<el-input style="width: 180px;" placeholder="时长" type="number"
|
<el-input style="width: 180px;" placeholder="时长" type="number"
|
||||||
v-model="nodeProps.timeLimit.timeout.value">
|
v-model="nodeProps.timeLimit.timeout.value">
|
||||||
<el-select style="width: 75px;" v-model="nodeProps.timeLimit.timeout.unit" slot="append" placeholder="请选择" filterable>
|
<el-select style="width: 75px;" v-model="nodeProps.timeLimit.timeout.unit" slot="append" placeholder="请选择" filterable>
|
||||||
@@ -122,54 +125,54 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="🙅 如果审批被驳回 👇">
|
<!-- <el-form-item label="🙅 如果审批被驳回 👇">-->
|
||||||
<el-radio-group v-model="nodeProps.refuse.type">
|
<!-- <el-radio-group v-model="nodeProps.refuse.type">-->
|
||||||
<el-radio label="TO_INITIAL">重新开始流程</el-radio>
|
<!-- <el-radio label="TO_INITIAL">重新开始流程</el-radio>-->
|
||||||
<el-radio label="TO_BEFORE">驳回到上级审批节点</el-radio>
|
<!-- <el-radio label="TO_BEFORE">驳回到上级审批节点</el-radio>-->
|
||||||
<el-radio label="TO_NODE">驳回到指定节点</el-radio>
|
<!-- <el-radio label="TO_NODE">驳回到指定节点</el-radio>-->
|
||||||
</el-radio-group>
|
<!-- </el-radio-group>-->
|
||||||
<div v-if="nodeProps.refuse.type === 'TO_NODE'">
|
<!-- <div v-if="nodeProps.refuse.type === 'TO_NODE'">-->
|
||||||
<span>指定节点:</span>
|
<!-- <span>指定节点:</span>-->
|
||||||
<el-select style="margin-left: 10px; width: 150px;" placeholder="选择跳转步骤" size="small"
|
<!-- <el-select style="margin-left: 10px; width: 150px;" placeholder="选择跳转步骤" size="small"-->
|
||||||
v-model="nodeProps.refuse.target" filterable>
|
<!-- v-model="nodeProps.refuse.target" filterable>-->
|
||||||
<el-option v-for="(node, index) in nodeOptions" :key="index" :label="node.name"
|
<!-- <el-option v-for="(node, index) in nodeOptions" :key="index" :label="node.name"-->
|
||||||
:value="node.id"></el-option>
|
<!-- :value="node.id"></el-option>-->
|
||||||
</el-select>
|
<!-- </el-select>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</el-form-item>
|
<!-- </el-form-item>-->
|
||||||
<el-form-item label="自定义监听器">
|
<!-- <el-form-item label="自定义监听器">-->
|
||||||
<div slot="label">
|
<!-- <div slot="label">-->
|
||||||
<span style="margin-left: 20px">使用自定义监听器: </span>
|
<!-- <span style="margin-left: 20px">使用自定义监听器: </span>-->
|
||||||
<!-- <el-switch v-model="config.listener.state" @change="getListener"></el-switch>-->
|
<!-- <!– <el-switch v-model="config.listener.state" @change="getListener"></el-switch>–>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div v-if="config.listener.state">
|
<!-- <div v-if="config.listener.state">-->
|
||||||
<div slot="label">
|
<!-- <div slot="label">-->
|
||||||
<span style="margin-right: 10px">设置监听器</span>
|
<!-- <span style="margin-right: 10px">设置监听器</span>-->
|
||||||
<el-button type="primary" @click="addListener(config.listener.list)" link> + 添加</el-button>
|
<!-- <el-button type="primary" @click="addListener(config.listener.list)" link> + 添加</el-button>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div v-for="(listen, index) in config.listener.list" :key="index">
|
<!-- <div v-for="(listen, index) in config.listener.list" :key="index">-->
|
||||||
<el-input v-if="listen.isSys" placeholder="监听器名称" :disabled="true" size="small" style="width: 100px;"
|
<!-- <el-input v-if="listen.isSys" placeholder="监听器名称" :disabled="true" size="small" style="width: 100px;"-->
|
||||||
v-model="listen.listenerName"/>
|
<!-- v-model="listen.listenerName"/>-->
|
||||||
<el-input v-if="!listen.isSys" placeholder="监听器名称" size="small" style="width: 100px;"
|
<!-- <el-input v-if="!listen.isSys" placeholder="监听器名称" size="small" style="width: 100px;"-->
|
||||||
v-model="listen.listenerName"/>
|
<!-- v-model="listen.listenerName"/>-->
|
||||||
<el-radio-group size="small" style="margin: 0 5px;" @change="typeChange(listen)" v-model="listen.isSys">
|
<!-- <el-radio-group size="small" style="margin: 0 5px;" @change="typeChange(listen)" v-model="listen.isSys">-->
|
||||||
<el-radio-button :label="true">内置</el-radio-button>
|
<!-- <el-radio-button :label="true">内置</el-radio-button>-->
|
||||||
<el-radio-button :label="false">自定义</el-radio-button>
|
<!-- <el-radio-button :label="false">自定义</el-radio-button>-->
|
||||||
</el-radio-group>
|
<!-- </el-radio-group>-->
|
||||||
<el-select v-if="listen.isSys" style="width: 180px;" v-model="listen.listenerValue" size="small"
|
<!-- <el-select v-if="listen.isSys" style="width: 180px;" v-model="listen.listenerValue" size="small"-->
|
||||||
@change="listenerOptionChange(listen)"
|
<!-- @change="listenerOptionChange(listen)"-->
|
||||||
placeholder="请选择表单字段" filterable>
|
<!-- placeholder="请选择表单字段" filterable>-->
|
||||||
<el-option v-for="option in listenerOption" :key="option.value" :label="option.label"
|
<!-- <el-option v-for="option in listenerOption" :key="option.value" :label="option.label"-->
|
||||||
:value="option.value"/>
|
<!-- :value="option.value"/>-->
|
||||||
</el-select>
|
<!-- </el-select>-->
|
||||||
<!-- <el-input v-if="listen.isSys" placeholder="请设置字段值" size="small" v-model="listen.listenerValue" style="width: 180px;"/>-->
|
<!-- <!– <el-input v-if="listen.isSys" placeholder="请设置字段值" size="small" v-model="listen.listenerValue" style="width: 180px;"/>–>-->
|
||||||
<el-button v-if="!listen.isSys" type="primary" size="small" @click="settingListener(listen)" link>设置</el-button>
|
<!-- <el-button v-if="!listen.isSys" type="primary" size="small" @click="settingListener(listen)" link>设置</el-button>-->
|
||||||
<el-button @click="delListener(config.listener.list, index)"
|
<!-- <el-button @click="delListener(config.listener.list, index)"-->
|
||||||
class="el-icon-delete" type="primary"
|
<!-- class="el-icon-delete" type="primary"-->
|
||||||
style="margin-left: 5px; color: #c75450;" link/>
|
<!-- style="margin-left: 5px; color: #c75450;" link/>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</el-form-item>
|
<!-- </el-form-item>-->
|
||||||
</el-form>
|
</el-form>
|
||||||
<!--
|
<!--
|
||||||
<el-dialog custom-class="custom-dialog" class="border" width="600px" title="定义监听器设置"
|
<el-dialog custom-class="custom-dialog" class="border" width="600px" title="定义监听器设置"
|
||||||
@@ -230,12 +233,13 @@ const showOrgSelect = ref(false)
|
|||||||
const orgPickerSelected = ref([])
|
const orgPickerSelected = ref([])
|
||||||
const approvalTypes = reactive([
|
const approvalTypes = reactive([
|
||||||
{name: "指定人员", type: "ASSIGN_USER"},
|
{name: "指定人员", type: "ASSIGN_USER"},
|
||||||
{name: "发起人自选", type: "SELF_SELECT"},
|
// {name: "发起人自选", type: "SELF_SELECT"},
|
||||||
{name: "连续多级主管", type: "LEADER_TOP"},
|
// {name: "连续多级主管", type: "LEADER_TOP"},
|
||||||
{name: "主管", type: "LEADER"},
|
// {name: "主管", type: "LEADER"},
|
||||||
{name: "角色", type: "ROLE"},
|
// {name: "角色", type: "ROLE"},
|
||||||
{name: "发起人自己", type: "SELF"},
|
{name: "发起人自己", type: "SELF"},
|
||||||
{name: "表单内联系人", type: "FORM_USER"}
|
// {name: "表单内联系人", type: "FORM_USER"},
|
||||||
|
// {name: "矩阵审批", type: "MATRIX_APPROVAL"},
|
||||||
])
|
])
|
||||||
const listenerOption = ref([])
|
const listenerOption = ref([])
|
||||||
const selectListen = ref({})
|
const selectListen = ref({})
|
||||||
|
|||||||
@@ -94,7 +94,9 @@
|
|||||||
<org-items :modelValue="users"/>
|
<org-items :modelValue="users"/>
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="condition.valueType === ValueType.date"></span>
|
<span v-else-if="condition.valueType === ValueType.date"></span>
|
||||||
<el-icon class="delete-icon" @click="delSubCondition(group, cindex)"><Minus /></el-icon>
|
<el-icon class="delete-icon" @click="delSubCondition(group, cindex)">
|
||||||
|
<Minus/>
|
||||||
|
</el-icon>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
@@ -119,7 +121,7 @@ const users = ref([])
|
|||||||
// const orgType = ref('user')
|
// const orgType = ref('user')
|
||||||
const showOrgSelect = ref(false)
|
const showOrgSelect = ref(false)
|
||||||
const groupNames = ref(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'])
|
const groupNames = ref(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'])
|
||||||
const supportTypes = ref([ValueType.number, ValueType.string, ValueType.date, ValueType.dateRange, ValueType.dept, ValueType.user])
|
const supportTypes = ref([ValueType.number, ValueType.string])
|
||||||
const explains = ref(
|
const explains = ref(
|
||||||
[
|
[
|
||||||
{label: '等于', value: '='},
|
{label: '等于', value: '='},
|
||||||
@@ -140,14 +142,20 @@ const selectedNode = computed(() => {
|
|||||||
return processStore.getSelectedNode()
|
return processStore.getSelectedNode()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const processFromPerms = computed(() => {
|
||||||
|
return processStore.getDesign().processFromPerms;
|
||||||
|
});
|
||||||
|
|
||||||
const conditionList = computed(() => {
|
const conditionList = computed(() => {
|
||||||
//条件数组
|
//条件数组
|
||||||
//构造可用条件选项
|
//构造可用条件选项
|
||||||
const conditionItems = []
|
const conditionItems = []
|
||||||
processStore.getDesign().formItems.forEach(item => filterCondition(item, conditionItems))
|
filterConditionMosr(conditionItems)
|
||||||
if (conditionItems.length === 0 || conditionItems[0].id !== 'root') {
|
// processStore.getDesign().formItems.forEach(item => filterCondition(item, conditionItems))
|
||||||
conditionItems.unshift({id: 'root', title: '发起人', valueType: 'User'})
|
// if (conditionItems.length === 0 || conditionItems[0].id !== 'root') {
|
||||||
}
|
// conditionItems.unshift({id: 'root', title: '发起人', valueType: 'User'})
|
||||||
|
// }
|
||||||
|
// conditionItems.unshift({id: 'root', title: '发起人', valueType: 'User'})
|
||||||
return conditionItems
|
return conditionItems
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -184,6 +192,14 @@ const selectUser = (value, orgType) => {
|
|||||||
users.value = value
|
users.value = value
|
||||||
orgPicker.value.showUserPicker()
|
orgPicker.value.showUserPicker()
|
||||||
}
|
}
|
||||||
|
const filterConditionMosr = (list) => {
|
||||||
|
processFromPerms.value.forEach((item) => {
|
||||||
|
console.log(item)
|
||||||
|
if (item.required && supportTypes.value.indexOf(item.valueType) > -1){
|
||||||
|
list.push({title: item.title, id: item.id, valueType: item.valueType})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const filterCondition = (item, list) => {
|
const filterCondition = (item, list) => {
|
||||||
//从表单中过滤出可以选择的条件
|
//从表单中过滤出可以选择的条件
|
||||||
@@ -206,7 +222,6 @@ const selected = (selected) => {
|
|||||||
users.value = userInfoList
|
users.value = userInfoList
|
||||||
//组织选择器的选中回调函数
|
//组织选择器的选中回调函数
|
||||||
// users.value.length = 0
|
// users.value.length = 0
|
||||||
// console.log('processStore.getAssignedUser()',processStore.getAssignedUser())
|
|
||||||
processStore.getAssignedUser().forEach(u => users.value = userInfoList)
|
processStore.getAssignedUser().forEach(u => users.value = userInfoList)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +243,6 @@ const conditionChange = (index, group) => {
|
|||||||
if (0 > group.conditions.findIndex(cd => cd.id === cid)) {
|
if (0 > group.conditions.findIndex(cd => cd.id === cid)) {
|
||||||
//新增条件
|
//新增条件
|
||||||
let condition = {...conditionList.value[index]}
|
let condition = {...conditionList.value[index]}
|
||||||
console.log('fs', condition, conditionList.value, index)
|
|
||||||
condition.compare = '';
|
condition.compare = '';
|
||||||
condition.value = []
|
condition.value = []
|
||||||
group.conditions.push(condition)
|
group.conditions.push(condition)
|
||||||
|
|||||||
@@ -18,24 +18,24 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="条件组关系" label-width="150px">
|
<!-- <el-form-item label="条件组关系" label-width="150px">-->
|
||||||
<el-switch v-model="selectedNode.props.groupsType" active-color="#409EFF"
|
<!-- <el-switch v-model="selectedNode.props.groupsType" active-color="#409EFF"-->
|
||||||
inactive-color="#c1c1c1" active-value="AND" inactive-value="OR"
|
<!-- inactive-color="#c1c1c1" active-value="AND" inactive-value="OR"-->
|
||||||
active-text="且" inactive-text="或">
|
<!-- active-text="且" inactive-text="或">-->
|
||||||
</el-switch>
|
<!-- </el-switch>-->
|
||||||
</el-form-item>
|
<!-- </el-form-item>-->
|
||||||
<el-form-item label="条件组表达式">
|
<!-- <el-form-item label="条件组表达式">-->
|
||||||
<el-input v-model="config.expression" placeholder="输入条件组关系表达式 &为与,|为或"/>
|
<!-- <el-input v-model="config.expression" placeholder="输入条件组关系表达式 &为与,|为或"/>-->
|
||||||
<span class="item-desc">使用表达式构建复杂逻辑,例如: (A & B) | C</span>
|
<!-- <span class="item-desc">使用表达式构建复杂逻辑,例如: (A & B) | C</span>-->
|
||||||
</el-form-item>
|
<!-- </el-form-item>-->
|
||||||
</el-form>
|
</el-form>
|
||||||
<div>
|
<!-- <div>-->
|
||||||
<el-button type="primary" icon="Plus" style="margin: 0 15px 15px 0" round
|
<!-- <el-button type="primary" icon="Plus" style="margin: 0 15px 15px 0" round-->
|
||||||
@click="addConditionGroup">
|
<!-- @click="addConditionGroup">-->
|
||||||
添加条件组
|
<!-- 添加条件组-->
|
||||||
</el-button>
|
<!-- </el-button>-->
|
||||||
<span class="item-desc">只有必填选项才能作为审批条件</span>
|
<!-- <span class="item-desc">只有必填选项才能作为审批条件</span>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<group-item/>
|
<group-item/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {defineProps, watch,computed} from "vue";
|
import {defineProps, computed} from "vue";
|
||||||
|
|
||||||
import {useProcessStore} from "@/stores/processStore.js";
|
import {useProcessStore} from "@/stores/processStore.js";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -45,18 +44,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
const processStore = useProcessStore();
|
const processStore = useProcessStore();
|
||||||
|
|
||||||
const tableData = ref([]);
|
|
||||||
const isIndeterminate = ref(false);
|
|
||||||
const permSelect = ref("");
|
const permSelect = ref("");
|
||||||
const checkStatus = reactive({
|
|
||||||
readOnly: true,
|
|
||||||
editable: false,
|
|
||||||
hide: false
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
let oldPermMap = new Map()
|
let oldPermMap = new Map()
|
||||||
@@ -66,7 +54,7 @@ const init = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
processStore.getSelectedNode().props.formPerms = [];
|
processStore.getSelectedNode().props.formPerms = [];
|
||||||
formPermsLoad(oldPermMap, processStore.getDesign().formItems);
|
formPermsLoadMosr(oldPermMap, processFromPerms.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const formPerms = computed(() => {
|
const formPerms = computed(() => {
|
||||||
@@ -81,12 +69,39 @@ const formItems = computed(() => {
|
|||||||
return processStore.getDesign().formItems;
|
return processStore.getDesign().formItems;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const processFromPerms = computed(() => {
|
||||||
|
return processStore.getDesign().processFromPerms;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const allSelect = (type) => {
|
const allSelect = (type) => {
|
||||||
permSelect.value = type;
|
permSelect.value = type;
|
||||||
formPerms.value.forEach(f => f.perm = type);
|
formPerms.value.forEach(f => f.perm = type);
|
||||||
};
|
};
|
||||||
|
const formPermsLoadMosr = (oldPermMap, perms) => {
|
||||||
|
|
||||||
|
perms.forEach(perm =>{
|
||||||
|
//刷新名称
|
||||||
|
let old = oldPermMap.get(perm.id)
|
||||||
|
if (old) {
|
||||||
|
old.title = perm.title;
|
||||||
|
old.required = perm.required;
|
||||||
|
formPerms.value.push(old);
|
||||||
|
} else {
|
||||||
|
formPerms.value.push({
|
||||||
|
id: perm.id, //todo ,id 就是字段名称
|
||||||
|
title: perm.title,
|
||||||
|
required: perm.required,
|
||||||
|
perm: nowNode.value.type === "ROOT" ? "E" : "R"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo 初始化表单权限的位置,表单字段信息放在config配置中心
|
||||||
const formPermsLoad = (oldPermMap, forms) => {
|
const formPermsLoad = (oldPermMap, forms) => {
|
||||||
forms.forEach(form => {
|
forms.forEach(form => {
|
||||||
if (form.name === "SpanLayout") {
|
if (form.name === "SpanLayout") {
|
||||||
@@ -100,7 +115,7 @@ const formPermsLoad = (oldPermMap, forms) => {
|
|||||||
formPerms.value.push(old);
|
formPerms.value.push(old);
|
||||||
} else {
|
} else {
|
||||||
formPerms.value.push({
|
formPerms.value.push({
|
||||||
id: form.id,
|
id: form.id, //todo ,id 就是字段名称
|
||||||
title: form.title,
|
title: form.title,
|
||||||
required: form.props.required,
|
required: form.props.required,
|
||||||
perm: nowNode.type === "ROOT" ? "E" : "R"
|
perm: nowNode.type === "ROOT" ? "E" : "R"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-tabs v-model="active" v-if="visible && name && formConfig.length > 0">
|
<!-- <el-tabs v-model="active" v-if="visible && name && formConfig.length > 0">-->
|
||||||
|
<el-tabs v-model="active" v-if="visible && name">
|
||||||
<el-tab-pane :label="name" name="properties">
|
<el-tab-pane :label="name" name="properties">
|
||||||
<component :is="com" :config="selectNode.props" @initRender="emit('initRender')"/>
|
<component :is="com" :config="selectNode.props" @initRender="emit('initRender')"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
@@ -22,6 +23,7 @@ import Condition from './ConditionNodeConfig.vue'
|
|||||||
import Trigger from './TriggerNodeConfig.vue'
|
import Trigger from './TriggerNodeConfig.vue'
|
||||||
import {useProcessStore} from '@/stores/processStore.js'
|
import {useProcessStore} from '@/stores/processStore.js'
|
||||||
import {computed, defineEmits} from 'vue'
|
import {computed, defineEmits} from 'vue'
|
||||||
|
|
||||||
const emit = defineEmits()
|
const emit = defineEmits()
|
||||||
|
|
||||||
const processStore = useProcessStore()
|
const processStore = useProcessStore()
|
||||||
@@ -31,9 +33,9 @@ const selectNode = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const formConfig = computed(() => {
|
// const formConfig = computed(() => {
|
||||||
return processStore.getDesign().formItems
|
// return processStore.getDesign().formItems
|
||||||
})
|
// })
|
||||||
|
|
||||||
|
|
||||||
const com = ref()
|
const com = ref()
|
||||||
@@ -44,7 +46,8 @@ const visible = ref(false)
|
|||||||
const name = computed(() => {
|
const name = computed(() => {
|
||||||
switch (processStore.getSelectedNode().type) {
|
switch (processStore.getSelectedNode().type) {
|
||||||
case 'ROOT':
|
case 'ROOT':
|
||||||
return '设置发起人';
|
// return '设置发起人';
|
||||||
|
return '节点设置';
|
||||||
case 'APPROVAL':
|
case 'APPROVAL':
|
||||||
return '设置审批人';
|
return '设置审批人';
|
||||||
case 'CC':
|
case 'CC':
|
||||||
@@ -56,7 +59,6 @@ const name = computed(()=>{
|
|||||||
|
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
console.log(processStore.getSelectedNode().type)
|
|
||||||
switch (processStore.getSelectedNode().type) {
|
switch (processStore.getSelectedNode().type) {
|
||||||
case 'APPROVAL' :
|
case 'APPROVAL' :
|
||||||
com.value = Approval;
|
com.value = Approval;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<!-- <div>-->
|
||||||
<p class="desc">选择能发起该审批的人员/部门,不选则默认开放给所有人</p>
|
<!-- <p class="desc">选择能发起该审批的人员/部门,不选则默认开放给所有人</p>-->
|
||||||
<el-button size="mini" @click="selectOrg" icon="el-icon-plus" type="primary" round>请选择</el-button>
|
<!-- <el-button size="mini" @click="selectOrg" icon="el-icon-plus" type="primary" round>请选择</el-button>-->
|
||||||
<org-items v-model="select"/>
|
<!-- <org-items v-model="select"/>-->
|
||||||
<org-picker title="请选择可发起本审批的人员/部门" multiple ref="orgPicker" :selected="select" @ok="selected"/>
|
<!-- <org-picker title="请选择可发起本审批的人员/部门" multiple ref="orgPicker" :selected="select" @ok="selected"/>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
|
无需设置
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -50,14 +50,14 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" align="center">
|
<el-table-column label="操作" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="primary" size="mini" v-perm="['rapid:regular:edit']"
|
<el-button type="primary" size="mini"
|
||||||
@click="handleEdit(scope.row.deploymentId)" link>编辑
|
@click="handleEdit(scope.row.deploymentId)" link>编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" size="mini" v-perm="['rapid:regular:edit']"
|
<!-- <el-button type="primary" size="mini"-->
|
||||||
@click="viewHistoricalVersion(scope.row)" link>历史
|
<!-- @click="viewHistoricalVersion(scope.row)" link>历史-->
|
||||||
</el-button>
|
<!-- </el-button>-->
|
||||||
<popover-delete :name="scope.row.version" :type="'版本'" :perm="['rapid:regular:del']"
|
<!-- <popover-delete :name="scope.row.version" :type="'版本'"-->
|
||||||
@delete="handleDelete(scope.row.deploymentId)"/>
|
<!-- @delete="handleDelete(scope.row.deploymentId)"/>-->
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
import Node from './Node.vue'
|
import Node from './Node.vue'
|
||||||
import {computed, defineExpose} from 'vue'
|
import {computed, defineExpose} from 'vue'
|
||||||
import {Stamp} from '@element-plus/icons-vue'
|
import {Stamp} from '@element-plus/icons-vue'
|
||||||
|
|
||||||
const emit = defineEmits(['insertNode', 'selected', 'delNode'])
|
const emit = defineEmits(['insertNode', 'selected', 'delNode'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
config: {
|
config: {
|
||||||
@@ -80,7 +81,7 @@ const content = computed(() => {
|
|||||||
if (text && text.title) {
|
if (text && text.title) {
|
||||||
return `表单(${text.title})内的人员`
|
return `表单(${text.title})内的人员`
|
||||||
} else {
|
} else {
|
||||||
return '该表单已被移除😥'
|
return '该表单已被移除'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "ROLE":
|
case "ROLE":
|
||||||
@@ -91,8 +92,10 @@ const content = computed(() => {
|
|||||||
} else {
|
} else {
|
||||||
return '指定角色(未设置)'
|
return '指定角色(未设置)'
|
||||||
}
|
}
|
||||||
|
case "MATRIX_APPROVAL":
|
||||||
|
return '矩阵审批'
|
||||||
default:
|
default:
|
||||||
return '未知设置项😥'
|
return '未知设置项'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
<component :is="headerIcon"/>
|
<component :is="headerIcon"/>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<ellipsis class="name" hover-tip :content="title"/>
|
<ellipsis class="name" hover-tip :content="title"/>
|
||||||
<el-icon v-if="!isRoot && designState" size="20" style="float:right;cursor: pointer" @click.stop="emit('delNode')">
|
<el-icon v-if="!isRoot && designState" size="20" style="float:right;cursor: pointer"
|
||||||
|
@click.stop="emit('delNode')">
|
||||||
<Close/>
|
<Close/>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
@@ -16,20 +17,17 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
<template v-if="selectUser.show && mode === 'view'">
|
<template v-if="selectUser.show && mode === 'view'">
|
||||||
<div class="avatar_button">
|
<div class="avatar_button">
|
||||||
<avatar-ellipsis :row="3" v-if="userInfo.length > 0" :user-info="userInfo"/>
|
<avatar-ellipsis :row="3" v-if="userInfo.length > 0" :mode="mode" :user-info="userInfo"/>
|
||||||
<el-button type="primary" :icon="Plus" circle/>
|
<el-button type="primary" :icon="Plus" circle/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="showAvatar">
|
<template v-else-if="showAvatar">
|
||||||
<span class="placeholder" v-if="userInfo.length === 0">{{ placeholder }}</span>
|
<span class="placeholder" v-if="userInfo.length === 0">{{ placeholder }}</span>
|
||||||
<div v-else v-for="item in userInfo" class="circle-user">
|
<avatar-ellipsis :row="3" v-if="userInfo.length > 0" :user-info="userInfo"/>
|
||||||
<span >{{item.name}}</span>
|
|
||||||
</div>
|
|
||||||
<!-- <avatar-ellipsis :row="3" :user-info="userInfo"/>-->
|
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<span class="placeholder" v-if="(content || '').trim() === ''">{{ placeholder }}</span>
|
<span class="placeholder" v-if="(content || '').trim() === ''">{{ placeholder }}</span>
|
||||||
<ellipsis :row="3" :content="content" v-else/>
|
<ellipsis :row="3" :content="content" :mode="mode" v-else/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="node-error" v-if="showError">
|
<div class="node-error" v-if="showError">
|
||||||
@@ -62,7 +60,7 @@ import InsertButton from '../common/InsertButton.vue'
|
|||||||
import Ellipsis from '../common/Ellipsis.vue'
|
import Ellipsis from '../common/Ellipsis.vue'
|
||||||
import AvatarEllipsis from '../common/AvatarEllipsis.vue'
|
import AvatarEllipsis from '../common/AvatarEllipsis.vue'
|
||||||
import SvgIcon from '@/components/svgIcon/index.vue'
|
import SvgIcon from '@/components/svgIcon/index.vue'
|
||||||
import {Close, Warning, Plus} from '@element-plus/icons-vue'
|
import {Close, Warning, Plus, Check, More} from '@element-plus/icons-vue'
|
||||||
|
|
||||||
const emit = defineEmits(['insertNode'])
|
const emit = defineEmits(['insertNode'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -154,7 +152,16 @@ const props = defineProps({
|
|||||||
const designState = computed(() => {
|
const designState = computed(() => {
|
||||||
return props.mode === 'design'
|
return props.mode === 'design'
|
||||||
})
|
})
|
||||||
|
const getState = (state) => {
|
||||||
|
switch (state) {
|
||||||
|
case 'finish':
|
||||||
|
return 'check'
|
||||||
|
case 'UNACTIVATED':
|
||||||
|
return 'more'
|
||||||
|
case 'RUNNING':
|
||||||
|
return 'loading'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
// let userInfo = this.$store.state.selectUserMap.get(this.nodeId);
|
// let userInfo = this.$store.state.selectUserMap.get(this.nodeId);
|
||||||
@@ -176,15 +183,6 @@ const init = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.circle-user{
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 1px solid #ACACAC;
|
|
||||||
}
|
|
||||||
.root {
|
.root {
|
||||||
&:before {
|
&:before {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ export default defineConfig({
|
|||||||
AutoImport({
|
AutoImport({
|
||||||
//自动导入vue相关函数
|
//自动导入vue相关函数
|
||||||
imports: ['vue','vue-router'],
|
imports: ['vue','vue-router'],
|
||||||
|
|
||||||
resolvers: [
|
resolvers: [
|
||||||
ElementPlusResolver(),
|
ElementPlusResolver(),
|
||||||
//自动导入图标组件
|
//自动导入图标组件
|
||||||
@@ -69,12 +68,20 @@ export default defineConfig({
|
|||||||
strictPort: false,
|
strictPort: false,
|
||||||
open: true,
|
open: true,
|
||||||
proxy: {
|
proxy: {
|
||||||
// '/api/admin': {
|
'/api/workflow': {
|
||||||
// target: 'http://dev-mosr.frp.feashow.cn/',
|
// target: 'http://frp.feashow.cn:31800/',
|
||||||
// // target: 'http://192.168.31.175:8000',
|
target: 'http://clay.frp.feashow.cn/',
|
||||||
// changeOrigin: true,
|
// target: 'http://192.168.31.175:8000',
|
||||||
// rewrite: (path) => path.replace(/^\/api/, '')
|
changeOrigin: true,
|
||||||
// },
|
rewrite: (path) => path.replace(/^\/api/, '')
|
||||||
|
},
|
||||||
|
'/api/admin': {
|
||||||
|
// target: 'http://frp.feashow.cn:31800/',
|
||||||
|
target: 'http://clay.frp.feashow.cn/',
|
||||||
|
// target: 'http://192.168.31.175:8000',
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/api/, '')
|
||||||
|
},
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://mosr.feashow.cn',
|
target: 'http://mosr.feashow.cn',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user