309 Commits
role ... dm

Author SHA1 Message Date
clay
8b69abfc9b Merge pull request 'fix: 修复问题' (#231) from master into dm
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/231
2024-05-24 08:12:15 +00:00
lilinyuan
6af7bf9d2f fix: 修复问题 2024-05-24 16:10:15 +08:00
clay
604fad9009 Merge pull request 'master' (#230) from master into dm
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/230
2024-05-24 07:54:17 +00:00
lilinyuan
9013d54add fix: 去掉log 2024-05-24 14:26:29 +08:00
lilinyuan
fd722b5c82 Merge branch 'master' of http://git.feashow.cn/clay/mosr-web 2024-05-24 14:24:39 +08:00
lilinyuan
a8e56fe985 fix: 修改新增编辑等单页面路由层级 2024-05-24 14:24:36 +08:00
clay
4953e96415 feat : 需求征集表单权限测试 2024-05-24 10:44:24 +08:00
5b85abd219 Merge pull request 'fix : 修复详情渲染细节' (#228) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/228
2024-05-23 16:16:00 +00:00
7156e34fde fix : 修复详情渲染细节 2024-05-24 00:12:53 +08:00
e903dd2994 Merge pull request 'fix : 修复权限按钮细节' (#227) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/227
2024-05-23 15:43:22 +00:00
549e307b3e fix : 修复权限按钮细节 2024-05-23 23:42:09 +08:00
390474ea24 Merge pull request 'fix : 修复页面细节' (#226) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/226
2024-05-23 12:48:45 +00:00
43c9cb03d3 fix : 修复页面细节 2024-05-23 20:48:09 +08:00
clay
5eb7e34571 fix : 用户nickname查询 2024-05-23 20:29:24 +08:00
clay
d12fb8a12b fix : 用户nickname查询 2024-05-23 20:28:46 +08:00
1991d7eada Merge pull request 'fix : 修复页面细节' (#225) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/225
2024-05-23 09:53:04 +00:00
31a12e566a fix : 修复页面细节 2024-05-23 17:52:48 +08:00
5c8679d5f9 Merge pull request 'fix : 修复页面细节' (#224) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/224
2024-05-23 09:39:12 +00:00
7e70c9271f fix : 修复页面细节 2024-05-23 17:38:58 +08:00
6748685712 Merge pull request 'fix : 修复页面细节' (#223) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/223
2024-05-23 08:44:19 +00:00
cd7f94e8f2 fix : 修复页面细节 2024-05-23 16:44:04 +08:00
clay
db8a96a664 feat : 需求征集index.vue 2024-05-23 15:53:33 +08:00
clay
17207b2c87 feat : 按钮全新啊demo 2024-05-23 15:48:31 +08:00
d6de4d5854 Merge pull request 'fix : 修复页面细节' (#222) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/222
2024-05-23 07:37:20 +00:00
bcdafbc7cd fix : 修复页面细节 2024-05-23 15:36:57 +08:00
clay
e9e5a0c785 feat : 修改菜单状态 2024-05-23 14:49:56 +08:00
clay
21f90e438c fix : 修复细节 2024-05-23 10:00:21 +08:00
e1b9f3f220 Merge pull request 'fix : 修复人员选择框' (#221) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/221
2024-05-22 15:53:21 +00:00
96d46e6480 fix : 修复人员选择框 2024-05-22 23:52:51 +08:00
6ab0c206c4 Merge pull request 'fix : 修复细节' (#219) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/219
2024-05-20 16:22:29 +00:00
a4255c3157 fix : 修复细节 2024-05-21 00:21:24 +08:00
39b1690c0a Merge pull request 'fix : 修复流程图渲染问题' (#218) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/218
2024-05-20 16:15:50 +00:00
9f4fe95e4d fix : 修复流程图渲染问题 2024-05-21 00:14:53 +08:00
1635482e09 Merge pull request 'fix : 重新提交全流程初步完成' (#217) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/217
2024-05-20 15:02:07 +00:00
3270aeef06 fix : 重新提交全流程初步完成 2024-05-20 23:01:53 +08:00
lilinyuan
6c80652416 feat: agree and reject 2024-05-20 22:18:17 +08:00
lilinyuan
c97091db4f feat: 主流程详情组件基本完成 2024-05-20 22:03:53 +08:00
1c57cb277b Merge pull request 'fix : 重新提交页面初始化' (#216) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/216
2024-05-20 09:56:49 +00:00
e648faba69 fix : 重新提交页面初始化 2024-05-20 17:56:38 +08:00
a663b84fab Merge pull request 'fix : 修复需求上报/详情下流程渲染' (#215) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/215
2024-05-20 03:47:24 +00:00
f83ae8df51 fix : 修复所属公司及详情loading 2024-05-20 11:45:53 +08:00
1d772e1414 fix : 修复需求上报/详情下流程渲染 2024-05-20 11:05:29 +08:00
92e9468cb9 Merge pull request 'fix : 修复页面细节' (#214) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/214
2024-05-19 16:59:19 +00:00
5c93eae4ce fix : 修复页面细节 2024-05-20 00:58:48 +08:00
5d7b6bc59f Merge pull request 'dj' (#213) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/213
2024-05-19 16:45:20 +00:00
1825b6c871 fix : 修复页面细节 2024-05-20 00:44:37 +08:00
dee7fdacf2 Merge pull request 'dj' (#212) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/212
2024-05-19 16:31:02 +00:00
dc7d90c349 Merge remote-tracking branch 'origin/master' 2024-05-20 00:29:46 +08:00
9661cdbb2b fix : 修复页面细节功能及附件上传组件 2024-05-20 00:29:31 +08:00
wenhua
3a4f9927c9 feat: up detail 2024-05-19 23:07:32 +08:00
1f4389eb5e fix : 修复项目申请/验收/结项功能 2024-05-19 20:39:54 +08:00
wenhua
4a90f4bc1e 合并冲突 2024-05-19 20:19:50 +08:00
wenhua
8155a4d160 feat: 需求上报详情 2024-05-19 20:17:55 +08:00
771a844552 Merge pull request 'fix : 修复页面' (#211) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/211
2024-05-19 10:01:01 +00:00
08a609e2a8 fix : 修复页面 2024-05-19 18:00:48 +08:00
d16045a1b2 Merge pull request 'fix : 修复项目立项页面' (#210) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/210
2024-05-19 08:40:20 +00:00
1fc0ae6ac0 fix : 修复项目立项页面 2024-05-19 16:40:05 +08:00
08f20bb171 Merge pull request 'fix : 修改细节' (#209) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/209
2024-05-19 08:20:12 +00:00
5421145583 fix : 修改细节 2024-05-19 16:19:53 +08:00
b7a0dc2545 Merge pull request 'fix : 修改审批记录样式' (#208) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/208
2024-05-19 07:27:32 +00:00
3bd6df74cc fix : 修改审批记录样式 2024-05-19 15:27:22 +08:00
wenhua
190a1d6477 Merge branches 'master' and 'master' of http://git.feashow.cn/clay/mosr-web 2024-05-19 14:04:30 +08:00
wenhua
cb7f6e9919 feat: 详情组件, 实例文件 2024-05-19 14:04:28 +08:00
5ea20654cc Merge pull request 'fix : 修复需求汇总详情功能' (#207) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/207
2024-05-19 05:23:23 +00:00
670c8a5653 fix : 修复需求汇总详情功能 2024-05-19 13:23:10 +08:00
206a024f4b Merge pull request 'fix : 修复需求汇总详情功能' (#206) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/206
2024-05-19 05:18:22 +00:00
89d5c86d8b fix : 修复需求汇总详情功能 2024-05-19 13:18:03 +08:00
397d5f0182 Merge pull request 'fix : 修复需求上报功能' (#205) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/205
2024-05-19 04:31:09 +00:00
10bc019866 fix : 修复需求上报功能 2024-05-19 12:29:59 +08:00
62620b1dc5 Merge pull request 'fix : 修复页面细节' (#204) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/204
2024-05-19 03:40:46 +00:00
ff68ce96af fix : 修复页面细节 2024-05-19 11:40:37 +08:00
65d933c027 Merge pull request 'fix : 修复页面细节' (#203) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/203
2024-05-19 03:26:53 +00:00
726c746a87 fix : 修复页面细节 2024-05-19 11:26:32 +08:00
c498a3de62 Merge pull request 'fix : 修复页面细节' (#202) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/202
2024-05-19 03:14:26 +00:00
d432e54bc8 fix : 修复页面细节 2024-05-19 11:09:51 +08:00
5b68ee6846 Merge pull request 'feat : 需求上报界面初始化' (#201) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/201
2024-05-18 18:04:09 +00:00
96e7ca1a67 feat : 需求上报界面初始化 2024-05-19 02:03:52 +08:00
9368ea24ab Merge pull request 'dj' (#200) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/200
2024-05-18 16:17:14 +00:00
c96cbf8415 fix : 修复细节 2024-05-19 00:16:40 +08:00
bab0421b6d Merge pull request 'fix : 修复tooltip细节' (#199) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/199
2024-05-18 15:05:04 +00:00
fccce985b6 Merge remote-tracking branch 'origin/master' 2024-05-18 23:05:01 +08:00
c675b1ec48 fix : 修复tooltip细节 2024-05-18 23:04:51 +08:00
02bda3c71f Merge pull request 'fix : 修复附件上传组件bug' (#198) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/198
2024-05-18 14:10:06 +00:00
b7ebd66729 fix : 修复附件上传组件bug 2024-05-18 22:08:08 +08:00
76c759c088 Merge pull request 'fix : 修复需求征集详情组件下载bug' (#197) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/197
2024-05-18 12:59:52 +00:00
e4e7444aff fix : 修复需求征集详情组件下载bug 2024-05-18 20:59:35 +08:00
a8f5f84b20 Merge pull request 'dj' (#196) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/196
2024-05-18 12:52:32 +00:00
716d18122f feat : 封装带有附件及其他文件上传的组件 2024-05-18 20:52:14 +08:00
2f19bb7bdc Merge remote-tracking branch 'origin/master' 2024-05-18 19:56:54 +08:00
8f8d954bb6 Merge pull request 'feat : 文件下载组件删除功能' (#195) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/195
2024-05-18 11:56:52 +00:00
0732acf8c7 feat : 文件下载组件删除功能 2024-05-18 19:54:58 +08:00
6540ac8991 Merge pull request 'fix : 替换文件下载方式' (#194) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/194
2024-05-18 09:33:33 +00:00
6009885c09 fix : 替换文件下载方式 2024-05-18 17:32:58 +08:00
83a8fac0fb Merge pull request 'dj' (#193) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/193
2024-05-18 09:13:26 +00:00
0c070154e1 fix : 修复需求征集详情组件引用细节 2024-05-18 17:12:51 +08:00
32a3ab3001 Merge remote-tracking branch 'origin/master' 2024-05-18 16:56:28 +08:00
d0fe340f9d Merge pull request 'feat : 新增需求征集组件' (#192) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/192
2024-05-17 15:25:09 +00:00
92d2278dfd Merge remote-tracking branch 'origin/master' 2024-05-17 23:24:52 +08:00
f5c6680c66 feat : 新增需求征集组件 2024-05-17 23:24:38 +08:00
b5e5a3f12a Merge pull request 'feat : 项目归档页面初始化' (#191) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/191
2024-05-17 13:27:15 +00:00
7869ff4e6a feat : 项目归档页面初始化 2024-05-17 21:26:15 +08:00
95f4610714 Merge pull request 'dj' (#189) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/189
2024-05-17 12:55:39 +00:00
9754b62038 feat : 新增需求征集删除功能和文件下载功能 2024-05-17 20:53:49 +08:00
573fff84e4 Merge remote-tracking branch 'origin/master' 2024-05-17 19:35:49 +08:00
lilinyuan
1f1ff3a466 fix: 调整权限按钮判断 2024-05-16 10:04:31 +08:00
79f2032fde feat : 项目归档和分摊页面初始化 2024-05-15 23:39:21 +08:00
lilinyuan
f820c25892 fix: 修改table显示bug 2024-05-15 16:35:36 +08:00
lilinyuan
a4cb59ff9a fix: 修改权限按钮逻辑判断 2024-05-15 16:00:24 +08:00
a7b6b44a42 Merge pull request 'feat : 项目实施分页面初始化' (#185) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/185
2024-05-15 06:20:09 +00:00
1f126592e1 feat : 项目实施分页面初始化 2024-05-15 14:19:36 +08:00
0f914237bf Merge pull request 'fix : 修复细节' (#183) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/183
2024-05-15 05:29:07 +00:00
9a0f5b0e12 fix : 修复细节 2024-05-15 13:28:53 +08:00
9f7e3778ad Merge pull request 'fix : 修复细节' (#181) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/181
2024-05-15 05:25:16 +00:00
01540a3144 fix : 修复细节 2024-05-15 13:24:44 +08:00
5e4e8d6389 Merge pull request 'fix : 修复需求征集新增功能' (#179) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/179
2024-05-15 01:49:01 +00:00
08579c8aad fix : 修复需求征集新增功能 2024-05-15 09:48:38 +08:00
5ae971e0ac Merge pull request 'dj' (#178) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/178
2024-05-14 16:27:50 +00:00
9ae0b7547c feat : 项目立项详情页面初始化 2024-05-15 00:18:40 +08:00
b2369d1702 feat : 项目实施页面初始化 2024-05-15 00:17:18 +08:00
8b6c9a7d1e Merge remote-tracking branch 'origin/master' 2024-05-14 23:53:02 +08:00
6097e74a9b Merge pull request 'feat : 项目立项申请页面初始化' (#177) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/177
2024-05-14 14:16:45 +00:00
11b794bf96 Merge remote-tracking branch 'origin/master' 2024-05-14 22:16:31 +08:00
2a72de08a4 feat : 项目立项申请页面初始化 2024-05-14 22:16:22 +08:00
77fcdc240b Merge pull request 'fix : 修复功能细节' (#175) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/175
2024-05-14 13:32:27 +00:00
6d8dbaa8c4 fix : 修复功能细节 2024-05-14 21:32:10 +08:00
d7b004ae80 Merge pull request 'fix : 修复细节' (#174) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/174
2024-05-14 13:07:27 +00:00
1f9a3603d8 fix : 修复细节 2024-05-14 21:07:17 +08:00
b8b165c205 Merge pull request 'fix : 修复路由规范问题' (#172) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/172
2024-05-14 12:56:36 +00:00
de2f566bd0 fix : 修复路由规范问题 2024-05-14 20:55:49 +08:00
38182da467 Merge pull request 'fix : 修复路由规范问题' (#171) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/171
2024-05-14 12:50:05 +00:00
de0e0be953 fix : 修复路由规范问题 2024-05-14 20:49:46 +08:00
ef1acd65b7 Merge pull request 'fix : 修复路由规范问题' (#170) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/170
2024-05-14 12:26:50 +00:00
27dcca6617 fix : 修复路由规范问题 2024-05-14 20:26:33 +08:00
2ad94511d0 Merge pull request 'dj' (#169) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/169
2024-05-14 09:56:48 +00:00
bfdf2cf4a2 feat : 项目立项页面初始化 2024-05-14 17:56:36 +08:00
4f4ef2cfde fix : 修复细节 2024-05-14 17:56:10 +08:00
222ab1bec7 Merge pull request 'fix : 修复细节' (#167) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/167
2024-05-14 09:14:30 +00:00
bead5edc86 fix : 修复细节 2024-05-14 17:11:59 +08:00
18caa0ee58 Merge pull request 'dj' (#165) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/165
2024-05-13 16:11:21 +00:00
96d8f1e48a Merge remote-tracking branch 'origin/master' 2024-05-14 00:09:46 +08:00
3bc24219ed fix : 修复首页tag报错 2024-05-14 00:09:36 +08:00
07d5380818 Merge pull request 'dj' (#163) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/163
2024-05-13 16:03:34 +00:00
cd91dd3cad fix : 修复首页卡死问题 2024-05-14 00:03:08 +08:00
edb235ff0d Merge remote-tracking branch 'origin/master' 2024-05-13 23:30:20 +08:00
9ade24768e fix : 优化样式 2024-05-13 23:30:07 +08:00
e753c27455 Merge pull request 'dj' (#162) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/162
2024-05-13 15:04:01 +00:00
1684e49662 Merge remote-tracking branch 'origin/master' 2024-05-13 23:03:15 +08:00
42ea1dde8b fix : 修复功能 2024-05-13 23:03:05 +08:00
wenhua
bb2a0ce177 Merge pull request 'xqhz' (#160) from xqhz into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/160
2024-05-13 14:36:20 +00:00
wenhua
9da6e82763 Merge pull request 'master' (#158) from master into xqhz
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/158
2024-05-13 14:31:08 +00:00
lilinyuan
31a88c232f feat: 重新上传表格组件 2024-05-13 22:30:50 +08:00
1c00a040f0 Merge pull request 'dj' (#159) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/159
2024-05-13 14:30:31 +00:00
lilinyuan
f46f95c4ad fix: 删除该分支表格组件 2024-05-13 22:29:07 +08:00
9e8e3e4705 Merge remote-tracking branch 'origin/master' 2024-05-13 22:29:01 +08:00
f55059eed7 fix : 修复功能 2024-05-13 22:28:44 +08:00
lilinyuan
3bec5a6620 fix: 合并冲突 2024-05-13 22:27:35 +08:00
lilinyuan
ad3fa0e688 feat: 表格组件更新 2024-05-13 22:25:37 +08:00
lilinyuan
0041bbbfa8 Merge branch 'xqhz' of http://git.feashow.cn/clay/mosr-web into xqhz 2024-05-13 22:23:00 +08:00
lilinyuan
bdc9c244a4 feat: 新增组件列展示配置 2024-05-13 22:22:55 +08:00
clay
acc38adae1 feat : workflow编辑器 无用功能屏蔽 2024-05-13 22:15:58 +08:00
clay
5911d0f6d2 feat : workflow编辑器 无用功能屏蔽 2024-05-13 19:28:16 +08:00
clay
66454b2023 Merge remote-tracking branch 'origin/master' 2024-05-13 17:41:27 +08:00
clay
8d51d68df1 feat : workflow编辑器 无用功能屏蔽 2024-05-13 17:41:17 +08:00
84a3981df3 Merge pull request 'fix : 修复编辑数据回显功能' (#154) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/154
2024-05-12 16:28:56 +00:00
64981433bf fix : 修复编辑数据回显功能 2024-05-13 00:27:53 +08:00
e5dfadb8c0 Merge pull request 'fix : 修复功能' (#153) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/153
2024-05-12 15:38:17 +00:00
888c01efbf fix : 修复功能 2024-05-12 23:38:04 +08:00
c206844e24 Merge pull request 'fix : 修复功能' (#152) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/152
2024-05-12 15:29:21 +00:00
4070e15e63 fix : 修复功能 2024-05-12 23:28:47 +08:00
92b9dd5e03 Merge pull request 'dd' (#150) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/150
2024-05-12 13:57:00 +00:00
2d73580195 fix : 修复功能 2024-05-12 21:56:44 +08:00
3538813100 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	src/api/project-demand/index.js
#	src/views/projectdemand/demandcollection/add.vue
2024-05-12 21:56:33 +08:00
71d78d9cca fix : 修复功能 2024-05-12 21:53:08 +08:00
clay
14fa25b509 Merge remote-tracking branch 'origin/master' 2024-05-12 20:27:45 +08:00
clay
bd220ad5b1 feat : 重新提交 2024-05-12 20:27:38 +08:00
4a7cffde2e Merge pull request 'fix : 修复功能' (#148) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/148
2024-05-12 11:42:43 +00:00
b170d42263 fix : 修复功能 2024-05-12 19:42:24 +08:00
d0e517e7d9 Merge pull request 'dj' (#147) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/147
2024-05-12 11:40:00 +00:00
55e0f28ebc fix : 修复功能 2024-05-12 19:39:39 +08:00
250f6344f1 fix : 修复功能 2024-05-12 19:08:41 +08:00
abbb4551ad Merge pull request 'fix : 修复功能' (#146) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/146
2024-05-12 11:05:35 +00:00
6ae58eefaf fix : 修复功能 2024-05-12 19:05:13 +08:00
9d63b64c91 Merge pull request 'fix : 修复上传文件功能' (#145) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/145
2024-05-12 09:03:39 +00:00
324cc268b5 fix : 修复上传文件功能 2024-05-12 17:03:12 +08:00
d5c7da1328 Merge pull request 'fix : 修复上传文件功能' (#144) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/144
2024-05-12 08:35:31 +00:00
13774dada9 fix : 修复上传文件功能 2024-05-12 16:34:10 +08:00
68cc3e7a12 Merge pull request 'fix : 修复编辑数据回显功能' (#143) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/143
2024-05-12 07:48:30 +00:00
72a8572910 fix : 修复编辑数据回显功能 2024-05-12 15:47:14 +08:00
86ddbf2ffb Merge pull request 'fix : 修复细节' (#142) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/142
2024-05-12 07:35:54 +00:00
d139b016a2 fix : 修复细节 2024-05-12 15:35:40 +08:00
8bdafdd087 Merge pull request 'dj' (#141) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/141
2024-05-12 07:16:14 +00:00
b4c91f3daf Merge remote-tracking branch 'origin/master'
# Conflicts:
#	src/views/workflow/process/nodes/Node.vue
2024-05-12 15:15:48 +08:00
clay
aaedb362b5 build : 按钮权限区分 2024-05-12 15:14:39 +08:00
548cab4cde fix : 修复文件删除功能 2024-05-12 15:14:28 +08:00
876bd1f9f9 fix : 修复文件删除功能 2024-05-12 15:11:37 +08:00
eeab66d8fb fix : 修复细节 2024-05-12 14:44:04 +08:00
clay
416fa2ed53 build : 流程演示 2024-05-12 14:23:34 +08:00
72210306b6 Merge pull request 'fix : 修复细节' (#139) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/139
2024-05-12 06:00:10 +00:00
6fbcdc82ca fix : 修复细节 2024-05-12 13:59:50 +08:00
8e671e959c Merge pull request 'fix : 修复细节' (#138) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/138
2024-05-12 05:06:10 +00:00
48e5d82acb fix : 修复细节 2024-05-12 13:05:52 +08:00
wenhua
ce2752af9b feat: 新增文件上传组件等 2024-05-12 01:29:49 +08:00
01021b640e Merge pull request 'fix : 修复细节' (#137) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/137
2024-05-11 15:23:20 +00:00
5e08db55fb fix : 修复细节 2024-05-11 23:22:55 +08:00
7810de1327 Merge pull request 'fix : 首页待办列表' (#136) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/136
2024-05-11 13:48:29 +00:00
b58dfcb566 fix : 首页待办列表 2024-05-11 21:48:16 +08:00
clay
44ed106775 build : 需求征集提交 2024-05-11 21:40:49 +08:00
a077e38fdc Merge pull request 'fix : 修复页面' (#135) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/135
2024-05-11 13:37:37 +00:00
9c6c494b80 fix : 修复页面 2024-05-11 21:37:15 +08:00
77301e09e4 Merge pull request 'fix : 修复详情页面' (#134) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/134
2024-05-11 13:16:18 +00:00
a7d9391e9a fix : 修复详情页面 2024-05-11 21:16:03 +08:00
af2667502a Merge pull request 'fix : 对接需求征集详情接口' (#133) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/133
2024-05-11 12:49:14 +00:00
eb061dd1a6 fix : 对接需求征集详情接口 2024-05-11 20:49:03 +08:00
clay
f0212046f3 build : 修改dm发布 2024-05-11 20:38:05 +08:00
5498337d3e Merge pull request 'fix : 对接需求征集详情接口' (#132) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/132
2024-05-11 10:06:40 +00:00
6c27a5f954 fix : 对接需求征集详情接口 2024-05-11 18:06:25 +08:00
615e0f85c7 Merge pull request 'dd' (#131) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/131
2024-05-11 09:50:54 +00:00
04d0e9a7d2 fix : 修复需求征集列表细节 2024-05-11 17:50:35 +08:00
0cf56d875e fix : 对接需求征集列表接口 2024-05-11 17:48:44 +08:00
779ebf093a Merge pull request 'fix : 对接需求征集列表接口' (#130) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/130
2024-05-11 09:41:04 +00:00
0d31b47a56 fix : 对接需求征集列表接口 2024-05-11 17:40:47 +08:00
clay
f7fddab0bd Merge remote-tracking branch 'origin/master' 2024-05-11 15:59:40 +08:00
clay
9da9b763be feat : 详情页修改 2024-05-11 15:59:25 +08:00
e935c870bf Merge pull request 'fix : 修复细节' (#129) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/129
2024-05-11 07:51:50 +00:00
c008aab0d3 fix : 修复细节 2024-05-11 15:51:19 +08:00
d9dce9e8e5 Merge pull request 'fix : 完善需求新增/详情页面' (#128) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/128
2024-05-11 07:42:10 +00:00
e6a515f673 fix : 完善需求新增/详情页面 2024-05-11 15:41:56 +08:00
5ce118a149 Merge pull request 'fix : 完善需求新增页面' (#127) from dd into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/127
2024-05-11 07:31:42 +00:00
452e2479e0 fix : 完善需求新增页面 2024-05-11 15:30:53 +08:00
clay
5c0e962626 feat : workflow前端内容检查 2024-05-11 15:10:43 +08:00
cf367951a5 Merge pull request 'fix : 完善页面' (#123) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/123
2024-05-11 06:59:05 +00:00
dde77b1425 fix : 完善页面 2024-05-11 14:58:41 +08:00
wenhua
3ba7845893 feat: 新增需求上报部分页面内容 2024-05-11 00:14:25 +08:00
wenhua
a5822ca276 fix: 修改权限按钮bug 2024-05-11 00:14:03 +08:00
332d843dc2 Merge pull request 'fix : 完善详情页面细节' (#122) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/122
2024-05-10 09:56:23 +00:00
fdca87d870 fix : 完善详情页面细节 2024-05-10 17:56:06 +08:00
1a211fec21 Merge pull request 'fix : 完善详情页面细节' (#120) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/120
2024-05-10 09:31:01 +00:00
5710597454 fix : 完善详情页面细节 2024-05-10 17:30:29 +08:00
clay
81d0987a9a feat : workflow适配 2024-05-10 15:14:11 +08:00
1ee39bfa0c Merge pull request 'dj' (#118) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/118
2024-05-09 16:30:11 +00:00
371a55cfe1 fix : 完善页面细节 2024-05-10 00:29:07 +08:00
90de57698b feat : 需求征集新增/编辑/详情页面初始化 2024-05-10 00:28:40 +08:00
858289ec0e Merge pull request 'fix :完善首页界面' (#116) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/116
2024-05-09 10:27:08 +00:00
bf6a683261 fix :完善首页界面 2024-05-09 18:26:40 +08:00
460dd793cf Merge pull request 'dj' (#115) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/115
2024-05-09 10:11:32 +00:00
be5150c7c4 feat: 初始化需求征集主页面 2024-05-09 18:11:11 +08:00
233f44990d Merge pull request 'master' (#114) from master into dj
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/114
2024-05-09 09:36:35 +00:00
wenhua
3403ca7ecb Merge pull request 'xqhz' (#113) from xqhz into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/113
2024-05-09 09:33:33 +00:00
lilinyuan
28b4637e01 feat: 初始化需求汇总主页面 2024-05-09 17:33:01 +08:00
lilinyuan
639caadc46 fix: 修复bug 2024-05-09 17:32:36 +08:00
lilinyuan
6557b5d2c8 fix: 修复bug 2024-05-09 17:32:21 +08:00
4f6b2dcc27 Merge pull request 'feat : 新增首页界面' (#111) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/111
2024-05-09 09:17:30 +00:00
dcc6866211 feat : 新增首页界面 2024-05-09 17:16:39 +08:00
wenhua
0e0e1f9bb9 Merge pull request 'feat: 初始化项目需求目录及页面文件' (#110) from master into xqhz
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/110
2024-05-09 08:19:28 +00:00
lilinyuan
0e0d206cc7 feat: 初始化项目需求目录及页面文件 2024-05-09 16:14:48 +08:00
wenhua
bfe24e1207 Merge pull request 'role' (#109) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/109
2024-05-09 07:30:12 +00:00
clay
2bb86ced15 feat : 测试sso单点登录之后的重定向路径4 2024-04-29 11:49:46 +08:00
clay
929228974a feat : 测试sso单点登录之后的重定向路径3 2024-04-29 11:27:56 +08:00
clay
eee3c3852e feat : 测试sso单点登录之后的重定向路径 2024-04-29 10:31:18 +08:00
clay
57bfb6f4a0 feat : 测试sso单点登录之后的重定向路径 2024-04-29 10:20:58 +08:00
clay
5d3ab890f3 feat : 测试sso单点登录之后的重定向路径 2024-04-29 10:10:50 +08:00
clay
3eecc3f4b9 Merge pull request 'role' (#102) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/102
2024-04-29 02:04:03 +00:00
wenhua
9217f019e5 Merge pull request 'fix: 按钮逻辑' (#100) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/100
2024-04-01 07:31:24 +00:00
wenhua
26b50d6103 Merge pull request 'fix: 调整菜单权限按钮' (#98) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/98
2024-04-01 07:08:40 +00:00
wenhua
12053b81b9 Merge pull request 'role' (#96) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/96
2024-04-01 06:36:33 +00:00
wenhua
360f0dd92d Merge pull request 'fix: 修改依赖源地址' (#94) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/94
2024-04-01 05:48:54 +00:00
wenhua
68c4ca5dc9 Merge pull request 'fix: 修改依赖源' (#92) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/92
2024-04-01 05:41:49 +00:00
wenhua
8f922a8815 Merge pull request 'role' (#90) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/90
2024-04-01 03:28:24 +00:00
lilinyuan
508e391823 feat: 恢复 2024-04-01 11:27:06 +08:00
lilinyuan
2560ed701f fix: 暂时删除 2024-04-01 11:25:27 +08:00
wenhua
c3e582ad33 Merge pull request 'feat: up' (#85) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/85
2024-04-01 03:00:32 +00:00
wenhua
fde73bd7b0 Merge pull request 'fix: 再试一次' (#83) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/83
2024-04-01 02:20:57 +00:00
wenhua
ef46911a5b Merge pull request 'fix: 使用原始ui库' (#81) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/81
2024-04-01 02:14:17 +00:00
clay
3b0637e1b3 Merge pull request 'master' (#80) from master into dm
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/80
2024-04-01 02:00:42 +00:00
wenhua
a3c4a79fd0 Merge pull request 'fix: 添加调试log' (#78) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/78
2024-04-01 01:53:04 +00:00
wenhua
450d483f39 Merge pull request 'fix: 菜单分配父子联动' (#76) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/76
2024-03-30 16:36:29 +00:00
wenhua
699c7ecc7d Merge pull request 'fix: 同步退出登录后再登录不同权限账号时菜单不更新问题' (#74) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/74
2024-03-30 16:24:00 +00:00
wenhua
0ffbdbbcc7 Merge pull request 'fix: 修复角色分配菜单父子关联不生效的问题' (#72) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/72
2024-03-30 16:13:08 +00:00
d784928d05 Merge pull request 'fix : 修改登录框宽度' (#70) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/70
2024-03-30 14:59:26 +00:00
a005409d92 fix : 修改登录框宽度 2024-03-30 22:59:01 +08:00
7b500e7ea1 Merge pull request 'fix : 修改登录界面样式' (#68) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/68
2024-03-29 14:58:32 +00:00
e9acf99ccb fix : 修改登录界面样式 2024-03-29 22:58:00 +08:00
clay
e950d9e687 Merge pull request 'build : 修改dm发布' (#67) from master into dm
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/67
2024-03-29 12:54:05 +00:00
clay
dd659cf135 build : 修改dm发布 2024-03-29 20:53:46 +08:00
clay
736798b540 Merge pull request 'build : 修改dm发布' (#66) from master into dm
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/66
2024-03-29 12:50:19 +00:00
clay
0c56e6a161 build : 修改dm发布 2024-03-29 20:50:06 +08:00
clay
190c77d71d Merge pull request 'build : 修改dm发布' (#65) from master into dm
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/65
2024-03-29 12:48:05 +00:00
clay
bba369abaa build : 修改dm发布 2024-03-29 20:47:49 +08:00
clay
6df354ec1b Merge pull request 'build : 修改dm发布' (#64) from master into dm
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/64
2024-03-29 12:45:11 +00:00
clay
fcff8c9cc4 build : 修改dm发布 2024-03-29 20:44:33 +08:00
clay
13d3428d7a build : 环境区分 2024-03-29 18:22:23 +08:00
clay
99cf83a563 Merge remote-tracking branch 'origin/master' 2024-03-29 18:10:33 +08:00
clay
f98103c61f build : 环境区分 2024-03-29 18:10:26 +08:00
wenhua
5986ab1eb4 Merge pull request 'fix: 生产环境禁用debugger' (#61) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/61
2024-03-29 09:14:28 +00:00
wenhua
ecf3fecd40 Merge pull request 'fix: 调整删除按钮展示逻辑' (#58) from uesr into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/58
2024-03-29 08:49:50 +00:00
lilinyuan
658f7de3c0 fix: 调整删除按钮展示逻辑 2024-03-29 16:49:15 +08:00
wenhua
46a6745f17 Merge pull request 'role' (#56) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/56
2024-03-29 07:46:43 +00:00
lilinyuan
d6ce782681 feat: 添加request 2024-03-29 15:45:14 +08:00
lilinyuan
aa3194dcc1 fix: 暂时删除request 2024-03-29 15:42:33 +08:00
clay
fa56d63dbb Merge remote-tracking branch 'origin/master' 2024-03-29 15:21:02 +08:00
clay
2ad0dbf8ab feat : 403 权限校验 2024-03-29 15:20:52 +08:00
wenhua
89b42dba2a Merge pull request 'uesr' (#52) from uesr into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/52
2024-03-29 07:19:39 +00:00
lilinyuan
c28b0e306d fix: 调整user编辑逻辑OA用户只能修改角色 2024-03-29 15:19:17 +08:00
wenhua
c88be616fc Merge pull request 'fix: 修复role新增编辑bug' (#50) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/50
2024-03-29 06:32:08 +00:00
wenhua
38b5e2d2af Merge pull request 'role' (#48) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/48
2024-03-29 06:15:51 +00:00
wenhua
b1b039a897 Merge pull request 'master' (#47) from master into uesr
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/47
2024-03-29 06:09:34 +00:00
wenhua
1e23fe08e3 Merge pull request 'fix: 修复role新增编辑bug, 调整列表页' (#45) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/45
2024-03-29 06:07:24 +00:00
wenhua
5fc036d12d Merge pull request 'role' (#43) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/43
2024-03-28 08:42:48 +00:00
wenhua
610b1a66b6 Merge pull request 'role' (#41) from role into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/41
2024-03-28 01:32:17 +00:00
95 changed files with 7486 additions and 982 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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
View File

@@ -0,0 +1,8 @@
import request from '@/utils/request.js'
export const getHomeInfo = () => {
return request({
url: '/workflow/mosr/process/task',
method: "get"
});
};

View 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"
});
};

View 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"
});
};

View File

@@ -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({

View File

@@ -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",
})
}

View File

@@ -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
})
}

View File

@@ -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,7 +251,8 @@ 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,9 +291,10 @@ 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;
} }
.scrollbar-dict { .scrollbar-dict {
@@ -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
View 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
View 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
View 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
View 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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View File

@@ -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>

View File

@@ -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技术支持信息是否显示

View 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>

View 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'
})
}

View 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>

View File

@@ -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)

View File

@@ -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>
@@ -58,22 +58,22 @@ const formInstance = ref(null)
const showMore = ref(false) const showMore = ref(false)
const filterConfig = computed(()=>{ const filterConfig = computed(() => {
const arr = props.searchConfig.filter(item=>{ const arr = props.searchConfig.filter(item => {
if(item.prop) return true if (item.prop) return true
}) })
return arr.length >= 4 && showMore.value ? arr : arr.slice(0, 3) return arr.length >= 4 && showMore.value ? arr : arr.slice(0, 3)
}) })
// 搜索功能表单元素默认值 // 搜索功能表单元素默认值
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
}) })
} }
watchEffect(()=>{ watchEffect(() => {
if(filterConfig.value.length) { if (filterConfig.value.length) {
setDefaultFormValues() setDefaultFormValues()
} }
}) })
@@ -90,8 +90,8 @@ const handleReset = () => {
emits('search', form.value) emits('search', form.value)
} }
onMounted(()=>{ onMounted(() => {
emits('getInstance', Object.assign({}, unref(formInstance),{ emits('getInstance', Object.assign({}, unref(formInstance), {
getValues, getValues,
handleReset, handleReset,
})) }))
@@ -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;

View File

@@ -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>

View File

@@ -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>

View File

@@ -12,13 +12,13 @@
</template> </template>
<script setup> <script setup>
import { useRoute, useRouter } from 'vue-router'; import {useRoute, useRouter} from 'vue-router';
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
watch(route, ()=> { watch(route, () => {
getBreadcrumb() getBreadcrumb()
}) })
@@ -29,7 +29,7 @@ const breadcrumbList = ref([])
const getBreadcrumb = () => { const getBreadcrumb = () => {
let matched = route.matched.filter(item => item.meta && item.meta.title) let matched = route.matched.filter(item => item.meta && item.meta.title)
const first = matched[0] const first = matched[0]
if(!isDashboard(first)) { if (!isDashboard(first)) {
matched = [{path: '/home', meta: {title: '首页'}}].concat(matched) matched = [{path: '/home', meta: {title: '首页'}}].concat(matched)
} }
breadcrumbList.value.length = 0; breadcrumbList.value.length = 0;
@@ -39,7 +39,7 @@ const getBreadcrumb = () => {
const isDashboard = (meta) => { const isDashboard = (meta) => {
const name = meta && meta.name const name = meta && meta.name
if(!name) { if (!name) {
return return
} }
return name.trim().toLocaleLowerCase() === 'Home'.toLocaleLowerCase() return name.trim().toLocaleLowerCase() === 'Home'.toLocaleLowerCase()

View File

@@ -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{

View File

@@ -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>

View File

@@ -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

View File

@@ -188,11 +188,17 @@ 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') {
next('/') next('/')
NProgress.done() NProgress.done()
} else { } else {

View File

@@ -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
View 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;
}
}

View File

@@ -1,48 +1,54 @@
import axios from "axios"; import axios from "axios";
import { AxiosCanceler } from "./axiosCanceler"; import {AxiosCanceler} from "./axiosCanceler";
import { ElMessageBox, ElNotification } from "element-plus"; import {ElMessageBox, ElNotification} from "element-plus";
import { getToken, removeToken } from "./auth"; import {getToken, removeToken} from "./auth";
axios.defaults.headers['Content-Type']='application/json' axios.defaults.headers['Content-Type'] = 'application/json'
const serveice = axios.create({ const serveice = axios.create({
baseURL: import.meta.env.VITE_BASE_URL, baseURL: import.meta.env.VITE_BASE_URL,
timeout: 6000 timeout: 6000
}) })
const axiosCanceler = new AxiosCanceler() const axiosCanceler = new AxiosCanceler()
serveice.interceptors.request.use(config=>{ serveice.interceptors.request.use(config => {
const ACCESS_TOKEN = getToken() || '' const ACCESS_TOKEN = getToken() || ''
if(ACCESS_TOKEN!==undefined && ACCESS_TOKEN!=='') { if (ACCESS_TOKEN !== undefined && ACCESS_TOKEN !== '') {
config.headers['Authorization']=ACCESS_TOKEN config.headers['Authorization'] = ACCESS_TOKEN
} }
// 检查是否有重复请求, 有则取消掉 // 检查是否有重复请求, 有则取消掉
axiosCanceler.removePendingRequest(config) axiosCanceler.removePendingRequest(config)
// 将请求加入pendingMap // 将请求加入pendingMap
axiosCanceler.addPendingRequest(config) axiosCanceler.addPendingRequest(config)
return config return config
},error=>{ }, error => {
Promise.reject(error) Promise.reject(error)
}) })
serveice.interceptors.response.use(response=>{ serveice.interceptors.response.use(response => {
axiosCanceler.removePendingRequest(response.config) axiosCanceler.removePendingRequest(response.config)
//二进制数据直接返回 //二进制数据直接返回
if(response.request.responseType === 'blob' || response.request.responseType === 'arraybuffer') { if (response.request.responseType === 'blob' || response.request.responseType === 'arraybuffer') {
return response.data return response.data
} }
return response.data return response.data
},error=>{ }, error => {
let response = error.response let response = error.response
const status = response.status; const status = response.status;
switch(status) { switch (status) {
case 401: case 401:
ElMessageBox.confirm('登录状态已过期,请重新登录','系统提示',{ ElMessageBox.confirm('登录状态已过期,请重新登录', '系统提示', {
confirmButtonText: '重新登录', confirmButtonText: '重新登录',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
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:
@@ -79,9 +85,9 @@ serveice.interceptors.response.use(response=>{
window.location = '/forbidden' window.location = '/forbidden'
break; break;
case 500: case 500:
if (response.data){ if (response.data) {
return response.data return response.data
}else { } else {
ElNotification({ ElNotification({
title: '系统提示', title: '系统提示',
message: '系统未知错误', message: '系统未知错误',

View File

@@ -15,8 +15,15 @@ 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>

View File

@@ -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>

View File

@@ -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;
} }
} }

View 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>

View 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>

View 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>

View 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>

View 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
});
};

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View File

@@ -90,7 +90,7 @@ const schame = computed(()=>{
} }
}, },
{ {
label: '角色权限', label: '角色标识',
prop: 'roleKey', prop: 'roleKey',
component: 'el-input', component: 'el-input',
props: { props: {

View File

@@ -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

View File

@@ -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 = () => {

View File

@@ -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
} }
}) })
} }

View File

@@ -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,8 +19,9 @@ 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";
const props = defineProps({ const props = defineProps({

View File

@@ -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,

View File

@@ -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";

View File

@@ -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,12 +86,12 @@ 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) {
for (let user of operationNew.userInfo) { for (let user of operationNew.userInfo) {
let userNew = initUser(user,operationNew.operation) let userNew = initUser(user, operationNew.operation)
userList.push(userNew) userList.push(userNew)
} }
operationNew.userInfo = userList operationNew.userInfo = userList
@@ -132,7 +105,7 @@ const init = () => {
const getAttachmentList = (attachments, image) => { const getAttachmentList = (attachments, image) => {
let result = []; let result = [];
if (attachments){ if (attachments) {
for (let attachment of attachments) { for (let attachment of attachments) {
if (attachment.isImage === image) { if (attachment.isImage === image) {
result.push(attachment) result.push(attachment)
@@ -142,7 +115,7 @@ const getAttachmentList = (attachments, image) => {
return result; return result;
} }
const initUser = (user,type) => { const initUser = (user, type) => {
let state = user.state let state = user.state
//创建节点 //创建节点
if (state === 'CREATE') { if (state === 'CREATE') {
@@ -154,7 +127,7 @@ const initUser = (user,type) => {
user["icon"] = 'CircleCheckFilled' user["icon"] = 'CircleCheckFilled'
user["color"] = "#0bbd87" user["color"] = "#0bbd87"
} }
if (type === "CC"){ if (type === "CC") {
user["icon"] = "Promotion" user["icon"] = "Promotion"
user["color"] = "#3395f8" user["color"] = "#3395f8"
} }
@@ -169,7 +142,7 @@ const initUser = (user,type) => {
user["icon"] = 'Close' user["icon"] = 'Close'
user["color"] = "#f56c6c" user["color"] = "#f56c6c"
} }
if (state === 'PASS'){ if (state === 'PASS') {
user["icon"] = 'MoreFilled' user["icon"] = 'MoreFilled'
user["color"] = "#c0c4cc" user["color"] = "#c0c4cc"
} }
@@ -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>

View File

@@ -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()

View File

@@ -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 () => {

View File

@@ -1,13 +1,26 @@
<template> <template>
<el-input v-model="processData.deploymentName" placeholder="请输入流程名称" /> <el-input v-model="processData.deploymentName" placeholder="请输入流程名称"/>
流程设置{{ processData.deploymentName }} <!-- <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 }}
</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>

View File

@@ -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;

View File

@@ -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,17 +17,15 @@
<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>
</template> </template>
<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'
} }
}) })
@@ -70,7 +74,7 @@ const initUser = (user) => {
user["icon"] = Close user["icon"] = Close
user["color"] = "#f56c6c" user["color"] = "#f56c6c"
} }
if (state === 'PASS'){ if (state === 'PASS') {
user["icon"] = MoreFilled user["icon"] = MoreFilled
user["color"] = "#c0c4cc" user["color"] = "#c0c4cc"
} }
@@ -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>

View File

@@ -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"-->

View File

@@ -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">
@@ -55,8 +53,8 @@
<div class="org-items" style="height: 350px;"> <div class="org-items" style="height: 350px;">
<el-empty :image-size="100" description="请点击左侧列表选择数据" v-show="selectList.length === 0"/> <el-empty :image-size="100" description="请点击左侧列表选择数据" v-show="selectList.length === 0"/>
<div v-for="(selectItem, selectIndex) in selectList" :key="selectIndex" class="org-item"> <div v-for="(selectItem, selectIndex) in selectList" :key="selectIndex" class="org-item">
<!-- <el-avatar :src="selectItem.avatar" style="margin-right: 5px;"></el-avatar>--> <!-- <el-avatar :src="selectItem.avatar" style="margin-right: 5px;"></el-avatar>-->
{{ selectItem.name}} {{ selectItem.name }}
<i class="el-icon-close" @click="noSelected(selectItem)"></i> <i class="el-icon-close" @click="noSelected(selectItem)"></i>
</div> </div>
</div> </div>
@@ -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,30 +129,41 @@ 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) => {
let params = {}
if (flag === 1) {
isSearch.value = true;
params = {
chooseId: 0,
chooseName: filterText.value
}
selectItem = {
type: -1,
value: "0"
};
} else {
const radioChange = (e) => { params = {
selectItem.type = -2; chooseId: radio.value,
chooseId.value = 0; chooseName: filterText.value
radio.value = e; }
expandedKeys.value = []; }
getList(); getMosrDept(params).then(res => {
}; console.log('selectItem.type', selectItem.type)
const getList = () => {
getUserTree(radio.value, chooseId.value).then(res => {
// 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: '暂无数据'
}] }]
} }
} else if (selectItem.type === 2) { } else if (selectItem.type === 2) {
@@ -187,16 +199,24 @@ 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 (data.expanded) { if (isSearch.value && item.type !== 0) {
if(expandedKeys.value.indexOf(item.value)===-1){ filterText.value = ""
expandedKeys.value.push(item.value); radio.value = item.id;
if (item.type !== 0) {
chooseId.value = item.id;
getList(); getList();
return; return;
} else if (!isSearch.value) {
//渲染子节点用户或部门及用户数据
if (data.expanded) {
if (expandedKeys.value.indexOf(item.value) === -1) {
expandedKeys.value.push(item.value);
if (item.type !== 0) {
radio.value = item.id;
getList();
return;
}
} }
} }
} }
@@ -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 {
} }
} }

View File

@@ -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>--> <!-- &lt;!&ndash; <el-switch v-model="config.listener.state" @change="getListener"></el-switch>&ndash;&gt;-->
</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;"/>--> <!-- &lt;!&ndash; <el-input v-if="listen.isSys" placeholder="请设置字段值" size="small" v-model="listen.listenerValue" style="width: 180px;"/>&ndash;&gt;-->
<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({})

View File

@@ -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,8 +222,7 @@ 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)
} }
const delGroup = (index) => { const delGroup = (index) => {
@@ -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)

View File

@@ -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>

View File

@@ -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"

View File

@@ -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>
@@ -21,7 +22,8 @@ import CcNode from './CcNodeConfig.vue'
import Condition from './ConditionNodeConfig.vue' 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()
@@ -41,10 +43,11 @@ const active = ref('properties')
const visible = ref(false) 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;

View File

@@ -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>

View File

@@ -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>

View File

@@ -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 '未知设置项'
} }
}) })

View File

@@ -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">
@@ -43,9 +41,9 @@
<div class="node-footer"> <div class="node-footer">
<div v-if="merge" class="branch-merge"> <div v-if="merge" class="branch-merge">
<svg-icon name="fenzhi" :class-name="'fen-icon'"/> <svg-icon name="fenzhi" :class-name="'fen-icon'"/>
<!-- <img data-v-1e7b1da5=""--> <!-- <img data-v-1e7b1da5=""-->
<!-- src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAABXlJREFUeF7tmm2IVGUUx3/nLkQUqxmkpAVhSPUllZX8EEGhvVgZQWCU6wcpsqi2mXtnoaBwoqLCufeO9oJYUJQiFZWlZPQCfYiIXkylstTyS1oWWeYWCe6cuLsz7t3r3Ll3du6907oz35bnPM9z/r895zznmWeECf6RCa6fDoBOBExwAp0UmOAB0CmCnRTopECbCZi2nivK1CMD7FpXlH+ydqctKZBz9QyjwkqFG4HzfKK/0gpvl/ulmBWIzAHkVmlRDFY2EihwwLFkRhYQxgzAtHW2CpcBc4CpOsg26eK7yVPYVFwu/9ZzPufq2VLhQBxhAk85lvSF2Y5l/3prjQlAvqR3IjwJTKqz6DeGssQuyLfBsbyjz6PcFgeAZyOwzLFk/QnrjHH/RACYtj6ncHuUCDWYXs7Lz367XEn3inB+1NzauMLGsiW3+u1b2b9lAH22LuiCD2IJED5yTbmiZpt3dAbKT7Hmjhjtdi25oPZnK/uH7dtUCpi2vqVwQ1wRWuHhWkW3StpTEb6IO3fIThhwTemuzWll/0QA5G39FTgrtghhs2vKELA7inra6d38HXvusOEnriWXHo+iFvZvGUDfap3VdYzdzQgIHmd5W7cBc2Ovoax1C3KXZ5/E/i3VgCQciNMD+J1Ug55yXjxo7QfgOdFKCvjyeL/C9MgoEBa5przrt0ti/+C+mRVB/8amrWsU7m2Ql/c5lqwJjre9CDZ1DMFnriXzw0SatvZW4FqBW6o2vwGvCGxyLPmw3rym9g8cwy0XQV8Ix2qEgH0C1ziWNCyceVu1uvZrriVLGqVGsainHO7mRyDynlCvEWupCI7Kxcat6BFg+OwW9ohyfSMIcQF44v/sZovAlRH1I7QVTwyAt1Cjy8hfh9hYvepGQogDoI74HYbSXzHwusTYl7FEAURVcdPWN+NAiAJQTzzCda4p+6N8iDPe1CkQZ8FAtY+E0AhA2uKHszTlT1QkhAHIQnwmAKr1IjQS6gHISnxmABpBCALIUnymAMIgKHxf6wMmH6E3cNTtSLLgZXoKNOgAR6UDyqyq7esKk3znfOriM48AXzc5AmGE1EFgWvXPTMS3DcAJ6TA6XDIT31YAoRCEc5JqcuKc8Kn3AVFO+E4BryvJVHzbI8BzwAdgi2vJ4ihgSY//nyIg8jqctPi2RYBp61wV5qsyR2BFVdhBhBe0wtdisNU15VAagoNrZh4BOVsfFcVCODVUoLBn6E2hIBvShpApgLyt3nvhRXFFCWxwLOmNaz8Wu8wA5G31ntQWNOukwD2OJc80Oy+ufSYAciVdJsJLcZ0K2nV1MbuUk51jnd9oXuoACmW9eHCQj49/T+j3RtiJslPgFxXmoVxe11nhPdeUq8clANPWPoXVQef9D6e1saEHVINHUBYF7Q1lnl2QL5OGkHoE5G19GRhVyBQ+L1tyST0xoa/Iygq3IOvGI4BdwIWjHBeecE15IExM3tYfgJmBOetcU2o9Q2IcsoiAw8Gf0qhyU7kgb4QCcPRTlNGvSspmtzD81J7kJ30AJX0fYeHo2seLjiXLG0TA78CZ/nGFB8uWPJakeG+t9AE4+jjK/XGLWtgTusBix5It4w5ArqRLRTjhl14IW40KD/kre66ki0R4p57IrgozS/2yb9wByDvqhbKX07Xv/oIavMfOP6pFb0pdgcqrbkFuTlp8JingbRIaBfEUHUOYltbtMPUaUNNo2rpeYWk8zSNWqvSmeSvMDIAnybT1boWnY0I4aigL7YJ4bXRqn0wBeCqG7gYVVqFcFapKWXt0gP5nizKQmvLqwpkDqAkaanmhB4MelOkI27XCDjHY7pqyN23htfXbBiArgVH7dABEETrZxzsRcLL/h6P0/Qc1qphfvB2K3wAAAABJRU5ErkJggg=="--> <!-- src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAABXlJREFUeF7tmm2IVGUUx3/nLkQUqxmkpAVhSPUllZX8EEGhvVgZQWCU6wcpsqi2mXtnoaBwoqLCufeO9oJYUJQiFZWlZPQCfYiIXkylstTyS1oWWeYWCe6cuLsz7t3r3Ll3du6907oz35bnPM9z/r895zznmWeECf6RCa6fDoBOBExwAp0UmOAB0CmCnRTopECbCZi2nivK1CMD7FpXlH+ydqctKZBz9QyjwkqFG4HzfKK/0gpvl/ulmBWIzAHkVmlRDFY2EihwwLFkRhYQxgzAtHW2CpcBc4CpOsg26eK7yVPYVFwu/9ZzPufq2VLhQBxhAk85lvSF2Y5l/3prjQlAvqR3IjwJTKqz6DeGssQuyLfBsbyjz6PcFgeAZyOwzLFk/QnrjHH/RACYtj6ncHuUCDWYXs7Lz367XEn3inB+1NzauMLGsiW3+u1b2b9lAH22LuiCD2IJED5yTbmiZpt3dAbKT7Hmjhjtdi25oPZnK/uH7dtUCpi2vqVwQ1wRWuHhWkW3StpTEb6IO3fIThhwTemuzWll/0QA5G39FTgrtghhs2vKELA7inra6d38HXvusOEnriWXHo+iFvZvGUDfap3VdYzdzQgIHmd5W7cBc2Ovoax1C3KXZ5/E/i3VgCQciNMD+J1Ug55yXjxo7QfgOdFKCvjyeL/C9MgoEBa5przrt0ti/+C+mRVB/8amrWsU7m2Ql/c5lqwJjre9CDZ1DMFnriXzw0SatvZW4FqBW6o2vwGvCGxyLPmw3rym9g8cwy0XQV8Ix2qEgH0C1ziWNCyceVu1uvZrriVLGqVGsainHO7mRyDynlCvEWupCI7Kxcat6BFg+OwW9ohyfSMIcQF44v/sZovAlRH1I7QVTwyAt1Cjy8hfh9hYvepGQogDoI74HYbSXzHwusTYl7FEAURVcdPWN+NAiAJQTzzCda4p+6N8iDPe1CkQZ8FAtY+E0AhA2uKHszTlT1QkhAHIQnwmAKr1IjQS6gHISnxmABpBCALIUnymAMIgKHxf6wMmH6E3cNTtSLLgZXoKNOgAR6UDyqyq7esKk3znfOriM48AXzc5AmGE1EFgWvXPTMS3DcAJ6TA6XDIT31YAoRCEc5JqcuKc8Kn3AVFO+E4BryvJVHzbI8BzwAdgi2vJ4ihgSY//nyIg8jqctPi2RYBp61wV5qsyR2BFVdhBhBe0wtdisNU15VAagoNrZh4BOVsfFcVCODVUoLBn6E2hIBvShpApgLyt3nvhRXFFCWxwLOmNaz8Wu8wA5G31ntQWNOukwD2OJc80Oy+ufSYAciVdJsJLcZ0K2nV1MbuUk51jnd9oXuoACmW9eHCQj49/T+j3RtiJslPgFxXmoVxe11nhPdeUq8clANPWPoXVQef9D6e1saEHVINHUBYF7Q1lnl2QL5OGkHoE5G19GRhVyBQ+L1tyST0xoa/Iygq3IOvGI4BdwIWjHBeecE15IExM3tYfgJmBOetcU2o9Q2IcsoiAw8Gf0qhyU7kgb4QCcPRTlNGvSspmtzD81J7kJ30AJX0fYeHo2seLjiXLG0TA78CZ/nGFB8uWPJakeG+t9AE4+jjK/XGLWtgTusBix5It4w5ArqRLRTjhl14IW40KD/kre66ki0R4p57IrgozS/2yb9wByDvqhbKX07Xv/oIavMfOP6pFb0pdgcqrbkFuTlp8JingbRIaBfEUHUOYltbtMPUaUNNo2rpeYWk8zSNWqvSmeSvMDIAnybT1boWnY0I4aigL7YJ4bXRqn0wBeCqG7gYVVqFcFapKWXt0gP5nizKQmvLqwpkDqAkaanmhB4MelOkI27XCDjHY7pqyN23htfXbBiArgVH7dABEETrZxzsRcLL/h6P0/Qc1qphfvB2K3wAAAABJRU5ErkJggg=="-->
<!-- alt="">--> <!-- alt="">-->
</div> </div>
<div class="btn"> <div class="btn">
<insert-button v-if="designState" @insertNode="type => emit('insertNode', type)"/> <insert-button v-if="designState" @insertNode="type => emit('insertNode', type)"/>
@@ -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;

View File

@@ -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,