134 Commits
gary ... dj

Author SHA1 Message Date
dj
781e7393e8 test : 测试ci/cd-5 2025-06-13 18:22:50 +08:00
dj
065eb6cfba test : 测试ci/cd-4 2025-06-13 18:17:01 +08:00
dj
9bd9cda872 test : 测试ci/cd-3 2025-06-13 18:10:24 +08:00
dj
cd2bfe8817 test : 测试ci/cd-2 2025-06-13 17:59:33 +08:00
dj
fa3171fecd test : 测试ci/cd-1 2025-06-13 17:50:21 +08:00
dj
28de3667f5 test : 测试ci/cd 2025-06-13 14:57:15 +08:00
dj
529f482bc7 test : 测试ci/cd 2025-06-13 14:39:23 +08:00
dj
bd35243cbd test : 测试ci/cd 2025-06-13 14:23:37 +08:00
6c7eddcf94 Merge pull request 'test : 测试ci/cd' (#1040) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1040
2025-06-13 06:18:59 +00:00
bacd397294 revert 215f7c6bbf
revert feat(expense-management): 添加研发工时超过21.75天的提示功能

- 在保存分配明细时,增加对研发人员总工时的计算
- 如果总工时超过21.75天,系统将发出警告通知- 优化了控制台日志输出,便于调试和监控
2025-06-13 06:14:19 +00:00
dj
b3dbb24bb2 test : 测试ci/cd 2025-06-13 14:11:25 +08:00
dj
f448ec47a3 test : 测试ci/cd 2025-06-12 15:26:52 +08:00
dj
a4674d497b test : 测试ci/cd 2025-06-12 15:18:29 +08:00
dj
43e0f98509 test : 测试ci/cd 2025-06-12 14:53:52 +08:00
dj
560bea739c test : 测试cicd 2025-06-12 14:07:25 +08:00
dj
1ed6156117 build(deps): 删除 moment 依赖 2025-06-12 12:08:41 +08:00
dj
7f0f74c844 build(deps): 添加 moment 依赖 2025-06-12 12:04:11 +08:00
dj
579cadd687 refactor(components): 优化文件上传成功提示 2025-06-12 11:42:09 +08:00
dj
1a120418f0 build: 调整 package.json 2025-06-12 11:28:25 +08:00
dj
e49b6ef1a3 build: 更新 Node.js 版本并调整 package.json 格式 2025-06-12 11:15:52 +08:00
dj
a0d9c58c77 fix(ProjectAttachment): 修改drone 2025-06-12 11:12:52 +08:00
dj
4bb0c49dc8 fix(ProjectAttachment): 修改drone 2025-06-12 11:08:03 +08:00
dj
aada3d785b fix(ProjectAttachment): 修改drone 2025-06-12 10:16:35 +08:00
dj
35b332f640 fix(ProjectAttachment): 添加依赖 2025-06-12 10:03:57 +08:00
dj
6afac9be28 fix(ProjectAttachment): 添加依赖 2025-06-12 09:35:00 +08:00
dj
dc064de364 fix(ProjectAttachment): 修改drone.yml 2025-06-12 09:28:02 +08:00
dj
78bafe0a7e fix(ProjectAttachment): 修改drone.yml 2025-06-12 09:24:29 +08:00
dj
d0960f6ad6 feat(FileUpload): 实现多文件批量上传功能
- 添加自定义上传逻辑,支持多文件上传- 优化文件选择和上传流程,实现自动上传
-增加上传进度提示和完成通知
- 修复了一些与上传相关的小问题
2025-06-11 22:48:27 +08:00
dj
e7b982ef6c fix(ProjectAttachment): 移除未使用的上传附件相关代码 2025-06-11 16:34:59 +08:00
dj
b5ada3a1ac feat(FileUpload): 添加文件上传中的 loading 效果 2025-06-11 14:19:55 +08:00
dj
215f7c6bbf feat(expense-management): 添加研发工时超过21.75天的提示功能
- 在保存分配明细时,增加对研发人员总工时的计算
- 如果总工时超过21.75天,系统将发出警告通知- 优化了控制台日志输出,便于调试和监控
2025-06-09 22:28:24 +08:00
dj
e4025b90e9 refactor(expense-management): 注释掉研发人员重复性检查代码
- 在 add.vue 文件中,注释掉了两段用于检查研发人员重复性的代码
- 此修改可能是为了暂时禁用重复性检查功能,或者准备替换为新的检查逻辑
2025-06-08 23:08:02 +08:00
dj
70d94f3c1d refactor(expense-management): 优化数字输入和附件处理
- 在 ProjectApply 组件中,将多个 el-input 组件替换为 el-input-number 组件,用于限制输入格式
- 在 ProjectAttachment 组件中,优化附件列表获取逻辑,实现附件去重功能
- 在 add.vue 文件中,启用 console.log 输出,用于调试项目 ID 和研发人员 ID 数组
2025-06-06 22:58:48 +08:00
dj
05275aed15 fix : 修复归档附件bug 2025-05-28 23:53:10 +08:00
dj
9758981d3f fix : 修复归档附件bug 2025-05-28 23:50:59 +08:00
dj
7c2d713035 fix(components): 优化多个组件的显示逻辑
- 在 ApprovalDetail组件中,改进了多个字段的显示逻辑,增加了对 0值的处理
- 在 AttachmentUpload 组件中,调整了必填项的显示逻辑
- 在 ProjectApply 组件中,修改了前置流程字段的显示条件
- 在 upload 组件中,优化了文件列表的处理逻辑
2025-05-28 23:01:16 +08:00
dj
f4330b60d5 refactor(ProjectApply): 优化归档附件上传逻辑 2025-05-28 16:50:55 +08:00
dj
f61d50dbfc refactor(components): 调整文件上传大小限制并优化附件展示逻辑 2025-05-23 09:07:02 +08:00
dj
66dc6df0d9 fix(ProjectAttachment): 重新获取附件列表
在删除附件后,添加了重新获取附件列表的调用,以确保界面上的附件列表是最新的。
2025-05-22 23:08:27 +08:00
dj
c7329f2f6d fix(ProjectAttachment): 修复删除附件后未及时更新文件列表的问题- 在删除文件后添加了更新文件列表的逻辑
- 优化了获取本地文件列表的方法
- 调整了文件列表的初始化位置
2025-05-22 22:56:06 +08:00
dj
673e4fa20a feat(ProjectAttachment): 优化文件上传和管理功能
- 新增本地存储功能,暂存未提交的文件
- 优化文件删除逻辑,区分本地和服务器文件
- 添加提交按钮,将本地文件上传到服务器
- 调整标签切换时的文件列表显示逻辑
- 优化代码结构,提高可读性和可维护性
2025-05-22 16:45:58 +08:00
dj
ee5fc2cba3 refactor(project-demand): 优化方案总结提交逻辑
- 移除了不必要的空数组初始化
-简化了 requirementId 的赋值逻辑
- 添加了空行以提高代码可读性
2025-05-22 10:06:44 +08:00
dj
b7ca97696a fix(project-demand): 修复专项经费选择框逻辑
- 修改了专项经费选择逻辑,确保在选择专项经费时正确处理 specialFund 和 specialFundId 的值
- 优化了代码结构,提高了可读性和维护性
2025-05-21 23:14:00 +08:00
dj
baea68c52a Merge remote-tracking branch 'origin/master' 2025-05-21 22:39:08 +08:00
dj
a2ed04e144 refactor(project-demand): 优化加载状态管理
- 在获取数据失败时添加 loading.value = false,确保正确更新加载状态
2025-05-21 22:38:53 +08:00
dj
287d6a3ad0 feat(project-demand): 编辑概览页面数据持久化 2025-05-21 14:31:38 +08:00
dj
673a26368a fix(project-demand): 修复专项基金选择问题 2025-05-21 12:55:23 +08:00
dj
9adea1060c feat(ProjectApply): 科技处用户申请项目时增加部门分管领导必选项 2025-05-19 22:13:03 +08:00
dj
4e5a4bb4b9 refactor(permission): 优化面包屑控制逻辑 2025-05-16 18:14:31 +08:00
dj
a5ebab16a6 fix : 修复需求上报缓存问题 2025-05-15 16:06:04 +08:00
dj
0cc1b63ae7 feat(project-management): 优化前置流程选择功能
- 在项目申请详情页面添加基本数据传递
- 实现前置流程的更改和选择功能
- 优化前置流程数据的存储和展示
- 添加对不可重复选择的前置流程的校验
2025-05-05 20:15:13 +08:00
dj
d76ef8ff9c feat(project-demand): 更新项目需求汇总功能
- 新增 getProjectName 方法,用于项目名称关键词匹配- 修改远程搜索方法,使用 getProjectName 替代 getRequirementName
- 更新 ProjectApply 组件,调整专项资金输入框显示逻辑
- 移除 proxy 配置中的注释
2025-05-05 17:53:55 +08:00
dj
f105485714 feat(project-demand): 添加项目名称远程搜索功能并优化前置流程显示逻辑
- 在项目需求概览页面添加项目名称远程搜索功能,提高搜索效率和准确性
- 优化项目申请详情页面的前置流程显示逻辑,根据不同场景调整标签宽度
2025-05-05 14:48:07 +08:00
dj
af275ea6c4 fix : 修复公告问题 2025-04-29 11:29:06 +08:00
dj
c27162f918 feat : 项目归档-实施附件 2025-04-27 14:28:59 +08:00
dj
f1b81d86a2 fix : 备份附件 2025-04-27 11:00:38 +08:00
dj
710ccbdf65 fix : 修复单位元 2025-04-24 21:48:23 +08:00
dj
7fcfc992fb refactor(project-management): 统一经费预算单位
- 在多个组件中将"预估经费预算"和"实际经费预算"的标签添加单位"(元)"
-调整部分组件的标签宽度以适应新的单位
- 此修改统一了经费预算的显示格式,提高了用户体验
2025-04-24 15:30:14 +08:00
dj
a792df80e6 feat(components): 增加审核意见必填校验 2025-04-23 22:46:58 +08:00
dj
5dccaa1ee7 fix : 标签不可编辑 2025-04-20 20:32:16 +08:00
dj
8aefca0c82 feat : 项目验收新增字段 2025-04-20 19:49:57 +08:00
dj
afda146103 feat : 项目归档-附件新增项目阶段字段 2025-04-20 14:43:57 +08:00
dj
11f7fa37aa feat : 年度计划新字段 2025-04-20 13:01:43 +08:00
dj
35c2e1d9b4 feat : 需求上报新增字段 2025-04-20 12:46:14 +08:00
dj
fe3a15fcbd fix: 调整详情页面知识产权输出项 2025-04-19 21:03:54 +08:00
dj
9fd97f6ea2 feat :需求上报新增字段 2025-04-19 20:13:11 +08:00
dj
cccd14ec79 fix: 移除预期成果形式相关代码 2025-04-19 19:03:10 +08:00
dj
958399a32a fix : 注释立项提交的前置流程 2025-04-19 13:43:36 +08:00
dj
8ea916c206 fix : 完善需求上报字段页面 2025-04-19 10:58:28 +08:00
dj
10e9c9de19 fix: 修复审批白名单中取消事件 2025-04-18 22:51:49 +08:00
dj
b032903ed4 fix(project): 调整知识产权相关表述和附件表格样式
- 将"知识产权状况"修改为"知识产权归属"
- 优化附件上传和展示组件的样式- 统一知识产权归属相关的标签和提示信息
- 调整部分组件的显示逻辑和样式
2025-04-18 22:37:22 +08:00
dj
696921243e fix : 首页字体颜色统一 2025-04-18 18:13:03 +08:00
dj
7200592f05 fix : 首页字体颜色统一 2025-04-18 14:04:44 +08:00
dj
963b7b93e3 Merge remote-tracking branch 'origin/master' 2025-04-18 11:22:24 +08:00
dj
86751acbd6 fix : 首页字体颜色统一 2025-04-18 11:22:00 +08:00
dj
fda0f4fcde fix: 编辑上报时主项目选项过滤当前项目 2025-04-15 23:56:05 +08:00
dj
2847c88c61 style(article-management): 优化附件列表样式
- 在 add.vue 和 detail.vue 中为附件列表项添加底部间距,提升可读性
- 保持附件列表样式在不同页面中的一致性
2025-04-15 23:29:30 +08:00
dj
2827c5ace6 feat: 费用导入功能 2025-04-15 23:14:46 +08:00
dj
9941fc14f6 fix: 注释公告附件列表相关代码 2025-04-15 22:33:38 +08:00
dj
c71208c3e4 feat: 抄送成功后刷新功能 2025-04-15 11:15:15 +08:00
dj
7e6b48b62a feat: 项目详情审批流程加立即抄送按钮 2025-04-15 10:40:52 +08:00
dj
e77820e145 fix: 修复附件上传和展示问题 2025-04-14 21:19:55 +08:00
dj
a1422067d0 feat: 审批流程加立即抄送按钮 2025-04-14 16:44:42 +08:00
dj
7579b77b2d feat: 添加导入研发费用明细表和模板下载功能 2025-04-14 15:43:48 +08:00
dj
c6390a8117 feat: 文章管理增加附件上传/删除/下载功能 2025-04-14 15:07:58 +08:00
dj
e20f8cad7f fix: 修复附件上传和展示问题 2025-04-13 21:22:22 +08:00
dj
5cf2e4d208 feat(article-management): 增加文章附件上传功能
- 在文章管理页面添加公告附件列表
- 实现附件上传和展示功能- 优化 Tinymce 组件,支持附件上传事件
2025-04-11 18:21:43 +08:00
dj
ad6d7af1a3 Merge remote-tracking branch 'origin/master' 2025-04-11 14:08:25 +08:00
dj
65a4c72fd0 style(mobile): 优化附件文件列表的展示效果 2025-04-11 14:08:02 +08:00
dj
810757e828 fix: 修复附件上传和展示问题 2025-04-09 23:11:06 +08:00
dj
af593b08da Merge remote-tracking branch 'origin/master' 2025-04-09 12:58:56 +08:00
dj
2b14bd19a4 fix : 修复项目归档附件项目基本信息展示 2025-04-09 12:58:34 +08:00
cc1d0c8cf2 Merge pull request 'fix : 修复项目实施附件上传功能' (#979) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/979
2025-04-09 02:58:50 +00:00
dj
f3d9ff44a3 fix : 修复项目实施附件上传功能 2025-04-09 10:58:26 +08:00
a3cbf4d24b Merge pull request 'fix : 修复项目实施附件上传功能' (#977) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/977
2025-04-09 01:42:17 +00:00
dj
d3b12bd64c fix : 修复项目实施附件上传功能 2025-04-09 09:37:53 +08:00
d0c677cfb4 Merge pull request 'dj' (#975) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/975
2025-04-08 16:23:33 +00:00
dj
e9469439e8 Merge remote-tracking branch 'origin/dj' 2025-04-09 00:16:51 +08:00
62035606c9 Merge pull request 'master' (#974) from master into dj
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/974
2025-04-08 16:16:26 +00:00
dj
b101d70c75 fix: 修复附件上传和展示问题 2025-04-09 00:15:01 +08:00
dj
8c5d08874f fix: 修复附件上传和展示问题 2025-04-09 00:14:10 +08:00
dj
25d5b20b65 fix: 修复附件上传和展示问题 2025-04-09 00:13:51 +08:00
dj
2f43919132 fix: 分摊明细导出调整参数 2025-04-08 23:05:42 +08:00
dj
7b619a9bef fix: 分摊明细导出调整参数 2025-04-08 00:30:32 +08:00
dj
a9a2be2c74 fix: 优化首页通知公告样式 2025-04-07 21:57:13 +08:00
dj
a307697028 fix: 优化移动端项目管理功能 2025-04-06 22:38:14 +08:00
dj
e8a5b4e788 feat(article-management): 首页通知公告加时间, 将"备注"字段改为"发文单位" 2025-04-06 21:25:30 +08:00
7b8cedcfb0 Merge pull request 'master' (#967) from master into dj
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/967
2025-04-06 09:10:49 +00:00
dj
d3c0b36657 refactor(views/components): 优化首页通知公告展示和项目附件搜索功能
- 首页通知公告:调整公告列表的序号显示逻辑
- 项目附件:改进附件搜索功能,支持按全部文件搜索
- 搜索组件:更新搜索界面文本,根据搜索范围动态显示标签或项目阶段
2025-04-06 17:10:08 +08:00
dj
eabf9cb3d6 refactor(project): 优化项目相关页面显示内容
- 修改项目需求、总结、立项、实施、归档页面中的编号标签
- 更新项目申请组件,根据项目类型动态显示实际专项资金输入框
-调整 API 代理配置
2025-04-06 16:47:23 +08:00
dj
348027f355 feat(project-management): 优化文件归档表格状态展示和权限控制 2025-04-03 00:34:04 +08:00
dj
ed22942ab2 fix(project-management): 优化附件启用禁用操作反馈 2025-04-03 00:11:21 +08:00
dj
119e3d8333 feat(ProjectAttachment): 优化文件上传标签逻辑 2025-04-03 00:09:41 +08:00
dj
bf34d8aa0c feat(ProjectAttachment): 添加文件下载功能 2025-04-02 23:34:45 +08:00
dj
69aa6aa0fb refactor(project-demand): 优化需求变更时特殊基金逻辑 2025-04-02 23:26:01 +08:00
dj
e54db551a6 feat(project-demand): 添加需求征集变更逻辑 2025-04-02 23:01:17 +08:00
6c91a0740a Merge pull request 'fix: 修改分摊明细页面路由跳转逻辑' (#962) from master into dj
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/962
2025-04-01 16:06:24 +00:00
dj
9174c09a6b fix: 修改分摊明细页面路由跳转逻辑 2025-04-02 00:05:48 +08:00
dj
4dc5ca40ee feat(share-detail): 添加分摊导出按钮 2025-04-02 00:02:49 +08:00
dj
1e29e6bdc4 feat(expense-management): 新增费用分摊功能并优化项目管理相关页面 2025-04-01 23:57:46 +08:00
a3bb1a9156 Merge pull request 'feat: 支出明细筛选和导出功能' (#958) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/958
2025-04-01 10:19:16 +00:00
dj
e9ced267ed feat: 支出明细筛选和导出功能 2025-04-01 13:04:34 +08:00
a87be0e6e2 Merge pull request 'dj' (#956) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/956
2025-03-31 15:16:28 +00:00
dj
98d8ea4805 feat(expense-management): 新增费用分摊功能并优化项目管理相关页面 2025-03-31 23:14:54 +08:00
dj
244f2e72b4 feat: 项目基本信息新增实际经费预算和专项资金相关字段 2025-03-31 14:12:28 +08:00
dj
f9aa6191ce feat(project-manage): 新增项目附件标签功能 2025-03-30 15:06:56 +08:00
dj
ebd7fa3851 feat(project-manage): 新增项目附件标签功能 2025-03-30 15:06:39 +08:00
2941847f54 Merge pull request 'dj' (#955) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/955
2025-03-29 12:25:32 +00:00
dj
ca9e281119 feat(project-manage): 新增项目附件标签功能 2025-03-29 20:24:53 +08:00
dj
a1ed160445 Merge remote-tracking branch 'origin/master' 2025-03-28 19:41:10 +08:00
dj
9db0e8e9ec feat(expense-management): 新增费用分摊功能 2025-03-25 15:17:08 +08:00
d73eb49461 Merge pull request 'dj' (#953) from dj into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/953
2025-03-25 06:28:09 +00:00
dj
b890372fc5 feat(ProjectAttachment): 优化项目附件组件功能和布局
- 移除了不必要的搜索和上传按钮
- 添加了文件上传功能和单个文件删除功能
- 优化了标签页切换逻辑
-调整了样式和布局
2025-03-25 14:27:48 +08:00
dj
53bab74ea9 feat(project-management): 更新项目管理相关页面文案并优化附件功能 2025-03-22 23:11:09 +08:00
65 changed files with 4591 additions and 797 deletions

View File

@@ -4,8 +4,6 @@ RUN rm -rf /etc/nginx/conf.d/default.conf
RUN rm -rf /etc/nginx/nginx.conf
COPY default.conf /etc/nginx/conf.d
COPY nginx.conf /etc/nginx/
COPY mosr.feashow.cn_chain.crt /etc/nginx/
COPY private.key /etc/nginx/
#RUN useradd -b /home/clay -m -s /bin/bash clay
#RUN chmod a+xr -R /home/clay && chown clay:clay -R /home/clay

View File

@@ -1,72 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIG3DCCBMSgAwIBAgIQDzIS+rldpl8FKv9qt1IuQDANBgkqhkiG9w0BAQsFADBb
MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg
SW5jLjElMCMGA1UEAxMcVHJ1c3RBc2lhIERWIFRMUyBSU0EgQ0EgMjAyNTAeFw0y
NTAzMTkwMDAwMDBaFw0yNTA2MTcyMzU5NTlaMBoxGDAWBgNVBAMTD21vc3IuZmVh
c2hvdy5jbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK92bSayd6Wo
wFJz+ldX8QEgQiUjEPyQB0rV+Op9/eZSmpC6y+DuS/CddOPaXs+t1fV9L2kQ1yWD
Byc7cZK2PnzGb8+Uh9BR3UtVaCxISGqxjvt2V1lIwXbBDOUjtkVVlchhGR+BrNzP
YGyMLhgdBDxhKK4ogBNOx23AzCpTGFsU7sL996qwYo2rhIE8UuYcw3deS4RtfMUx
zt58wn1s+9kki6Qti7dLw3Bg0eCXop+7/FC09fg5Nh3EygMlZvLyvNOFig+o/Fk3
6ibp2N56yFLEfe+WNj4xPCad/3Cevh5BIgTsSAPBh6J5Jk4IXoL8PuCSc96d79Bg
SVGNGhRuCgcCAwEAAaOCAtswggLXMB8GA1UdIwQYMBaAFLQSKKW0wB2fKXFpPNkR
lkp1aVDAMB0GA1UdDgQWBBTL9/e/QUue1NxlPXspxQ/RzXhzxTAaBgNVHREEEzAR
gg9tb3NyLmZlYXNob3cuY24wPgYDVR0gBDcwNTAzBgZngQwBAgEwKTAnBggrBgEF
BQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIF
oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIweQYIKwYBBQUHAQEEbTBr
MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUH
MAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9UcnVzdEFzaWFEVlRMU1JT
QUNBMjAyNS5jcnQwDAYDVR0TAQH/BAIwADCCAX8GCisGAQQB1nkCBAIEggFvBIIB
awFpAHYATnWjJ1yaEMM4W2zU3z9S6x3w4I4bjWnAsfpksWKaOd8AAAGVrKDPywAA
BAMARzBFAiAJkC1pvmPIhgdAkRoyPCItM4oRM5Bb8OI3zVzNvdNTkQIhAN1Fq4mU
GJYrJkOmwvJ2Mb5upB50Ic8C7KatpMdKEFM7AHYAfVkeEuF4KnscYWd8Xv340Idc
FKBOlZ65Ay/ZDowuebgAAAGVrKDQBwAABAMARzBFAiAT9jfX08uN94aIeK84IySz
jUPDa1MSWjJKsA3XusY3GAIhAJ9PvGtFx9+UM9YNNT7BZUq6hhVvhYWhlf+d0qpy
uEl9AHcAzxFW7tUufK/zh1vZaS6b6RpxZ0qwF+ysAdJbd87MOwgAAAGVrKDP+AAA
BAMASDBGAiEA0c9dt1JwyAMzQtv7UsPaKEJ5sp6HDaSWe5BGIYWsYrcCIQDjS6L1
9TF6SpcEWHH6bl952VQb6Xvt1JmmKUNX6iK2xTANBgkqhkiG9w0BAQsFAAOCAgEA
0E2VWQjWgEBz968xq2cpYGv2Enfs2TWpynuoPTwY83V7h2ejNbpjgyW1gT/kQkxa
G5k4jpkVmNMaj3CAvK4IA5jOPh6dhzBG35Qc0PwRm0eovcUdUNUd0g4EOv82p2s1
ab1SWNYoxGdS+y+LHhfFZ7CoVcSvBz+LHBlPTVTkLA0SWLA0fhS3pl5oGIilMtSM
znCUUuMBtMQBv7sFX2gDEYwxGaMn3lpoqBGkpx4UBc51z/U3+X9zLqu6n/GpLC72
+qz6QtQVm0Np8gcjul0ebQqAPwDG4U+9jYEmdwVHZ0iUKgyZPECPU+TTtHx0TFS3
B5JXy8vbGJBqpwq6hMnu/SFm+GY3iPk7N0Aj5+9QNcl2FTF8k/nCoK3MuY71ZmxR
E1NY6Hl5KpKzBqc7JG4iqQxJ0dD9Racn4wegGDlX0Vr2U+ohHYeETNJXOX+JT4tc
1PBdfiywbX+FCdE2ZPehWa6dt4fnPBC/9lSywrzOWLNt9z1a/Mh73N5F6ndaXq1p
v/N3Q0qnXpW1RZa6Baqlfvk2vqhraRbT9YH5Y+f51DhtVB6fbELO/pJr1H5kh0XI
CczHkGTGD7xZloNfTMLP2AVguIXJ0EASAAMw/MBRWvSd4He2lLHvujEqTXsTISgv
v+/5bZP8qBk3/oEgdLjlmqWY1sesBH84tiMZcxCkPNM=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFnjCCBIagAwIBAgIQCSYyO0lk42hGFRLe8aXVLDANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
MjAeFw0yNTAxMDgwMDAwMDBaFw0zNTAxMDcyMzU5NTlaMFsxCzAJBgNVBAYTAkNO
MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSUwIwYDVQQD
ExxUcnVzdEFzaWEgRFYgVExTIFJTQSBDQSAyMDI1MIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEA0fuEmuBIsN6ZZVq+gRobMorOGIilTCIfQrxNpR8FUZ9R
/GfbiekbiIKphQXEZ7N1uBnn6tXUuZ32zl6jPkZpHzN/Bmgk1BWSIzVc0npMzrWq
/hrbk5+KddXJdsNpeG1+Q8lc8uVMBrztnxaPb7Rh7yQCsMrcO4hgVaqLJWkVvEfW
ULtoCHQnNaj4IroG6VxQf1oArQ8bPbwpI02lieSahRa78FQuXdoGVeQcrkhtVjZs
ON98vq5fPWZX2LFv7e5J6P9IHbzvOl8yyQjv+2/IOwhNSkaXX3bI+//bqF9XW/p7
+gsUmHiK5YsvLjmXcvDmoDEGrXMzgX31Zl2nJ+umpRbLjwP8rxYIUsKoEwEdFoto
Aid59UEBJyw/GibwXQ5xTyKD/N6C8SFkr1+myOo4oe1UB+YgvRu6qSxIABo5kYdX
FodLP4IgoVJdeUFs1Usa6bxYEO6EgMf5lCWt9hGZszvXYZwvyZGq3ogNXM7eKyi2
20WzJXYMmi9TYFq2Fa95aZe4wki6YhDhhOO1g0sjITGVaB73G+JOCI9yJhv6+REN
D40ZpboUHE8JNgMVWbG1isAMVCXqiADgXtuC+tmJWPEH9cR6OuJLEpwOzPfgAbnn
2MRu7Tsdr8jPjTPbD0FxblX1ydW3RG30vwLF5lkTTRkHG9epMgpPMdYP7nY/08MC
AwEAAaOCAVYwggFSMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLQSKKW0
wB2fKXFpPNkRlkp1aVDAMB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
dgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
dC5jb20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E
aWdpQ2VydEdsb2JhbFJvb3RHMi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov
L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDARBgNV
HSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBAJ4a3svh316GY2+Z7EYx
mBIsOwjJSnyoEfzx2T699ctLLrvuzS79Mg3pPjxSLlUgyM8UzrFc5tgVU3dZ1sFQ
I4RM+ysJdvIAX/7Yx1QbooVdKhkdi9X7QN7yVkjqwM3fY3WfQkRTzhIkM7mYIQbR
r+y2Vkju61BLqh7OCRpPMiudjEpP1kEtRyGs2g0aQpEIqKBzxgitCXSayO1hoO6/
71ts801OzYlqYW9OQQQ2GCJyFbD6XHDjdpn+bWUxTKWaMY0qedSCbHE3Kl2QEF0C
ynZ7SbC03yR+gKZQDeTXrNP1kk5Qhe7jSXgw+nhbspe0q/M1ZcNCz+sPxeOwdCcC
gJE=
-----END CERTIFICATE-----

View File

@@ -25,31 +25,9 @@ http {
keepalive_timeout 65;
# HTTP重定向到HTTPS
server {
listen 80;
listen [::]:80;
server_name mosr.feashow.cn;
return 301 https://$host$request_uri; # 强制跳转HTTPS
}
# 新增HTTPS服务器块
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name www.abc.com;
# SSL证书配置
ssl_certificate /etc/nginx/mosr.feashow.cn_chain.crt;
ssl_certificate_key /etc/nginx/private.key;
# 优化SSL配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
location /api {
proxy_pass http://gateway.$PROFILES.svc.cluster.local:8080;
@@ -69,6 +47,5 @@ http {
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
}
}

View File

@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCvdm0msnelqMBS
c/pXV/EBIEIlIxD8kAdK1fjqff3mUpqQusvg7kvwnXTj2l7PrdX1fS9pENclgwcn
O3GStj58xm/PlIfQUd1LVWgsSEhqsY77dldZSMF2wQzlI7ZFVZXIYRkfgazcz2Bs
jC4YHQQ8YSiuKIATTsdtwMwqUxhbFO7C/feqsGKNq4SBPFLmHMN3XkuEbXzFMc7e
fMJ9bPvZJIukLYu3S8NwYNHgl6Kfu/xQtPX4OTYdxMoDJWby8rzThYoPqPxZN+om
6djeeshSxH3vljY+MTwmnf9wnr4eQSIE7EgDwYeieSZOCF6C/D7gknPene/QYElR
jRoUbgoHAgMBAAECggEABmJQMV6/9LKRoM5gduoXtjtGvNQsS4wv/7yOTHXeFZG+
1vI89cel0rDf7mRlG7hO9xohbfizY0WDrp0+kiB4YJDVw587W8yGuTV3z1in7d3c
/nA9WF3J0DjQ78tfV+F3zC0gPWG5+OTAtOJa0PzJSSsd0Exf8JPmtKsVopqYYcPv
RL2uP+NfcsxIEPz7rBBqiTGbOgsoKIpVZWiV6dmGOHLnI3ktWE8GXyIFv0VO6kp2
fk/Z2uU9rfS9Qc9NijVdZ5AejdSh70iWNdiVMTSXZ69XLQCiY1h/376mraAPZTC1
T0fYAtaOdyRrYLIW3yuznZa6hz351+t4TjJHQGjAUQKBgQDe8FS3yM85Ve3qlNaV
pzjpjkv8cn8u43Hyk88owNACxkvzUXx15YE+AGjjycVO5rbyC1mtdE2MKX8cd5T/
cA75RoSDxBTR7xi9eqBzJpQ7hm2rTaZSkHhu4P9KsthgQFFYQB6EkZgYczLOs/OV
UmPMuKwL7HcwuRf00jjAOoJPdwKBgQDJe7R4PS0VBAWnh3lC9R/NEbEoFQ6LUwPh
Qgmgj6LRB/1NgaC7ekDCSyfFlTtpnRDD+WqCrZDiB1ZZehyUObvr0Y0Cb4Y77Fjh
lPVG0kfcKUldMpJIfeex0LPBwYHC62Y0ztNQmtgTldDjX04b4gAEgpUReHVTJtDr
6S1wRPVd8QKBgHIL0+roqUmVcc5NMbEBCJZCGxEbqYBdDg+gGZupdz/UHUpt5xOQ
wprrLr1InM0OLYyIzelz06/eEo6HhgteUeqnbmbRyizS+X8E2kvN8oq47CVz5Z/b
FCD0rOSTtSkX/gT9WB9NM9deJyGi4PsEWNWDq0+2OgsMxPqTCEEeLUdlAoGAHNmB
tdXMpr20sZBMZLIEo7Bs1XhuZLS2UYLLLhpjDds/AeIVycJvk2J/h2Me5rh+thD4
l02S+Upjqtw5S2AY8GNI9ZhSeDIXZ/WUSVfCwluHDbk4CPk+O8/ObWfv1KEwOU+E
In6JggRprKTw4j0yE3M/NQkyg32DXMQ+pVy6ZYECgYEAmW/+vm3X2NMj8yjr0Io2
P3F/9EHPkrGHNC3Qj6Q2mFus6oDe6NwOQg5Su0fFC77spHFi1g/MlGUxbzoxjVxH
1wQmwCHBJuJ97H9MOJ9K2v88/pkvfFGthkTLpbcJLqX57WVEVnVKBMNhpLrlp+0r
T3tV8tN010INwiQkaoqCsuw=
-----END PRIVATE KEY-----

View File

@@ -9,6 +9,13 @@ export const addAllocation = (data) => {
data
});
};
export const addShare = (data) => {
return request({
url:'/workflow/mosr/cost/share',
method: "post",
data
});
};
export const getAllocationDetail = (allocationId) => {
return request({
url: `/workflow/mosr/cost/allocation/info/${allocationId}`,
@@ -61,6 +68,13 @@ export const editAllocation = (data) => {
data
});
};
export const applyCcSend = (data) => {
return request({
url: '/workflow/mosr/cc/send',
method: "post",
data
});
};
export const deleteAllocation = (id) => {
return request({
url: `/workflow/mosr/cost/allocation/${id}`,
@@ -79,3 +93,15 @@ export const shareExportExcel = (allocationId) => {
}
);
};
export const shareDetailExport= (data) => {
return axios.post(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/cost/share/export`,
data, {
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};

View File

@@ -25,6 +25,16 @@ export const getRequirementName = (requirementName) => {
method: "get"
});
};
//需求汇总-项目名称关键词匹配
export const getProjectName = (projectName) => {
return request({
url: `workflow/mosr/requirement/collect`,
method: "get",
params:{
projectName:projectName
}
});
};
//获取需求上报 流程信息
export const getProcessInfo = (specialFund) => {
return request({

View File

@@ -85,6 +85,35 @@ export const getTags = (projectId) => {
method: "get"
});
};
export const getTagList = (projectId) => {
return request({
url: `/workflow/mosr/file/tag/list`,
method: "get",
params:{
projectId: projectId
}
});
};
export const addTag = (data) => {
return request({
url: '/workflow/mosr/file/tag/add',
method: "post",
data:data
});
};
export const updateTag = (data) => {
return request({
url: '/workflow/mosr/file/tag/update',
method: "post",
data:data
});
};
export const delTag = (tageId) => {
return request({
url: `/workflow/mosr/file/tag/${tageId}`,
method: "delete"
});
};
export const getPhaseProcess = () => {
return request({
url: '/workflow/phase/change/process',
@@ -197,3 +226,15 @@ export const ledgerTemplateDownload = () => {
}
);
};
//费用明细模板下载
export const costTemplateDownload = () => {
return axios.get(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/rd/expense/download/template`,
{
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};

View File

@@ -479,6 +479,11 @@ html, body, #app, .el-container, .el-aside, .el-main {
height: 1.4em;
margin-right: 5px;
}
.file-svg{
width: 1.4em;
height: 1.4em;
fill: #BEA266;
}
.middle-icon {
width: 1.4em;
height: 1.4em;

View File

@@ -1,5 +1,5 @@
<template>
<el-form :model="formData" ref="applyForm" :rules="rules" :label-position="labelPosition" style="margin-left: 5px">
<el-form :model="formData" ref="applyForm" :rules="rules" :label-position="labelPosition" :style="{marginLeft: label==='项目验收附件'?'25px': label==='项目立项附件'?'25px':'5px'}">
<el-row>
<!-- <el-col :span="24">-->
<!-- <el-form-item :label="label" prop="attachment" >-->
@@ -22,12 +22,12 @@
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="24">
<el-form-item :label="label" prop="" required>
<el-form-item :label="label" prop="" :required="label!='项目归档附件'">
<file-upload @getFile="getOtherFile"/>
<el-button color="#DED0B2" v-if="templateDownloadBtnShow" @click="handleImportTemplateDownload"
style="margin-left: 10px">模板下载
</el-button>
<fvTable style="width: 100%;max-height: 160px;" v-if="showTable" height="160" :tableConfig="tableConfig"
<fvTable style="width: 100%;" :height="label=='项目立项附件'?'160':'160'" :scrollbar-always-on="true" :style="{maxHeight:label=='项目立项附件'?'160px':'160px',height:label=='项目立项附件'?'160px':'160px'}" v-if="showTable" :tableConfig="tableConfig"
:data="allFileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
@@ -532,12 +532,10 @@ defineExpose({
})
</script>
<style scoped>
:deep(.el-table--fit ) {
height: 300px !important;
}
</style>
<style lang="scss" scoped>
:deep(.el-table--fit ) {
height: 160px !important;
}
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {

View File

@@ -28,6 +28,9 @@
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
/>
</div>
<el-button color="#DED0B2" style="margin-left: 10px"
@click="handleCarbonCopy()">立即抄送
</el-button>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
@@ -36,6 +39,10 @@
<process-diagram-viewer v-if="processViewer&&changeDiagram" :id-name="idName?idName:type"/>
</div>
</div>
<user-picker :multiple="true" ref="carbonCopyUserRef" title="请选择抄送人员"
v-model:value="carbonCopyUserList" @ok="carbonCopyUserPickerOk"
@cancelOrClear="carbonCopyUserPickerOk"/>
<file-preview ref="filePreviewRef" :fullscreen="fullscreen" v-if="filePreviewShow"
:fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
@@ -49,6 +56,8 @@ import {ElLoading, ElNotification} from 'element-plus';
import {downloadFile} from "@/api/project-demand";
import {searchImplementationFileList} from "@/api/project-manage/attachment";
import {getTags} from "@/api/project-manage";
import {applyCcSend} from "@/api/expense-manage";
import UserPicker from "@/views/workflow/process/common/UserPicker.vue";
const changeDiagram = ref(false)
const props = defineProps({
@@ -104,6 +113,8 @@ const props = defineProps({
}
})
const form = ref()
const carbonCopyUserList = ref([])
const carbonCopyUserRef = ref()
const editSingleTableConfig = reactive({
columns: [
@@ -279,23 +290,207 @@ const schema = computed(() => {
// }
// })
} else if (props.type == 'execute') {
arr = [{
label: '部门分管领导',
prop: 'optionalChargeLeadership',
colProps: {
span: 24
arr = [
{
label: '实际专利(项)',
prop: 'actualNewPatent',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewPatent ? props.formData.actualNewPatent :props.formData.actualNewPatent==0?0: <span>{'--'}</span>
}
</div>
)
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.optionalChargeLeadership?.length > 0 ? props.formData.optionalChargeLeadership.map(item => {
return <span>{item.name} </span>
}) : <span>{'--'}</span>
}
</div>
)
},]
{
label: '实际软件著作权(项)',
prop: 'actualSoftwareCopyright',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualSoftwareCopyright ? props.formData.actualSoftwareCopyright : props.formData.actualSoftwareCopyright==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际技术标准(项)',
prop: 'actualTechnicalNorms',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualTechnicalNorms ? props.formData.actualTechnicalNorms : props.formData.actualTechnicalNorms==0?0:<span>{'--'}</span>
}
</div>
)
},
{
label: '实际新产品(项)',
prop: 'actualNewProduct',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewProduct ? props.formData.actualNewProduct : props.formData.actualNewProduct==0?0:<span>{'--'}</span>
}
</div>
)
},
{
label: '实际新工艺(项)',
prop: 'actualNewProcess',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewProcess ? props.formData.actualNewProcess : props.formData.actualNewProcess==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际新装置(项)',
prop: 'actualNewDevice',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewDevice ? props.formData.actualNewDevice :props.formData.actualNewDevice==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际新材料(项)',
prop: 'actualNewMaterials',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewMaterials ? props.formData.actualNewMaterials : props.formData.actualNewMaterials==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际计算机软件(项)',
prop: 'actualComputerSoftware',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualComputerSoftware ? props.formData.actualComputerSoftware : props.formData.actualComputerSoftware==0?0:<span>{'--'}</span>
}
</div>
)
},
{
label: '实际论文论著(项)',
prop: 'actualThesis',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualThesis ? props.formData.actualThesis : props.formData.actualThesis==0?0:<span>{'--'}</span>
}
</div>
)
},
{
label: '实际研究报告(项)',
prop: 'actualResearchReport',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualResearchReport ? props.formData.actualResearchReport : props.formData.actualResearchReport==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际商标(项)',
prop: 'actualTrademark',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualTrademark ? props.formData.actualTrademark :props.formData.actualTrademark==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际其他(项)',
prop: 'actualOther',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div style="white-space: pre-wrap;">
{
props.formData.actualOther ? props.formData.actualOther : props.formData.actualOther==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '部门分管领导',
prop: 'optionalChargeLeadership',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.optionalChargeLeadership?.length > 0 ? props.formData.optionalChargeLeadership.map(item => {
return <span>{item.name} </span>
}) : <span>{'--'}</span>
}
</div>
)
}
]
if (props.preProcessShow == 'EDIT') {
preProcess = {
@@ -334,22 +529,22 @@ const schema = computed(() => {
// })
} else if (props.type == 'archivist') {
arr = [
// {
// label: '项目归档附件',
// prop: 'singleFile',
// colProps: {
// span: 24
// },
// labelWidth: 'left',
// component: () => {
// let singleFileArray = [props.formData.singleFile]
// return props.formData.singleFile ? <fvTable style="width: 100%;max-height: 80px;" height="80"
// tableConfig={editSingleTableConfig}
// data={singleFileArray} isSettingCol={false} pagination={false}>
// </fvTable>
// : <span>--</span>
// }
// },
// {
// label: '项目归档附件',
// prop: 'singleFile',
// colProps: {
// span: 24
// },
// labelWidth: 'left',
// component: () => {
// let singleFileArray = [props.formData.singleFile]
// return props.formData.singleFile ? <fvTable style="width: 100%;max-height: 80px;" height="80"
// tableConfig={editSingleTableConfig}
// data={singleFileArray} isSettingCol={false} pagination={false}>
// </fvTable>
// : <span>--</span>
// }
// },
]
} else if (props.type == 'phase') {
arr = [
@@ -381,7 +576,7 @@ const filePreviewParam = ref({
})
const filePreviewShow = ref(false)
const route = useRoute()
const emit = defineEmits(['update:value'])
const emit = defineEmits(['update:value', 'ccSend'])
const _value = computed({
get() {
return props.value;
@@ -390,6 +585,40 @@ const _value = computed({
emit("update:value", val);
}
})
const handleCarbonCopy = () => {
carbonCopyUserRef.value.showUserPicker()
}
const carbonCopyUserPickerOk = (userList) => {
carbonCopyUserList.value = userList.map(item => item.id)
console.log('localFormData.value', props.data)
console.log("🚀 ~ file:'carbonCopyUserList.value ", carbonCopyUserList.value)
addUser()
}
const addUser = async () => {
const res = await applyCcSend({
instanceId: props.data.processInstanceId,
// message:props.data.remark,
projectId: route.query.projectId,
state: route.query.step,
userIds: carbonCopyUserList.value
})
console.log('res', res)
if (res.code === 1000) {
ElNotification({
title: '提示',
message: '抄送成功',
type: 'success'
})
emit('ccSend')
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
}
const clickToPreview = (row) => {
filePreviewShow.value = false
filePreviewParam.value = {

View File

@@ -3,7 +3,7 @@
<el-form-item :label="title" v-if="fileListShow === 'READ' || fileListShow === 'EDIT'" :label-position="labelAlign" :style="{marginTop: '10px',marginLeft: tag!=='需求上报'?'15px':'0'}">
<file-upload @getFile="getOtherFile" v-if="fileListShow === 'EDIT'"/>
<!-- :style="{width:isOpenPrint?'610px': '100%'}" table-layout="auto" id="printTable"-->
<fvTable style="width:100%;max-height: 160px;" v-if="processViewer" height="160" :tableConfig="tableConfig"
<fvTable style="width:100%;" :height="tag=='项目立项'?'160':'160'" :style="{maxHeight:tag=='项目立项'?'160px':'160px',height:tag=='项目立项'?'160px':'160px'}" v-if="processViewer" :scrollbar-always-on="true" :tableConfig="tableConfig"
:data="_value" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
@@ -81,7 +81,9 @@ const tableConfig = reactive({
{
prop: 'tag',
label: '标签',
align: 'center'
align: 'center',
showOverflowTooltip: false,
minWidth: props.fileNameTableWidth,
},
{
prop: 'size',

View File

@@ -206,6 +206,14 @@ const rollbackHandler = async () => {
}
const handleAgree = async () => {
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
// const values = form.value.getValues()
const params = {
taskId: props.taskId,

View File

@@ -1,11 +1,101 @@
<template>
<div class="apply-block">
<baseTitle :title="getTitleName(title)+'信息'"></baseTitle>
<el-form :model="localFormData" ref="formRef" label-width="auto" v-if="step!=='50'">
<el-form :model="localFormData" ref="formRef" label-width="auto" v-if="step!=='50'" :rules="rules">
<el-row v-if="title==='apply'">
<el-col :span="6">
<!-- label-width="106"-->
<el-form-item label="实际经费预算(元)" prop="actualEconomicEstimate" label-width="130">
<el-input-number v-model="localFormData.actualEconomicEstimate" placeholder="请输入实际经费预算" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" v-if="isSpecialFund">
<!-- label-width="106" -->
<el-form-item label="实际专项资金(元)" prop="specialFundAmount" label-width="140">
<el-input-number v-model="localFormData.specialFundAmount" placeholder="请输入实际专项资金" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="title==='check'">
<el-col :span="6">
<el-form-item label="实际专利(项)" prop="actualNewPatent" label-width="130">
<el-input-number v-model="localFormData.actualNewPatent" placeholder="请输入实际专利数量" style="margin-right: 20px" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -10px">
<el-form-item label="实际软件著作权(项)" prop="actualSoftwareCopyright" label-width="150">
<el-input-number v-model="localFormData.actualSoftwareCopyright" placeholder="请输入实际软件著作权数量":controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -5px">
<el-form-item label="实际技术标准(项)" prop="actualTechnicalNorms" label-width="150">
<el-input-number v-model="localFormData.actualTechnicalNorms" placeholder="请输入实际技术标准数量":controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="实际新产品(项)" prop="actualNewProduct" label-width="160" style="margin-right: -10px">
<el-input-number v-model="localFormData.actualNewProduct" placeholder="请输入实际新产品数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="实际新工艺(项)" prop="actualNewProcess" label-width="130" >
<el-input-number v-model="localFormData.actualNewProcess" placeholder="请输入实际新工艺数量" style="margin-right: 20px" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -10px">
<el-form-item label="实际新装置(项)" prop="actualNewDevice" label-width="150">
<el-input-number v-model="localFormData.actualNewDevice" placeholder="请输入实际新装置数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -5px">
<el-form-item label="实际新材料(项)" prop="actualNewMaterials" label-width="150">
<el-input-number v-model="localFormData.actualNewMaterials" placeholder="请输入实际新材料数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="实际计算机软件(项)" prop="actualComputerSoftware" label-width="160" style="margin-right: -10px">
<el-input-number v-model="localFormData.actualComputerSoftware" placeholder="请输入实际计算机软件数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="实际论文论著(项)" prop="actualThesis" label-width="130" style="margin-right: 20px">
<el-input-number v-model="localFormData.actualThesis" placeholder="请输入实际论文论著数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -10px">
<el-form-item label="实际研究报告(项)" prop="actualResearchReport" label-width="150">
<el-input-number v-model="localFormData.actualResearchReport" placeholder="请输入实际研究报告数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -5px">
<el-form-item label="实际商标(项)" prop="actualTrademark" label-width="150">
<el-input-number v-model="localFormData.actualTrademark" placeholder="请输入实际商标数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="实际其他(项)" prop="actualOther" label-width="130" style="margin-right: 10px">
<el-input rows="4" type="textarea" v-model="localFormData.actualOther" placeholder="请输入实际其他项" >
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="6" v-if="title==='apply'">
<!-- label-width="106"-->
<el-form-item label="项目负责人" :required="true" prop="" label-width="111">
<el-form-item label="项目负责人" :required="true" prop="" label-width="130">
<el-button style="margin-right: 10px" color="#DED0B2" @click="handleShowProjectChargePersonTable">
{{ projectChargePersonUserList?.length !== 0 ? '更改' : '请选择' }}
</el-button>
@@ -13,56 +103,66 @@
{{ item.name }}
</div>
<user-picker :multiple="false" ref="projectChargePersonUserPicker" title="请选择项目负责人"
v-model:value="projectChargePersonUserList" @ok="projectChargePersonUserPickerOk" @cancelOrClear="projectChargePersonUserPickerCancel"/>
v-model:value="projectChargePersonUserList" @ok="projectChargePersonUserPickerOk"
@cancelOrClear="projectChargePersonUserPickerCancel"/>
</el-form-item>
</el-col>
<el-col :span="6" v-if="title==='apply'">
<el-form-item label="项目成员" :required="true" prop="" label-width="85"
<el-form-item label="项目成员" :required="true" prop="" label-width="140"
>
<el-button color="#DED0B2" style="margin-right: 10px" @click="handleShowProjectPersonTable">
{{ projectPersonUserList?.length !== 0 ? '更改' : getProjectPerson(projectPersonUserList) ? '更改' : '请选择' }}
{{
projectPersonUserList?.length !== 0 ? '更改' : getProjectPerson(projectPersonUserList) ? '更改' : '请选择'
}}
</el-button>
<div v-for="(item,index) in getProjectPerson(projectPersonUserList)" :key="item.id" >
{{ item.name }}{{index != getProjectPerson(projectPersonUserList)?.length - 1 ? '' : ''}}
<div v-for="(item,index) in getProjectPerson(projectPersonUserList)" :key="item.id">
{{ item.name }}{{ index != getProjectPerson(projectPersonUserList)?.length - 1 ? '' : '' }}
</div>
<user-picker :multiple="true" ref="projectPersonUserPicker" title="请选择项目成员"
v-model:value="projectPersonUserList" @ok="projectPersonUserPickerOk" @cancelOrClear="projectPersonUserPickerCancel"/>
v-model:value="projectPersonUserList" @ok="projectPersonUserPickerOk"
@cancelOrClear="projectPersonUserPickerCancel"/>
</el-form-item>
</el-col>
<el-col :span="6" v-if="title==='apply'||title==='check'">
<el-form-item label="部门分管领导" :label-width="title==='check'?110:115">
<el-form-item label="部门分管领导" :label-width="title==='check'?130:115" :required="isKcjUser()">
<el-button color="#DED0B2" style="margin-right: 10px" @click="handleShowOptionalChargeLeadershipPicker">
{{
optionalChargeLeadershipList?.length !== 0 ? '更改' : getOptionalChargeLeadershipList(optionalChargeLeadershipList) ? '更改' : '请选择'
}}
</el-button>
<div v-for="(item,index) in getOptionalChargeLeadershipList(optionalChargeLeadershipList)" :key="item.id">
{{ item.name }}{{index != getOptionalChargeLeadershipList(optionalChargeLeadershipList)?.length - 1 ? '' : ''}}
{{
item.name
}}{{ index != getOptionalChargeLeadershipList(optionalChargeLeadershipList)?.length - 1 ? '' : '' }}
</div>
<user-picker :multiple="true" ref="optionalChargeLeadershipPickerRef" title="请选择部门分管领导"
v-model:value="optionalChargeLeadershipList" @ok="optionalChargeLeaderPickerOk" @cancelOrClear="optionalChargeLeaderPickerCancel"/>
v-model:value="optionalChargeLeadershipList" @ok="optionalChargeLeaderPickerOk"
@cancelOrClear="optionalChargeLeaderPickerCancel"/>
</el-form-item>
</el-col>
<el-col :span="24" v-if="preProcessShow === 'EDIT'">
<el-form-item label="前置流程" :required="preProcessRequired" prop="preProcess" label-width="125">
<el-button color="#DED0B2" @click="handleShowPreTable" style="margin-right: 10px">
{{
localFormData.preProcess && localFormData.preProcess?.length > 0 ? '更改' : sessionParams.preProcess && sessionParams.preProcess?.length > 0 ? '更改' : '请选择'
}}
</el-button>
<div v-for="(item,index) in getRequestName(localFormData.preProcess)" :key="item.requestId">
<a :href="item.baseUrl" target="_blank"
style="color: #2a99ff;cursor: pointer">{{ item.requestName }}<span
v-if="index != localFormData.preProcess?.length -1"></span>
</a>
</div>
<el-col :span="24" v-if="preProcessShow === 'EDIT'||title==='apply'||title==='check'">
<el-form-item label="前置流程" :required="preProcessRequired" prop="preProcess" :label-width="title==='apply'?130:125">
<select-pre-process :formData="localFormData" :basicData="basicData"/>
<!-- <el-button color="#DED0B2" @click="handleShowPreTable" style="margin-right: 10px">-->
<!-- {{-->
<!-- localFormData.preProcess && localFormData.preProcess?.length > 0 ? '更改' : sessionParams.preProcess && sessionParams.preProcess?.length > 0 ? '更改' : '请选择'-->
<!-- }}-->
<!-- </el-button>-->
<!-- <div v-for="(item,index) in getRequestName(localFormData.preProcess)" :key="item.requestId">-->
<!-- <a :href="item.baseUrl" target="_blank"-->
<!-- style="color: #2a99ff;cursor: pointer">{{ item.requestName }}<span-->
<!-- v-if="index != localFormData.preProcess?.length -1"></span>-->
<!-- </a>-->
<!-- </div>-->
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- v-if="showAttachment"-->
<AttachmentUpload ref="attachment" :label="getTitleName(title)+'附件'" :showTable="showTable"
v-model:otherFileList="otherFileList" :tag="getTitleName(props.title)" :templateName="getTemplateName(props.title)" :templateDownloadBtnShow="props.title==='apply'?true:props.title==='check'"
v-model:otherFileList="otherFileList" :tag="getTitleName(props.title)"
:templateName="getTemplateName(props.title)"
:templateDownloadBtnShow="props.title==='apply'?true:props.title==='check'"
@getAttachment="getAttachment" v-model:singleList="singleList" :showSingleTable="showSingleTable"
@getOtherFile="getOtherFile" :showFileList="true" :formData="localFormData"
:preview="mode == 'resubmit'"/>
@@ -91,8 +191,8 @@
</div>
</div>
<div class="oper-page-btn">
<el-button color="#DED0B2" v-if="mode === 'submit'" @click="handleSubmit">提交</el-button>
<el-button color="#DED0B2" v-else-if="mode === 'resubmit'" @click="handleSubmit">重新提交</el-button>
<el-button color="#DED0B2" v-if="mode === 'submit'" @click="handleSubmit(formRef)">提交</el-button>
<el-button color="#DED0B2" v-else-if="mode === 'resubmit'" @click="handleSubmit(formRef)">重新提交</el-button>
<el-button @click="handleBack">返回</el-button>
</div>
@@ -102,8 +202,8 @@
<el-dialog v-if="showPreTable" title="前置流程" v-model="showPreTable" width="80%">
<el-form :model="preProcessForm" inline @submit.prevent="searchPreProcess">
<el-form-item label="请求名称">
<el-input v-model="preProcessForm.requestName" placeholder="请输入请求名称" clearable>
</el-input>
<el-input-number v-model="preProcessForm.requestName" placeholder="请输入请求名称" clearable>
</el-input-number>
</el-form-item>
<el-form-item>
<el-button color="#DED0B2" @click="searchPreProcess">搜索</el-button>
@@ -140,7 +240,7 @@
<script setup lang="jsx">
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
import {ElNotification} from "element-plus";
import {ElLoading, ElNotification} from "element-plus";
import {
getApplyProcess,
getPreProcess,
@@ -157,9 +257,14 @@ import {useProcessStore} from '@/stores/processStore.js';
import {useTagsView} from '@/stores/tagsview.js'
import Paging from "@/components/pagination/index.vue";
import UserPicker from "@/views/workflow/process/common/UserPicker.vue";
import {getBaseInfoApi, getMapProjectStateInfo} from "@/components/steps/api";
import {useAuthStore} from "@/stores/userstore";
const authStore = useAuthStore()
const userInfo =ref( authStore.userinfo)
const router = useRouter()
const route = useRoute()
const formRef = ref()
const changeDiagram = ref(false)
const showSingleTable = ref(false)
const projectChargePersonUserList = ref([])
@@ -186,6 +291,10 @@ const props = defineProps({
type: Object,
default: {}
},
basicData: {
type: Object,
default: {}
},
formData: {
type: Object,
default: {}
@@ -211,11 +320,24 @@ const pageInfo = reactive({
pageNum: 1,
pageSize: 10,
})
// const rules = reactive({
// preProcess: [{required: true, message: '请选择前置流程', trigger: 'blur'}],
// projectChargePerson: [{required: true, message: '请选择项目负责人', trigger: 'blur'}],
// projectPerson: [{required: true, message: '请选择项目成员', trigger: 'blur'}],
// })
const rules = reactive({
actualEconomicEstimate: [{required: true, message: '请输入实际经费预算', trigger: ['blur', 'change']}],
specialFundAmount: [{required: true, message: '请输入实际专项资金', trigger: 'blur'}],
// projectPerson: [{required: true, message: '请选择项目成员', trigger: 'blur'}],
actualNewPatent: [{required: true, message: '请输入实际专利数量', trigger: ['blur', 'change']}],
actualTechnicalNorms: [{required: true, message: '请输入实际技术标准数量', trigger: ['blur', 'change']}],
actualSoftwareCopyright: [{required: true, message: '请输入实际软件著作权数量', trigger: ['blur', 'change']}],
actualNewProduct: [{required: true, message: '请输入实际新产品数量', trigger: ['blur', 'change']}],
actualNewProcess: [{required: true, message: '请输入实际新工艺数量', trigger: ['blur', 'change']}],
actualNewMaterials: [{required: true, message: '请输入实际新材料数量', trigger: ['blur', 'change']}],
actualNewDevice: [{required: true, message: '请输入实际新装置数量', trigger: ['blur', 'change']}],
actualComputerSoftware: [{required: true, message: '请输入实际计算机软件数量', trigger: ['blur', 'change']}],
actualThesis: [{required: true, message: '请输入实际论文论著数量', trigger: ['blur', 'change']}],
actualResearchReport: [{required: true, message: '请输入实际研究报告数量', trigger: ['blur', 'change']}],
actualTrademark: [{required: true, message: '请输入实际商标数量', trigger: ['blur', 'change']}],
actualOther: [{required: true, message: '请输入实际其他项数量', trigger: ['blur', 'change']}],
})
const tagsViewStore = useTagsView()
const processStore = useProcessStore()
const localProjectPerson = ref([])
@@ -243,6 +365,7 @@ const selectRows = ref([])
const projectId = ref(route.query.projectId)
const sessionParams = ref({})
const optionalChargeLeadershipPickerRef = ref()
const isSpecialFund = ref(false)
const optionalChargeLeadershipList = ref([])
const filePreviewParam = ref({
fileUrl: '',
@@ -250,8 +373,55 @@ const filePreviewParam = ref({
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const isKcjUser=()=>{
const hasDstiAdmin = userInfo.value.roles?.some(item => item.roleKey != 'dsti_admin');
return hasDstiAdmin;
}
const getSummaryInfo = async () => {
if (props.mode === 'resubmit') return;
if(props.title === 'check'){
const loading = ElLoading.service({fullscreen: true})
try {
const projectId = route.query.projectId
const {code, data, msg} = await getMapProjectStateInfo(projectId, '10')
if (code === 1000) {
localFormData.value.actualNewPatent= data.formData.newPatent
localFormData.value.actualSoftwareCopyright= data.formData.softwareCopyright
localFormData.value.actualTechnicalNorms= data.formData.technicalNorms
localFormData.value.actualNewProduct= data.formData.newProduct
localFormData.value.actualNewProcess= data.formData.newProcess
localFormData.value.actualNewDevice= data.formData.newDevice
localFormData.value.actualNewMaterials= data.formData.newMaterials
localFormData.value.actualComputerSoftware= data.formData.computerSoftware
localFormData.value.actualThesis= data.formData.thesis
localFormData.value.actualResearchReport= data.formData.researchReport
localFormData.value.actualTrademark= data.formData.trademark
localFormData.value.actualOther= data.formData.other
const getTemplateName=(type)=>{
loading.close()
} else {
ElNotification({
title: '提示',
message: msg,
type: 'error'
})
loading.close()
}
} catch {
loading.close()
}
}
}
getSummaryInfo()
const getInfo = async () => {
const {code, data} = await getBaseInfoApi(route.query.projectId)
isSpecialFund.value = data.isSpecialFund
}
getInfo()
const getTemplateName = (type) => {
switch (type) {
case 'apply':
return '科技创新项目立项模板'
@@ -266,9 +436,9 @@ const handleShowOptionalChargeLeadershipPicker = () => {
const optionalChargeLeaderPickerOk = (userList) => {
optionalChargeLeadershipList.value = userList
if(userList?.length>0){
if (userList?.length > 0) {
localStorage.setItem('optionalChargeLeadershipList', JSON.stringify(optionalChargeLeadershipList.value))
}else {
} else {
localStorage.removeItem('optionalChargeLeadershipList')
}
}
@@ -347,27 +517,27 @@ const handleShowProjectChargePersonTable = () => {
}
const projectChargePersonUserPickerOk = (userList) => {
projectChargePersonUserList.value = userList
if(userList?.length>0){
if (userList?.length > 0) {
localStorage.setItem('projectChargePersonUserList', JSON.stringify(projectChargePersonUserList.value))
}else {
} else {
localStorage.removeItem('projectPersonUserList')
}
}
const handleShowProjectPersonTable = () => {
projectPersonUserPicker.value.showUserPicker()
}
const projectChargePersonUserPickerCancel=(userList)=>{
const projectChargePersonUserPickerCancel = (userList) => {
projectChargePersonUserList.value = userList
}
const projectPersonUserPickerCancel=(userList)=>{
const projectPersonUserPickerCancel = (userList) => {
projectPersonUserList.value = userList
}
const projectPersonUserPickerOk = (userList) => {
projectPersonUserList.value = userList
if(userList?.length>0){
if (userList?.length > 0) {
localStorage.setItem('projectPersonUserList', JSON.stringify(userList))
}else {
} else {
localStorage.removeItem('projectPersonUserList')
}
}
@@ -404,9 +574,15 @@ const choosePreProcess = () => {
requestName: item.requestName,
baseUrl: item.baseUrl
}
preProcessArray.push(preProcessObj)
if(props.mode === 'resubmit'){
localFormData.value.preProcess.push(preProcessObj)
}else{
preProcessArray.push(preProcessObj)
}
})
localFormData.value.preProcess = preProcessArray
if(props.mode !== 'resubmit'){
localFormData.value.preProcess = preProcessArray
}
showPreTable.value = false
localStorage.setItem('preProcess', JSON.stringify(preProcessArray))
}
@@ -489,109 +665,182 @@ const getFileParam = (item) => {
tag: item.tag
}
}
const handleSubmit = async () => {
let files = []
if (props.mode === 'resubmit') {
attachment.value.allFileList.forEach(item => {
files.push(getFileParam(item))
})
} else {
otherFileList.value.forEach(item => {
files.push(getFileParam(item))
})
}
// console.info("🚀 ~method:handleSubmit -----", files,attachment.value.isHaveOneFile)
if (!attachment.value.isHaveOneFile) {
attachment.value.validate()
ElNotification({
title: '提示',
message: '请上传附件',
type: 'error'
})
return;
} else {
attachment.value.clearValidate()
}
let projectPersonIds = []
for (const item of projectPersonUserList.value) {
projectPersonIds.push(parseInt(item.id))
}
let params = {
deploymentId: deploymentId.value,
requirementId: route.query.id,
fileList: files,
// singleFile: attachment.value.singleFile,
projectId: projectId.value,
preProcess: JSON.stringify(localFormData.value.preProcess)
}
if (sessionParams.value.preProcess && !localFormData.value.preProcess) {
params.preProcess = JSON.stringify(sessionParams.value.preProcess)
}
// console.log(params.preProcess)
let res
if (props.step === '20') {
if (projectChargePersonUserList.value && projectChargePersonUserList.value.length === 0) {
ElNotification({
title: '提示',
message: '请选择项目负责人!',
type: 'error'
})
return;
}
if (projectPersonUserList.value && projectPersonUserList.value.length === 0) {
ElNotification({
title: '提示',
message: '请选择项目成员!',
type: 'error'
})
return;
}
params.projectChargePerson = parseInt(projectChargePersonUserList.value[0].id)
params.projectPersonIds = projectPersonIds
params.optionalChargeLeadership = optionalChargeLeadershipList.value
const handleSubmit = async (instance) => {
if (props.step == 50) {
let files = []
if (props.mode === 'resubmit') {
res = await resubmitApply(params)
attachment.value.allFileList.forEach(item => {
files.push(getFileParam(item))
})
} else {
res = await projectApply(params)
otherFileList.value.forEach(item => {
files.push(getFileParam(item))
})
}
} else if (props.step === '40') {
params.optionalChargeLeadership = optionalChargeLeadershipList.value
if (props.mode === 'resubmit') {
res = await resubmitCheck(params)
} else {
res = await projectCheck(params)
// console.info("🚀 ~method:handleSubmit -----", files,attachment.value.isHaveOneFile)
// if (!attachment.value.isHaveOneFile) {
// attachment.value.validate()
// ElNotification({
// title: '提示',
// message: '请上传附件',
// type: 'error'
// })
// return;
// } else {
// attachment.value.clearValidate()
// }
let projectPersonIds = []
for (const item of projectPersonUserList.value) {
projectPersonIds.push(parseInt(item.id))
}
} else if (props.step === '50') {
let params = {
...localFormData.value,
deploymentId: deploymentId.value,
requirementId: route.query.id,
fileList: files,
// singleFile: attachment.value.singleFile,
projectId: route.query.projectId,
actualEconomicEstimate: parseFloat(localFormData.value.actualEconomicEstimate),
specialFundAmount: parseFloat(localFormData.value.specialFundAmount),
preProcess: JSON.stringify(localFormData.value.preProcess)
}
if (sessionParams.value.preProcess && !localFormData.value.preProcess) {
params.preProcess = JSON.stringify(sessionParams.value.preProcess)
}
console.log('params', params.fileList)
let res
if (props.mode === 'resubmit') {
res = await resubmitConclusion(params)
} else {
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)
if (props.step === '20') {
await router.push({
name: 'Initiation'
})
} else if (props.step === '40') {
await router.push({
name: 'Implementation'
})
} else if (props.step === '50') {
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'
})
}
} else {
if (!instance) return
instance.validate(async (valid) => {
if (!valid) {
ElNotification({
title: '提示',
message: '请完善数据,再提交!',
type: 'error'
})
return;
}
let files = []
if (props.mode === 'resubmit') {
attachment.value.allFileList.forEach(item => {
files.push(getFileParam(item))
})
} else {
otherFileList.value.forEach(item => {
files.push(getFileParam(item))
})
}
// console.info("🚀 ~method:handleSubmit -----", files,attachment.value.isHaveOneFile)
if (!attachment.value.isHaveOneFile) {
attachment.value.validate()
ElNotification({
title: '提示',
message: '请上传附件',
type: 'error'
})
return;
} else {
attachment.value.clearValidate()
}
let projectPersonIds = []
for (const item of projectPersonUserList.value) {
projectPersonIds.push(parseInt(item.id))
}
let params = {
// singleFile: attachment.value.singleFile,
...localFormData.value,
projectId: route.query.projectId,
deploymentId: deploymentId.value,
requirementId: route.query.id,
fileList: files,
actualEconomicEstimate: parseFloat(localFormData.value.actualEconomicEstimate)||null,
specialFundAmount: parseFloat(localFormData.value.specialFundAmount)||null,
preProcess: JSON.stringify(localFormData.value.preProcess)
}
if (sessionParams.value.preProcess && !localFormData.value.preProcess) {
params.preProcess = JSON.stringify(sessionParams.value.preProcess)
}
console.log('params', params)
let res
if (props.step === '20') {
if (projectChargePersonUserList.value && projectChargePersonUserList.value.length === 0) {
ElNotification({
title: '提示',
message: '请选择项目负责人!',
type: 'error'
})
return;
}
if (projectPersonUserList.value && projectPersonUserList.value.length === 0) {
ElNotification({
title: '提示',
message: '请选择项目成员!',
type: 'error'
})
return;
}
if (optionalChargeLeadershipList.value && optionalChargeLeadershipList.value.length === 0&&isKcjUser()) {
ElNotification({
title: '提示',
message: '请选择部门分管领导!',
type: 'error'
})
return;
}
params.projectChargePerson = parseInt(projectChargePersonUserList.value[0].id)
params.projectPersonIds = projectPersonIds
params.optionalChargeLeadership = optionalChargeLeadershipList.value
if (props.mode === 'resubmit') {
res = await resubmitApply(params)
} else {
res = await projectApply(params)
}
} else if (props.step === '40') {
params.optionalChargeLeadership = optionalChargeLeadershipList.value
if (props.mode === 'resubmit') {
res = await resubmitCheck(params)
} else {
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)
if (props.step === '20') {
await router.push({
name: 'Initiation'
})
} else if (props.step === '40') {
await router.push({
name: 'Implementation'
})
}
}
})
}
}
const init = async () => {
let id = projectId.value
let id = route.query.projectId
if (!id) return;
processDiagramViewer.value = false
let res
@@ -606,7 +855,7 @@ const init = async () => {
let data = res.data
deploymentId.value = data.deploymentId
deploymentData.value = data
preProcessRequired.value = data.deploymentName === '重大项目立项' || data.deploymentName === '重大项目验收';
// preProcessRequired.value = data.deploymentName === '重大项目立项' || data.deploymentName === '重大项目验收';
processStore.setDesign(data)
processStore.runningList.value = data.runningList;
processStore.endList.value = data.endList;
@@ -642,7 +891,6 @@ watchEffect(() => {
// if (props.formData.projectChargePerson != null) {
// localFormData.value.projectChargePerson = props.formData.projectChargePerson.id
// }
if (localStorage.getItem('preProcess')) {
let param = JSON.parse(localStorage.getItem('preProcess'))
localFormData.value.preProcess = param

View File

@@ -1,52 +1,92 @@
<template>
<el-row style="padding-bottom: 20px">
<el-row>
<el-col :span="24">
<baseTitle :title="'项目附件'"></baseTitle>
</el-col>
<el-form :model="attachmentParam" inline style="margin-left: 15px">
<el-form-item label="标签" prop="tag">
<el-select v-model="attachmentParam.tag" placeholder="请选择标签" clearable filterable style="width: 300px">
<el-option
v-for="item in tagsOption"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleSearch" color="#DED0B2">搜索</el-button>
<el-button v-if="uploadState&&isLineBtn" color="#DED0B2" @click="handleUpload">上传附件</el-button>
</el-form-item>
</el-form>
<el-col v-if="!isLineBtn" :span="24" style="margin-bottom: 8px;margin-left: 15px">
<el-button v-if="uploadState" color="#DED0B2" @click="handleUpload">上传附件</el-button>
</el-col>
<fvTable style="width: 100%;min-height:311px;max-height: 311px" v-if="showAttachmentTable" height="311"
:tableConfig="executeTableConfig" class="execute-apply-table"
:data="otherAttachmentList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleTabClick" @tab-remove="tabRemove"
style="margin-left: 15px;margin-top: -10px">
<el-tab-pane name="all" :closable="false" label="全部">
</el-tab-pane>
<el-tab-pane v-for="item in tagsOption" :closable="item.isClose==1&&uploadState"
:key="item.tagId"
:label="item.fileTag"
:name="item.tagId">
<div class="tag-title">
<div></div>
{{ item.fileTag }}
</div>
</el-tab-pane>
<el-tab-pane name="plus" v-if="uploadState" :closable="false">
<template #label>
<div style="margin-top: 4px;">
<el-icon color="#BEA266">
<Plus/>
</el-icon>
</div>
</template>
</el-tab-pane>
</el-tabs>
</el-row>
<file-preview ref="filePreviewRef" :fullscreen="false" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
<div style="margin-top:10px;margin-bottom: 8px;margin-left: 15px;display: flex">
<!-- <el-button color="#DED0B2" @click="handleUpload">上传附件</el-button>-->
<file-upload v-if="!isLineBtn&&uploadState&&activeName!='plus'&&activeName!='all'" @getFile="getFile"/>
<el-button color="#DED0B2" @click="handleEditTag"
v-if="activeName!='all'&&activeName!='plus'&&uploadState&&!isDefault"
style="margin-left: 10px;">编辑
</el-button>
</div>
<fvTable style="width: 100%;min-height:311px;max-height: 311px" v-if="showAttachmentTable" height="311"
:scrollbar-always-on="true"
:tableConfig="executeTableConfig" class="execute-apply-table"
:data="otherAttachmentList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
<div class="oper-page-btn" style="margin-right: 90px" v-if="uploadState">
<el-button color="#DED0B2" @click="handleSubmit()">提交</el-button>
</div>
<file-preview ref="filePreviewRef" :fullscreen="false" v-if="filePreviewShow" :fileName="filePreviewParam.fileName"
:fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
<el-dialog v-model="tagNameShow" center width="450" top="40vh">
<div style="display: flex;align-items: center">标签
<el-input v-model="fileParam.tagName" placeholder="请输入标签名称" style="width: 335px;" clearable/>
</div>
<div class="oper" style="display: flex;justify-content: flex-end;margin-top: 10px">
<el-button color="#DED0B2" @click="changeTag()">确定</el-button>
<el-button @click="tagNameShow=false">取消</el-button>
</div>
</el-dialog>
</template>
<script setup lang="jsx">
import {getTags} from "@/api/project-manage";
import {ElLoading, ElNotification} from "element-plus";
import {searchImplementationFileList} from "@/api/project-manage/attachment";
import {addTag, delTag, getTagList, updateTag} from "@/api/project-manage";
import {ElLoading, ElMessageBox, ElNotification} from "element-plus";
import {searchImplementationFileList, uploadFileList} from "@/api/project-manage/attachment";
import {deleteFile, downloadFile} from "@/api/project-demand";
import {nextTick, onActivated} from "vue";
const router = useRouter()
const route = useRoute()
const attachmentParam = reactive({
tag: ''
})
const fileParam = ref({
tagName: ''
})
const uploadState = ref(false)
const tagNameShow = ref(false)
const isDefault = ref(false)
const tagsOption = ref([])
const fileList = ref([])
const allFiles = ref([])
const showAttachmentTable = ref(true)
const activeName = ref('all')
const props = defineProps({
fileNameTableWidth: {
@@ -72,6 +112,7 @@ const executeTableConfig = reactive({
label: '文件名',
align: 'center',
width: props.fileNameTableWidth,
showOverflowTooltip: false,
currentRender: ({row, index}) => (
<div style="color: #2a99ff;cursor: pointer;" onClick={() => clickToPreview(row)}>{row.originalFileName}</div>)
},
@@ -79,6 +120,7 @@ const executeTableConfig = reactive({
prop: 'tag',
label: '标签',
align: 'center',
showOverflowTooltip: false,
},
{
prop: 'size',
@@ -95,12 +137,18 @@ const executeTableConfig = reactive({
return (
<div>
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
{
uploadState.value ?
<popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => deleteSingleFile(row)}/> : ''
}
</div>
)
}
}
]
})
// row.newFile ?: ''
const otherAttachmentList = ref([])
const filePreviewParam = ref({
@@ -109,39 +157,288 @@ const filePreviewParam = ref({
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const clickToPreview=(row)=>{
const uploadLoading = ref(false)
const isEdit = ref(false)
const isCloseByList = (index) => {
// otherAttachmentList.length>0?false:true
return otherAttachmentList.value.length == 0;
}
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 deleteSingleFile = (row) => {
console.log("🚀 ~ file: ", row)
deleteFile(row.fileId).then(res => {
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
if (row.newFile) {
const finalList = getLocalList().filter(item => item.fileId !== row.fileId);
localStorage.setItem(`implementAllFileList-${route.query.projectId}`, JSON.stringify(finalList))
} else {
otherAttachmentList.value.splice(otherAttachmentList.value.findIndex((item) => item.fileId === row.fileId), 1);
}
getAttachmentList()
activeName.value = 'all'
}
});
}
const changeTag = async () => {
let res = null
if (isEdit.value) {
res = await updateTag({
tagId: activeName.value,
fileTag: fileParam.value.tagName,
projectId: route.query.projectId,
})
changeFileList(fileParam.value.tagName, true)
} else {
res = await addTag({
projectId: route.query.projectId,
fileTag: fileParam.value.tagName
})
getAttachmentList()
fileParam.value.tagName = ''
activeName.value = 'all'
}
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
tagNameShow.value = false;
}
const tabRemove = async (val) => {
if (otherAttachmentList.value && otherAttachmentList.value.length > 0) {
ElNotification({
title: '提示',
message: '该标签下存在文件,不能删除标签。如需删除标签,请先删除该标签下的所有文件。',
type: 'error'
})
return;
}
ElMessageBox.confirm(`确认删除名称为${getTagName(val)}的标签吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
let res = await delTag(val)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
getTagsOption()
otherAttachmentList.value = allFiles.value
}
})
}
const handleEditTag = () => {
fileParam.value.tagName = getTagName(activeName.value)
if (otherAttachmentList.value && otherAttachmentList.value.length > 0) {
ElNotification({
title: '提示',
message: '该标签下存在文件,不能编辑标签。如需编辑标签,请先删除该标签下的所有文件。',
type: 'error'
})
return;
}
tagNameShow.value = true
isEdit.value = true
}
const getTagName = (name) => {
const tagArray = tagsOption.value.filter((item1) => item1.tagId == name)
let tagName = ''
if (tagArray && tagArray.length > 0) {
tagName = tagArray[0].fileTag
}
return tagName
}
const handleTabClick = (item, e) => {
const defaultArray = tagsOption.value.filter(item1 => item1.tagId == item.props.name)
if (defaultArray && defaultArray.length > 0) {
isDefault.value = defaultArray[0].isDefault == 1
} else {
isDefault.value = false
}
tagNameShow.value = item.props.name == 'plus';
if (item.props.name == 'plus') {
isEdit.value = false
fileParam.value.tagName = ''
}
if (item.props.name != 'plus') {
if (item.props.name == 'all') {
changeFileList('all')
} else {
changeFileList(getTagName(item.props.name))
}
// if (item.props.name == 'all') {
// otherAttachmentList.value = allFiles.value
// } else {
// otherAttachmentList.value = allFiles.value.filter(item1 => item1.tag == getTagName(item.props.name))
// }
}
// showAttachmentTable.value = false
// nextTick(() => {
// showAttachmentTable.value = true
// })
}
const compositeParam = (item) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: getTagName(activeName.value) || '项目实施',
}
}
const getFile = (val) => {
console.log('上传文件', val)
fileList.value = getLocalList()
let fileObj = compositeParam(val)
fileList.value.push(fileObj)
localStorage.setItem(`implementAllFileList-${route.query.projectId}`, JSON.stringify(fileList.value))
otherAttachmentList.value.push(fileObj)
// handleSubmit([fileObj])
}
const handleSubmit = async () => {
if (getLocalList().length == 0) {
ElNotification({
title: '提示',
message: '暂无文件可提交',
type: 'warning'
})
return;
} else {
let params = {
fileList: getLocalList(),
projectId: route.query.projectId,
targetState: "30"
}
let res = await uploadFileList(params)
if (res.code !== 1000) {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'success'
})
localStorage.removeItem(`implementAllFileList-${route.query.projectId}`)
// list.forEach(item => {
// otherAttachmentList.value.push(item)
// })
getAttachmentList()
fileList.value = []
}
// changeFileList('all',true)
}
}
const clickToPreview = (row) => {
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
nextTick(() => {
filePreviewShow.value = true
})
}
const handleSearch = () => {
const changeFileList = (tag, flag) => {
let params = {}
if (tag == 'all') {
otherAttachmentList.value = allFiles.value
// params = {
// targetId: route.query.projectId,
// targetState: "30",
// }
otherAttachmentList.value = [...otherAttachmentList.value, ...getLocalList()];
} else {
const filw = getLocalList().filter(item1 => item1.tag === tag);
const filteredAllFiles = allFiles.value.filter(item1 => item1.tag === tag);
// 使用 fileId 作为唯一标识进行去重
const seen = new Set();
const uniqueFiles = [...filteredAllFiles, ...filw].filter(item => {
if (!seen.has(item.fileId)) {
seen.add(item.fileId);
return true;
}
return false;
});
otherAttachmentList.value = uniqueFiles;
// params = {
// targetId: route.query.projectId,
// targetState: "30",
// tag: tag
// }
}
showAttachmentTable.value = false
// searchImplementationFileList(params).then(res => {
// if (res.code === 1000) {
// if(tag == 'all'&&flag){
// // allFiles.value = res.data.fileList
// }else{
// otherAttachmentList.value =res.data.fileList
// }
if (flag) {
getTagsOption(flag)
}
nextTick(() => {
showAttachmentTable.value = true
})
// }
// })
}
const getLocalList = () => {
if (localStorage.getItem(`implementAllFileList-${route.query.projectId}`) && JSON.parse(localStorage.getItem(`implementAllFileList-${route.query.projectId}`))) {
return JSON.parse(localStorage.getItem(`implementAllFileList-${route.query.projectId}`))
} else {
return []
}
}
const getAttachmentList = () => {
const loading = ElLoading.service({fullscreen: true})
let params = {
targetId: route.query.projectId,
targetState: "30"
}
if (attachmentParam.tag) {
tagsOption.value.forEach(item => {
if (item.value === attachmentParam.tag) {
attachmentParam.tag = item.label
}
})
params.tag = attachmentParam.tag
}
showAttachmentTable.value = false
searchImplementationFileList(params).then(res => {
showAttachmentTable.value = false
if (res.code === 1000) {
otherAttachmentList.value = res.data.fileList
otherAttachmentList.value = [...res.data.fileList, ...getLocalList()]
allFiles.value = [...res.data.fileList, ...getLocalList()]
uploadState.value = res.data.upload
getTagsOption()
nextTick(() => {
showAttachmentTable.value = true
})
activeName.value = 'all'
loading.close()
} else {
ElNotification({
@@ -153,11 +450,56 @@ const handleSearch = () => {
}
})
}
const getTagsOption = () => {
const getTagsOption = (flag) => {
if (!route.query.projectId) return
getTags(route.query.projectId).then(res => {
getTagList(route.query.projectId).then(res => {
if (res.code === 1000) {
tagsOption.value = res.data
tagsOption.value = res.data.rows
let list = []
if (flag) {
list = allFiles.value
} else {
list = otherAttachmentList.value
}
tagsOption.value.forEach((tag, index) => {
// const filterArray = list.filter(item => tag.fileTag == item.tag)
// console.log("🚀 ~ file:filterArray ", filterArray)
tagsOption.value[index].isClose = 1
// tagsOption.value[index].isClose = filterArray.length > 0 ? 0 : 1
})
console.log("🚀 otherAttachmentList.value", allFiles.value)
console.log("🚀 ~ file:\tagsOption.value ", tagsOption.value)
let defaultArray = [
{
tagId: 'd1',
fileTag: '合同(专项任务书)',
isDefault: 1,
isClose: 2
},
{
tagId: 'd2',
fileTag: '周报',
isDefault: 1,
isClose: 2
},
{
tagId: 'd3',
fileTag: '阶段性验收',
isDefault: 1,
isClose: 2
},
{
tagId: 'd4',
fileTag: '科研成果',
isDefault: 1,
isClose: 2
}
]
tagsOption.value = [...defaultArray, ...tagsOption.value]
// if (!res.data.rows || res.data.rows.length == 0) return;
// activeName.value=res.data.rows[0].tagId
} else {
ElNotification({
title: '提示',
@@ -178,11 +520,9 @@ const handleUpload = () => {
}
})
}
handleSearch()
getTagsOption()
onActivated(()=>{
handleSearch()
getTagsOption()
getAttachmentList()
onActivated(() => {
getAttachmentList()
})
</script>
<style lang="scss">
@@ -217,8 +557,52 @@ onActivated(()=>{
}
}
</style>
<style scoped>
<style scoped lang="scss">
:deep(.el-dialog__body) {
padding: 0 !important;
}
.tag-title {
display: flex;
align-items: center;
margin-top: 15px;
> div {
margin-right: 5px;
width: 4px;
height: 20px;
background-color: #BEA266;
}
}
:deep(.el-table--fit ) {
height: 311px !important;
}
:deep(.el-tabs__nav) {
//width: 75vw;
}
:deep(.el-tabs__item) {
flex: none !important;
}
:deep(.el-tabs__header) {
margin-bottom: 0;
}
:deep(.el-tabs__item.is-active) {
color: #BEA266;
}
:deep(.el-tabs__active-bar) {
background-color: #BEA266;
}
.file-tag {
width: 100%;
display: flex;
border-bottom: 2px solid #f6f6f6;
/*align-items: center;*/
}
</style>

View File

@@ -3,41 +3,88 @@
<el-form :model="localFormData" ref="summaryForm" :rules="rules">
<baseTitle title="预期知识产权"></baseTitle>
<el-row gutter="20" style="margin-bottom: -18px;margin-left: 5px">
<!-- <el-col :span="6">-->
<!-- <el-form-item label="预期成果形式" prop="resultForm">-->
<!-- <span>{{ filterDict(cacheStore.getDict('result_form'), localFormData.resultForm) }}</span>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="6">
<el-form-item label="预期成果形式" prop="resultForm">
<span>{{ filterDict(cacheStore.getDict('result_form'), localFormData.resultForm) }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="知识产权状况" prop="intellectualProperty">
<el-form-item label="知识产权归属" prop="intellectualProperty">
<span>{{
filterDict(cacheStore.getDict('intellectual_property'), 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">
<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">
<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 label="预估技术标准(项)" prop="technicalNorms">
<span>{{ localFormData.technicalNorms }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="其他(项)" prop="other">
<span>{{ localFormData.other }}</span>
<el-form-item label="预估新产品(项)" prop="newProduct">
<span>{{ localFormData.newProduct }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估新工艺(项)" prop="newProcess">
<span>{{ localFormData.newProcess }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估新装置(项)" prop="newDevice">
<span>{{ localFormData.newDevice }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估新材料(项)" prop="newMaterials">
<span>{{ localFormData.newMaterials }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估计算机软件(项)" prop="computerSoftware">
<span>{{ localFormData.computerSoftware }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估论文论著(项)" prop="thesis">
<span>{{ localFormData.thesis }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估研究报告(项)" prop="researchReport">
<span>{{ localFormData.researchReport }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估商标(项)" prop="trademark">
<span>{{ localFormData.trademark }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估其他(项)" prop="other">
<span style="white-space: pre-wrap">{{ localFormData.other }}</span>
</el-form-item>
</el-col>
</el-row>
@@ -57,18 +104,18 @@
</el-row>
<baseTitle title="需求上报申请书" style="margin-bottom: -3px;"></baseTitle>
<!-- <el-row gutter="20" style="margin-bottom: -15px;">-->
<!-- <el-col :span="24">-->
<!-- <single-file-component tag="需求上报" v-model:value="localFormData.singleFile" :processViewer="processViewer"/>-->
<!-- &lt;!&ndash; <el-form-item>&ndash;&gt;-->
<!-- &lt;!&ndash; {{localFormData.singleFile}}&ndash;&gt;-->
<!-- &lt;!&ndash; <el-button type="primary" link @click="handleDownload(localFormData.singleFile)" style="font-size: 16px">&ndash;&gt;-->
<!-- &lt;!&ndash; {{ localFormData.singleFile?.originalFileName }}&ndash;&gt;-->
<!-- &lt;!&ndash; </el-button>&ndash;&gt;-->
<!-- &lt;!&ndash; </el-form-item>&ndash;&gt;-->
<!-- </el-col>-->
<!-- </el-row>-->
<!--/* <baseTitle title="附件文件" style="margin-bottom: 0"></baseTitle>*/-->
<!-- <el-row gutter="20" style="margin-bottom: -15px;">-->
<!-- <el-col :span="24">-->
<!-- <single-file-component tag="需求上报" v-model:value="localFormData.singleFile" :processViewer="processViewer"/>-->
<!-- &lt;!&ndash; <el-form-item>&ndash;&gt;-->
<!-- &lt;!&ndash; {{localFormData.singleFile}}&ndash;&gt;-->
<!-- &lt;!&ndash; <el-button type="primary" link @click="handleDownload(localFormData.singleFile)" style="font-size: 16px">&ndash;&gt;-->
<!-- &lt;!&ndash; {{ localFormData.singleFile?.originalFileName }}&ndash;&gt;-->
<!-- &lt;!&ndash; </el-button>&ndash;&gt;-->
<!-- &lt;!&ndash; </el-form-item>&ndash;&gt;-->
<!-- </el-col>-->
<!-- </el-row>-->
<!--/* <baseTitle title="附件文件" style="margin-bottom: 0"></baseTitle>*/-->
<el-row gutter="20" style="margin-bottom: -18px;">
<el-col :span="24" class="file-table-style">
<file-component tag="需求上报"
@@ -99,8 +146,8 @@
</div>
</div>
<div v-perm="['annual:plan:approve']" v-if="data.state==='4'">
<baseTitle title="前置流程"></baseTitle>
<select-pre-process :formData="localFormData"/>
<!-- <baseTitle title="前置流程"></baseTitle>-->
<!-- <select-pre-process :formData="localFormData"/>-->
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
@@ -123,6 +170,9 @@
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
/>
</div>
<el-button color="#DED0B2" style="margin-left: 10px"
@click="handleCarbonCopy()">立即抄送
</el-button>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
@@ -133,6 +183,10 @@
</div>
</div>
</el-form>
<user-picker :multiple="true" ref="carbonCopyUserRef" title="请选择抄送人员"
v-model:value="carbonCopyUserList" @ok="carbonCopyUserPickerOk"
@cancelOrClear="carbonCopyUserPickerOk"/>
<div class="oper-page-btn" v-perm="['annual:plan:approve']" v-if="data.state==='4'">
<el-button type="danger" @click="handleRejectPlan">驳回年度计划</el-button>
<el-button color="#DED0B2" @click="handleAgreePlan">通过年度计划</el-button>
@@ -153,8 +207,10 @@ import FileComponent from "./FileComponent.vue";
import {ElNotification} from "element-plus";
import {approvePlan} from "@/api/project-demand/summary";
import SelectPreProcess from "@/components/SelectPreProcess.vue";
import {applyCcSend} from "@/api/expense-manage";
import UserPicker from "@/views/workflow/process/common/UserPicker.vue";
const emit = defineEmits(['update:value'])
const emit = defineEmits(['update:value','ccSend'])
const tagsViewStore = useTagsView()
const cacheStore = useCacheStore()
const props = defineProps({
@@ -192,6 +248,8 @@ const router = useRouter()
const fundOption = ref([])
const companyOption = ref([])
const dictName = ref({})
const carbonCopyUserList = ref([])
const carbonCopyUserRef = ref()
const rules = reactive({
auditOpinion: [{required: true, message: '请输入审核意见', trigger: 'blur'}],
})
@@ -203,6 +261,39 @@ const _value = computed({
emit("update:value", val);
}
})
const handleCarbonCopy = () => {
carbonCopyUserRef.value.showUserPicker()
}
const carbonCopyUserPickerOk = (userList) => {
carbonCopyUserList.value = userList.map(item => item.id)
console.log('localFormData.value', props.data)
console.log("🚀 ~ file:'carbonCopyUserList.value ", carbonCopyUserList.value)
addUser()
}
const addUser = async () => {
const res = await applyCcSend({
instanceId: props.data.processInstanceId,
projectId: route.query.projectId,
state: route.query.step,
userIds: carbonCopyUserList.value
})
console.log('res', res)
if (res.code === 1000) {
ElNotification({
title: '提示',
message: '抄送成功',
type: 'success'
})
emit('ccSend')
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
}
const handleRejectPlan = async () => {
// const values = form.value.getValues()
// console.log('route',route.query.projectId)
@@ -232,6 +323,14 @@ const handleRejectPlan = async () => {
})
}
const handleAgreePlan = async () => {
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
const params = {
auditOpinion: _value.value,
projectId: parseInt(route.query.projectId),
@@ -321,7 +420,8 @@ getFundOptions()
overflow-y: auto;
padding-bottom: 0 !important;
}
.file-table-style{
.file-table-style {
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {

View File

@@ -1,13 +1,14 @@
<template>
<el-upload :file-list="_value"
:action="uploadFileUrl"
<el-upload :file-list="_value" ref="uploadRef"
action="#"
:headers="headers"
:limit="maxSize"
with-credentials
:multiple="multiple"
:data="uploadParams"
:data="uploadParams" :on-change="handleChange"
:http-request="customUpload"
:show-file-list="showFileList"
:auto-upload="true"
:auto-upload="false"
:before-upload="beforeUpload"
:on-success="handleUploadSuccess"
:on-error="uploadError"
@@ -19,16 +20,20 @@
</template>
<script setup>
import { ElMessageBox, ElNotification} from "element-plus";
import {ElLoading, ElMessage, ElMessageBox, ElNotification} from "element-plus";
import {getToken} from '@/utils/auth'
import {nextTick} from "vue";
import axios from "axios";
const baseURL = import.meta.env.VITE_BASE_URL
const uploadFileUrl = ref(baseURL + "/workflow/process/file/upload")
const headers = reactive({
'Content-Type': 'multipart/form-data',
authorization: getToken()
})
const loading = ref(false)
const showTable = ref(false)
const uploadIndex = ref(0)
const uploadParams = ref({})
const props = defineProps({
value: {
@@ -39,7 +44,7 @@ const props = defineProps({
},
maxSize: {
type: Number,
default: 30
default: 999999
},
showFileList: {
type: Boolean,
@@ -54,8 +59,9 @@ const props = defineProps({
default: true
}
})
const emit = defineEmits(["input", "getFile", "delete"])
const uploadRef = ref(null); // el-upload 的 ref
const uploadPromises = ref([]); // 跟踪每个文件的上传状态
const emit = defineEmits(["input", "beforeUpload","getFile", "delete"])
const fileList = ref([])
const _value = computed({
get() {
@@ -73,9 +79,79 @@ const beforeRemove = (file) => {
}).then(() => true)
}
const uploadLoading = ref(false)
const uploadFile = ref([])
const handleRemove = (file) => {
emit("delete", file.response.data.id)
}
// 文件选择变化时触发
const handleChange = (file, files) => {
console.log(file, files,'files')
uploadIndex.value++
uploadFile.value.push(file)
};
watch(() => uploadIndex.value, (newVal) => {
console.log('newVal',newVal)
startUpload(uploadFile.value); // 自动触发上传
},{
deep: true
})
// 自定义上传逻辑
const customUpload = async (options) => {
const formData = new FormData();
formData.append('file', options.raw);
try {
const response = await axios.post(uploadFileUrl.value, formData, {
headers: headers,
});
fileList.value.push(response.data.data)
emit("getFile", response.data.data)
return response.data; // 成功时返回响应
} catch (error) {
throw new Error('上传失败'); // 失败时抛出错误
}
};
// 触发所有文件上传
const startUpload = (files) => {
uploadLoading.value= ElLoading.service({
fullscreen: true,
text: '文件上传中...',
})
if (files.length === 0) {
return; // 没有文件时直接返回
}
uploadPromises.value = []; // 重置 Promise 数组
files.forEach((file) => {
// 触发每个文件的上传
const promise = new Promise((resolve, reject) => {
customUpload(file).then(resolve)
.catch(reject);
});
uploadPromises.value.push(promise);
});
// 使用 Promise.all 监听所有文件上传完成
Promise.all(uploadPromises.value)
.then(() => {
ElNotification({
title: '提示',
message: '所有文件上传完成!',
type: 'success'
})
files = []; // 清空文件列表
uploadRef.value.clearFiles(); // 清空上传组件
nextTick(() => {
uploadLoading.value.close()
uploadLoading.value=null
})
})
};
const beforeUpload = () => {
loading.value = true
return true

View File

@@ -0,0 +1,114 @@
<template>
<el-upload :file-list="[]"
:limit="maxSize"
with-credentials
:multiple="multiple"
:http-request="httpRequestHandle"
:data="uploadParams"
:auto-upload="true"
:show-file-list="false"
:before-upload="beforeUpload"
:before-remove="beforeRemove"
:on-remove="handleRemove"
>
<el-button color="#DED0B2" style="margin-right: 10px;" :disabled="disabled">导入</el-button>
</el-upload>
</template>
<script setup>
import {ElMessageBox, ElNotification} from "element-plus";
import {getToken} from '@/utils/auth'
import axios from "axios";
const props = defineProps({
value: {
type: Array,
default: () => {
return []
}
},
maxSize: {
type: Number,
default: 30
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false
},
})
const baseURL = import.meta.env.VITE_BASE_URL
const uploadFileUrl = ref(baseURL + "/workflow/mosr/rd/expense/import")
const headers = reactive({
authorization: getToken()
})
// const loading = ref(false)
const uploadParams = ref({})
const emit = defineEmits(["input", "getFile", "delete"])
const beforeRemove = (file) => {
return ElMessageBox.confirm(`确认删除名称为${file.name}的文件吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => true)
}
const handleRemove = (file) => {
emit("delete", file.response.data.id)
}
const beforeUpload = () => {
// loading.value = true
return true
}
const httpRequestHandle = (param) => {
let file = param.file
axios.post(uploadFileUrl.value, {
file: file
}, {
headers: {
'Content-Type': 'multipart/form-data',
...headers
}
}).then(res => {
handleUploadSuccess(res)
}).catch(error => {
uploadError(error)
})
}
const handleUploadSuccess = (res) => {
let data = res.data
ElNotification({
title: '提示',
message: data.code === 1000 ? '上传成功' : '上传失败',
type: data.code === 1000 ? 'success' : 'error'
})
emit("success")
}
const uploadError = (error) => {
console.log("🚀 ~ file:'error ", error.response.data.msg)
// loading.value = false
ElNotification({
title: '提示',
message: error.response.data.msg,
type: 'error'
})
}
defineExpose({
handleRemove
})
</script>
<style lang="scss" scoped>
a {
font-size: 14px;
color: #2a99ff;
}
</style>

View File

@@ -4,8 +4,8 @@
<el-form-item label="名称" prop="fileName">
<el-input v-model="attachment.fileName" placeholder="请输入文件名查询" clearable filterable style="width: 300px"/>
</el-form-item>
<el-form-item label="类型" prop="targetState" v-if="allFile">
<el-select v-model="attachment.targetState" placeholder="请选择类型" clearable filterable style="width: 300px">
<el-form-item label="项目阶段" prop="targetState" v-if="allFile">
<el-select v-model="attachment.targetState" placeholder="请选择项目阶段" clearable filterable style="width: 300px">
<el-option
v-for="item in cacheStore.getDict('archive_file_type')"
:key="item.value"
@@ -31,7 +31,7 @@
</el-form-item>
</el-form>
<el-card style="width: 100%;overflow-y: hidden">
<fvTable style="width: 100%;max-height: 318px" v-if="showTable" height="318" :tableConfig="tableConfig"
<fvTable style="width: 100%;max-height: 318px" v-if="showTable" height="318" :tableConfig="allFile?tableConfigAll:tableConfig"
:data="fileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="99" description="暂无数据" style="padding: 0"/>
@@ -96,7 +96,67 @@ const tableConfig = reactive({
},
{
prop: 'tag',
label: '标签',
label:'标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'createTime',
label: '上传时间',
align: 'center',
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
return (
<div>
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
</div>
)
}
}
]
})
const tableConfigAll = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width:85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'targetState',
label:'项目阶段',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.targetState&&row.targetState !== null&&row.targetState!==undefined) {
return (<Tag dictType={'archive_file_type'} value={row.targetState}/>)
} else {
return '--'
}
}
},
{
prop: 'tag',
label:'标签',
align: 'center'
},
{

View File

@@ -28,7 +28,8 @@
</el-form>
<el-table :data="preProcessList" v-loading="loading"
@select="handleSelect" @select-all="handleSelect" row-key="requestId" ref="preProcessTable">
<el-table-column type="selection" width="55" :reserve-selection="true"/>
<el-table-column type="selection" width="55" :reserve-selection="true"
:selectable="checkSelectable"/>
<el-table-column prop="requestId" label="请求id"></el-table-column>
<el-table-column prop="requestName" label="请求名称"></el-table-column>
<el-table-column prop="lastOperatorName" label="最后操作人名称"></el-table-column>
@@ -70,11 +71,13 @@ const props = defineProps({
})
const loading = ref(false)
//暂存数据
const originalProcess = ref([])
const currentList = ref([])
const showPreTable = ref(false)
const selectRows = ref([])
const preProcessList = ref([])
const total = ref(0)
const preProcessTable = ref()
const localFormData = ref({
projectPersonIds: [],
projectChargePerson: null,
@@ -102,7 +105,7 @@ const getPreProcessTag = (impact,basicImpact) => {
}
if (data == 1) {
//一般项目
return '一般项目20万以下要总经理审批'
return '研发费用20万元以下科技创新项目报总经理审批'
} else if (data == 2) {
//重大项目
return '重大项目20万元到500万元之间要总办会审批'
@@ -118,8 +121,33 @@ const handleReset = () => {
const handleSelect = async (selection) => {
selectRows.value = selection
}
const checkSelectable=(row)=>{
const detailProcessStr = localStorage.getItem('detailProcess');
let preProcessArray = []
if (detailProcessStr) {
try {
preProcessArray = JSON.parse(detailProcessStr)
} catch (e) {
preProcessArray=[]
}
if (preProcessArray&&preProcessArray.length > 0) {
for (let i = 0; i < preProcessArray.length; i++) {
return preProcessArray[i].requestId !== row.requestId;
}
}else{
return true
}
}
}
const handleShowPreTable = () => {
showPreTable.value = true
nextTick(() => {
localFormData.value.preProcess?.forEach((item) => {
if (preProcessTable.value) {
preProcessTable.value.toggleRowSelection(item, true)
}
})
})
getPreProcessList()
}
const handleCancel = () => {
@@ -129,17 +157,30 @@ const handleCancel = () => {
const choosePreProcess = () => {
let preProcessObj = {}
let preProcessArray = []
const detailProcessStr = localStorage.getItem('detailProcess');
try {
originalProcess.value = JSON.parse(detailProcessStr)
} catch (e) {
originalProcess.value=[]
}
selectRows.value.forEach((item) => {
preProcessObj = {
requestId: item.requestId,
requestName: item.requestName,
baseUrl: item.baseUrl
const exists = originalProcess.value?.some(dp => dp.requestId === item.requestId)
if (!exists) {
preProcessObj = {
requestId: item.requestId,
requestName: item.requestName,
baseUrl: item.baseUrl
}
preProcessArray.push(preProcessObj)
}
preProcessArray.push(preProcessObj)
})
localFormData.value.preProcess = preProcessArray
showPreTable.value = false
if(props.formData.mode === 'view'||props.formData.mode === 'resubmit'){
localFormData.value.preProcess = [...originalProcess.value,...preProcessArray]
}else{
localFormData.value.preProcess = preProcessArray
}
localStorage.setItem('preProcess', JSON.stringify(preProcessArray))
showPreTable.value = false
}
const getPreProcessList = () => {
@@ -154,13 +195,6 @@ const getPreProcessList = () => {
searchArray.push(item)
}
})
// res.data.forEach((item) => {
// localFormData.value.preProcess.forEach((item1) => {
// if (item.requestId == item1.requestId) {
// preProcessTable.value.toggleRowSelection(item)
// }
// })
// })
total.value = searchArray.length
currentList.value = searchArray
preProcessList.value = currentList.value.slice(0, 10)
@@ -177,6 +211,7 @@ const handleCurrentChange = (val) => {
pageInfo.pageNum = val;
preProcessList.value = currentList.value.slice((val - 1) * pageInfo.pageSize, val * pageInfo.pageSize)
};
watchEffect(() => {
return Object.keys(props.formData).length && (localFormData.value = props.formData)
})

View File

@@ -38,7 +38,7 @@ import 'tinymce/plugins/wordcount'
import 'tinymce/plugins/autosave'
import '@/assets/axupimgs/plugin.js'//多图上传插件
const emit = defineEmits(['update:value'])
const emit = defineEmits(['update:value','getFiles'])
const props = defineProps({
//默认值
value: {
@@ -56,7 +56,6 @@ const props = defineProps({
plugins: {
type: [String, Array],
default:
//
"preview searchreplace autolink directionality visualblocks visualchars fullscreen image axupimgs link media template code codesample table pagebreak nonbreaking anchor insertdatetime advlist lists wordcount autosave",
},
toolbar: {
@@ -79,6 +78,7 @@ const props = defineProps({
default: 500
}
})
const fileLists=ref([])
const content = ref(props.value);
const imgUrl = ref();
// const apiKey = reactive("v4zo4n22oanvco29ws5drh0pecuf3gh53clx53cccj3grjwg");
@@ -169,6 +169,15 @@ const init = reactive({
type: res.code === 1000 ? 'success' : 'error'
})
loading.close()
console.log("🚀 ~ file:res.data ", res.data)
res.data.originalFileName=res.data.originalFilename
console.log("🚀 ~ file:'meta.filetype ",meta.filetype )
if (res && res.data && res.data.fileType &&
!["png", "jpg", "jpeg","gif", "svg","ico"].includes(res.data.fileType.toLowerCase())){
fileLists.value.push(res.data)
emit('getFiles',fileLists.value)
}
const fileUrl = res.data.url;
// '?fileId='+res.data.id+
callback(fileUrl + '?fileName=' + res.data.originalFilename, {text: file.name, title: file.name});

View File

@@ -279,7 +279,7 @@ const schema = computed(() => {
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 6
@@ -294,6 +294,22 @@ const schema = computed(() => {
</div>
)
},
{
label: '实际经费预算(元)',
prop: 'actualEconomicEstimate',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.actualEconomicEstimate ?
<span>{toThousands(baseFormData.value?.actualEconomicEstimate)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '产学研联合',
prop: 'industryUniversityResearch',
@@ -334,7 +350,23 @@ const schema = computed(() => {
}
},
{
label: '申请总部专项资金(元)',
label: '预估专项资金(元)',
prop: 'forecastSpecialFundAmount',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.forecastSpecialFundAmount ?
<span>{toThousands(baseFormData.value?.forecastSpecialFundAmount)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际专项资金(元)',
prop: 'specialFundAmount',
colProps: {
span: 6

View File

@@ -1,5 +1,8 @@
<template>
<div class="fv-table-container">
<el-button v-if="tableConfig.export && tableConfig.export.open&&changeExportPosition" @click="exportTable" color="#DED0B2"
style="float: left;margin-right: 10px">导出
</el-button>
<!-- 表格头部按钮 -->
<div class="fv-table-btn" v-if="tableConfig.btns">
<div class="table-head-btn">
@@ -15,7 +18,7 @@
</el-button>
</div>
</div>
<el-button v-if="tableConfig.export && tableConfig.export.open" @click="exportTable" color="#DED0B2"
<el-button v-if="tableConfig.export && tableConfig.export.open&&!changeExportPosition" @click="exportTable" color="#DED0B2"
style="margin-bottom: 10px">导出
</el-button>
<!-- 列显示配置 -->
@@ -121,6 +124,11 @@ const props = defineProps({
type: Boolean,
default: true
},
//是否改变导出位置, 导出在btns前面
changeExportPosition: {
type: Boolean,
default: false
},
// 是否显示列配置
isSettingCol: {
type: Boolean,

View File

@@ -1,6 +1,6 @@
<template>
<div class="link-box">
<el-scrollbar noresize height="34" >
<el-scrollbar noresize height="36" >
<!-- style="display: flex"-->
<div >
<router-link

View File

@@ -37,9 +37,11 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
if (res.code === 1000) {
const sRouter = JSON.parse(JSON.stringify(res.data))
const mData = JSON.parse(JSON.stringify(res.data))
// console.log(JSON.parse(JSON.stringify(sRouter)), 'sRouter');
const firstFormat = setRouterLevel(JSON.parse(JSON.stringify(sRouter)))
console.log(firstFormat, 'firstFormat');
asyncRouters.value = formatAsyncRouters(JSON.parse(JSON.stringify(firstFormat)))
console.log('asyncRouters.value',firstFormat);
menuList.value = [...menuList.value, ...generateMenu(mData)]
addAsyncRouters(asyncRouters.value)
isLoadRoutes.value = false
@@ -52,16 +54,23 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
}
const setRouterLevel = (routers) => {
return routers.filter(item=>{
if(item.component === 'Layout') {
if(item.children) {
// console.log("🚀 ~ file: item.children ", item.children )
item.children.forEach(v=>{
if(v.children) {
slRouters.value = [...toRaw(slRouters.value), ...v.children]
delete v.children
// console.log("🚀 ~ file:item.children",item.children)
// console.log("🚀 ~ file: v.children ", v.children )
// slRouters.value = [ ...toRaw(v.children)]
// delete v.children
// slRouters.value = [ ...v.children]
// return v.children
item.children = [...item.children,...v.children]
}
})
item.children = [...item.children, ...toRaw(slRouters.value)]
}
}
return true
@@ -81,6 +90,7 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
}
if (route.children !== null && route.children && route.children.length !== 0) {
route.children = formatAsyncRouters(route.children)
}
return true
})
@@ -90,6 +100,8 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
routers.forEach(route => {
router.addRoute(route)
})
console.log("🚀 ~ file: ", routers)
}
const generateMenu = (routes) => {

View File

@@ -1,36 +1,68 @@
<template>
<div v-loading="loading" class="add-block">
<baseTitle title="文章信息录入"></baseTitle>
<el-form :model="formData" ref="fundForm" :rules="rules" style="margin-left: 5px;margin-bottom: -18px">
<el-form :model="formData" ref="fundForm" :rules="rules" style="margin-left: 5px;margin-bottom: -18px">
<el-row gutter="30">
<el-col :span="6" style="margin-left: 10px">
<el-form-item label="文章标题" prop="articleTitle">
<el-input v-model="formData.articleTitle" placeholder="请输入文章标题" clearable></el-input>
</el-form-item>
<el-form-item label="文章标题" prop="articleTitle">
<el-input v-model="formData.articleTitle" placeholder="请输入文章标题" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="文章类型" prop="articleType">
<el-select v-model="formData.articleType" placeholder="请选择文章类型" clearable filterable>
<el-option
v-for="item in cacheStore.getDict('article_type')"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="文章类型" prop="articleType">
<el-select v-model="formData.articleType" placeholder="请选择文章类型" clearable filterable>
<el-option
v-for="item in cacheStore.getDict('article_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="remarks">
<el-input v-model="formData.remarks" placeholder="请输入备注" clearable></el-input>
<el-col :span="6">
<el-form-item label="发文单位" prop="remarks">
<el-input v-model="formData.remarks" placeholder="请输入发文单位" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-left: 10px">
<el-form-item label="文章内容" prop="articleContent">
<Tinymce v-model:value="formData.articleContent" imageUrl="/workflow/process/file/upload" :height="500" v-if="showTinymce" :toolbar="['undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image axupimgs']" />
<!-- link-->
<Tinymce v-model:value="formData.articleContent"
imageUrl="/workflow/process/file/upload" :height="500" v-if="showTinymce"
:toolbar="['undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | image axupimgs']"/>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-bottom: -10px">
<el-form-item label="附件上传" prop="" style="margin-left: 20px;">
<file-upload @getFile="getFiles"/>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-left:90px;">
<!-- <el-form-item label="公告附件列表" prop=""-->
<!-- style="display: flex;flex-direction: column;justify-content: flex-start;">-->
<!-- <template #label>-->
<!-- <div style="width: 100%;display: flex;align-items: center;justify-content: flex-start">-->
<!-- <el-icon size="16">-->
<!-- <Paperclip/>-->
<!-- </el-icon>-->
<!-- 公告附件列表-->
<!-- </div>-->
<!-- </template>-->
<el-col :span="24" style="margin-left: -15px">
<div style="display: flex;flex-direction: column">
<div v-for="(item,index) in formData.fileList" style="display: flex;align-items: center;margin-bottom: 5px">
附件{{ index + 1 }} <a :href="item.url" style="color: #409eff;" class="a-style" target="_blank">{{ item.originalFileName }}</a>
<el-icon size="18" style="margin:0 20px;cursor: pointer" color="#409eff" @click="handleDelete(item,index)">
<CircleClose/>
</el-icon>
<el-button type="primary" link @click="handleDownload(item)" style="font-size: 16px;margin-left: 10px">下载</el-button>
</div>
</div>
</el-col>
<!-- </el-form-item>-->
</el-col>
</el-row>
</el-form>
<div class="oper-page-btn">
@@ -42,10 +74,14 @@
</template>
<script setup lang="jsx">
import {ElNotification} from "element-plus";
import {ElMessageBox, ElNotification} from "element-plus";
import {addArticle, editArticle, getArticleDetail} from "@/api/article";
import {useTagsView} from '@/stores/tagsview.js'
import { useCacheStore } from "@/stores/cache.js";
import {useCacheStore} from "@/stores/cache.js";
import {deleteFile, downloadFile} from "../../api/project-demand";
import FileUpload from "../../components/FileUpload.vue";
import Tinymce from "../../components/Tinymce.vue";
const cacheStore = useCacheStore();
const tagsViewStore = useTagsView()
const router = useRouter()
@@ -53,26 +89,79 @@ const route = useRoute()
const loading = ref(false)
const showTinymce = ref(true)
const fundForm = ref()
const formData = ref({})
const formData = ref({
fileList:[]
})
const routerName = ref(router.currentRoute.value.name)
const rules = reactive({
articleTitle: [{required: true, message: '请输入文章标题', trigger: ['blur', 'change']}],
articleType: [{required: true, message: '请输入文章类型', trigger: ['blur', 'change']}],
articleContent: [{required: true, message: '请输入文章内容', trigger: ['blur', 'change']}],
})
const handleDelete = (row,index) => {
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) {
formData.value.fileList.splice(index, 1)
}
})
})
}
const handleBack = () => {
history.back()
}
const getFiles = (val) => {
console.log("🚀 ~ file:val ", val)
val.originalFileName=val.originalFilename
let file = compositeParam(val)
formData.value.fileList.push(file)
}
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 submitParam = (item) => {
console.log("🚀 ~ file:item.fileList ", item.fileList)
item.fileList= item.fileList.map((it)=>{
return {
...it,
articleId:item.articleId
}
})
return {
articleContent: item.articleContent,
articleTitle: item.articleTitle,
articleType: item.articleType,
remarks: item.remarks,
articleId: item.articleId,
fileList: item.fileList
}
}
const compositeParam = (item) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: 'article'
}
}
const handleSubmit = async (instance) => {
if (!instance) return
instance.validate(async (valid) => {
@@ -104,6 +193,7 @@ const handleResubmit = () => {
articleId: route.query.id,
...submitParam(formData.value)
}
console.log('params', params)
editArticle(params).then(res => {
ElNotification({
title: '提示',
@@ -124,11 +214,11 @@ const getDetailInfo = async () => {
if (res.code === 1000) {
formData.value = res.data
loading.value = false
showTinymce.value=false
showTinymce.value = false
nextTick(() => {
showTinymce.value=true
showTinymce.value = true
})
}else{
} else {
ElNotification({
title: '提示',
message: res.msg,
@@ -145,6 +235,9 @@ onMounted(async () => {
</script>
<style scoped lang="scss">
.a-style:hover{
text-decoration: underline !important;
}
.company-select {
:deep(.el-form-item__content .el-select__wrapper ) {
width: 750px;
@@ -166,6 +259,7 @@ onMounted(async () => {
height: auto;
}
}
:deep(.el-table--fit ) {
height: 300px !important;
}
@@ -176,9 +270,11 @@ onMounted(async () => {
:deep(.el-input-number) {
width: 88.5%;
.el-input__wrapper{
padding: 1px 11px!important;
.el-input__wrapper {
padding: 1px 11px !important;
}
.el-input__inner {
text-align: left;
}

View File

@@ -5,7 +5,7 @@
<div class="article-title">
<Tag dictType="article_type" :value="formData.articleType"/>
<span>{{ formData.articleTime }}</span>
<span>备注{{ formData.remarks }}</span>
<span>发文单位{{ formData.remarks }}</span>
</div>
<el-row gutter="20">
<el-col :span="24">
@@ -13,6 +13,14 @@
<div class="article-a" v-html="formData.articleContent" @click="clickHandle"></div>
</el-form-item>
</el-col>
<el-col :span="24">
<div style="display: flex;flex-direction: column">
<div v-for="(item,index) in formData.fileList" style="display: flex;align-items: center;margin-bottom: 5px">
附件{{ index + 1 }} <a :href="item.url" style="color: #409eff;" class="a-style" target="_blank">{{ item.originalFileName }}</a>
<el-button type="primary" link @click="handleDownload(item)" style="font-size: 16px;margin-left: 10px">下载</el-button>
</div>
</div>
</el-col>
</el-row>
</el-form>
</div>
@@ -43,7 +51,7 @@ const clickHandle = (e) => {
fileName
}
// handleDownload(fileId,fileName)
download(item)
// download(item)
// }else {
// e.preventDefault()
// }
@@ -64,6 +72,15 @@ const clickHandle = (e) => {
// })
// })
// }
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 download = (row) => {
const x = new window.XMLHttpRequest();
x.open('GET', row.url, true);
@@ -101,6 +118,7 @@ onMounted(async () => {
</script>
<style lang="scss">
.article-a {
a {
color: #409eff !important;
@@ -112,7 +130,9 @@ onMounted(async () => {
}
</style>
<style scoped lang="scss">
.a-style:hover{
text-decoration: underline !important;
}
.article-detail {
padding: 0 30px;
padding-top: 15px;

View File

@@ -93,8 +93,15 @@ const articleTableConfig = reactive({
},
{
prop: 'remarks',
label: '备注',
align: 'center'
label: '发文单位',
align: 'center',
currentRender: ({row, index}) => {
if (!row.remarks|| row.remarks == undefined || row.remarks == null) {
return '--'
} else {
return row.remarks
}
}
},
{
prop: 'oper',

View File

@@ -0,0 +1,275 @@
<template>
<fvSearchForm :searchConfig="searchConfig" @search="search" style="margin-left: 15px"></fvSearchForm>
<div style="float: left">
<import-cost-excel @success="importTheExpenseLedger"/>
</div>
<fvTable ref="tableIns" class="tablte" :tableConfig="tableConfig" @headBtnClick="headBtnClick" :changeExportPosition="true">
<template #empty>
<el-empty description="暂无数据"/>
</template>
</fvTable>
</template>
<script setup lang="jsx">
import {reactive, ref} from "vue";
import {useRoute, useRouter} from "vue-router";
import {costTemplateDownload, exportExcel, ledgerTemplateDownload} from "../../../api/project-manage";
import ImportCostExcel from "@/components/ImportCostExcel.vue";
const router = useRouter()
const route = useRoute()
const searchConfig = ref([
{
label: '主项目',
prop: 'masterProjectName',
component: 'el-input',
props: {
placeholder: '请输入主项目查询',
clearable: true,
filterable: true,
checkStrictly: true
}
},
{
label: '子项目',
prop: 'subProjectName',
component: 'el-input',
props: {
placeholder: '请输入子项目查询',
clearable: true,
filterable: true,
checkStrictly: true
}
},
{
label: '会计凭证记载金额(元)',
prop: 'recordedAmount',
component: 'el-input',
props: {
placeholder: '请输入会计凭证记载金额查询',
clearable: true,
filterable: true,
checkStrictly: true
}
},
{
label: '归集研发费用金额(元)',
prop: 'rdAmount',
component: 'el-input',
props: {
placeholder: '请输入归集研发费用金额查询',
clearable: true,
filterable: true,
checkStrictly: true
}
},
// {
// label: '项目类型',
// prop: 'projectType',
// component: shallowRef(fvSelect),
// props: {
// placeholder: '请选择项目类型',
// cacheKey: 'project_type',
// clearable: true,
// filterable: true,
// remote: true
// },
// colProps: {}
// },
// {
// label: '归档时间',
// prop: 'filingTime',
// component: 'el-date-picker',
// props: {
// placeholder: '请选择归档时间',
// clearable: true,
// type:'date',
// format: 'YYYY-MM-DD HH:mm',
// valueFormat:'YYYY-MM-DD HH:mm',
// },
// colProps: {}
// },
])
const tableIns = ref()
const tableConfig = reactive({
columns: [
// {
// prop: 'name',
// type: 'index',
// label: '序号',
// align: 'center',
// width:85,
// index: index => {
// return (tableIns.value.getQuery().pageNum - 1) * tableIns.value.getQuery().pageSize + index + 1
// }
// },
{
prop: 'rdYear',
label: '年',
align: 'center',
width: 80
},
{
prop: 'rdMonth',
label: '月',
align: 'center',
width: 80
},
{
prop: 'rdDay',
label: '日',
align: 'center',
width: 80
},
{
prop: 'masterProjectName',
label: '主项目',
align: 'center',
width: 120,
},
{
prop: 'subProjectName',
label: '子项目',
align: 'center',
width: 120,
},
{
prop: 'certificateDate',
label: '凭证日期',
align: 'center',
width: 120,
},
{
prop: 'voucherNumber',
label: '凭证号',
align: 'center'
},
{
prop: 'entryNumber',
label: '分录号',
align: 'center',
},
{
prop: 'digest',
label: '摘要',
align: 'center',
showOverflowTooltip: false,
},
{
prop: 'accountCode',
label: '科目编码',
align: 'center',
showOverflowTooltip: false,
},
{
prop: 'accountName',
label: '科目名称',
align: 'center',
showOverflowTooltip: false,
},
{
prop: 'auxiliaryItem',
label: '辅助项',
align: 'center',
showOverflowTooltip: false,
},
{
prop: 'recordedAmount',
label: '会计凭证记载金额(元)',
align: 'center',
width: 170
},
{
prop: 'rdAmount',
label: '归集研发费用金额(元)',
align: 'center',
width: 170
},
],
api: '/workflow/mosr/rd/expense/list',
params: {},
btns: [
{name: '模板下载', key: 'down', color: '#DED0B2'},
// {name: '导入', key: 'import', color: '#DED0B2'}
],
export:{
open :true,
fileName:`研发费用明细表`
}
})
const search = (val) => {
tableConfig.params = {...val}
tableIns.value.refresh()
}
const headBtnClick = (key) => {
switch (key) {
case 'down':
handleImportTemplateDownload()
break;
case 'import':
handleAdd()
break;
}
}
const exportTable = () => {
const $e = tableIns.value.$el
let $table = $e.querySelector('.el-table__fixed')
if (!$table) {
$table = $e
}
exportExcel($table, (5 + (Object.keys(tableData.value[0]).length - 5) * 5), "四川省国有资产经营投资管理有限责任公司科技创新项目人工成本分摊明细表", 2)
}
//导入模板下载
const handleImportTemplateDownload=()=>{
costTemplateDownload().then(res => {
let link = document.createElement('a')
try {
let blob = new Blob([res.data],{type: 'application/vnd.ms-excel'});
let _fileName = "研发费用明细表模板.xlsx"//文件名,中文无法解析的时候会显示 _(下划线),生产环境获取不到
link.style.display='none';
// 兼容不同浏览器的URL对象
const url = window.URL || window.webkitURL || window.moxURL;
link.href=url.createObjectURL(blob);
link.setAttribute('download', _fileName.substring(_fileName.lastIndexOf('_')+1))
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
url.revokeObjectURL(link.href);//销毁url对象
}catch (e) {
console.log('下载的文件出错',e)
}
})
}
const importTheExpenseLedger = () => {
tableIns.value.refresh()
}
</script>
<style scoped lang="scss">
:deep(.el-form-item__label-wrap){
margin-left: 0!important;
}
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: -25px !important;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: -13px !important;
}
}
}
:deep(.el-date-editor--month){
width: 100%;
}
</style>

View File

@@ -0,0 +1,232 @@
<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 {toThousands} from '@/utils/changePrice.js'
import { getSubCompOpt } from '@/api/user/user.js';
const router = useRouter()
const route = useRoute()
const searchConfig = ref(
[
{
label: '主项目',
prop: 'masterProjectName',
component: 'el-input',
props: {
placeholder: '请输入主项目查询',
clearable: true,
filterable: true,
checkStrictly: true
}
},
{
label: '子项目',
prop: 'subProjectName',
component: 'el-input',
props: {
placeholder: '请输入子项目查询',
clearable: true,
filterable: true,
checkStrictly: true
}
},
{
label: '项目类型',
prop: 'projectType',
component: shallowRef(fvSelect),
props: {
placeholder: '请选择项目类型',
cacheKey: 'project_type',
clearable: true,
filterable: true,
remote: true
},
colProps: {}
},
// {
// label: '归档时间',
// prop: 'filingTime',
// component: 'el-date-picker',
// props: {
// placeholder: '请选择归档时间',
// clearable: true,
// type:'date',
// format: 'YYYY-MM-DD HH:mm',
// valueFormat:'YYYY-MM-DD HH:mm',
// },
// colProps: {}
// },
])
const tableIns = ref()
const tableConfig = reactive({
columns: [
// {
// prop: 'name',
// type: 'index',
// label: '序号',
// align: 'center',
// width:85,
// index: index => {
// return (tableIns.value.getQuery().pageNum - 1) * tableIns.value.getQuery().pageSize + index + 1
// }
// },
{
prop: 'paymentYear',
label: '支付年份',
align: 'center'
},
{
prop: 'paymentMonth',
label: '支付月份',
align: 'center'
},
{
prop: 'masterProjectName',
label: '主项目',
align: 'center',
width: 120,
},
{
prop: 'subProjectName',
label: '子项目',
align: 'center',
width: 120,
},
{
prop: 'projectType',
label: '项目类型',
align: 'center',
width: 120,
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.projectType&&row.projectType !== null&&row.projectType!==undefined) {
return (<Tag dictType={'project_type'} value={row.projectType}/>)
} else {
return '--'
}
}
},
{
prop: 'rdType',
label: 'R&D统计类型',
align: 'center',
width: 200
},
{
prop: 'rdSub',
label: 'R&D统计子项',
align: 'center',
width: 150
},
{
prop: 'paymentProcessType',
label: '付款流程类型',
align: 'center',
width: 150
},
{
prop: 'processState',
label: '流程状态',
align: 'center',
},
{
prop: 'filingTime',
label: '归档时间',
align: 'center',
width: 180
},
{
prop: 'paymentProcessNum',
label: '付款流程编号',
align: 'center',
width: 150
},
{
prop: 'paymentAmount',
label: '付款金额',
align: 'center',
},
{
prop: 'paymentSubject',
label: '付款/请款事由',
align: 'center',
width: 130
},
{
prop: 'contractNum',
label: '合同编号',
align: 'center',
},
{
prop: 'contractName',
label: '合同名称',
align: 'center',
},
{
prop: 'contractSumAmount',
label: '合同总额(元)',
align: 'center',
width: 130
},
{
prop: 'recipientName',
label: '收款方名称',
align: 'center',
width: 130
},
{
prop: 'remarks',
label: '备注说明',
align: 'center',
},
],
api: '/workflow/mosr/payment/list',
params: {},
export:{
open :true,
fileName:`科研项日现金支出明细表`
}
})
const search = (val) => {
tableConfig.params = {...val}
tableIns.value.refresh()
}
const init = async () => {
const res = await getSubCompOpt()
searchConfig.value.find(item=>item.prop == 'affiliatedCompanyIds').props.data = res.data
}
// init()
</script>
<style scoped lang="scss">
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: -25px !important;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: -13px !important;
}
}
}
:deep(.el-date-editor--month){
width: 100%;
}
</style>

View File

@@ -204,7 +204,7 @@ const tableConfig = reactive({
},
{
prop: 'economicEstimate',
label: '经费预算(元)',
label: '预估经费预算(元)',
align: 'center',
width: 150,
currentRender:({row})=>{

View File

@@ -0,0 +1,591 @@
<template>
<div v-loading="loading" style="padding: 0 30px">
<el-form :model="formData" ref="form" :rules="rules" style="margin-left: 5px;margin-top: 18px">
<el-row :gutter="30">
<!-- <el-col :span="6" style="margin-left: -15px">-->
<!-- <el-form-item label="分摊名称" prop="shareName" >-->
<!-- <el-input v-model="formData.shareName" placeholder="请输入分摊名称" clearable>-->
<!-- </el-input>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="6" style="margin-left: -10px">
<el-form-item label="分摊月份" prop="apportionmentMonth" label-width="80">
<el-date-picker
v-model="formData.apportionmentMonth"
type="month"
format="YYYY-MM"
value-format="YYYY-MM"
placeholder="选择月"
>
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="3" >
<el-button color="#DED0B2" @click="handleAdd" style="font-size: 16px">添加一行</el-button>
</el-col>
<el-table v-if="showTable" :data="formData.tableData" style="width: 100%">
<el-table-column prop="projectId" label="项目名称" min-width="230">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.projectId?'1':rules.projectId">
<el-select v-model="scope.row.projectId" placeholder="请选择项目名称" clearable filterable @change="selectProject(scope.row,scope.$index)">
<el-option
v-for="item in nameOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="researchPersonnelId" label="研发人员" min-width="180">
<template #default="scope">
<el-form-item prop="researchPersonnelId">
{{ scope.row.researchPersonnel }}
<el-button color="#DED0B2" @click="showPersonnelPicker(scope.row,scope.$index)"
style="margin-left: 10px">
{{ scope.row.researchPersonnel ? '更改' : '请选择研发人员' }}
</el-button>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="wagesPayable" label="当月总工时(天)" min-width="175">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.wagesPayable?'1':rules.wagesPayable">
<div>21.75</div>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="researchDuration" label="当月研发工时(天)" min-width="175">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.researchDuration?'1':rules.researchDuration">
<el-input-number v-model="scope.row.researchDuration" placeholder="请输入当月研发工时" :controls="false"/>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="oper" label="操作" min-width="130">
<template #default="scope">
<el-button type="primary" @click="handleCopy(scope.row)" link style="font-size: 16px">复制</el-button>
<el-button type="primary" @click="handleDelete(scope.$index)" link style="font-size: 16px">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-row>
</el-form>
<user-picker :multiple="false" ref="userPicker" title="请选择研发人员" v-model:value="userList"
@ok="selectedResearchPersonnel" @cancelOrClear="researchPersonnelPickerCancel"
:setNullToSelectList="true" :isResearch="true"/>
<div class="oper-page-btn">
<el-button color="#DED0B2" v-if="routerName==='Sharedetail/add'" @click="handleSubmit(form)">提交</el-button>
<el-button color="#DED0B2" v-else @click="handleResubmit(form)">重新提交</el-button>
<el-button @click="handleBack">返回</el-button>
</div>
</div>
</template>
<script setup lang="jsx">
import {ElNotification} from "element-plus";
import {useTagsView} from '@/stores/tagsview.js'
import {
addAllocation,
getAllocationDetail,
getAllocationProcess,
getResearchUser,
getProjectOption,
editAllocation,
getAllocationDetailList, addShare
} from "@/api/expense-manage";
import {useProcessStore} from '@/stores/processStore.js';
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import UserPicker from "@/views/workflow/process/common/UserPicker.vue";
localStorage.removeItem('originallySelectedList')
const userList = ref([])
const changeDiagram = ref(false)
const rules = reactive({
// shareName: [{required: true, message: '请输入分摊名称', trigger: ['blur', 'change']}],
apportionmentMonth: [{required: true, message: '请选择月份', trigger: ['blur', 'change']}],
projectId: [{required: true, message: '请选择项目名称', trigger: ['blur', 'change']}],
// researchPersonnelId: [{required: true, message: '请选择研发人员', trigger: ['blur', 'change']}],
// wagesPayable: [{required: true, message: '请输入应发工资', trigger: ['blur', 'change']}],
// performance: [{required: true, message: '请输入绩效', trigger: ['blur', 'change']}],
// reserveFund: [{required: true, message: '请输入公积金', trigger: ['blur', 'change']}],
// socialSecurity: [{required: true, message: '请输入社保', trigger: ['blur', 'change']}],
// annuity: [{required: true, message: '请输入年金', trigger: ['blur', 'change']}],
// workday: [{required: true, message: '请输入工作日', trigger: ['blur', 'change']}],
researchDuration: [{required: true, message: '请输入研发时长', trigger: ['blur', 'change']}],
})
const processStore = useProcessStore()
const opentionData = ref({})
const processInstanceData = ref()
const processDiagramViewer = ref(false)
const loading = ref(false)
const isRepeatResearchPersonnel = ref(false)
const showTable = ref(true)
const route = useRoute()
const router = useRouter()
const routerName = ref(router.currentRoute.value.name)
const tagsViewStore = useTagsView()
const formData = ref({
tableData: [
{
projectId: '',
projectName: '',
// researchPersonnelId: '',
// wagesPayable: null,
// performance: null,
// reserveFund: null,
// socialSecurity: null,
// annuity: null,
workday: '21.75',
researchDuration: null,
}
]
})
const userPicker = ref()
const form = ref()
const currentReachPerson = ref({})
const currentRow = ref()
const currentIndex = ref()
const nameOptions = ref([])
const researchOptions = ref([])
const showPersonnelPicker = (row, index) => {
currentRow.value = row
currentIndex.value = index
if (row.companyName&&row.researchPersonnelId) {
let userObj = {
id: row.researchPersonnelId,
name: row.researchPersonnel,
companyName: row.companyName,
accountType: row.accountType,
}
userList.value = [userObj]
} else if (!row.researchPersonnel) {
userList.value = []
}
nextTick(() => {
userPicker.value.showUserPicker()
})
}
const selectProject=(row,index)=>{
console.log('row,index',row,index)
//先选择人员, 再选择项目: 再添加一行,重复操作
const projectIdArray = formData.value.tableData.map(item => item.projectId)
const researchPersonnelIdArray = formData.value.tableData.map(item => item.researchPersonnelId)
console.log('projectIdArray',projectIdArray)
console.log('researchPersonnelIdArray',researchPersonnelIdArray)
const projectNumObj = getSelectProjectAndResearchPersonnelNum(projectIdArray)
const researchPersonnelNumObj = getSelectProjectAndResearchPersonnelNum(researchPersonnelIdArray)
let repeatProjectName=getProjectName(row.projectId)
// console.log('currentRow.value',currentRow.value)
// for (let researchPersonnelIdKey in researchPersonnelNumObj) {//先判断人员是否重复
// if(currentRow.value.projectId){
// if(researchPersonnelNumObj[researchPersonnelIdKey]>1){
// ElNotification({
// title: '警告',
// message: `${repeatProjectName} 项目下,同一个研发人员不能分摊多次!`,
// type: 'warning',
// })
// row.researchPersonnelId = ''
// row.researchPersonnel = ''
// row.companyName = ''
// row.accountType = ''
// }
// }
//
// }
// for (let projectIdKey in projectNumObj) {
// // console.log('projectNumObjKey', projectIdKey, projectNumObj[projectIdKey])
// if(projectNumObj[projectIdKey]>1){
// // console.log('getProjectName(projectIdKey)',getProjectName(projectIdKey))
// repeatProjectName=getProjectName(projectIdKey)
//
// }
// }
}
const researchPersonnelPickerCancel = (select) => {
console.log('select',select)
if(select.length>0){
formData.value.tableData?.forEach((item, index) => {
if (index === currentIndex.value) {
item.researchPersonnelId = select[0].id
item.researchPersonnel = select[0].name
item.companyName = select[0].companyName
item.accountType = select[0].accountType
}
})
}else{
formData.value.tableData?.forEach((item, index) => {
if (index === currentIndex.value) {
item.researchPersonnelId = ''
item.researchPersonnel = ''
item.companyName = ''
item.accountType = ''
}
})
}
}
const selectedResearchPersonnel = (select) => {
if(select.length>0){
formData.value.tableData?.forEach((item, index) => {
if (index === currentIndex.value) {
item.researchPersonnelId = select[0].id
item.researchPersonnel = select[0].name
item.companyName = select[0].companyName
item.accountType = select[0].accountType
}
})
}else{
formData.value.tableData?.forEach((item, index) => {
if (index === currentIndex.value) {
item.researchPersonnelId = ''
item.researchPersonnel = ''
item.companyName = ''
item.accountType = ''
}
})
}
//以下是为" 同一项目下,同一人不能分摊多次 "
const projectIdArray = formData.value.tableData?.map(item => item.projectId)
const researchPersonnelIdArray = formData.value.tableData?.map(item => item.researchPersonnelId)
const projectNumObj = getSelectProjectAndResearchPersonnelNum(projectIdArray)
const researchPersonnelNumObj = getSelectProjectAndResearchPersonnelNum(researchPersonnelIdArray)
let repeatProjectName=''
for (let projectIdKey in projectNumObj) {
// console.log('projectNumObjKey', projectIdKey, projectNumObj[projectIdKey])
if(projectNumObj[projectIdKey]>1){
// console.log('getProjectName(projectIdKey)',getProjectName(projectIdKey))
repeatProjectName=getProjectName(projectIdKey)
}
}
// for (let researchPersonnelIdKey in researchPersonnelNumObj) {
// // console.log('researchPersonnelIdKey', researchPersonnelIdKey, researchPersonnelNumObj[researchPersonnelIdKey])
// if(researchPersonnelNumObj[researchPersonnelIdKey]>1&&repeatProjectName&&currentRow.value.projectId){
// isRepeatResearchPersonnel.value=true
// ElNotification({
// title: '警告',
// message: `${repeatProjectName} 项目下,同一个研发人员不能分摊多次!`,
// type: 'warning',
// })
// formData.value.tableData.forEach((item,index)=>{
// if (index === currentIndex.value) {
// item.researchPersonnelId = ''
// item.researchPersonnel = ''
// item.companyName = ''
// item.accountType = ''
// }
// })
// }else{
// userList.value = select
// }
// }
}
/**
* 获取一个项目/研发人员的选择次数
* @param projectIdArray
* @returns {{}}
*/
const getSelectProjectAndResearchPersonnelNum = (projectIdArray) => {
const obj = {};
for (let i = 0, l = projectIdArray.length; i < l; i++) {
const item = projectIdArray[i];
obj[item] = (obj[item] + 1) || 1;
}
return obj;
}
const getResearchOptions = async () => {
const res = await getResearchUser()
researchOptions.value = res.data
}
const getProjectOptions = async () => {
const res = await getProjectOption()
nameOptions.value = res.data
}
const getProjectName = (id) => {
let label = ''
nameOptions.value.forEach(item => {
if (item.value == id) {
label = item.label
}
})
return label
}
const handleAdd = () => {
let row = {
projectId: '',
projectName: '',
researchPersonnelId: '',
researchPersonnel: '',
wagesPayable: null,
performance: null,
reserveFund: null,
socialSecurity: null,
annuity: null,
workday: '21.75',
researchDuration: null,
}
currentReachPerson.value.name = ''
formData.value.tableData.push(row)
}
const handleCopy = (row) => {
let copyObj = {
projectId: row.projectId,
projectName: '',
// accountType: row.accountType,
// companyName: row.companyName,
// researchPersonnelId: row.researchPersonnelId,
// researchPersonnel: row.researchPersonnel,
wagesPayable: row.wagesPayable,
performance: row.performance,
reserveFund: row.reserveFund,
socialSecurity: row.socialSecurity,
annuity: row.annuity,
workday: '21.75',
researchDuration: row.researchDuration,
}
formData.value.tableData.push(copyObj)
}
const handleDelete = (index) => {
formData.value.tableData.splice(index, 1)
}
const handleSubmit = (instance) => {
console.log('tableData', formData.value.tableData)
if (!instance) return
instance.validate(async (valid) => {
if (!valid) {
ElNotification({
title: '提示',
message: '请完善数据,再提交!',
type: 'error'
})
return;
}
let researchPersonnelId = ''
formData.value.tableData.forEach(item => {
item.projectName = getProjectName(item.projectId)
researchPersonnelId = item.researchPersonnelId
if (item.performance == 0) {
item.performance = null
}
})
if (!researchPersonnelId) {
ElNotification({
title: '提示',
message: '请选择研发人员',
type: 'error'
})
return;
}
let params = {
apportionmentMonth: formData.value.apportionmentMonth,
usrAllocations: formData.value.tableData,
}
console.log('params', params.usrAllocations, formData.value.tableData)
const resultMap = params.usrAllocations.reduce((acc, item) => {
if (!acc[item.researchPersonnelId]) {
acc[item.researchPersonnelId] = [];
}
acc[item.researchPersonnelId].push(item);
return acc;
}, {});
const exceedList = [];
Object.entries(resultMap).forEach(([id, items]) => {
const totalDuration = items.reduce((sum, item) => sum + (item.researchDuration || 0), 0);
const preciseTotalDuration = parseFloat(totalDuration.toFixed(2));
if (preciseTotalDuration > 21.75) {
// 收集超出的研发人员ID及总工时
exceedList.push({ id, totalDuration: preciseTotalDuration });
}
});
// 从 resultMap 中获取 researchPersonnel
const exceedResearchPersonnel = exceedList.map(item => {
const id = item.id;
const personnelItems = resultMap[id];
// 获取第一个对象中的 researchPersonnel假设所有对象的 researchPersonnel 相同)
const researchPersonnel = personnelItems[0].researchPersonnel;
return { id, researchPersonnel, totalDuration: item.totalDuration };
});
console.log('超过21.75的研发人员:', exceedResearchPersonnel);
if (exceedResearchPersonnel.length > 0) {
console.log('以下研发人员的总研发工时超过21.75天:', exceedResearchPersonnel);
ElNotification({
title: '提示',
message: `以下研发人员的总研发工时超过21.75天:${exceedResearchPersonnel.map(e => e.researchPersonnel).join('')}`,
type: 'warning'
});
}
// 调用函数
console.log('是大V',resultMap)
const {code, msg} = await addShare(params)
ElNotification({
title: '提示',
message: msg,
type: code === 1000 ? 'success' : 'error'
})
if (code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
router.push({
name: 'Share'
})
}
})
}
const handleResubmit = (instance) => {
if (!instance) return
instance.validate(async (valid) => {
if (!valid) {
ElNotification({
title: '提示',
message: '请完善数据,再提交!',
type: 'error'
})
return;
}
let researchPersonnelId = ''
formData.value.tableData.forEach(item => {
item.allocationId = formData.value.allocationId
item.projectName = getProjectName(item.projectId)
researchPersonnelId = item.researchPersonnelId
if (item.performance == 0) {
item.performance = null
}
})
if (!researchPersonnelId) {
ElNotification({
title: '提示',
message: '请选择研发人员',
type: 'error'
})
return;
}
let params = {
allocationId: formData.value.allocationId,
shareName: formData.value.shareName,
apportionmentMonth: formData.value.apportionmentMonth,
usrAllocations: formData.value.tableData,
deploymentId: processInstanceData.value.deploymentId,
}
// console.log('params', params, formData.value.tableData)
const {code, msg} = await editAllocation(params)
ElNotification({
title: '提示',
message: msg,
type: code === 1000 ? 'success' : 'error'
})
if (code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
router.push({
name: 'Share'
})
}
})
}
const getDetailInfo = () => {
loading.value = true
getAllocationDetail(route.query.id).then(res => {
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
getDetailList()
formData.value = res.data.formData
opentionData.value = res.data
loading.value = false
}
})
}
const getDetailList = async () => {
let params = {
allocationId: route.query.id
}
showTable.value = false
const {code, data, msg} = await getAllocationDetailList(params)
if (code === 1000) {
data.rows.forEach(item => {
item.researchPersonnelId = Number(item.researchPersonnelId)
})
formData.value.tableData = data.rows
nextTick(() => {
showTable.value = true
})
} else {
ElNotification({
title: '提示',
message: msg,
type: 'error'
})
}
}
const init = async () => {
processDiagramViewer.value = false
await getResearchOptions()
await getProjectOptions()
getAllocationProcess().then(res => {
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;
nextTick(() => {
processDiagramViewer.value = true
})
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
})
}
const handleBack = () => {
history.back()
}
onMounted(() => {
init()
if (route.query.id) {
getDetailInfo()
}
})
</script>
<style scoped lang="scss">
:deep(.el-table--enable-row-transition) {
.el-table__body td.el-table__cell {
.cell {
.el-form-item {
margin-top: 20px;
}
}
}
}
:deep(.el-date-editor--month) {
width: 100% !important;
}
:deep(.el-input-number) {
width: 100%;
.el-input__inner {
text-align: left;
}
}
</style>

View File

@@ -0,0 +1,219 @@
<template>
<fvSearchForm :searchConfig="searchConfig" @search="search" style="margin-left: 16px"></fvSearchForm>
<!-- <el-button color="#DED0B2" style="float: left;margin: 0 10px 10px 0" @click="exportTable">导出</el-button>-->
<fvTable ref="tableIns" :tableConfig="tableConfig" @headBtnClick="headBtnClick" style="margin-top: 15px" @selectionChange="selectionChange">
<template #empty>
<el-empty description="暂无数据"/>
</template>
</fvTable>
</template>
<script setup lang="jsx">
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
import { getSubCompOpt } from '@/api/user/user.js';
import {reactive, ref} from "vue";
import {shareDetailExport, shareExportExcel} from "@/api/expense-manage";
import {ElMessage} from "element-plus";
const router = useRouter()
const route = useRoute()
const searchConfig = reactive([
{
label: '子项目',
prop: 'subProjectName',
component: 'el-input',
props: {
placeholder: '请输入子项目查询',
clearable: true,
filterable: true,
checkStrictly: true
}
},
// {
// label: '支付月份',
// prop: 'apportionmentMonth',
// component: 'el-date-picker',
// props: {
// placeholder: '请选择支付月份',
// clearable: true,
// type:'month',
// format: 'YYYY-MM',
// valueFormat:"YYYY-MM"
// },
// colProps: {}
// },
// {
// label: '人员性质',
// prop: 'personnelNature',
// component: shallowRef(fvSelect),
// props: {
// placeholder: '请选择人员性质',
// clearable: true,
// filterable: true,
// cacheKey: 'nature_of_personnel'
// }
// },
])
const tableIns = ref()
const selectData = ref([])
const tableConfig = reactive({
columns: [
{
type: 'selection',
prop: 'selection',
},
// {
// prop: 'name',
// type: 'index',
// label: '序号',
// align: 'center',
// width:85,
// index: index => {
// return (tableIns.value.getQuery().pageNum - 1) * tableIns.value.getQuery().pageSize + index + 1
// }
// },
{
prop: 'paymentYear',
label: '支付年份',
align: 'center'
},
{
prop: 'paymentMonth',
label: '支付月份',
align: 'center'
},
{
prop: 'masterProjectName',
label: '主项目',
align: 'center',
},
{
prop: 'subProjectName',
label: '子项目',
align: 'center',
},
{
prop: 'researchPersonnel',
label: '研发人员',
align: 'center',
showOverflowTooltip: false,
},
{
prop: 'personnelNature',
label: '人员性质',
align: 'center',
width: 120,
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.personnelNature&&row.personnelNature !== null&&row.personnelNature!==undefined) {
return (<Tag dictType={'nature_of_personnel'} value={row.personnelNature}/>)
} else {
return '--'
}
}
},
{
prop: 'researchDuration',
label: '当月研发工时(天)',
align: 'center',
// currentRender:({row})=>{
// return <span>{toThousands(row.afterTax)}</span>
// }
},
{
prop: 'workday',
label: '当月总工时(天)',
align: 'center',
showOverflowTooltip: false,
},
{
prop: 'subtotal',
label: '人工成本分摊(元)',
align: 'center',
},
],
api: '/workflow/mosr/cost/share',
params: {},
btns: [
{name: '添加分摊', key: 'add', color: '#DED0B2'},
{name: '导出', key: 'export', color: '#DED0B2'}
],
export:{
open :false,
}
})
const search = (val) => {
tableConfig.params = {...val}
tableIns.value.refresh()
}
const headBtnClick = (key) => {
switch (key) {
case 'add':
handleAdd()
break;
case 'export':
exportTable()
break;
}
}
const selectionChange = (data) => {
console.log('data', data)
selectData.value=data.map(item=>item.id)
}
const exportTable = () => {
console.log('selectData',selectData.value)
if (selectData.value.length === 0) {
ElMessage.warning('请选择要导出的费用分摊')
return
}
shareDetailExport(selectData.value).then(res => {
console.log(res)
let fileName = `科技研发项目工时及成本分摊汇总表.xlsx`
const blob = new Blob([res.data])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = fileName
a.click()
})
}
const handleAdd = () => {
router.push({
name: 'Sharedetail/add',
query: {}
})
}
const init = async () => {
const res = await getSubCompOpt()
searchConfig.value.find(item=>item.prop == 'affiliatedCompanyIds').props.data = res.data
}
// init()
</script>
<style scoped lang="scss">
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
//margin-left: -25px !important;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
//margin-left: -13px !important;
}
}
}
:deep(.el-date-editor--month){
width: 100%;
}
</style>

View File

@@ -4,7 +4,8 @@
<el-col :xs="24" :sm="24" :md="24" :lg="17" :xl="17">
<div class="top-left" id="topLeft">
<el-card shadow="never">
<div class="notice-title">{{getTimePeriod()}}提醒您<span><span>{{ taskTabList[0].num }}</span>个项目待立项</span></div>
<div class="notice-title">{{ getTimePeriod() }}提醒您<span><span>{{ taskTabList[0].num }}</span>个项目待立项</span>
</div>
<el-row class="statistics">
<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-for="(item,index) in taskTabList" :key="index">
<div class="block" :style="{'background-image':'url('+getImgUrl(item.icon)+')'}"
@@ -20,7 +21,7 @@
<el-card shadow="never" class="todo-bg" @tab-add="refreshTodoOrDoneList(activeName)">
<el-tabs v-model="activeName" editable>
<template #add-icon>
<div @click="refreshTodoOrDoneList" style="margin-left: -50px">
<div @click="refreshTodoOrDoneList" style="margin-left: -50px;font-size: 14px">
刷新一下
<div style="width: 31px"></div>
</div>
@@ -28,14 +29,14 @@
<el-tab-pane :label="'待办('+(todoList?.length||0) +''" name="first">
<div class="todo-top">
<div class="bell">
<el-icon size="20" color="#F55815">
<el-icon size="16" color="#F55815">
<BellFilled/>
</el-icon>
<span>您有{{ todoList?.length || 0 }}条待办需要处理</span>
</div>
<div class="todo-more" @click="handleTodoList(1)">
<span>查看更多</span>
<el-icon color="#1F63E6" size="18">
<el-icon color="#1F63E6" size="16">
<ArrowRight/>
</el-icon>
</div>
@@ -72,14 +73,14 @@
<el-tab-pane :label="'已办(' + (doneList?.length||0) + ''" name="second">
<div class="todo-top">
<div class="bell">
<el-icon size="20" color="#F55815">
<el-icon size="16" color="#F55815">
<BellFilled/>
</el-icon>
<span>您有{{ todoList.length }}条待办需要处理</span>
</div>
<div class="todo-more" @click="handleTodoList(2)">
<span>查看更多</span>
<el-icon color="#1F63E6" size="18">
<el-icon color="#1F63E6" size="16">
<ArrowRight/>
</el-icon>
</div>
@@ -132,12 +133,16 @@
</el-icon>
</div>
</div>
<div class="notice-block">
<div class="notice-block notice-box">
<div v-if="noticeList&&noticeList.length==0">
<el-empty image-size="135" description="暂无通知公告~"/>
</div>
<div v-for="(item,index) in noticeList" class="notice" @click="handleGoToArticleDetail(item)">
<span>{{ index > 8 ? '' : 0 }}{{ index + 1 }}</span>{{ item.articleTitle }}
<span>{{ index > 8 ? '' : 0 }}{{ index + 1 }}</span>
<span>{{ item.articleTitle }}</span>
<span>
{{ item.articleTime }}
</span>
</div>
</div>
</div>
@@ -240,7 +245,7 @@
<!-- <div>-->
<!-- <span>{{ index > 8 ? '' : 0 }}{{ index + 1 }}</span>{{ item.title }}-->
<!-- </div>-->
<div :style="{'color': item.isRead ? '#1F63E6' : 'rgba(0,0,0,0.5)'}">
<div :style="{'color': item.isRead ? '#1F63E6' : '#000'}">
<span>{{ item.articleTitle }}</span>
<span class="dot" v-if="item.isRead"></span>
</div>
@@ -379,8 +384,8 @@ const fundPieOption = ref({
align: 'left',
icon: 'circle',
textStyle: {
color: 'rgba(0,0,0,0.6)',
fontSize: '12px'
color: '#000',
fontSize: '14px'
},
},
graphic: { //图形中间图片
@@ -393,18 +398,19 @@ const fundPieOption = ref({
},
left: 'center',
right: 'center',
top: '42%'
top: '45%'
}]
},
series: [
{
type: 'pie',
radius: [65, 90],
center: ['50%', '50%'],
center: ['50%', '55%'],
top: '10%',
left: '8',
label: {
show: true,
fontSize:14,
formatter: '{b}\n{d}%'
// formatter: params => {
// console.log(params)
@@ -446,12 +452,12 @@ const fundPieOption = ref({
clockWise: false,
hoverAnimation: false,
radius: ['70%', '70%'],//边框大小
center: ['50%', '50%'],//边框位置
center: ['50%', '55%'],//边框位置
tooltip: {
show: false
},
label: {
show: false
show: false,
},
emphasis: {
show: false
@@ -481,6 +487,7 @@ const moneyPieOption = ref({
center: ['50%', '50%'],
label: {
normal: {
fontSize:14,
show: true,
position: 'inner',
formatter: function (data) {
@@ -520,7 +527,7 @@ onMounted(async () => {
helpDocList.value = await getArticleList(2)
problemList.value = await getArticleList(3)
})
const getTimePeriod=()=>{
const getTimePeriod = () => {
// 获取当前日期和时间
const now = new Date();
// 获取当前小时数
@@ -535,11 +542,11 @@ const getTimePeriod=()=>{
return "中午好";
} else if (hour >= 14 && hour < 18) {
return "下午好";
} else if (hour >= 18 && hour <= 22) {
} else if (hour >= 18 && hour <= 22) {
return "晚上好";
} else if (hour >= 23 || hour <= 1) {
return "午夜好";
} else if (hour > 1&& hour <= 5) {
} else if (hour > 1 && hour <= 5) {
return "夜深了";
}
}
@@ -548,7 +555,7 @@ const handleTodoList = (type) => {
router.push({
path: '/todolist',
})
} else if (type == 2){
} else if (type == 2) {
router.push({
path: '/donelist',
})
@@ -562,23 +569,23 @@ const handleGoToArticleDetail = (row) => {
}
})
}
const goToArticleList = (type,otherHelpType) => {
let queryType=''
if(type){
queryType=type
}else{
const goToArticleList = (type, otherHelpType) => {
let queryType = ''
if (type) {
queryType = type
} else {
console.info("🚀 ~method:'otherHelpType' -----", otherHelpType)
if(otherHelpType=='first'){
queryType= '1'
}else if(otherHelpType=='second'){
queryType= '2'
}else if(otherHelpType=='third'){
queryType= '3'
if (otherHelpType == 'first') {
queryType = '1'
} else if (otherHelpType == 'second') {
queryType = '2'
} else if (otherHelpType == 'third') {
queryType = '3'
}
}
router.push({
name: 'Manage',
query:{
query: {
type: queryType
}
})
@@ -783,17 +790,17 @@ const handleView = (row) => {
}
})
}
// else if (row.targetState == '10' && row.targetId) {
// router.push({
// name: 'Summary/detail',
// query: {
// projectId: row.targetId,
// state: row.state,
// source: 'home'
// }
// })
// else if (row.targetState == '10' && row.targetId) {
// router.push({
// name: 'Summary/detail',
// query: {
// projectId: row.targetId,
// state: row.state,
// source: 'home'
// }
// })
// }
else if (row.targetState == '10'||row.targetState == '20' || row.targetState == '40' || row.targetState == '50') {
else if (row.targetState == '10' || row.targetState == '20' || row.targetState == '40' || row.targetState == '50') {
router.push({
name: 'Implementation/detail',
query: {
@@ -834,6 +841,13 @@ const handleView = (row) => {
</script>
<style lang="scss" scoped>
:deep(.el-input){
width: 84px!important;
}
:deep(.el-input__inner){
font-size: 14px;
color: #000;
}
@media (min-width: 1200px) and (max-width: 1918px) {
//.right-top {
// height: 684px !important;
@@ -996,7 +1010,7 @@ const handleView = (row) => {
.total-money {
height: 25px;
font-weight: 400;
font-size: 15px;
font-size: 14px;
color: #000000;
line-height: 18px;
}
@@ -1032,14 +1046,14 @@ const handleView = (row) => {
> div:last-child {
font-weight: 400;
font-size: 15px;
font-size: 14px;
color: #000000;
letter-spacing: 1px;
margin-left: 28px;
}
.company-name {
font-size: 12px;
font-size: 14px;
color: rgba(0, 0, 0, 0.6);
letter-spacing: 1px;
margin-left: 10px;
@@ -1100,7 +1114,7 @@ const handleView = (row) => {
:deep(.el-tabs__new-tab ) {
width: 67px !important;
border: none !important;
color: #1476E3;
color: #1476E3;
font-size: 14px;
line-height: 51px !important;
height: 51px !important;
@@ -1125,11 +1139,11 @@ const handleView = (row) => {
.el-tabs__nav {
.el-tabs__item {
flex: 1;
font-size: 16px;
width: 120px;
font-size: 14px;
width: 100px;
//font-weight: 600;
height: 51px;
color: rgba(0, 0, 0, 0.5);
color: #000;
}
.el-tabs__item.is-active {
@@ -1192,7 +1206,7 @@ const handleView = (row) => {
margin-left: 14px;
color: #000000;
letter-spacing: 1px;
font-size: 16px;
font-size: 14px;
> span {
color: #F40E0E;
@@ -1255,7 +1269,7 @@ const handleView = (row) => {
flex-direction: column;
//align-items: flex-end;
font-weight: 400;
color: rgba(0, 0, 0, 0.5);
color:#000;
letter-spacing: 1px;
font-size: 12px;
@@ -1338,13 +1352,13 @@ const handleView = (row) => {
justify-content: space-between;
font-size: 14px;
margin-bottom: 12px;
margin-left: 20px;
margin-left: 4px;
.bell {
display: flex;
align-items: center;
color: #F55815;
color: #F55815;
font-size: 15px;
> span {
@@ -1375,13 +1389,13 @@ const handleView = (row) => {
> span:first-child {
white-space: nowrap;
font-size: 36px;
font-size: 34px;
font-weight: bold;
margin-bottom: 10px;
> span {
margin-left: 10px;
font-size: 13px;
font-size: 14px;
}
}
@@ -1389,6 +1403,7 @@ const handleView = (row) => {
white-space: nowrap;
color: #fff;
margin-bottom: 10px;
font-size: 14px;
}
}
}
@@ -1413,8 +1428,7 @@ const handleView = (row) => {
justify-content: space-between;
height: 47px !important;
line-height: 47px !important;
color: rgba(0, 0, 0, 0.5) !important;
color: #000 !important;
> div:first-child {
position: relative;
text-overflow: ellipsis;
@@ -1451,7 +1465,35 @@ const handleView = (row) => {
margin-left: 20px;
font-weight: 400;
letter-spacing: 1px;
color: rgba(0, 0, 0, 0.5)
color: #000
}
}
}
.notice-box {
.notice {
display: flex;
justify-content: space-between;
> span:first-child {
margin-right: 10px;
margin-left: 10px;
color: #1476E3;
font-weight: bold;
font-size: 16px;
}
> span:nth-child(2) {
display: block;
width: 65%;
overflow: hidden;
text-overflow: ellipsis;
}
&:hover {
color: #1476E3;
background: #F6FBFE;
}
}
}
@@ -1485,7 +1527,7 @@ const handleView = (row) => {
height: 75px;
line-height: 75px;
padding: 0 15px;
font-size: 12px;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -1493,9 +1535,9 @@ const handleView = (row) => {
> span:first-child {
margin-right: 10px;
margin-left: 10px;
font-size: 14px;
color: #1476E3;
font-weight: bold;
font-size: 16px;
}
&:hover {
@@ -1524,8 +1566,8 @@ const handleView = (row) => {
.fund-pie {
width: 100%;
height: 25px;
font-size: 12px;
color: rgba(0, 0, 0, 0.5);
font-size: 14px;
color: #000;
text-align: center;
//margin-top: 15px;
}
@@ -1543,7 +1585,7 @@ const handleView = (row) => {
.tag {
width: 7px;
height: 18px;
height: 14px;
background: linear-gradient(#1476E3 0%, #99C9FF 100%);
margin-right: 5px;
border-radius: 2px;
@@ -1553,6 +1595,7 @@ const handleView = (row) => {
> span {
white-space: nowrap;
color: #000000;
font-size: 14px;
//font-weight: 600;
}
}

View File

@@ -1,4 +1,5 @@
<template>
<div class="login-box">
<el-form
:model="loginForm"

View File

@@ -79,14 +79,14 @@
<div v-else>--</div>
</template>
</el-table-column>
<el-table-column prop="resultForm" label="预期成果形式" align="center" min-width="100px">
<template #default="scope">
<div v-if="scope.row.resultForm !== null">
<Tag style="margin-top: 3px" dictType="result_form" v-for="item in scope.row.resultForm" :value="item"/>
</div>
<div v-else>--</div>
</template>
</el-table-column>
<!-- <el-table-column prop="resultForm" label="预期成果形式" align="center" min-width="100px">-->
<!-- <template #default="scope">-->
<!-- <div v-if="scope.row.resultForm !== null">-->
<!-- <Tag style="margin-top: 3px" dictType="result_form" v-for="item in scope.row.resultForm" :value="item"/>-->
<!-- </div>-->
<!-- <div v-else>&#45;&#45;</div>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column prop="technicalStandard" label="预期技术标准制定" align="center">
<template #default="scope">
<div v-if="scope.row.technicalStandard !== null">
@@ -114,15 +114,22 @@
<el-table-column prop="prospectiveIntellectualProperty" label="预期知识产权" align="center" width="190">
<template #default="scope">
<div style="text-align: left">
发明专利{{ scope.row.inventionPatent ? scope.row.inventionPatent : 0 }}<br>
实用新型专利{{ scope.row.newPatent ? scope.row.newPatent : 0 }}<br>
专利{{ scope.row.newPatent ? scope.row.newPatent : 0 }}<br>
软件著作权{{ scope.row.softwareCopyright ? scope.row.softwareCopyright : 0 }}<br>
著作权{{ scope.row.copyright ? scope.row.copyright : 0 }}<br>
其他{{ scope.row.other ? scope.row.other : 0 }}
技术标准{{ scope.row.technicalNorms ? scope.row.technicalNorms : 0 }}<br>
新产品{{ scope.row.newProduct ? scope.row.newProduct : 0 }}<br>
新工艺{{ scope.row.newProcess ? scope.row.newProcess : 0 }}<br>
新装置{{ scope.row.newDevice ? scope.row.newDevice : 0 }}<br>
新材料{{ scope.row.newMaterials ? scope.row.newMaterials : 0 }}<br>
计算机软件{{ scope.row.computerSoftware ? scope.row.computerSoftware : 0 }}<br>
论文论著{{ scope.row.thesis ? scope.row.thesis : 0 }}<br>
研究报告{{ scope.row.researchReport ? scope.row.researchReport : 0 }}<br>
商标{{ scope.row.trademark ? scope.row.trademark : 0 }}<br>
其他项:<br> <span style="white-space: pre-wrap;">{{ scope.row.other ? scope.row.other : 0 }}</span>
</div>
</template>
</el-table-column>
<el-table-column prop="intellectualProperty" label="知识产权状况" align="center">
<el-table-column prop="intellectualProperty" label="知识产权归属" align="center">
<template #default="scope">
<div v-if="scope.row.intellectualProperty !== null">
<Tag dictType="intellectual_property" :value="scope.row.intellectualProperty"/>
@@ -130,12 +137,12 @@
<div v-else>--</div>
</template>
</el-table-column>
<el-table-column prop="intellectualProperty" label="经费预算(元)" align="center">
<el-table-column prop="intellectualProperty" label="预估经费预算(元)" align="center">
<template #default="scope">
<span>{{ toThousands(scope.row.economicEstimate) }}</span>
</template>
</el-table-column>
<el-table-column prop="specialFundAmount" label="专项资金(元)" align="center">
<el-table-column prop="specialFundAmount" label="预估专项资金(元)" align="center">
<template #default="scope">
<span>{{ toThousands(scope.row.specialFundAmount) }}</span>
</template>

View File

@@ -46,6 +46,11 @@ const tableConfig = reactive({
return (tableIns.value.getQuery().pageNum - 1) * tableIns.value.getQuery().pageSize + index + 1
}
},
{
prop: 'processNumber',
label: '征集编号',
align: 'center',
},
{
prop: 'requirementName',
label: '征集名称',

View File

@@ -1,7 +1,7 @@
<template>
<div class="detail-block" v-loading="loading" :style="{padding:!formData.isSpecialFund?'0 30px':'0 0 0 30px'}">
<baseTitle title="项目基本信息"></baseTitle>
<el-form :model="formData" ref="summaryForm" :rules="rules" :label-width="!formData.isSpecialFund?130:160"
<el-form :model="formData" ref="summaryForm" :rules="rules" :label-width="!formData.isSpecialFund?145:160"
:scroll-to-error="true">
<el-row gutter="30" style="margin-bottom: -18px;"
:style="{marginLeft:!formData.isSpecialFund?'-8.5px':'-48.5px'}">
@@ -183,15 +183,15 @@
</el-form-item>
</el-col>
<el-col :span="6" v-if="formData.isSpecialFund">
<el-form-item label="预估专项资金(元)" prop="specialFundAmount">
<el-form-item label="预估专项资金(元)" prop="forecastSpecialFundAmount">
<el-input
v-model="formData.specialFundAmount"
v-model="formData.forecastSpecialFundAmount"
placeholder="请输入预估专项资金"
clearable
:formatter="(value) => value.replace(/\B(?=(\d{3})+(?!\d))/g, ',')"
:parser="(value) => value.replace(/\$\s?|(,*)+[^0-9.]/g, '')" @change="changeCollectData"
/>
<!-- <el-input-number v-model="formData.specialFundAmount" placeholder="请输入预估专项资金" :controls="false"/>-->
<!-- <el-input-number v-model="formData.forecastSpecialFundAmount" placeholder="请输入预估专项资金" :controls="false"/>-->
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'0':'-40px'}">
@@ -232,10 +232,10 @@
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?route.query.id?'-10px':'0':'0'}">
<el-form-item label="需求征集" prop="requirementId" required>
<template v-if="formData.requirementDefaultName">{{ formData.requirementDefaultName }}</template>
<el-form-item label="需求征集" prop="" required>
<template v-if="requirementDefaultName">{{ requirementDefaultName }}</template>
<el-select v-else v-model="formData.requirementId" clearable placeholder="请选择需求征集"
@change="changeCollectData">
@change="changeCollectData();changeRequirement()">
<el-option
v-for="item in requirementList"
:key="item.value"
@@ -249,23 +249,23 @@
<baseTitle title="预期知识产权"></baseTitle>
<el-row gutter="30" style="margin-bottom: -18px;"
:style="{marginLeft:!formData.isSpecialFund?'-8.5px':'-48.5px'}">
<el-col :span="12">
<el-form-item label="预期成果形式" prop="resultForm"
:style="{marginRight:!formData.isSpecialFund?'0':route.query.id?'':'40px'}">
<el-select v-model="formData.resultForm" placeholder="请选择预期成果形式" clearable filterable multiple
@change="changeCollectData">
<el-option
v-for="item in cacheStore.getDict('result_form')"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'-10px':'-40px'}">
<el-form-item label="知识产权状况" prop="intellectualProperty">
<el-select v-model="formData.intellectualProperty" placeholder="请选择知识产权状况" clearable filterable
<!-- <el-col :span="12">-->
<!-- <el-form-item label="预期成果形式" prop="resultForm"-->
<!-- :style="{marginRight:!formData.isSpecialFund?'0':route.query.id?'':'40px'}">-->
<!-- <el-select v-model="formData.resultForm" placeholder="请选择预期成果形式" clearable filterable multiple-->
<!-- @change="changeCollectData">-->
<!-- <el-option-->
<!-- v-for="item in cacheStore.getDict('result_form')"-->
<!-- :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="intellectualProperty">
<el-select v-model="formData.intellectualProperty" placeholder="请选择知识产权归属" clearable filterable
@change="changeCollectData">
<el-option
v-for="item in cacheStore.getDict('intellectual_property')"
@@ -276,37 +276,80 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'-10px':'-40px'}">
<el-form-item label="发明专利(项)" prop="inventionPatent">
<el-input-number v-model="formData.inventionPatent" placeholder="请输入发明专利数量" :controls="false"
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'0':route.query.id?'0':'-40px'}" >
<el-form-item label="预估专利(项)" prop="newPatent">
<el-input-number v-model="formData.newPatent" placeholder="请输入预估专利数量" :controls="false"
@change="changeCollectData"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="新型专利(项)" prop="newPatent">
<el-input-number v-model="formData.newPatent" placeholder="请输入实用性新型专利数量" :controls="false"
@change="changeCollectData"
style="width: 100%"/>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'-10px':route.query.id?'-40px':'0'}">
<el-form-item label="预估软件著作权(项)" prop="softwareCopyright">
<el-input-number v-model="formData.softwareCopyright" placeholder="请输入预估软件著作权数量" :controls="false"
@change="changeCollectData"/>
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'0':route.query.id?'':'-40px'}">
<el-form-item label="软件著作权(项)" prop="softwareCopyright">
<el-input-number v-model="formData.softwareCopyright" placeholder="请输入软件著作权数量" :controls="false"
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'-10px':route.query.id?'-40px':'-40px'}">
<el-form-item label="预估技术标准(项)" prop="technicalNorms">
<el-input-number v-model="formData.technicalNorms" placeholder="请输入预估技术标准数量" :controls="false"
@change="changeCollectData"/>
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'0':route.query.id?'0':'0'}">
<el-form-item label="预估新产品(项)" prop="newProduct">
<el-input-number v-model="formData.newProduct" placeholder="请输入预估新产品数量" :controls="false"
@change="changeCollectData"/>
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'0':route.query.id?'0':'-40px'}">
<el-form-item label="预估新工艺(项)" prop="newProcess">
<el-input-number v-model="formData.newProcess" placeholder="请输入预估新工艺数量" :controls="false"
@change="changeCollectData"/>
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'-10px':route.query.id?'-40px':'0'}">
<el-form-item label="著作权(项)" prop="copyright">
<el-input-number v-model="formData.copyright" placeholder="请输入著作权数量" :controls="false"
<el-form-item label="预估新装置(项)" prop="newDevice">
<el-input-number v-model="formData.newDevice" placeholder="请输入预估新装置数量" :controls="false"
@change="changeCollectData"/>
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'-10px':'-40px'}">
<el-form-item label="其他(项)" prop="other">
<el-input-number v-model="formData.other" placeholder="请输入其他数量" :controls="false"
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'-10px':route.query.id?'-40px':'-40px'}">
<el-form-item label="预估新材料(项)" prop="newMaterials">
<el-input-number v-model="formData.newMaterials" placeholder="请输入预估新材料数量" :controls="false"
@change="changeCollectData"/>
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'0':route.query.id?'0':'0'}">
<el-form-item label="预估计算机软件(项)" prop="computerSoftware">
<el-input-number v-model="formData.computerSoftware" placeholder="请输入预估计算机软件数量" :controls="false"
@change="changeCollectData"/>
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'0':route.query.id?'0':'-40px'}">
<el-form-item label="预估论文论著(项)" prop="thesis">
<el-input-number v-model="formData.thesis" placeholder="请输入预估论文论著数量" :controls="false"
@change="changeCollectData"/>
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'-10px':route.query.id?'-40px':'0'}">
<el-form-item label="预估研究报告(项)" prop="researchReport">
<el-input-number v-model="formData.researchReport" placeholder="请输入预估研究报告数量" :controls="false"
@change="changeCollectData"/>
</el-form-item>
</el-col>
<el-col :span="6" :style="{marginLeft:!formData.isSpecialFund?'-10px':route.query.id?'-40px':'-40px'}">
<el-form-item label="预估商标(项)" prop="trademark">
<el-input-number v-model="formData.trademark" placeholder="请输入预估商标数量" :controls="false"
@change="changeCollectData"/>
</el-form-item>
</el-col>
<el-col :span="24" >
<el-form-item label="预估其他(项)" prop="other">
<el-input rows="4" type="textarea" v-model="formData.other" placeholder="请输入预估其他项"
@change="changeCollectData" :style="{marginRight:!formData.isSpecialFund?'20px':'80px'}"/>
</el-form-item>
</el-col>
</el-row>
<baseTitle title="项目描述"></baseTitle>
<el-row gutter="30" style="margin-bottom: -18px;"
@@ -388,9 +431,10 @@ 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';
import {getFormInfo} from "@/api/project-demand";
import {getFormInfo, getInfo} from "@/api/project-demand";
import {getFundOption} from "@/api/special-fund";
import UserPicker from "@/views/workflow/process/common/UserPicker.vue";
import {nextTick} from "vue";
const authStore = useAuthStore()
const changeDiagram = ref(false)
@@ -405,6 +449,7 @@ const loading = ref(false)
const processDiagramViewer = ref(false)
const tagsViewStore = useTagsView()
const companyOption = ref([])
const requirementDefaultName = ref('')
const summaryForm = ref()
const deploymentId = ref()
const optionalChargeLeadershipPickerRef = ref()
@@ -421,6 +466,7 @@ const formData = ref({
isSpecialFund: false,
industryUniversityResearch: '1',
governmentDeclaration: '1',
other: '无',
resultForm: []
})
@@ -434,20 +480,31 @@ const rules = reactive({
investmentType: [{required: true, message: '请选择出资类型', trigger: ['blur', 'change']}],
projectImpact: [{required: true, message: '请选择项目影响', trigger: ['blur', 'change']}],
businessSegment: [{required: true, message: '请选择所属业务板块', trigger: ['blur', 'change']}],
resultForm: [{required: true, message: '请选择预期成果形式', trigger: ['blur', 'change']}],
// resultForm: [{required: true, message: '请选择预期成果形式', trigger: ['blur', 'change']}],
technicalStandard: [{required: true, message: '请选择预期技术标准制定', trigger: ['blur', 'change']}],
industryUniversityResearch: [{required: true, message: '请选择产学研联合', trigger: ['blur', 'change']}],
governmentDeclaration: [{required: true, message: '请选择开展政府申报', trigger: ['blur', 'change']}],
intellectualProperty: [{required: true, message: '请选择知识产权状况', trigger: ['blur', 'change']}],
inventionPatent: [{required: true, message: '请输入发明专利数量', trigger: ['blur', 'change']}],
newPatent: [{required: true, message: '请输入实用性新型专利数量', trigger: ['blur', 'change']}],
intellectualProperty: [{required: true, message: '请选择知识产权归属', trigger: ['blur', 'change']}],
newPatent: [{required: true, message: '请输入专利数量', trigger: ['blur', 'change']}],
technicalNorms: [{required: true, message: '请输入技术标准数量', trigger: ['blur', 'change']}],
softwareCopyright: [{required: true, message: '请输入软件著作权数量', trigger: ['blur', 'change']}],
copyright: [{required: true, message: '请输入著作权数量', trigger: ['blur', 'change']}],
other: [{required: true, message: '请输入其他数量', trigger: ['blur', 'change']}],
newProduct: [{required: true, message: '请输入新产品数量', trigger: ['blur', 'change']}],
newProcess: [{required: true, message: '请输入新工艺数量', trigger: ['blur', 'change']}],
newMaterials: [{required: true, message: '请输入新材料数量', trigger: ['blur', 'change']}],
newDevice: [{required: true, message: '请输入新装置数量', trigger: ['blur', 'change']}],
computerSoftware: [{required: true, message: '请输入计算机软件数量', trigger: ['blur', 'change']}],
thesis: [{required: true, message: '请输入论文论著数量', trigger: ['blur', 'change']}],
researchReport: [{required: true, message: '请输入研究报告数量', trigger: ['blur', 'change']}],
trademark: [{required: true, message: '请输入商标数量', trigger: ['blur', 'change']}],
other: [{required: true, message: '请输入其他项数量', trigger: ['blur', 'change']}],
economicEstimate: [{required: true, message: '请输入预估经费预算', trigger: ['blur', 'change']}],
isSpecialFund: [{required: true, message: '请选择是否为专项资金', trigger: ['blur', 'change']}],
isWithinBudget: [{required: true, message: '请选择是否在预算内', trigger: ['blur', 'change']}],
specialFundAmount: [{required: true, message: '请输入专项资金', trigger: ['blur', 'change']}],
forecastSpecialFundAmount: [{required: true, message: '请输入专项资金', trigger: ['blur', 'change']}],
serviceDescription: [{required: true, message: '请输入现有业务描述', trigger: ['blur', 'change']}],
contentDescription: [{required: true, message: '请输入研发项目关键内容描述', trigger: ['blur', 'change']}]
})
@@ -461,6 +518,7 @@ watch(() => singleList.value, (newVal) => {
}, {deep: true})
localStorage.removeItem('originallySelectedList')
if (name.value === 'Summary/edit') {
} else {
if (localStorage.getItem('collectData')) {
let collectData = JSON.parse(localStorage.getItem('collectData'))
@@ -473,9 +531,31 @@ if (name.value === 'Summary/edit') {
formData.value = collectData
}
}
const changeRequirement=async ()=>{
await getInfo(formData.value.requirementId).then(res => {
if (res.code === 1000) {
console.log('formData.requirementId',formData.value.requirementId,res)
formData.value.isSpecialFund = res.data.formData.isSpecialFund
if ( res.data.formData.isSpecialFund) {
formData.value.specialFundId = res.data.formData.specialFundId
formData.value.specialFund = res.data.formData.specialFund
}else{
formData.value.specialFundId = null
formData.value.specialFund = null
}
}
})
}
const changeCollectData = () => {
if (name.value === 'Summary/edit') {
// params.fileList= attachment.value.allFileList
let params = {
...formData.value,
deploymentId: deploymentId.value,
requirementId: route.query.id ? route.query.id : formData.value.requirementId ? formData.value.requirementId : null
}
localStorage.setItem(`collectResubmitData-${route.query.projectId}`, JSON.stringify(params))
} else {
let params = {
...formData.value,
@@ -507,14 +587,25 @@ const disabledDate = (time) => {
const getProjectList = () => {
getProjectOption().then(res => {
if (res.code === 1000) {
masterProjectList.value = res.data
if(name.value === 'Summary/edit'){
masterProjectList.value = res.data.filter(item => item.value!=route.query.projectId)
}else{
masterProjectList.value = res.data
}
}
})
}
getProjectList()
const getRequirementList = () => {
getRequirementOption().then(res => {
if (res.code === 1000) {
res.data= res.data?.map(item=>{
return {
label: item.label,
value: item.value+''
}
})
requirementList.value = res.data
}
})
@@ -525,7 +616,7 @@ const getIsFund = async () => {
// loading.value = true
await getFormInfo(route.query.id).then(res => {
if (res.code === 1000) {
formData.value.requirementDefaultName = res.data.requirementName
requirementDefaultName.value = res.data.requirementName
// loading.value = false
formData.value.isSpecialFund = res.data.isSpecialFund
if (res.data.isSpecialFund) {
@@ -636,8 +727,11 @@ const handleSubmit = debounce(async (instance) => {
if (formData.value.singleFile !== undefined) {
formData.value.singleFile = getFileParam(formData.value.singleFile)
}
if (formData.value.isSpecialFund && !formData.value.specialFund) {
if (formData.value.isSpecialFund) {
formData.value.specialFund = getFundName(formData.value.specialFundId)
}else{
formData.value.specialFundId = 0
formData.value.specialFund=null
}
if (formData.value.masterProjectId) {
formData.value.masterProjectName = getProjectName(formData.value.masterProjectId)
@@ -696,8 +790,11 @@ const handleResubmit = debounce((instance) => {
})
}
formData.value.optionalChargeLeadership = optionalChargeLeadershipList.value
if (formData.value.isSpecialFund && !formData.value.specialFund) {
if (formData.value.isSpecialFund) {
formData.value.specialFund = getFundName(formData.value.specialFundId)
}else{
formData.value.specialFundId = 0
formData.value.specialFund=null
}
if (formData.value.masterProjectId) {
formData.value.masterProjectName = getProjectName(formData.value.masterProjectId)
@@ -722,7 +819,7 @@ const handleResubmit = debounce((instance) => {
fileList: otherFiles,
requirementId: route.query.id ? route.query.id : formData.value.requirementId ? formData.value.requirementId : '-1'
}
// console.log('重新提交params', params, formData.value.specialFund, formData.value.specialFundId)
console.log('重新提交params', params)
resubmitReported(params).then(res => {
ElNotification({
title: '提示',
@@ -734,8 +831,8 @@ const handleResubmit = debounce((instance) => {
router.push({
name: 'Summary'
})
// localStorage.removeItem('collectData')
}
localStorage.removeItem(`collectResubmitData-${route.query.projectId}`)
})
})
})
@@ -752,7 +849,25 @@ const getDetailInfo = async () => {
opentionData.value = res.data
optionalChargeLeadershipList.value = formData.value.optionalChargeLeadership
loading.value = false
if (name.value === 'Summary/edit') {
if (localStorage.getItem(`collectResubmitData-${route.query.projectId}`)) {
let collectResubmitData = JSON.parse(localStorage.getItem(`collectResubmitData-${route.query.projectId}`))
if(formData.value.projectId==collectResubmitData.projectId){
if (collectResubmitData.fileList) {
otherFileList.value = collectResubmitData.fileList
}
if (collectResubmitData.optionalChargeLeadership) {
optionalChargeLeadershipList.value = collectResubmitData.optionalChargeLeadership
}
formData.value = collectResubmitData
}
}
}
}else{
loading.value = false
ElNotification({
title: '提示',
message: res.msg,

View File

@@ -6,7 +6,7 @@
<script setup lang="jsx">
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
import {addPlan, getRequirementName} from "@/api/project-demand/summary";
import {addPlan, getProjectName, getRequirementName} from "@/api/project-demand/summary";
import {getSubCompOpt} from "@/api/user/user";
import {filterRequirementName} from "@/api/project-demand";
@@ -73,6 +73,36 @@ const searchConfig = ref([
},
component: shallowRef(fvSelect),
},
{
label: '项目名称',
prop: 'projectName',
props: {
placeholder: '请输入项目名称',
clearable: true,
filterable: true,
options: [],
remote: true,
remoteMethod:async (val)=>{
if(val){
const res=await getProjectName(val)
if(res.code==1000){
let optionObj={}
let optionsMap = new Map();
res.data.rows.forEach(item=>{
optionObj={
value:item.projectName,
label:item.projectName
}
optionsMap.set(optionObj.value, optionObj);
})
// 将 Map 转换为数组
searchConfig.value.find(item => item.prop == 'projectName').props.options = Array.from(optionsMap.values())
}
}
}
},
component: shallowRef(fvSelect),
},
{
label: '项目类型',
prop: 'projectType',
@@ -88,7 +118,7 @@ const searchConfig = ref([
},
{
label: '承办单位',
prop: 'undertaker',
prop: 'affiliatedCompanyId',
component: 'el-tree-select',
props: {
placeholder: '请输入承办单位查询',
@@ -218,6 +248,11 @@ const tableConfig = reactive({
return (tableIns.value.getQuery().pageNum - 1) * tableIns.value.getQuery().pageSize + index + 1
}
},
{
prop: 'processNumber',
label: '项目编号',
align: 'center',
},
{
prop: 'requirementName',
label: '征集名称',
@@ -441,7 +476,7 @@ const handleDetail = (row) => {
}
const init = async () => {
const res = await getSubCompOpt()
searchConfig.value.find(item=>item.prop == 'undertaker').props.data = res.data
searchConfig.value.find(item=>item.prop == 'affiliatedCompanyId').props.data = res.data
}
init()

View File

@@ -157,7 +157,7 @@ const schema = computed(() => {
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 6
@@ -171,6 +171,21 @@ const schema = computed(() => {
}
</div>
)
}, {
label: '实际经费预算(元)',
prop: 'actualEconomicEstimate',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.actualEconomicEstimate ?
<span>{toThousands(baseFormData.value?.actualEconomicEstimate)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '产学研联合',
@@ -210,9 +225,24 @@ const schema = computed(() => {
colProps: {
span: 6
}
},{
label: '预估专项资金(元)',
prop: 'forecastSpecialFundAmount',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.forecastSpecialFundAmount ?
<span>{toThousands(baseFormData.value?.forecastSpecialFundAmount)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '申请总部专项资金(元)',
label: '实际专项资金(元)',
prop: 'specialFundAmount',
colProps: {
span: 6
@@ -249,6 +279,13 @@ const schema = computed(() => {
colProps: {
span: 6
}
},
{
label: '主项目',
prop: 'masterProjectName',
colProps: {
span: 6
}
}
]
})

View File

@@ -11,7 +11,7 @@
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
import {toThousands} from '@/utils/changePrice.js'
import {switchAttachmentState} from "@/api/project-manage/attachment";
import {ElMessageBox} from "element-plus";
import {ElMessageBox, ElNotification} from "element-plus";
import { getSubCompOpt } from '@/api/user/user.js';
import {filterProjectName} from "@/api/project-manage";
import {filterRequirementName} from "@/api/project-demand";
@@ -216,6 +216,12 @@ const tableConfig = reactive({
return (tableIns.value.getQuery().pageNum - 1) * tableIns.value.getQuery().pageSize + index + 1
}
},
{
prop: 'processNumber',
label: '项目编号',
align: 'center',
},
{
prop: 'requirementName',
label: '征集名称',
@@ -275,7 +281,7 @@ const tableConfig = reactive({
},
{
prop: 'economicEstimate',
label: '经费预算(元)',
label: '预估经费预算(元)',
align: 'center',
width: 150,
currentRender:({row})=>{
@@ -312,10 +318,18 @@ const tableConfig = reactive({
width: 100,
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.state !== null) {
return (<Tag dictType={'project_filing'} value={row.state}/>)
} else {
return '--'
let buttons = new Set(Array.from(row.buttons))
if (!buttons.has("openFileSwitch")&&row.state!=1) {
console.log('row',row)
return (<Tag dictType={'project_filing'} value={'0'}/>)
}else if (buttons.has("openFileSwitch")) {
return (<Tag dictType={'project_filing'} value={'4'}/>)
}else{
if (row.state !== null) {
return (<Tag dictType={'project_filing'} value={row.state}/>)
} else {
return '--'
}
}
}
},
@@ -342,10 +356,10 @@ const tableConfig = reactive({
btn.push({label: '编辑', prem: ['project:management:filing:conclusion'], func: () => handleEdit(row), type: 'primary'})
}
if (buttons.has("openFileSwitch")) {
btn.push({label: '开启上传', prem: ['project:management:filing:conclusion'], func: () => handleOpenUpload(row,true), type: 'primary'})
btn.push({label: '开启上传', prem: ['filing:attachment:switch'], func: () => handleOpenUpload(row,true), type: 'primary'})
}
if (buttons.has("closeFileSwitch")) {
btn.push({label: '关闭上传', prem: ['project:management:filing:conclusion'], func: () => handleOpenUpload(row,false), type: 'primary'})
btn.push({label: '关闭上传', prem: ['filing:attachment:switch'], func: () => handleOpenUpload(row,false), type: 'primary'})
}
return (
<div style={{width: '100%'}}>
@@ -420,6 +434,7 @@ const handleEdit = (row) => {
})
}
const handleOpenUpload=(row,flag)=>{
console.log('tableIns',tableIns.value)
ElMessageBox.confirm(`是否确认${flag?'开启':'关闭'}上传文件?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@@ -430,7 +445,15 @@ const handleOpenUpload=(row,flag)=>{
projectId: row.projectId
}
switchAttachmentState(params).then(res=>{
tableIns.value.refresh()
if(res.code==1000){
tableIns.value.refresh()
}else{
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
})
})
}

View File

@@ -168,7 +168,7 @@ const schema = computed(() => {
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 6
@@ -183,6 +183,22 @@ const schema = computed(() => {
</div>
)
},
{
label: '实际经费预算(元)',
prop: 'actualEconomicEstimate',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.actualEconomicEstimate ?
<span>{toThousands(baseFormData.value?.actualEconomicEstimate)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '产学研联合',
prop: 'industryUniversityResearch',
@@ -223,7 +239,23 @@ const schema = computed(() => {
}
},
{
label: '申请总部专项资金(元)',
label: '预估专项资金(元)',
prop: 'forecastSpecialFundAmount',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.forecastSpecialFundAmount ?
<span>{toThousands(baseFormData.value?.forecastSpecialFundAmount)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际专项资金(元)',
prop: 'specialFundAmount',
colProps: {
span: 6
@@ -260,6 +292,13 @@ const schema = computed(() => {
colProps: {
span: 6
}
},
{
label: '主项目',
prop: 'masterProjectName',
colProps: {
span: 6
}
}
]
})

View File

@@ -163,7 +163,7 @@ const schema = computed(() => {
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 6
@@ -178,6 +178,22 @@ const schema = computed(() => {
</div>
)
},
{
label: '实际经费预算(元)',
prop: 'actualEconomicEstimate',
colProps: {
span: 6
},
component: () => (
<div>
{
basicData.value?.actualEconomicEstimate ?
<span>{toThousands(basicData.value?.actualEconomicEstimate)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '产学研联合',
prop: 'industryUniversityResearch',
@@ -218,7 +234,23 @@ const schema = computed(() => {
}
},
{
label: '申请总部专项资金(元)',
label: '预估专项资金(元)',
prop: 'forecastSpecialFundAmount',
colProps: {
span: 6
},
component: () => (
<div>
{
basicData.value?.forecastSpecialFundAmount ?
<span>{toThousands(basicData.value?.forecastSpecialFundAmount)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际专项资金(元)',
prop: 'specialFundAmount',
colProps: {
span: 6
@@ -255,6 +287,13 @@ const schema = computed(() => {
colProps: {
span: 6
}
},
{
label: '主项目',
prop: 'masterProjectName',
colProps: {
span: 6
}
}
]
})

View File

@@ -177,7 +177,7 @@ const schema = computed(() => {
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 6
@@ -232,7 +232,7 @@ const schema = computed(() => {
}
},
{
label: '申请总部专项资金(元)',
label: '预估专项资金(元)',
prop: 'specialFundAmount',
colProps: {
span: 6

View File

@@ -13,9 +13,9 @@
:formData="detailData.formData"
:data="detailData"
:processViewer="commonProvessViewer"
:fileListShow="fileListShow"
:fileListShow="fileListShow" @ccSend="ccSendRefresh"
v-model:value="auditOpinion"/>
<ApprovalDetail type="approval"
<ApprovalDetail type="approval" @ccSend="ccSendRefresh"
v-if="showActive == '20'&&!editShow"
:formData="detailData.formData"
:data="detailData"
@@ -27,7 +27,7 @@
<div v-if="showActive == '30'&&!editShow">
<project-attachment/>
</div>
<ApprovalDetail type="execute"
<ApprovalDetail type="execute" @ccSend="ccSendRefresh"
v-if="showActive == '40'&&!editShow"
:formData="detailData.formData"
:data="detailData"
@@ -36,7 +36,7 @@
:preProcessShow="preProcessShow"
:basicData="basicData"
v-model:value="auditOpinion"/>
<ApprovalDetail type="archivist"
<ApprovalDetail type="archivist" @ccSend="ccSendRefresh"
v-if="showActive == '50'&&!editShow"
:formData="detailData.formData"
:data="detailData"
@@ -50,6 +50,7 @@
:mode="mode"
:step="showActive"
:data="detailData"
:basicData="basicData"
:preProcessShow="preProcessShow"
:formData="detailData.formData"/>
</template>
@@ -98,7 +99,9 @@ localStorage.removeItem('projectPersonUserList')
localStorage.removeItem('optionalChargeLeadershipList')
localStorage.removeItem('originallySelectedList')
const ccSendRefresh=()=>{
getAllInfo(route.query.step)
}
const getAllInfo = async (state) => {
const loading = ElLoading.service({fullscreen: true})
detailData.value = {
@@ -113,6 +116,7 @@ const getAllInfo = async (state) => {
if (code === 1000) {
data.formData.preProcess = data.formData.preProcess ? JSON.parse(data.formData.preProcess) : undefined
detailData.value = data
localStorage.setItem('detailProcess', JSON.stringify(data.formData.preProcess))
mode.value = data.formData.mode
processStore.setDesign(data)
processStore.runningList.value = data.runningList;

View File

@@ -219,6 +219,12 @@ const tableConfig = reactive({
return (tableIns.value.getQuery().pageNum - 1) * tableIns.value.getQuery().pageSize + index + 1
}
},
{
prop: 'processNumber',
label: '项目编号',
align: 'center',
},
{
prop: 'requirementName',
label: '征集名称',
@@ -292,7 +298,7 @@ const tableConfig = reactive({
},
{
prop: 'economicEstimate',
label: '经费预算(元)',
label: '预估经费预算(元)',
align: 'center',
width: 150,
currentRender:({row})=>{

View File

@@ -230,7 +230,7 @@ const schema = computed(() => {
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 6
@@ -244,6 +244,21 @@ const schema = computed(() => {
}
</div>
)
}, {
label: '实际经费预算(元)',
prop: 'actualEconomicEstimate',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.actualEconomicEstimate ?
<span>{toThousands(baseFormData.value?.actualEconomicEstimate)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '产学研联合',
@@ -283,9 +298,24 @@ const schema = computed(() => {
colProps: {
span: 6
}
}, {
label: '预估专项资金(元)',
prop: 'forecastSpecialFundAmount',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.forecastSpecialFundAmount ?
<span>{toThousands(baseFormData.value?.forecastSpecialFundAmount)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '申请总部专项资金(元)',
label: '实际专项资金(元)',
prop: 'specialFundAmount',
colProps: {
span: 6
@@ -322,6 +352,13 @@ const schema = computed(() => {
colProps: {
span: 6
}
},
{
label: '主项目',
prop: 'masterProjectName',
colProps: {
span: 6
}
}
]
})

View File

@@ -170,7 +170,7 @@ const schema = computed(() => {
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 6
@@ -184,6 +184,21 @@ const schema = computed(() => {
}
</div>
)
},{
label: '实际经费预算(元)',
prop: 'actualEconomicEstimate',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.actualEconomicEstimate ?
<span>{toThousands(baseFormData.value?.actualEconomicEstimate)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '产学研联合',
@@ -223,9 +238,24 @@ const schema = computed(() => {
colProps: {
span: 6
}
}, {
label: '预估专项资金(元)',
prop: 'forecastSpecialFundAmount',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.forecastSpecialFundAmount ?
<span>{toThousands(baseFormData.value?.forecastSpecialFundAmount)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '申请总部专项资金(元)',
label: '实际专项资金(元)',
prop: 'specialFundAmount',
colProps: {
span: 6
@@ -262,6 +292,13 @@ const schema = computed(() => {
colProps: {
span: 6
}
},
{
label: '主项目',
prop: 'masterProjectName',
colProps: {
span: 6
}
}
]
})

View File

@@ -145,7 +145,7 @@ const schema = computed(() => {
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 6
@@ -159,6 +159,21 @@ const schema = computed(() => {
}
</div>
)
}, {
label: '实际经费预算(元)',
prop: 'actualEconomicEstimate',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.actualEconomicEstimate ?
<span>{toThousands(baseFormData.value?.actualEconomicEstimate)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '产学研联合',
@@ -200,7 +215,23 @@ const schema = computed(() => {
}
},
{
label: '申请总部专项资金(元)',
label: '预估专项资金(元)',
prop: 'forecastSpecialFundAmount',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.forecastSpecialFundAmount ?
<span>{toThousands(baseFormData.value?.forecastSpecialFundAmount)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际专项资金(元)',
prop: 'specialFundAmount',
colProps: {
span: 6
@@ -237,6 +268,13 @@ const schema = computed(() => {
colProps: {
span: 6
}
},
{
label: '主项目',
prop: 'masterProjectName',
colProps: {
span: 6
}
}
]
})

View File

@@ -4,22 +4,37 @@
<fvForm :schema="schema" @getInstance="(e)=>baseForm = e" label-position="left" label-width="left"
style="margin-left: 15px;margin-bottom: -18px"></fvForm>
<baseTitle title="项目实施-上传附件" ></baseTitle>
<el-form :model="formData" ref="tagForm" label-width="auto">
<el-form-item label="标签名称" prop="tagName" style="margin-left: 15px;">
<el-input v-model="formData.tagName" placeholder="请输入标签名称" style="width: 300px;margin-right: 10px" v-if="showInput" clearable/>
<el-select v-model="formData.tagName" placeholder="请选择标签名称" clearable filterable style="width: 300px;margin-right: 10px" v-else>
<el-option
v-for="item in tagsOption"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-button type="primary" link @click="changeInput">{{ showInput ? '选择' : '输入' }}</el-button>
</el-form-item>
</el-form>
<!-- <baseTitle title="其他文件"></baseTitle>-->
<file-upload @getFile="getFile" :disabled="!formData.tagName" :title="!formData.tagName?'请先选择/输入标签!':''" style="margin-left: 15px"/>
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleTabClick" @tab-remove="tabRemove"
style="margin-left: 15px;margin-top: -10px">
<el-tab-pane name="all" :closable="false" label="全部">
</el-tab-pane>
<el-tab-pane v-for="item in tagsOption" :closable="item.isClose==1"
:key="item.tagId"
:label="item.fileTag"
:name="item.tagId">
<div class="tag-title">
<div></div>
{{ item.fileTag }}
</div>
</el-tab-pane>
<el-tab-pane name="plus" :closable="false">
<template #label>
<div style="margin-top: 4px;">
<el-icon color="#BEA266">
<Plus/>
</el-icon>
</div>
</template>
</el-tab-pane>
</el-tabs>
<div style="margin-top:10px;margin-bottom: 8px;margin-left: 15px;display: flex">
<file-upload v-if="activeName!='plus'&&activeName!='all'" @getFile="getFile"/>
<el-button color="#DED0B2" @click="handleEditTag" v-if="activeName!='all'&&activeName!='plus'&&!isDefault"
style="margin-left: 10px;">编辑
</el-button>
</div>
<fvTable style="width: 100%;max-height: 318px;" v-if="showTable" height="318" :tableConfig="tableConfig"
:data="fileList" :isSettingCol="false" :pagination="false">
<template #empty>
@@ -31,15 +46,25 @@
</div>
<file-preview ref="filePreviewRef" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
<el-dialog v-model="tagNameShow" center width="450" top="40vh">
<div style="display: flex;align-items: center">标签
<el-input v-model="fileParam.tagName" placeholder="请输入标签名称" style="width: 335px;" clearable/>
</div>
<div class="oper" style="display: flex;justify-content: flex-end;margin-top: 10px">
<el-button color="#DED0B2" @click="changeTag()">确定</el-button>
<el-button @click="tagNameShow=false">取消</el-button>
</div>
</el-dialog>
</div>
</template>
<script setup lang="jsx">
import {getTags} from "@/api/project-manage";
import {ElNotification} from "element-plus";
import {addTag, delTag, getTagList, getTags, updateTag} from "@/api/project-manage";
import {ElMessageBox, ElNotification} from "element-plus";
import {useTagsView} from '@/stores/tagsview.js'
import {uploadFileList} from "@/api/project-manage/attachment";
import {computed, ref} from "vue";
import {searchImplementationFileList, uploadFileList} from "@/api/project-manage/attachment";
import {computed, nextTick, ref} from "vue";
import {getBaseInfoApi} from "@/components/steps/api";
import {deleteFile, downloadFile} from "@/api/project-demand";
@@ -52,7 +77,11 @@ const tagsViewStore = useTagsView()
const route = useRoute()
const router = useRouter()
const fileList = ref([])
const allFileList = ref([])
const activeName = ref('all')
const tagNameShow = ref(false)
const showInput = ref(false)
const isDefault = ref(false)
const baseFormData = ref([])
const schema = computed(() => {
return [
@@ -182,7 +211,7 @@ const schema = computed(() => {
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 6
@@ -197,6 +226,22 @@ const schema = computed(() => {
</div>
)
},
{
label: '实际经费预算(元)',
prop: 'actualEconomicEstimate',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.actualEconomicEstimate ?
<span>{toThousands(baseFormData.value?.actualEconomicEstimate)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '产学研联合',
prop: 'industryUniversityResearch',
@@ -237,7 +282,23 @@ const schema = computed(() => {
}
},
{
label: '申请总部专项资金(元)',
label: '预估专项资金(元)',
prop: 'forecastSpecialFundAmount',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.forecastSpecialFundAmount ?
<span>{toThousands(baseFormData.value?.forecastSpecialFundAmount)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际专项资金(元)',
prop: 'specialFundAmount',
colProps: {
span: 6
@@ -246,7 +307,7 @@ const schema = computed(() => {
<div>
{
baseFormData.value?.specialFundAmount ?
<span>{ toThousands(baseFormData.value?.specialFundAmount )}</span>
<span>{toThousands(baseFormData.value?.specialFundAmount)}</span>
: <span>{'--'}</span>
}
</div>
@@ -274,12 +335,19 @@ const schema = computed(() => {
colProps: {
span: 6
}
},
{
label: '主项目',
prop: 'masterProjectName',
colProps: {
span: 6
}
}
]
})
const baseForm = ref()
const tagsOption = ref([])
const formData = ref({
const fileParam = ref({
tagName: ''
})
const tableConfig = reactive({
@@ -318,8 +386,11 @@ const tableConfig = reactive({
return (
<div>
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
<popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => handleDelete(row)}/>
{
row.oldType ? null : <popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => handleDelete(row)}/>
}
</div>
)
}
@@ -338,11 +409,147 @@ const filePreviewParam = ref({
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const isEdit = ref(false)
const changeTag = async () => {
let res = null
if (isEdit.value) {
res = await updateTag({
tagId: activeName.value,
fileTag: fileParam.value.tagName,
projectId: route.query.projectId,
})
} else {
res = await addTag({
projectId: route.query.projectId,
fileTag: fileParam.value.tagName
})
fileParam.value.tagName = ''
activeName.value = 'all'
}
getTagsOption()
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
tagNameShow.value = false;
}
const getOldFileList = (tag,flag) => {
let params = {}
if (tag == 'all') {
params = {
targetId: route.query.projectId,
targetState: "30",
}
} else {
params = {
targetId: route.query.projectId,
targetState: "30",
tag: getTagName(activeName.value)
}
}
showTable.value = false
searchImplementationFileList(params).then(res => {
if (res.code === 1000) {
if(tag == 'all'){
res.data.fileList?.forEach(item=>{
item.oldType=true
fileList.value.push(item)
})
}else{
res.data.fileList?.forEach(item=>{
item.oldType=true
if(getTagName(activeName.value)==item.tag){
fileList.value.push(item)
}
})
console.log("🚀 ~ file:'fileList.value ",fileList.value)
}
if(flag){
getTagsOption(flag)
}
nextTick(() => {
showTable.value = true
})
changeImplementFile()
}
})
}
const handleEditTag = () => {
fileParam.value.tagName = getTagName(activeName.value)
if(fileList.value&&fileList.value.length>0){
ElNotification({
title: '提示',
message: '该标签下存在文件,不能编辑标签。如需编辑标签,请先删除该标签下的所有文件。',
type: 'error'
})
return;
}
tagNameShow.value = true
isEdit.value = true
}
const tabRemove = async (val) => {
if(fileList.value&&fileList.value.length>0){
ElNotification({
title: '提示',
message: '该标签下存在文件,不能删除标签。如需删除标签,请先删除该标签下的所有文件。',
type: 'error'
})
return;
}
ElMessageBox.confirm(`确认删除名称为${getTagName(val)}的标签吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
let res = await delTag(val)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
getTagsOption()
}
})
}
const handleTabClick = (item) => {
activeName.value = item.props.name
const defaultArray=tagsOption.value.filter(item1=>item1.tagId==item.props.name)
if(defaultArray&&defaultArray.length>0){
isDefault.value=defaultArray[0].isDefault==1
}else{
isDefault.value=false
}
tagNameShow.value = item.props.name == 'plus';
if (item.props.name == 'plus') {
isEdit.value = false
fileParam.value.tagName = ''
}
const fileArray=JSON.parse(localStorage.getItem('implementFile'))
if (item.props.name != 'plus') {
if (item.props.name == 'all') {
fileList.value=fileArray
getOldFileList('all')
} else {
fileList.value=fileArray.filter(item1 => item1.tag == getTagName(item.props.name))
getOldFileList()
showTable.value = false
nextTick(() => {
showTable.value = true
})
}
}
}
if(localStorage.getItem('implementFile')){
fileList.value=JSON.parse(localStorage.getItem('implementFile'))
allFileList.value=JSON.parse(localStorage.getItem('implementFile'))
}
const changeImplementFile=()=>{
localStorage.setItem('implementFile', JSON.stringify(fileList.value))
localStorage.setItem('implementFile', JSON.stringify(allFileList.value))
}
const clickToPreview=(row)=>{
@@ -358,7 +565,7 @@ const clickToPreview=(row)=>{
}
onActivated(() => {
console.log('onActivated')
formData.value.tagName = '';
fileParam.value.tagName = '';
showTable.value = false
nextTick(() => {
showTable.value = true
@@ -371,7 +578,7 @@ const filterDict = (data, value) => {
let label = ''
let result = []
if (value instanceof Array) {
value.forEach(item1 => {
value?.forEach(item1 => {
data.find(item => {
if (item.value == item1) {
result.push(item.label)
@@ -425,14 +632,54 @@ const getBaseInfo = async () => {
getBaseInfo()
const changeInput = () => {
showInput.value = !showInput.value;
formData.value.tagName = '';
fileParam.value.tagName = '';
}
const getTagName = (name) => {
const tagArray = tagsOption.value.filter((item1) => item1.tagId == name)
let tagName = ''
if (tagArray && tagArray.length > 0) {
tagName = tagArray[0].fileTag
}
return tagName
}
const getTagsOption = () => {
if (!route.query.projectId) return
getTags(route.query.projectId).then(res => {
getTagList(route.query.projectId).then(res => {
if (res.code === 1000) {
showInput.value = res.data.length === 0;
tagsOption.value = res.data
tagsOption.value = res.data.rows
console.log("🚀 ~ file: res.data.rows ", res.data.rows)
tagsOption.value?.forEach((tag, index) => {
tagsOption.value[index].isClose =1
})
let defaultArray=[
{
tagId: 'd1',
fileTag: '合同(专项任务书)',
isDefault: 1,
isClose: 2
},
{
tagId: 'd2',
fileTag: '周报',
isDefault: 1,
isClose: 2
},
{
tagId: 'd3',
fileTag: '阶段性验收',
isDefault: 1,
isClose: 2
},
{
tagId: 'd4',
fileTag: '科研成果',
isDefault: 1,
isClose: 2
}
]
tagsOption.value=[...defaultArray,...tagsOption.value]
console.log("🚀 ~ file:tagsOption.value ", tagsOption.value)
}else{
ElNotification({
title: '提示',
@@ -444,9 +691,9 @@ const getTagsOption = () => {
}
const compositeParam = (item) => {
tagsOption.value.forEach(item => {
if (item.value == formData.value.tagName) {
formData.value.tagName = item.label
tagsOption.value?.forEach(item => {
if (item.value == fileParam.value.tagName) {
fileParam.value.tagName = item.label
}
})
return {
@@ -456,7 +703,7 @@ const compositeParam = (item) => {
fileType: item.fileType,
url: item.url,
newFile: true,
tag: formData.value.tagName,
tag: getTagName(activeName.value) || '项目实施',
}
}
const getFile = (val) => {
@@ -464,24 +711,17 @@ const getFile = (val) => {
showTable.value = false
let fileObj = compositeParam(val)
fileList.value.push(fileObj)
allFileList.value.push(fileObj)
nextTick(() => {
showTable.value = true
})
changeImplementFile()
}
const handleSubmit = async (instance) => {
if (!instance) return
instance.validate(async (valid) => {
if (!valid) {
ElNotification({
title: '提示',
message: '请完善数据,再提交!',
type: 'error'
})
return;
}
const files=JSON.parse(localStorage.getItem('implementFile'))
let params = {
fileList: fileList.value,
fileList: files,
projectId: route.query.projectId,
targetState: "30"
}
@@ -525,9 +765,9 @@ const handleSubmit = async (instance) => {
}
localStorage.removeItem('implementFile')
}
})
}
getTagsOption()
getOldFileList('all')
</script>
<style scoped lang="scss">
@@ -550,4 +790,12 @@ getTagsOption()
}
}
}
:deep(.el-tabs__item.is-active) {
color: #BEA266;
}
:deep(.el-tabs__active-bar) {
background-color: #BEA266;
}
</style>

View File

@@ -253,7 +253,7 @@ const schema = computed(() => {
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 6
@@ -268,6 +268,22 @@ const schema = computed(() => {
</div>
)
},
{
label: '实际经费预算(元)',
prop: 'actualEconomicEstimate',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.actualEconomicEstimate ?
<span>{toThousands(baseFormData.value?.actualEconomicEstimate)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '产学研联合',
prop: 'industryUniversityResearch',
@@ -315,7 +331,23 @@ const schema = computed(() => {
}
},
{
label: '申请总部专项资金(元)',
label: '预估专项资金(元)',
prop: 'forecastSpecialFundAmount',
colProps: {
span: 6
},
component: () => (
<div>
{
baseFormData.value?.forecastSpecialFundAmount ?
<span>{toThousands(baseFormData.value?.forecastSpecialFundAmount)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际专项资金(元)',
prop: 'specialFundAmount',
colProps: {
span: 6
@@ -352,6 +384,13 @@ const schema = computed(() => {
colProps: {
span: 6
}
},
{
label: '主项目',
prop: 'masterProjectName',
colProps: {
span: 6
}
}
]
})

View File

@@ -214,6 +214,11 @@ const tableConfig = reactive({
return (tableIns.value.getQuery().pageNum - 1) * tableIns.value.getQuery().pageSize + index + 1
}
},
{
prop: 'processNumber',
label: '项目编号',
align: 'center',
},
{
prop: 'requirementName',
label: '征集名称',
@@ -274,7 +279,7 @@ const tableConfig = reactive({
},
{
prop: 'economicEstimate',
label: '经费预算(元)',
label: '预估经费预算(元)',
align: 'center',
width: 150,
currentRender:({row})=>{

View File

@@ -1,16 +1,16 @@
<template>
<div v-loading="loading">
<baseTitle v-if="type!='phase'" :title="getTagName(type)+'信息'" ></baseTitle>
<baseTitle v-if="type!='phase'" :title="getTagName(type)+'信息'"></baseTitle>
<fvForm :schema="schema" @getInstance="(e)=>form = e" style="margin-left: 15px"></fvForm>
<el-form :model="formData" label-width="auto">
<file-component
:title="getTagName(type)+'附件'"
:fileNameTableWidth="300"
:tag="getTagName(type)"
v-model:value="formData.fileList"
:processViewer="processViewer"
:file-list-show="fileListShow"
labelAlign="top"
:title="getTagName(type)+'附件'"
:fileNameTableWidth="150"
:tag="getTagName(type)"
v-model:value="formData.fileList"
:processViewer="processViewer"
:file-list-show="fileListShow"
labelAlign="top"
/>
</el-form>
<div v-if="data.taskId">
@@ -36,7 +36,8 @@
</div>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram" :isColumn="true"
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:isColumn="true"
:operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" :id-name="idName?idName:type"/>
@@ -115,7 +116,8 @@ const editSingleTableConfig = reactive({
label: '文件名',
align: 'center',
width: 300,
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
currentRender: ({row, index}) => (
<div style="color: #2a99ff;cursor: pointer;" onClick={() => clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
@@ -192,7 +194,7 @@ const schema = computed(() => {
colProps: {
span: 24
},
labelWidth:'left',
labelWidth: 'left',
component: () => (
<div>
{
@@ -209,12 +211,13 @@ const schema = computed(() => {
colProps: {
span: 24
},
labelWidth:'left',
labelWidth: 'left',
component: () => (
<div>
{
props.formData.projectPersonList ? props.formData.projectPersonList.map((item, index) => {
return <span>{item.name} <span>{index != props.formData.projectPersonList?.length - 1 ? '' : ''}</span></span>
return <span>{item.name}
<span>{index != props.formData.projectPersonList?.length - 1 ? '' : ''}</span></span>
}) : <span>{'--'}</span>
}
</div>
@@ -273,7 +276,188 @@ const schema = computed(() => {
// }
// })
} else if (props.type == 'execute') {
arr = [{
arr = [
{
label: '实际专利(项)',
prop: 'actualNewPatent',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewPatent ? props.formData.actualNewPatent : <span>{'--'}</span>
}
</div>
)
},
{
label: '实际软件著作权(项)',
prop: 'actualSoftwareCopyright',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualSoftwareCopyright ? props.formData.actualSoftwareCopyright : <span>{'--'}</span>
}
</div>
)
},
{
label: '实际技术标准(项)',
prop: 'actualTechnicalNorms',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualTechnicalNorms ? props.formData.actualTechnicalNorms : <span>{'--'}</span>
}
</div>
)
},
{
label: '实际新产品(项)',
prop: 'actualNewProduct',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewProduct ? props.formData.actualNewProduct : <span>{'--'}</span>
}
</div>
)
},
{
label: '实际新工艺(项)',
prop: 'actualNewProcess',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewProcess ? props.formData.actualNewProcess : <span>{'--'}</span>
}
</div>
)
},
{
label: '实际新装置(项)',
prop: 'actualNewDevice',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewDevice ? props.formData.actualNewDevice : <span>{'--'}</span>
}
</div>
)
},
{
label: '实际新材料(项)',
prop: 'actualNewMaterials',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewMaterials ? props.formData.actualNewMaterials : <span>{'--'}</span>
}
</div>
)
},
{
label: '实际计算机软件(项)',
prop: 'actualComputerSoftware',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualComputerSoftware ? props.formData.actualComputerSoftware : <span>{'--'}</span>
}
</div>
)
},
{
label: '实际论文论著(项)',
prop: 'actualThesis',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualThesis ? props.formData.actualThesis : <span>{'--'}</span>
}
</div>
)
},
{
label: '实际研究报告(项)',
prop: 'actualResearchReport',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualResearchReport ? props.formData.actualResearchReport : <span>{'--'}</span>
}
</div>
)
},
{
label: '实际商标(项)',
prop: 'actualTrademark',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualTrademark ? props.formData.actualTrademark : <span>{'--'}</span>
}
</div>
)
},
{
label: '实际其他(项)',
prop: 'actualOther',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div style="white-space: pre-wrap;">
{
props.formData.actualOther ? props.formData.actualOther : <span>{'--'}</span>
}
</div>
)
},
{
label: '部门分管领导',
prop: 'optionalChargeLeadership',
colProps: {
@@ -309,22 +493,22 @@ const schema = computed(() => {
}
arr.push(preProcess)
// arr.push(
// {
// label: '项目验收附件',
// prop: 'singleFile',
// colProps: {
// span: 24
// },
// labelWidth: 'left',
// component: () => {
// let singleFileArray = [props.formData.singleFile]
// return props.formData.singleFile ? <fvTable style="width: 100%;max-height: 80px;" height="80"
// tableConfig={editSingleTableConfig}
// data={singleFileArray} isSettingCol={false} pagination={false}>
// </fvTable>
// : <span>--</span>
// }
// })
// {
// label: '项目验收附件',
// prop: 'singleFile',
// colProps: {
// span: 24
// },
// labelWidth: 'left',
// component: () => {
// let singleFileArray = [props.formData.singleFile]
// return props.formData.singleFile ? <fvTable style="width: 100%;max-height: 80px;" height="80"
// tableConfig={editSingleTableConfig}
// data={singleFileArray} isSettingCol={false} pagination={false}>
// </fvTable>
// : <span>--</span>
// }
// })
} else if (props.type == 'archivist') {
arr = [
// {
@@ -377,14 +561,14 @@ const _value = computed({
emit("update:value", val);
}
})
const clickToPreview=(row)=>{
const clickToPreview = (row) => {
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
nextTick(() => {
filePreviewShow.value = true
})
}
@@ -393,7 +577,7 @@ const getTagName = (type) => {
case 'approval':
return '项目立项'
case 'execute':
return '项目实施'
return '项目验收'
case 'archivist':
return '项目归档'
case 'phase':

View File

@@ -52,7 +52,7 @@
<el-row>
<el-col :span="24">
<baseTitle v-if="fileListShow === 'READ' || fileListShow === 'EDIT'" title="附件文件"></baseTitle>
<file-component title="" tag="需求征集" :fullscreen="true" :fileNameTableWidth="300"
<file-component title="" tag="需求征集" :fullscreen="true" :fileNameTableWidth="150"
v-model:value="formData.fileList" :processViewer="processViewer"
:file-list-show="fileListShow"/>
</el-col>

View File

@@ -201,6 +201,14 @@ const rollbackHandler = async () => {
}
}
const handleAgree = async () => {
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
// const values = form.value.getValues()
const params = {
taskId: props.taskId,

View File

@@ -21,19 +21,28 @@
<span>{{ toThousands(formData.residualAmount) }}</span>
</el-form-item>
</el-col>
<baseTitle title="介绍"></baseTitle>
<!-- <baseTitle title="介绍"></baseTitle>-->
<!-- <el-col :span="24">-->
<!-- <el-form-item>-->
<!-- <el-card style="width: 100%">-->
<!-- <div v-html="formData.introduce">-->
<!-- </div>-->
<!-- </el-card>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="24">
<el-form-item>
<el-card style="width: 100%">
<div v-html="formData.introduce">
</div>
</el-card>
<el-form-item label="专项资金情况说明" >
<div style="white-space: pre-wrap">{{formData.introduce}}
</div>
</el-form-item>
</el-col>
</el-row>
<el-row style="margin-top: -18px;" class="projects">
<baseTitle title="关联项目"></baseTitle>
<el-col :span="24">
<el-form-item>
<fvTable style="width: 100%;max-height:160px" height="160" v-if="showTable" :tableConfig="projectTable"
<fvTable style="width: 100%;max-height:160px" height="160" v-if="showTable" :scrollbar-always-on="true" :tableConfig="projectTable"
:data="formData.projects" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
@@ -41,10 +50,12 @@
</fvTable>
</el-form-item>
</el-col>
</el-row>
<el-row style="margin-top: -18px;" class="projects">
<baseTitle title="附件文件"></baseTitle>
<el-col :span="24">
<el-form-item>
<fvTable style="width: 100%;max-height: 160px;" height="160" v-if="showTable" :tableConfig="fileTable"
<fvTable style="width: 100%;max-height: 160px;" height="160" v-if="showTable":scrollbar-always-on="true" :tableConfig="fileTable"
:data="formData.files" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
@@ -123,12 +134,15 @@ const projectTable = reactive({
prop: 'projectName',
label: '项目名称',
align: 'center',
showOverflowTooltip: false,
width: 200,
},
{
prop: 'specialFundAmount',
label: '项目金额',
align: 'center',
minWidth: 120,
showOverflowTooltip: false,
currentRender:({row})=>{
return <span>{toThousands(row.specialFundAmount)}</span>
}
@@ -137,7 +151,7 @@ const projectTable = reactive({
prop: 'startTime',
label: '项目时间',
align: 'center',
width: 150,
width: 180,
},
// {
// prop: 'oper',

View File

@@ -211,7 +211,7 @@ const schema = computed(() => {
)
},
{
label: '所属业务板块',
label: '业务板块',
prop: 'businessSegment',
colProps: {
span: 24
@@ -258,8 +258,9 @@ const schema = computed(() => {
</div>
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 24
@@ -274,6 +275,22 @@ const schema = computed(() => {
</div>
)
},
{
label: '实际经费预算(元)',
prop: 'actualEconomicEstimate',
colProps: {
span: 24
},
component: () => (
<div>
{
baseFormData.value?.actualEconomicEstimate ?
<span>{toThousands(baseFormData.value?.actualEconomicEstimate)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '产学研联合',
prop: 'industryUniversityResearch',
@@ -320,9 +337,27 @@ const schema = computed(() => {
span: 24
}
},
{
label: '申请总部专项资金(元)',
prop: 'specialFundAmount',
label: '预估专项资金(元)',
prop: 'forecastSpecialFundAmount',
colProps: {
span: 24
},
component: () => (
<div>
{
baseFormData.value?.forecastSpecialFundAmount ?
<span>{toThousands(baseFormData.value?.forecastSpecialFundAmount)}</span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际专项资金(元)',
prop: 'forecastSpecialFundAmount',
colProps: {
span: 24
},
@@ -336,12 +371,36 @@ const schema = computed(() => {
</div>
)
},
{
label: '是否在预算内',
prop: 'isWithinBudget',
colProps: {
span: 24
},
component: () => (
<div>
{
baseFormData.value?.isWithinBudget!=null ? baseFormData.value?.isWithinBudget?
<span>{'预算内'}</span>
: <span>{'预算外'}</span>:'--'
}
</div>
)
},
{
label: '部门分管领导',
prop: 'optionalChargeLeadership',
colProps: {
span: 24
}
},
{
label: '主项目',
prop: 'masterProjectName',
colProps: {
span: 24
}
}
]
})
@@ -579,6 +638,9 @@ watchEffect(() => {
</script>
<style lang="scss" scoped>
:deep(.el-step__title){
font-size: 14px;
}
.steps-box {
padding: 10px 0;
}

View File

@@ -4,12 +4,7 @@
<baseTitle title="预期知识产权"></baseTitle>
<el-row gutter="20" style="margin-bottom: -18px;margin-left: 5px">
<el-col :span="24">
<el-form-item label="预期成果形式" prop="resultForm">
<span>{{ filterDict(cacheStore.getDict('result_form'), localFormData.resultForm) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="知识产权状况" prop="intellectualProperty">
<el-form-item label="知识产权归属" prop="intellectualProperty">
<span>{{
filterDict(cacheStore.getDict('intellectual_property'), localFormData.intellectualProperty)
}}</span>
@@ -17,31 +12,77 @@
</el-col>
<el-col :span="24">
<el-form-item label="发明专利(项)" prop="inventionPatent">
<span>{{ localFormData.inventionPatent }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="新型专利(项)" prop="newPatent">
<el-form-item label="预估专利(项)" prop="newPatent">
<span>{{ localFormData.newPatent }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="软件著作权(项)" prop="softwareCopyright">
<el-form-item label="预估软件著作权(项)" prop="softwareCopyright">
<span>{{ localFormData.softwareCopyright }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="著作权(项)" prop="copyright">
<span>{{ localFormData.copyright }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="其他(项)" prop="other">
<span>{{ localFormData.other }}</span>
<el-form-item label="预估技术标准(项)" prop="technicalNorms">
<span>{{ localFormData.technicalNorms }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预估新产品(项)" prop="newProduct">
<span>{{ localFormData.newProduct }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预估新工艺(项)" prop="newProcess">
<span>{{ localFormData.newProcess }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预估新装置(项)" prop="newDevice">
<span>{{ localFormData.newDevice }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预估新材料(项)" prop="newMaterials">
<span>{{ localFormData.newMaterials }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预估计算机软件(项)" prop="computerSoftware">
<span>{{ localFormData.computerSoftware }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预估论文论著(项)" prop="thesis">
<span>{{ localFormData.thesis }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预估研究报告(项)" prop="researchReport">
<span>{{ localFormData.researchReport }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预估商标(项)" prop="trademark">
<span>{{ localFormData.trademark }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预估其他(项)" prop="other">
<span style="white-space: pre-wrap">{{ localFormData.other }}</span>
</el-form-item>
</el-col>
</el-row>
<baseTitle title="项目描述"></baseTitle>
<el-row gutter="20" style="margin-bottom: -18px;margin-left: 5px;">
@@ -74,7 +115,7 @@
<!-- </el-col>-->
<el-col :span="24">
<file-component
tag="需求上报" :fileNameTableWidth="300" :fullscreen="true"
tag="需求上报" :fileNameTableWidth="150" :fullscreen="true"
v-model:value="localFormData.fileList"
:processViewer="processViewer"
:file-list-show="fileListShow"
@@ -94,7 +135,7 @@
</el-form-item>
</div>
<div v-if="data.state==='5'" style="margin-bottom: 15px">
<baseTitle title="前置流程"></baseTitle>
<baseTitle title="前置流程" v-if="localFormData.preProcess"></baseTitle>
<div style="display: flex;align-items: center;flex-wrap: wrap;">
<div v-for="(item,index) in localFormData.preProcess" :key="item.requestId">
<a :href="item.baseUrl" target="_blank"
@@ -105,8 +146,8 @@
</div>
</div>
<div v-perm="['annual:plan:approve']" v-if="data.state==='4'">
<baseTitle title="前置流程"></baseTitle>
<select-pre-process :formData="localFormData"/>
<!-- <baseTitle title="前置流程"></baseTitle>-->
<!-- <select-pre-process :formData="localFormData"/>-->
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
@@ -239,6 +280,14 @@ const handleRejectPlan = async () => {
})
}
const handleAgreePlan = async () => {
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
const params = {
auditOpinion: _value.value,
projectId: parseInt(route.query.projectId),

View File

@@ -26,7 +26,7 @@
:preProcessShow="preProcessShow"
v-model:value="auditOpinion"/>
<div v-if="showActive == '30'">
<project-attachment fileNameTableWidth="300" :isLineBtn="true"/>
<project-attachment fileNameTableWidth="200" :isLineBtn="true"/>
</div>
<ApprovalDetail type="execute"
v-if="showActive == '40'"

View File

@@ -167,7 +167,7 @@ const schema = computed(() => {
)
},
{
label: '经费预算(元)',
label: '预估经费预算(元)',
prop: 'economicEstimate',
colProps: {
span: 24
@@ -222,7 +222,7 @@ const schema = computed(() => {
}
},
{
label: '申请总部专项资金(元)',
label: '预估专项资金(元)',
prop: 'specialFundAmount',
colProps: {
span: 24

View File

@@ -1,6 +1,6 @@
<template>
<fvSearchForm :searchConfig="researchFundSearchConfig" @search="searchResearchFund"
style="margin-left: 16px"></fvSearchForm>
></fvSearchForm>
<fvTable ref="tableIns" :tableConfig="researchFundTableConfig" @headBtnClick="headBtnClick">
<template #empty>
<el-empty description="暂无数据"/>
@@ -30,7 +30,7 @@ const researchFundSearchConfig = ref([
}
},
{
label: '研发资金金额',
label: '研发资金金额(元)',
prop: 'rdAmount',
component: 'el-input',
props: {
@@ -74,7 +74,7 @@ const researchFundTableConfig = reactive({
},
{
prop: 'rdAmount',
label: '研发资金金额',
label: '研发资金金额(元)',
align: 'center',
currentRender:({row})=>{
return <span>{toThousands(row.rdAmount)}</span>

View File

@@ -3,7 +3,7 @@
<fvTable ref="tableIns" :tableConfig="tableConfig" @headBtnClick="headBtnClick"
@selectionChange="selectionChange"></fvTable>
<user-picker :multiple="true" ref="whiteUserRef" title="请选择人员"
v-model:value="whiteUserList" @ok="whiteUserPickerOk" @cancelOrClear="whiteUserPickerOk"/>
v-model:value="whiteUserList" @ok="whiteUserPickerOk"/>
</template>

View File

@@ -34,7 +34,6 @@
<script setup>
import {defineProps,defineEmits} from 'vue'
// import {timeLength} from '../utils/date'

View File

@@ -1,5 +1,4 @@
//时间转换为String类型
const moment = require("moment");
function simpleDateFormat(pattern) {
var fmt = new Object();
@@ -83,36 +82,36 @@ function consumingTime(dateBegin, dateEnd) {
return dayDiff + "天 " + hours + "小时 " + minutes + " 分钟" + seconds + " 秒";
}
export function timeLength(start, dateEnd) {
// //如果时间格式是正确的,那下面这一步转化时间格式就可以不用了
let mstart = moment(start);
let mend = moment(dateEnd);
let years = mend.diff(start, "years");
let months = mend.diff(start, "months");
let days = mend.diff(start, "days");
let hours = mend.diff(start, "hours");
let minutes = mend.diff(start, "minutes");
minutes = minutes % 60;
hours = hours % 24;
months = months % 12;
//因为每月天不固定,所以天要特殊动态处理
if (mstart.date() < mend.date()) {
days = mend.date() - mstart.date();
if (minutes > 0 || hours > 0) {
days--;
}
}
//处理超过俩月且天超过31
if (days > 31 && mend.month() - mstart.month() >= 2) {
//将日期推至上月求差
days = mend.diff(mstart.add(mend.month() - mstart.month() - 1, "month"), "days");
}
return `${years > 0 ? years + "年 " : " "}` + `${months > 0 ? months + "个月 " : " "}` + `${days > 0 ? days + "天 " : " "}`
+ `${hours > 0 ? hours + "小时 " : " "}` + `${minutes > 0 ? minutes + "分钟 " : " "}`;
}
// export function timeLength(start, dateEnd) {
// // //如果时间格式是正确的,那下面这一步转化时间格式就可以不用了
// let mstart = moment(start);
// let mend = moment(dateEnd);
// let years = mend.diff(start, "years");
// let months = mend.diff(start, "months");
// let days = mend.diff(start, "days");
// let hours = mend.diff(start, "hours");
// let minutes = mend.diff(start, "minutes");
// minutes = minutes % 60;
// hours = hours % 24;
// months = months % 12;
// //因为每月天不固定,所以天要特殊动态处理
// if (mstart.date() < mend.date()) {
// days = mend.date() - mstart.date();
// if (minutes > 0 || hours > 0) {
// days--;
// }
// }
// //处理超过俩月且天超过31
// if (days > 31 && mend.month() - mstart.month() >= 2) {
// //将日期推至上月求差
// days = mend.diff(mstart.add(mend.month() - mstart.month() - 1, "month"), "days");
// }
// return `${years > 0 ? years + "年 " : " "}` + `${months > 0 ? months + "个月 " : " "}` + `${days > 0 ? days + "天 " : " "}`
// + `${hours > 0 ? hours + "小时 " : " "}` + `${minutes > 0 ? minutes + "分钟 " : " "}`;
// }
module.exports = {
formatToYYYYMMDD: simpleDateFormatByMoreLine,
consumingTime: consumingTime,
timeLength: timeLength
// timeLength: timeLength
}

View File

@@ -68,7 +68,7 @@
</el-table-column>
</el-table>
</div>
<paging :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[10, 20, 30, 40,50]"
<paging :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[10, 20, 30, 40,50]"
:total="total" @changeSize="handleSizeChange" @goPage="handleCurrentChange"/>
<el-dialog v-model="isVisited" title="历史" width="800px">
<div class="table">
@@ -118,10 +118,12 @@ import {
deleteHistoryVersion
} from "@/api/workflow/process-definition.js";
import {Search, Refresh, Delete, Plus, Edit, Download, Document} from '@element-plus/icons-vue'
import {ElMessage, ElMessageBox} from "element-plus";
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
import {useCacheStore} from '@/stores/cache.js'
import PointTag from "@/components/PointTag.vue";
import Paging from "@/components/pagination/index.vue";
import UserPicker from "./common/UserPicker.vue";
import {applyCcSend} from "@/api/expense-manage";
const dictStore = useCacheStore()
dictStore.setCacheKey(['normal_disable'])
@@ -144,6 +146,7 @@ const loading = ref(true)
const list = ref([])
const queryForm = ref()
const total = ref()
const chooseRow = ref({})
const selectDefinition = ref(null)
const historyVersionList = ref([])
const singleTable = ref()
@@ -151,6 +154,8 @@ const isVisited = ref(false)
onActivated(() => {
getList()
})
//重置搜索
const handleReset = () => {
queryForm.value.resetFields()
@@ -182,7 +187,6 @@ const handleAdd = () => {
path: '/workflow/process/add',
})
}
const handleEdit = (deploymentId) => {
router.push({
path: `/workflow/process/edit/${deploymentId}`,

View File

@@ -9,7 +9,8 @@ import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import Inspect from 'vite-plugin-inspect'
import viteSvgIcons from 'vite-plugin-svg-icons'
import path from 'path'
import path from 'node:path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
@@ -42,7 +43,7 @@ export default defineConfig({
}),
viteSvgIcons({
// 指定需要缓存的图标文件夹
iconDirs: [path.resolve(__dirname, 'src/assets/svg')],
iconDirs: [path.resolve(process.cwd(), 'src/assets/svg')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]',
}),
@@ -53,6 +54,7 @@ export default defineConfig({
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
build: {
minify: 'esbuild',
terserOptions: {
@@ -69,22 +71,22 @@ export default defineConfig({
open: true,
proxy: {
// '/api/workflow': {
// // target: 'http://frp.feashow.cn:31800/',
// target: 'http://clay.frp.feashow.cn/',
// 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/admin': {
// // target: 'http://frp.feashow.cn:31800/',
// target: 'http://clay.frp.feashow.cn/',
// 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/auth': {
// // target: 'http://frp.feashow.cn:31800/',
// target: 'http://clay.frp.feashow.cn/',
// 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/, '')
@@ -103,5 +105,8 @@ export default defineConfig({
// changeOrigin: true,
// }
}
}
},
esbuild: {
target: 'esnext', // 强制使用最新 ES 模块
},
})