356 Commits
gary ... master

Author SHA1 Message Date
65a852d380 Merge pull request 'prod' (#1105) from prod into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1105
2025-08-22 08:51:55 +00:00
dj
0efd2a7db2 feat(project-demand): 优化需求提交按钮显示逻辑
- 在 routerName 为 Requirement/add 且 formData.state 为 '3' 时显示提交按钮
- 在 routerName为 Requirement/edit 且 formData.state为 '3' 时显示重新提交按钮
- 为 formData 添加 state 字段初始化为 ''
2025-08-22 16:19:41 +08:00
dj
83c01575e6 style:优化日期选择器样式
- 调整年份选择器的宽度为 100%,以适应页面布局
2025-08-20 09:22:49 +08:00
dj
5808145c01 fix(views): 修改日期选择器的格式为单月显示
- 在 expense-management 模块下的 cost-detail 和 expend-detail 页面中
- 将日期选择器的 format 和 valueFormat 属性从 'MM' 修改为 'M'
- 这个修改使得日期选择器显示单个月份,而不是两位数的月份
2025-08-20 00:02:29 +08:00
dj
e1543e05b4 refactor(expense-management):恢复并优化日期选择功能
- 在成本详情、支出详情和分摊详情页面中重新启用年份和月份选择功能
-优化日期选择器的格式和价值格式
- 在搜索时去除月份参数的前置0,确保正确传递参数
- 调整搜索表单的样式,移除多余的样式属性
2025-08-20 00:00:44 +08:00
dj
d20b968307 feat(expense-management): 为成本明细页面添加年份和月份筛选功能
- 在成本明细、支出明细和分摊明细页面的搜索表单中添加了年份和月份选择器
- 优化了搜索表单的样式和布局- 注释掉了部分未使用的代码
2025-08-19 16:14:23 +08:00
dj
7735d20021 feat(expense-management): 添加项目名称搜索的本地存储功能
- 在成本明细、支出明细和共享明细页面中,为大师项目名称和子项目名称的搜索框添加本地存储功能
- 当用户输入搜索值时,从本地存储中获取已保存的项目名称选项
- 当用户清空搜索框时,将当前加载的项目名称选项保存到本地存储
- 优化了项目名称搜索的用户体验,减少了重复请求服务器的次数
2025-08-19 16:07:29 +08:00
831f017482 Merge pull request 'refactor(plan): 将年度计划相关文案统一修改为项目计划' (#1104) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1104
2025-08-06 14:08:49 +00:00
dj
827978f7bd refactor(plan): 将年度计划相关文案统一修改为项目计划
- 修改了多个组件和 API 中的年度计划名称、提示文本等
- 统一使用项目计划替代年度计划,提高文案一致性
2025-08-06 22:06:17 +08:00
b16893955d Merge pull request 'master' (#1103) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1103
2025-08-06 14:02:48 +00:00
dj
41830600bf feat(project-demand): 添加需求汇总行键值
在项目需求汇总视图中添加了行键值属性,以优化数据展示和操作。
2025-08-06 22:02:27 +08:00
76a5ebbeb9 Merge pull request 'prod' (#1102) from prod into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1102
2025-08-04 02:03:30 +00:00
dj
a26088a756 feat(expense-management): 优化项目名称远程搜索功能
- 在项目需求概览页面添加主项目列表缓存到本地存储
-重构费用管理模块中项目名称远程搜索方法,提高代码复用性
- 优化主项目和子项目名称的加载和搜索逻辑
2025-08-04 10:02:50 +08:00
4229cb9d74 Merge pull request 'refactor(expense-management): 优化费用管理三个模块中搜索配置的选项处理' (#1101) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1101
2025-08-03 11:41:45 +00:00
dj
a64715717b refactor(expense-management): 优化费用管理三个模块中搜索配置的选项处理
- 移除了 cost-detail、expend-detail 和 share-detail 组件中不必要的条件判断
-简化了选项对象的创建和添加到 Map 中的逻辑
- 提高了代码的可读性和维护性
2025-08-03 19:41:29 +08:00
f18ae8b1ee Merge pull request 'feat(project-demand): 实现主子项目名称模糊查询功能' (#1100) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1100
2025-08-03 10:56:46 +00:00
dj
19c566cd0d feat(project-demand): 实现主子项目名称模糊查询功能
- 在项目需求汇总、成本明细、支出明细和共享明细页面添加主子项目名称模糊查询功能
- 新增相关 API 接口和方法以支持模糊查询
- 优化 fvSelect 组件以适配远程搜索功能
2025-08-03 18:55:53 +08:00
3c459f4be2 Merge pull request 'fix(filling): 修改用户管理归属部门显示' (#1099) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1099
2025-08-01 15:14:10 +00:00
dj
1ad6e021a1 fix(filling): 修改用户管理归属部门显示 2025-08-01 22:50:59 +08:00
6cbc3f83e6 Merge pull request 'master' (#1098) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1098
2025-07-27 12:40:09 +00:00
dj
9560a964e7 fix(filling): 修改下属公司归档状态 2025-07-27 20:39:21 +08:00
94bd9930b6 Merge pull request 'prod' (#1097) from prod into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1097
2025-07-22 16:24:29 +00:00
f2e80e4874 Merge pull request 'fix : 需求上报部分字段默认null' (#1096) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1096
2025-07-22 16:23:07 +00:00
dj
62e98b9e3f fix : 需求上报部分字段默认null 2025-07-23 00:21:28 +08:00
zhangkaihuai
a620b248f4 更新 .drone.yml 2025-07-22 07:52:07 +00:00
zhangkaihuai
e2e4d3226f 更新 .drone.yml 2025-07-22 07:45:47 +00:00
zhangkaihuai
af2788583f 更新 .drone.yml 2025-07-22 07:42:40 +00:00
zhangkaihuai
ba58089e94 更新 .drone.yml 2025-07-22 07:29:18 +00:00
zhangkaihuai
88dcbf3196 更新 .drone.yml 2025-07-22 07:26:24 +00:00
9092b1e960 Merge pull request 'master' (#1095) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1095
2025-07-22 07:13:45 +00:00
dj
3ddd24cc70 fix : 修复支出明细-项目类型字段 2025-07-22 15:13:22 +08:00
1fb3345afe Merge pull request 'fix : 屏蔽账号编辑' (#1094) from prod into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1094
2025-07-11 02:27:43 +00:00
dj
d1fe0faad1 fix : 屏蔽账号编辑 2025-07-11 10:24:32 +08:00
64d10a711d Merge pull request 'fix : 修复角色修改权限' (#1093) from prod into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1093
2025-07-11 02:19:47 +00:00
dj
1d5e8a23ed fix : 修复角色修改权限 2025-07-11 10:12:48 +08:00
2973bbe6a7 Merge pull request 'prod' (#1092) from prod into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1092
2025-07-10 03:34:00 +00:00
zhangkaihuai
8974282b44 更新 docker.sh 2025-07-10 03:26:55 +00:00
zhangkaihuai
81705482a8 更新 docker.sh 2025-07-10 03:22:00 +00:00
9cc8d337be Merge pull request 'fix : 修复实施图片' (#1091) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1091
2025-07-09 14:59:44 +00:00
973dc0f2e4 fix : 修复实施图片 2025-07-09 22:56:09 +08:00
db696ca389 Merge pull request 'feat(components): 调整分页组件默认页码和每页条数' (#1090) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1090
2025-07-03 15:30:50 +00:00
dj
64e2ff0647 feat(components): 调整分页组件默认页码和每页条数
- 将 fvPagination 组件的默认每页条数从 10 调整为 20
- 在 pageSizes 数组中添加 100 选项
- 更新 fvTable 组件中的默认每页条数和 pageSizes 配置
- 修改首页专项资金项目和研发投入资金的相关文案
2025-07-03 23:30:22 +08:00
53b0e4b240 Merge pull request 'master' (#1089) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1089
2025-07-03 15:08:34 +00:00
dj
17010a15a3 fix : 修复首页数量 2025-07-03 23:08:16 +08:00
f74743c00f Merge pull request 'fix : 修复首页数量' (#1088) from prod into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1088
2025-07-03 15:01:37 +00:00
dj
e14b6d676c fix : 修复首页数量 2025-07-03 18:41:57 +08:00
3ecea87de8 Merge pull request 'prod' (#1087) from prod into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1087
2025-06-25 10:05:41 +00:00
dj
cb290acf09 test : ci/cd 2025-06-25 17:52:27 +08:00
f6cabee345 Merge pull request 'feat(upload): 优化文件上传组件逻辑' (#1086) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1086
2025-06-25 09:41:38 +00:00
dj
8b03d62a75 feat(upload): 优化文件上传组件逻辑
- 在删除文件时,将删除的文件信息存储到本地存储中
- 在选择文件时,检查本地存储中是否有删除的文件信息,并从选择的文件中移除
- 优化了文件上传流程,提高了用户体验
2025-06-25 17:41:15 +08:00
1674d1acd0 Merge pull request 'fix(ProjectAttachment): 优化附件删除逻辑' (#1085) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1085
2025-06-25 07:38:49 +00:00
dj
41a455338f fix(ProjectAttachment): 优化附件删除逻辑
- 在删除其他附件时,同时从 allFiles 中移除对应文件
- 移除删除附件后不必要的重新获取附件列表操作
2025-06-25 15:38:22 +08:00
5b67f97021 Merge pull request 'master' (#1084) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1084
2025-06-20 01:57:33 +00:00
dj
a451f7481e style(fvTable): 移除表格单元格悬停时的宽度限制
- 注释掉 .fv-table :deep(.el-tooltip) 中的 width: 100% !important 样式
-此修改解决了单元格内容过长时导致的表格布局问题
2025-06-20 09:57:06 +08:00
2400660b1f Merge pull request 'prod' (#1083) from prod into master
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1083
2025-06-14 16:37:37 +00:00
dj
26e0009ebd test : ci/cd 2025-06-15 00:36:56 +08:00
dj
34b0b88f07 test : ci/cd 2025-06-15 00:31:01 +08:00
dj
37a3cd75a2 test : ci/cd 2025-06-15 00:25:25 +08:00
dj
81d4002034 test : ci/cd 2025-06-15 00:10:47 +08:00
dj
5c000cdba3 test : ci/cd 2025-06-15 00:06:42 +08:00
zhangkaihuai
5dcdbe9ae1 Merge pull request 'zhangkaihuai-patch-1' (#1082) from zhangkaihuai-patch-1 into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1082
2025-06-14 15:25:46 +00:00
zhangkaihuai
4371ccb5e7 更新 .drone.yml 2025-06-14 15:25:22 +00:00
zhangkaihuai
f9ef5c7087 更新 .drone.yml 2025-06-14 15:20:57 +00:00
zhangkaihuai
bf2f28960f Merge pull request '更新 .drone.yml' (#1081) from zhangkaihuai-patch-1 into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1081
2025-06-14 14:56:58 +00:00
zhangkaihuai
f42eacd06e 更新 .drone.yml 2025-06-14 14:56:50 +00:00
861a6489c7 Merge pull request 'test : ci/cd' (#1080) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1080
2025-06-14 11:26:25 +00:00
dj
9133f7a7e3 test : ci/cd 2025-06-14 19:26:13 +08:00
e9be87990c Merge pull request '3' (#1079) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1079
2025-06-14 11:10:24 +00:00
dj
ec8db3c199 test : ci/cd 2025-06-14 19:09:36 +08:00
d2520336cb Merge pull request 'test : ci/cd' (#1078) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1078
2025-06-14 10:59:38 +00:00
dj
e97db1a70d test : ci/cd 2025-06-14 18:59:25 +08:00
afd27e38b5 Merge pull request 'test : ci/cd' (#1077) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1077
2025-06-14 10:50:02 +00:00
dj
7dd5120133 test : ci/cd 2025-06-14 18:49:22 +08:00
75da0633e5 Merge pull request 'test : ci/cd' (#1076) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1076
2025-06-14 10:43:23 +00:00
dj
41b498066f test : ci/cd 2025-06-14 18:43:10 +08:00
c852448089 Merge pull request 'test : ci/cd' (#1075) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1075
2025-06-14 10:40:34 +00:00
dj
9cd744d44e test : ci/cd 2025-06-14 18:40:23 +08:00
a7917137c9 Merge pull request 'test : ci/cd' (#1074) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1074
2025-06-14 10:30:29 +00:00
dj
85346fa343 test : ci/cd 2025-06-14 18:30:04 +08:00
e5b205870d Merge pull request 'test : ci/cd' (#1073) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1073
2025-06-14 10:26:12 +00:00
dj
5ae66763e1 test : ci/cd 2025-06-14 18:26:02 +08:00
9221d27960 Merge pull request 'test : ci/cd' (#1072) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1072
2025-06-14 10:23:34 +00:00
dj
c442b9b2fd test : ci/cd 2025-06-14 18:23:25 +08:00
25c94284ca Merge pull request 'test : ci/cd' (#1071) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1071
2025-06-14 10:18:34 +00:00
dj
5da74960f2 test : ci/cd 2025-06-14 18:18:22 +08:00
cdcb76d009 Merge pull request 'test : ci/cd' (#1070) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1070
2025-06-14 10:14:51 +00:00
dj
c87b5c57a6 test : ci/cd 2025-06-14 18:14:39 +08:00
fd0d70072b Merge pull request '4' (#1069) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1069
2025-06-14 09:39:44 +00:00
dj
747f675cfc test : ci/cd 2025-06-14 17:39:30 +08:00
941b06ab8b Merge pull request 'test : ci/cd' (#1068) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1068
2025-06-14 09:35:23 +00:00
dj
3e6f86abfd test : ci/cd 2025-06-14 17:35:12 +08:00
01ccc1ddcd Merge pull request '12' (#1067) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1067
2025-06-14 08:56:34 +00:00
dj
b6ac47e88b test : ci/cd 2025-06-14 16:56:18 +08:00
707486c69d Merge pull request 'test : ci/cd' (#1066) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1066
2025-06-14 08:50:34 +00:00
dj
2ef726b95b test : ci/cd 2025-06-14 16:50:17 +08:00
697af99240 Merge pull request 'test : ci/cd' (#1065) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1065
2025-06-14 08:46:41 +00:00
dj
ee2f7a9162 test : ci/cd 2025-06-14 16:45:18 +08:00
476f6a794d Merge pull request 'test : ci/cd' (#1064) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1064
2025-06-14 08:40:58 +00:00
dj
0c53ee8392 test : ci/cd 2025-06-14 16:40:48 +08:00
4c1e892d35 Merge pull request 'test : ci/cd' (#1063) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1063
2025-06-14 08:37:07 +00:00
dj
ac6d7863da test : ci/cd 2025-06-14 16:36:56 +08:00
ea33ffb60a Merge pull request 'test : ci/cd' (#1062) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1062
2025-06-14 08:31:16 +00:00
dj
a1ae39cbd7 test : ci/cd 2025-06-14 16:31:03 +08:00
0ada78f180 Merge pull request 'test : ci/cd' (#1061) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1061
2025-06-14 08:29:25 +00:00
dj
60e29aca8d test : ci/cd 2025-06-14 16:29:03 +08:00
3db2901a03 Merge pull request 'test : ci/cd' (#1060) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1060
2025-06-14 08:25:50 +00:00
dj
7428fe43d4 test : ci/cd 2025-06-14 16:25:38 +08:00
18592571a4 Merge pull request 'test : ci/cd' (#1059) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1059
2025-06-14 07:44:49 +00:00
dj
4bb03409f4 test : ci/cd 2025-06-14 15:42:17 +08:00
7fec9c5735 Merge pull request 'test : ci/cd 2' (#1058) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1058
2025-06-14 07:26:53 +00:00
dj
3d9f22d503 test : ci/cd 2 2025-06-14 15:26:40 +08:00
76c9a38718 Merge pull request 'test : ci/cd1' (#1057) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1057
2025-06-14 07:21:25 +00:00
dj
af7d0ac580 test : ci/cd1 2025-06-14 15:21:14 +08:00
4888a7e077 Merge pull request 'test : ci/cd' (#1056) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1056
2025-06-14 07:18:38 +00:00
dj
47a2f61036 test : ci/cd 2025-06-14 15:18:22 +08:00
f26e40df90 Merge pull request 'master' (#1055) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1055
2025-06-14 07:13:11 +00:00
dj
07103258f7 test : ci/cd 2025-06-14 15:12:49 +08:00
dj
8fa0d72cc4 test : ci/cd 2025-06-14 15:09:17 +08:00
7684444e93 Merge pull request 'test : ci/cd' (#1054) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1054
2025-06-14 07:05:25 +00:00
dj
81446971e5 test : ci/cd 2025-06-14 15:04:38 +08:00
5930a2c4b6 Merge pull request 'test : ci/cd' (#1053) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1053
2025-06-14 06:57:14 +00:00
dj
052c0090e3 test : ci/cd 2025-06-14 14:56:46 +08:00
d24892141a Merge pull request 'test : ci/cd' (#1052) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1052
2025-06-14 06:43:28 +00:00
dj
83dc28630b test : ci/cd 2025-06-14 14:43:10 +08:00
086fdb36e9 Merge pull request 'test : ci/cd' (#1051) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1051
2025-06-14 06:35:32 +00:00
dj
ba4c4fccdd test : ci/cd 2025-06-14 14:35:18 +08:00
bc79cfc0bc Merge pull request 'test : ci/cd' (#1050) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1050
2025-06-14 06:17:25 +00:00
dj
35d4d1b7ba test : ci/cd 2025-06-14 14:17:14 +08:00
71324efd0c Merge pull request 'test : 测试ci/cd-5' (#1049) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1049
2025-06-13 10:23:30 +00:00
dj
781e7393e8 test : 测试ci/cd-5 2025-06-13 18:22:50 +08:00
1eea7a377c Merge pull request 'test : 测试ci/cd-4' (#1048) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1048
2025-06-13 10:17:23 +00:00
dj
065eb6cfba test : 测试ci/cd-4 2025-06-13 18:17:01 +08:00
35a2f755a2 Merge pull request 'test : 测试ci/cd-3' (#1047) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1047
2025-06-13 10:10:41 +00:00
dj
9bd9cda872 test : 测试ci/cd-3 2025-06-13 18:10:24 +08:00
dd6181880a Merge pull request 'test : 测试ci/cd-2' (#1046) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1046
2025-06-13 09:59:51 +00:00
dj
cd2bfe8817 test : 测试ci/cd-2 2025-06-13 17:59:33 +08:00
8b6406c4e0 Merge pull request 'test : 测试ci/cd-1' (#1045) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1045
2025-06-13 09:50:39 +00:00
dj
fa3171fecd test : 测试ci/cd-1 2025-06-13 17:50:21 +08:00
177ccee058 Merge pull request 'test : 测试ci/cd' (#1044) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1044
2025-06-13 06:57:28 +00:00
dj
28de3667f5 test : 测试ci/cd 2025-06-13 14:57:15 +08:00
05a5385d87 Merge pull request 'test : 测试ci/cd' (#1043) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1043
2025-06-13 06:39:59 +00:00
dj
529f482bc7 test : 测试ci/cd 2025-06-13 14:39:23 +08:00
20fb592584 Merge pull request 'test : 测试ci/cd' (#1042) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1042
2025-06-13 06:23:55 +00:00
dj
bd35243cbd test : 测试ci/cd 2025-06-13 14:23:37 +08:00
d7ca84a4a0 Merge pull request 'master' (#1041) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1041
2025-06-13 06:19:11 +00: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
3588257f61 revert 215f7c6bbf
revert feat(expense-management): 添加研发工时超过21.75天的提示功能

- 在保存分配明细时,增加对研发人员总工时的计算
- 如果总工时超过21.75天,系统将发出警告通知- 优化了控制台日志输出,便于调试和监控
2025-06-13 06:18:21 +00:00
6c47337318 Merge pull request 'revert 215f7c6bbf084b0bf6dbee1303a2539a3c21c3ad' (#1039) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1039
2025-06-13 06:14: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
9e194f5f04 Merge pull request 'test : 测试ci/cd' (#1038) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1038
2025-06-12 07:29:49 +00:00
dj
f448ec47a3 test : 测试ci/cd 2025-06-12 15:26:52 +08:00
f633862434 Merge pull request 'test : 测试ci/cd' (#1037) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1037
2025-06-12 07:19:39 +00:00
dj
a4674d497b test : 测试ci/cd 2025-06-12 15:18:29 +08:00
e8aee6f01c Merge pull request 'test : 测试ci/cd' (#1036) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1036
2025-06-12 06:54:14 +00:00
dj
43e0f98509 test : 测试ci/cd 2025-06-12 14:53:52 +08:00
10b66cbf15 Merge pull request 'master' (#1035) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1035
2025-06-12 06:07:46 +00: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
4321b42003 Merge pull request 'build(deps): 添加 moment 依赖' (#1034) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1034
2025-06-12 04:05:02 +00:00
dj
7f0f74c844 build(deps): 添加 moment 依赖 2025-06-12 12:04:11 +08:00
c1065cb084 Merge pull request 'refactor(components): 优化文件上传成功提示' (#1033) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1033
2025-06-12 03:42:56 +00:00
dj
579cadd687 refactor(components): 优化文件上传成功提示 2025-06-12 11:42:09 +08:00
78f4135efb Merge pull request 'build: 调整 package.json' (#1032) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1032
2025-06-12 03:29:12 +00:00
dj
1a120418f0 build: 调整 package.json 2025-06-12 11:28:25 +08:00
d3ae1c1205 Merge pull request 'build: 更新 Node.js 版本并调整 package.json 格式' (#1031) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1031
2025-06-12 03:16:06 +00:00
dj
e49b6ef1a3 build: 更新 Node.js 版本并调整 package.json 格式 2025-06-12 11:15:52 +08:00
6fbf37ab78 Merge pull request 'fix(ProjectAttachment): 修改drone' (#1030) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1030
2025-06-12 03:13:47 +00:00
dj
a0d9c58c77 fix(ProjectAttachment): 修改drone 2025-06-12 11:12:52 +08:00
b3900a2a1c Merge pull request 'fix(ProjectAttachment): 修改drone' (#1029) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1029
2025-06-12 03:08:20 +00:00
dj
4bb0c49dc8 fix(ProjectAttachment): 修改drone 2025-06-12 11:08:03 +08:00
4f6c36a20a Merge pull request 'fix(ProjectAttachment): 修改drone' (#1028) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1028
2025-06-12 02:17:12 +00:00
dj
aada3d785b fix(ProjectAttachment): 修改drone 2025-06-12 10:16:35 +08:00
fef4c57bd5 Merge pull request 'fix(ProjectAttachment): 添加依赖' (#1027) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1027
2025-06-12 02:04:22 +00:00
dj
35b332f640 fix(ProjectAttachment): 添加依赖 2025-06-12 10:03:57 +08:00
31da00d7e3 Merge pull request 'fix(ProjectAttachment): 添加依赖' (#1026) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1026
2025-06-12 01:36:07 +00:00
dj
6afac9be28 fix(ProjectAttachment): 添加依赖 2025-06-12 09:35:00 +08:00
b54289a0a5 Merge pull request 'fix(ProjectAttachment): 修改drone.yml' (#1025) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1025
2025-06-12 01:28:38 +00:00
dj
dc064de364 fix(ProjectAttachment): 修改drone.yml 2025-06-12 09:28:02 +08:00
7f656447b2 Merge pull request 'fix(ProjectAttachment): 修改drone.yml' (#1024) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1024
2025-06-12 01:25:35 +00:00
dj
78bafe0a7e fix(ProjectAttachment): 修改drone.yml 2025-06-12 09:24:29 +08:00
ddf5159fbc Merge pull request 'master' (#1023) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1023
2025-06-11 14:49:29 +00: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
418effdb04 Merge pull request 'feat(expense-management): 添加研发工时超过21.75天的提示功能' (#1022) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1022
2025-06-09 14:28:50 +00:00
dj
215f7c6bbf feat(expense-management): 添加研发工时超过21.75天的提示功能
- 在保存分配明细时,增加对研发人员总工时的计算
- 如果总工时超过21.75天,系统将发出警告通知- 优化了控制台日志输出,便于调试和监控
2025-06-09 22:28:24 +08:00
57a1d2700f Merge pull request 'refactor(expense-management): 注释掉研发人员重复性检查代码' (#1021) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1021
2025-06-08 15:11:01 +00:00
dj
e4025b90e9 refactor(expense-management): 注释掉研发人员重复性检查代码
- 在 add.vue 文件中,注释掉了两段用于检查研发人员重复性的代码
- 此修改可能是为了暂时禁用重复性检查功能,或者准备替换为新的检查逻辑
2025-06-08 23:08:02 +08:00
e44380c000 Merge pull request 'refactor(expense-management): 优化数字输入和附件处理' (#1020) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1020
2025-06-07 01:30:52 +00: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
14c6ed1168 Merge pull request 'fix : 修复归档附件bug' (#1019) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1019
2025-05-28 15:53:32 +00:00
dj
05275aed15 fix : 修复归档附件bug 2025-05-28 23:53:10 +08:00
47d5863361 Merge pull request 'fix : 修复归档附件bug' (#1018) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1018
2025-05-28 15:51:11 +00:00
dj
9758981d3f fix : 修复归档附件bug 2025-05-28 23:50:59 +08:00
a946247849 Merge pull request 'master' (#1017) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1017
2025-05-28 15:03:54 +00: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
1a38381ab8 Merge pull request 'refactor(components): 调整文件上传大小限制并优化附件展示逻辑' (#1016) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1016
2025-05-23 01:08:02 +00:00
dj
f61d50dbfc refactor(components): 调整文件上传大小限制并优化附件展示逻辑 2025-05-23 09:07:02 +08:00
f5b9339b36 Merge pull request 'fix(ProjectAttachment): 重新获取附件列表' (#1015) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1015
2025-05-22 15:09:20 +00:00
dj
66dc6df0d9 fix(ProjectAttachment): 重新获取附件列表
在删除附件后,添加了重新获取附件列表的调用,以确保界面上的附件列表是最新的。
2025-05-22 23:08:27 +08:00
a3c7439a7f Merge pull request 'fix(ProjectAttachment): 修复删除附件后未及时更新文件列表的问题- 在删除文件后添加了更新文件列表的逻辑' (#1014) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1014
2025-05-22 14:57:02 +00:00
dj
c7329f2f6d fix(ProjectAttachment): 修复删除附件后未及时更新文件列表的问题- 在删除文件后添加了更新文件列表的逻辑
- 优化了获取本地文件列表的方法
- 调整了文件列表的初始化位置
2025-05-22 22:56:06 +08:00
59699b6118 Merge pull request 'feat(ProjectAttachment): 优化文件上传和管理功能' (#1013) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1013
2025-05-22 08:46:46 +00:00
dj
673e4fa20a feat(ProjectAttachment): 优化文件上传和管理功能
- 新增本地存储功能,暂存未提交的文件
- 优化文件删除逻辑,区分本地和服务器文件
- 添加提交按钮,将本地文件上传到服务器
- 调整标签切换时的文件列表显示逻辑
- 优化代码结构,提高可读性和可维护性
2025-05-22 16:45:58 +08:00
eb2a5581ca Merge pull request 'refactor(project-demand): 优化方案总结提交逻辑' (#1012) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1012
2025-05-22 02:09:05 +00:00
dj
ee5fc2cba3 refactor(project-demand): 优化方案总结提交逻辑
- 移除了不必要的空数组初始化
-简化了 requirementId 的赋值逻辑
- 添加了空行以提高代码可读性
2025-05-22 10:06:44 +08:00
952884a7fe Merge pull request 'fix(project-demand): 修复专项经费选择框逻辑' (#1011) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1011
2025-05-21 15:17:49 +00:00
dj
b7ca97696a fix(project-demand): 修复专项经费选择框逻辑
- 修改了专项经费选择逻辑,确保在选择专项经费时正确处理 specialFund 和 specialFundId 的值
- 优化了代码结构,提高了可读性和维护性
2025-05-21 23:14:00 +08:00
6ba9fa4bee Merge pull request 'master' (#1010) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1010
2025-05-21 14:39:55 +00: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
8a218ad270 Merge pull request 'feat(project-demand): 编辑概览页面数据持久化' (#1009) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1009
2025-05-21 06:31:54 +00:00
dj
287d6a3ad0 feat(project-demand): 编辑概览页面数据持久化 2025-05-21 14:31:38 +08:00
9813f8c585 Merge pull request 'fix(project-demand): 修复专项基金选择问题' (#1008) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1008
2025-05-21 04:55:59 +00:00
dj
673a26368a fix(project-demand): 修复专项基金选择问题 2025-05-21 12:55:23 +08:00
9b90dbc649 Merge pull request 'feat(ProjectApply): 科技处用户申请项目时增加部门分管领导必选项' (#1007) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1007
2025-05-19 14:13:55 +00:00
dj
9adea1060c feat(ProjectApply): 科技处用户申请项目时增加部门分管领导必选项 2025-05-19 22:13:03 +08:00
4f471494cc Merge pull request 'refactor(permission): 优化面包屑控制逻辑' (#1006) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1006
2025-05-16 10:15:13 +00:00
dj
4e5a4bb4b9 refactor(permission): 优化面包屑控制逻辑 2025-05-16 18:14:31 +08:00
b4d6d97e27 Merge pull request 'fix : 修复需求上报缓存问题' (#1005) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1005
2025-05-15 08:06:29 +00:00
dj
a5ebab16a6 fix : 修复需求上报缓存问题 2025-05-15 16:06:04 +08:00
6ad76d1571 Merge pull request 'master' (#1004) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1004
2025-05-05 12:15:31 +00: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
df99acd638 Merge pull request 'fix : 修复公告问题' (#1003) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1003
2025-04-29 03:29:31 +00:00
dj
af275ea6c4 fix : 修复公告问题 2025-04-29 11:29:06 +08:00
68830daab3 Merge pull request 'master' (#1002) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1002
2025-04-27 06:29:31 +00:00
dj
c27162f918 feat : 项目归档-实施附件 2025-04-27 14:28:59 +08:00
dj
f1b81d86a2 fix : 备份附件 2025-04-27 11:00:38 +08:00
0c24d2cf51 Merge pull request 'fix : 修复单位元' (#1001) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1001
2025-04-24 13:48:41 +00:00
dj
710ccbdf65 fix : 修复单位元 2025-04-24 21:48:23 +08:00
7001261f01 Merge pull request 'refactor(project-management): 统一经费预算单位' (#1000) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/1000
2025-04-24 07:30:38 +00:00
dj
7fcfc992fb refactor(project-management): 统一经费预算单位
- 在多个组件中将"预估经费预算"和"实际经费预算"的标签添加单位"(元)"
-调整部分组件的标签宽度以适应新的单位
- 此修改统一了经费预算的显示格式,提高了用户体验
2025-04-24 15:30:14 +08:00
b7be0a34ae Merge pull request 'feat(components): 增加审核意见必填校验' (#999) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/999
2025-04-23 14:47:41 +00:00
dj
a792df80e6 feat(components): 增加审核意见必填校验 2025-04-23 22:46:58 +08:00
b56e5b3544 Merge pull request 'fix : 标签不可编辑' (#998) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/998
2025-04-20 12:32:35 +00:00
dj
5dccaa1ee7 fix : 标签不可编辑 2025-04-20 20:32:16 +08:00
6aa074bfa3 Merge pull request 'feat : 项目验收新增字段' (#997) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/997
2025-04-20 11:50:58 +00:00
dj
8aefca0c82 feat : 项目验收新增字段 2025-04-20 19:49:57 +08:00
e518791ddd Merge pull request 'master' (#996) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/996
2025-04-20 06:44:18 +00: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
2ed2cae599 Merge pull request 'fix : 注释立项提交的前置流程' (#995) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/995
2025-04-19 05:43:49 +00:00
dj
958399a32a fix : 注释立项提交的前置流程 2025-04-19 13:43:36 +08:00
745971087c Merge pull request 'fix : 完善需求上报字段页面' (#994) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/994
2025-04-19 02:58:46 +00:00
dj
8ea916c206 fix : 完善需求上报字段页面 2025-04-19 10:58:28 +08:00
e0aefecf50 Merge pull request 'fix: 修复审批白名单中取消事件' (#993) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/993
2025-04-18 14:52:27 +00:00
dj
10e9c9de19 fix: 修复审批白名单中取消事件 2025-04-18 22:51:49 +08:00
950b32270b Merge pull request 'master' (#992) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/992
2025-04-18 14:40:16 +00: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
c17149235f Merge pull request 'fix: 编辑上报时主项目选项过滤当前项目' (#991) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/991
2025-04-15 16:00:21 +00:00
dj
fda0f4fcde fix: 编辑上报时主项目选项过滤当前项目 2025-04-15 23:56:05 +08:00
560485f255 Merge pull request 'style(article-management): 优化附件列表样式' (#990) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/990
2025-04-15 15:31:31 +00:00
dj
2847c88c61 style(article-management): 优化附件列表样式
- 在 add.vue 和 detail.vue 中为附件列表项添加底部间距,提升可读性
- 保持附件列表样式在不同页面中的一致性
2025-04-15 23:29:30 +08:00
5611fd9f02 Merge pull request 'feat: 费用导入功能' (#989) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/989
2025-04-15 15:14:57 +00:00
dj
2827c5ace6 feat: 费用导入功能 2025-04-15 23:14:46 +08:00
750a4c8178 Merge pull request 'fix: 注释公告附件列表相关代码' (#988) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/988
2025-04-15 14:34:01 +00:00
dj
9941fc14f6 fix: 注释公告附件列表相关代码 2025-04-15 22:33:38 +08:00
8b94f044db Merge pull request 'feat: 抄送成功后刷新功能' (#987) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/987
2025-04-15 03:15:54 +00:00
dj
c71208c3e4 feat: 抄送成功后刷新功能 2025-04-15 11:15:15 +08:00
b2fb3fbb67 Merge pull request 'feat: 项目详情审批流程加立即抄送按钮' (#986) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/986
2025-04-15 02:41:27 +00:00
dj
7e6b48b62a feat: 项目详情审批流程加立即抄送按钮 2025-04-15 10:40:52 +08:00
4aa0b093bb Merge pull request 'fix: 修复附件上传和展示问题' (#985) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/985
2025-04-14 13:20:20 +00:00
dj
e77820e145 fix: 修复附件上传和展示问题 2025-04-14 21:19:55 +08:00
66d2c3c7cf Merge pull request 'master' (#984) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/984
2025-04-14 13:19:48 +00: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
4f3a8550eb Merge pull request 'master' (#983) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/983
2025-04-11 06:09:41 +00: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
5ea25ae8ae Merge pull request 'fix: 修复附件上传和展示问题' (#982) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/982
2025-04-09 15:11:29 +00:00
dj
810757e828 fix: 修复附件上传和展示问题 2025-04-09 23:11:06 +08:00
e82c6e2316 Merge pull request 'master' (#981) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/981
2025-04-09 04:59:16 +00: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
da69cb4dba Merge pull request 'master' (#980) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/980
2025-04-09 02:59:02 +00: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
375a678fc3 Merge pull request 'master' (#978) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/978
2025-04-09 01:42:30 +00: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
c213b3b41c Merge pull request 'master' (#976) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/976
2025-04-08 16:24:02 +00: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
382bad4cb3 Merge pull request 'master' (#973) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/973
2025-04-08 16:14:37 +00: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
8f5b9fc637 Merge pull request 'fix: 分摊明细导出调整参数' (#972) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/972
2025-04-07 16:30:53 +00:00
dj
7b619a9bef fix: 分摊明细导出调整参数 2025-04-08 00:30:32 +08:00
f33543c540 Merge pull request 'fix: 优化首页通知公告样式' (#971) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/971
2025-04-07 13:57:40 +00:00
dj
a9a2be2c74 fix: 优化首页通知公告样式 2025-04-07 21:57:13 +08:00
3160e86710 Merge pull request 'fix: 优化移动端项目管理功能' (#970) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/970
2025-04-06 14:38:30 +00:00
dj
a307697028 fix: 优化移动端项目管理功能 2025-04-06 22:38:14 +08:00
062f9c7bee Merge pull request 'feat(article-management): 首页通知公告加时间, 将"备注"字段改为"发文单位"' (#969) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/969
2025-04-06 13:26:05 +00:00
dj
e8a5b4e788 feat(article-management): 首页通知公告加时间, 将"备注"字段改为"发文单位" 2025-04-06 21:25:30 +08:00
da9624663e Merge pull request 'master' (#968) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/968
2025-04-06 09:11:03 +00: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
b84c2ce131 Merge pull request 'feat(project-management): 优化文件归档表格状态展示和权限控制' (#966) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/966
2025-04-02 16:34:20 +00:00
dj
348027f355 feat(project-management): 优化文件归档表格状态展示和权限控制 2025-04-03 00:34:04 +08:00
579f2777cf Merge pull request 'master' (#965) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/965
2025-04-02 16:11:32 +00: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
011566cb22 Merge pull request 'feat(ProjectAttachment): 添加文件下载功能' (#964) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/964
2025-04-02 15:37:56 +00:00
dj
bf34d8aa0c feat(ProjectAttachment): 添加文件下载功能 2025-04-02 23:34:45 +08:00
7f3fedc2f2 Merge pull request 'master' (#963) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/963
2025-04-02 15:28:05 +00: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
f0fe6c8269 Merge pull request 'master' (#961) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/961
2025-04-01 16:06:06 +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
09705e634a Merge pull request 'feat(expense-management): 新增费用分摊功能并优化项目管理相关页面' (#960) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/960
2025-04-01 15:58:33 +00:00
dj
1e29e6bdc4 feat(expense-management): 新增费用分摊功能并优化项目管理相关页面 2025-04-01 23:57:46 +08:00
e49d8cfb5e Merge pull request 'master' (#959) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/959
2025-04-01 10:19:27 +00: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
ef9a536b5c Merge pull request 'master' (#957) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/957
2025-03-31 15:16:40 +00: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
fe09ced0bc Merge pull request 'master' (#954) from master into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/954
2025-03-25 06:37:02 +00: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
zhangkaihuai
023256630e 更新 Dockerfile 2025-03-19 12:24:06 +00:00
zhangkaihuai
f65663071a 更新 nginx.conf 2025-03-19 12:13:31 +00:00
zhangkaihuai
9a55494da7 更新 nginx.conf 2025-03-19 08:07:37 +00:00
zhangkaihuai
d5a07e772f 更新 nginx.conf 2025-03-19 07:55:07 +00:00
zhangkaihuai
42499bcb22 更新 nginx.conf 2025-03-19 07:40:27 +00:00
zhangkaihuai
0243d6fc56 Merge pull request '更新 nginx.conf' (#952) from gary into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/952
2025-03-19 07:34:21 +00:00
zhangkaihuai
78435bbcac Merge pull request 'gary' (#951) from gary into prod
Reviewed-on: http://git.feashow.cn/clay/mosr-web/pulls/951
2025-03-19 07:32:49 +00:00
338 changed files with 62439 additions and 58094 deletions

View File

@@ -1,41 +1,41 @@
### Java template
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Maven template
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
### Example user template template
### Example user template
# IntelliJ project files
.idea
*.iml
out
gen
!build
!default.conf
!nginx.conf
### Java template
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Maven template
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
### Example user template template
### Example user template
# IntelliJ project files
.idea
*.iml
out
gen
!build
!default.conf
!nginx.conf

View File

@@ -8,7 +8,7 @@ steps:
- name: build-package
image: node:16.20.0
image: node:18.19.0
volumes:
- name: cache
path: /drone/src/node_modules
@@ -23,11 +23,18 @@ steps:
- cp docker.sh /app/build/$DRONE_REPO_NAME/
- cp nginx.conf /app/build/$DRONE_REPO_NAME/
- npm -v
- node -v
- mkdir -p ./node_modules
- export NODE_MODULES_PATH=`pwd`/node_modules
- npm config set registry https://registry.npmmirror.com
- set NODE_OPTIONS=--openssl-legacy-provider
- npm install
- npm install --legacy-peer-deps
- npm install codemirror
# - npm install patch-package
# - npx patch-package
# - npm info unplugin-icons
- npm list package-manager-detector
# - npm install unplugin-icons@latest @antfu/install-pkg@latest package-manager-detector@latest
- npm run build
- ls /app/build/$DRONE_REPO_NAME/
- echo $NODE_MODULES_PATH

View File

@@ -1,2 +1,2 @@
# 开发环境基地址
VITE_BASE_URL='/api'
# 开发环境基地址
VITE_BASE_URL='/api'

View File

@@ -1,3 +1,3 @@
# 生产环境基地址
VITE_BASE_URL='/api'
# 生产环境基地址
VITE_BASE_URL='/api'

56
.gitignore vendored
View File

@@ -1,28 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -1,19 +1,19 @@
FROM 10.7.127.190:38080/nginx:latest
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
#USER clay
COPY ./dist /home/clay
WORKDIR /home/clay
EXPOSE 80
FROM 10.7.127.190:38080/nginx:latest
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
#USER clay
COPY ./dist /home/clay
WORKDIR /home/clay
EXPOSE 80

View File

@@ -1,2 +1,2 @@
# 科技创新项目管理平台
# 科技创新项目管理平台

View File

@@ -1,19 +1,19 @@
server {
listen 80;
listen [::]:80;
location /api {
proxy_pass http://gateway.dev.svc.cluster.local:8080;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
#proxy_set_header Host $host;
rewrite "^/api/(.*)$" /$1 break;
}
location / {
root /home/clay;
index index.html index.htm;
}
}
server {
listen 80;
listen [::]:80;
location /api {
proxy_pass http://gateway.dev.svc.cluster.local:8080;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
#proxy_set_header Host $host;
rewrite "^/api/(.*)$" /$1 break;
}
location / {
root /home/clay;
index index.html index.htm;
}
}

View File

@@ -1,51 +1,51 @@
apiVersion: v1
kind: Service
metadata:
name: $DRONE_REPO_NAME
spec:
type: NodePort
ports:
- name: $PORTS_NAME
nodePort: $PORTS_PORT
port: 80
protocol: TCP
targetPort: 80
selector:
app: $DRONE_REPO_NAME
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: $DRONE_REPO_NAME
spec:
replicas: 1
selector:
matchLabels:
app: $DRONE_REPO_NAME
template:
metadata:
labels:
app: $DRONE_REPO_NAME
spec:
imagePullSecrets:
- name: harbor
containers:
- image: $REGISTRY/$REGISTRY_NAMESPACE/$DRONE_REPO_NAME:$DRONE_COMMIT
name: $DRONE_REPO_NAME
imagePullPolicy: Always
env:
- name: TIME_ZONE
value: Asia/Shanghai
- name: REF_NAME
value: dev
resources:
requests:
memory: 0.1Gi
cpu: 0.1
limits:
memory: 2Gi
cpu: 2
ports:
- containerPort: 80
name: app-port
apiVersion: v1
kind: Service
metadata:
name: $DRONE_REPO_NAME
spec:
type: NodePort
ports:
- name: $PORTS_NAME
nodePort: $PORTS_PORT
port: 80
protocol: TCP
targetPort: 80
selector:
app: $DRONE_REPO_NAME
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: $DRONE_REPO_NAME
spec:
replicas: 1
selector:
matchLabels:
app: $DRONE_REPO_NAME
template:
metadata:
labels:
app: $DRONE_REPO_NAME
spec:
imagePullSecrets:
- name: harbor
containers:
- image: $REGISTRY/$REGISTRY_NAMESPACE/$DRONE_REPO_NAME:$DRONE_COMMIT
name: $DRONE_REPO_NAME
imagePullPolicy: Always
env:
- name: TIME_ZONE
value: Asia/Shanghai
- name: REF_NAME
value: dev
resources:
requests:
memory: 0.1Gi
cpu: 0.1
limits:
memory: 2Gi
cpu: 2
ports:
- containerPort: 80
name: app-port

View File

@@ -8,6 +8,7 @@ app_version=$DRONE_COMMIT
echo ${app_version}
# 打包编译docker镜像
echo '----build image start----'
echo ${group_name}/${app_name}
docker build -t ${group_name}/${app_name} .
echo '----build image success----'
docker tag ${group_name}/${app_name} $REGISTRY/$REGISTRY_NAMESPACE/${app_name}:${app_version}

View File

@@ -1,13 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>科技创新项目管理平台</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>科技创新项目管理平台</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

View File

@@ -1,72 +1,72 @@
-----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-----
-----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

@@ -1,74 +1,52 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Headers' '*';
add_header 'Access-Control-Allow-Methods' '*';
access_log /var/log/nginx/access.log main;
sendfile on;
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;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Host $host;
rewrite "^/api/(.*)$" /$1 break;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
client_max_body_size 30m;
}
location / {
root /home/clay;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
}
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Headers' '*';
add_header 'Access-Control-Allow-Methods' '*';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
listen [::]:80;
location /api {
proxy_pass http://gateway.$PROFILES.svc.cluster.local:8080;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Host $host;
rewrite "^/api/(.*)$" /$1 break;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
client_max_body_size 30m;
}
location / {
root /home/clay;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
}

View File

@@ -1,53 +1,59 @@
{
"name": "mosr-web",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@antv/g6": "^3.5.7",
"@tinymce/tinymce-vue": "^4.0.7",
"axios": "^1.4.0",
"d3": "^7.8.5",
"docx-preview": "^0.3.2",
"echarts": "^5.4.2",
"element-plus": "^2.6.0",
"file-saver": "^2.0.5",
"highlight.js": "9.18.5",
"jquery": "^3.6.0",
"js-cookie": "^3.0.5",
"nprogress": "^0.2.0",
"pinia": "^2.0.35",
"sass": "^1.62.1",
"scss": "^0.2.4",
"sql-formatter": "^2.3.4",
"tinymce": "^5.0.4",
"unplugin-icons": "^0.16.1",
"vite-plugin-inspect": "^0.7.26",
"vue": "^3.2.47",
"vue-clipboard3": "^2.0.0",
"vue-codemirror": "^6.1.1",
"vue-json-viewer": "^3.0.4",
"vue-router": "^4.1.6",
"vue3-pdf-app": "^1.0.3",
"vue3-print-nb": "^0.1.4",
"vuedraggable": "^4.1.0",
"xlsx": "^0.18.5",
"xlsx-style-vite": "^0.0.2"
},
"devDependencies": {
"@codemirror/lang-java": "^6.0.1",
"@codemirror/lang-javascript": "^6.1.9",
"@codemirror/lang-sql": "^6.5.4",
"@vitejs/plugin-vue": "^4.2.1",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"lodash": "^4.17.21",
"unplugin-auto-import": "^0.15.3",
"unplugin-vue-components": "^0.24.1",
"vite": "^4.3.4",
"vite-plugin-svg-icons": "^0.4.0"
}
}
{
"name": "mosr-web",
"version": "0.0.0",
"type": "module",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build --config vite.config.mjs",
"preview": "vite preview"
},
"overrides": {
"package-manager-detector": "1.0.0",
"@iconify/utils": "2.2.1"
},
"dependencies": {
"@antv/g6": "^3.5.7",
"@tinymce/tinymce-vue": "^4.0.7",
"axios": "^1.4.0",
"d3": "^7.8.5",
"docx-preview": "^0.3.2",
"echarts": "^5.4.2",
"element-plus": "^2.6.0",
"file-saver": "^2.0.5",
"highlight.js": "9.18.5",
"jquery": "^3.6.0",
"js-cookie": "^3.0.5",
"nprogress": "^0.2.0",
"pinia": "^2.0.35",
"sass": "^1.62.1",
"scss": "^0.2.4",
"sql-formatter": "^2.3.4",
"tinymce": "^5.0.4",
"unplugin-icons": "^0.16.1",
"vite-plugin-inspect": "^0.7.26",
"vue": "^3.2.47",
"vue-clipboard3": "^2.0.0",
"vue-codemirror": "^6.1.1",
"vue-json-viewer": "^3.0.4",
"vue-router": "^4.1.6",
"vue3-pdf-app": "^1.0.3",
"vue3-print-nb": "^0.1.4",
"vuedraggable": "^4.1.0",
"xlsx": "^0.18.5",
"xlsx-style-vite": "^0.0.2"
},
"devDependencies": {
"@codemirror/lang-java": "^6.0.1",
"@codemirror/lang-javascript": "^6.1.9",
"@codemirror/lang-sql": "^6.5.4",
"@vitejs/plugin-vue": "^4.2.1",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"lodash": "^4.17.21",
"unplugin-auto-import": "^0.15.3",
"unplugin-vue-components": "^0.24.1",
"vite": "^4.3.4",
"vite-plugin-svg-icons": "^0.4.0"
}
}

View File

@@ -1,28 +1,28 @@
-----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-----
-----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-----

File diff suppressed because one or more lines are too long

View File

@@ -1,61 +1,61 @@
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 1.4;
margin: 1rem;
}
table {
border-collapse: collapse;
}
/* Apply a default padding if legacy cellpadding attribute is missing */
table:not([cellpadding]) th,
table:not([cellpadding]) td {
padding: 0.4rem;
}
/* Set default table styles if a table has a positive border attribute
and no inline css */
table[border]:not([border="0"]):not([style*="border-width"]) th,
table[border]:not([border="0"]):not([style*="border-width"]) td {
border-width: 1px;
}
/* Set default table styles if a table has a positive border attribute
and no inline css */
table[border]:not([border="0"]):not([style*="border-style"]) th,
table[border]:not([border="0"]):not([style*="border-style"]) td {
border-style: solid;
}
/* Set default table styles if a table has a positive border attribute
and no inline css */
table[border]:not([border="0"]):not([style*="border-color"]) th,
table[border]:not([border="0"]):not([style*="border-color"]) td {
border-color: #ccc;
}
figure {
display: table;
margin: 1rem auto;
}
figure figcaption {
color: #999;
display: block;
margin-top: 0.25rem;
text-align: center;
}
hr {
border-color: #ccc;
border-style: solid;
border-width: 1px 0 0 0;
}
code {
background-color: #e8e8e8;
border-radius: 3px;
padding: 0.1rem 0.2rem;
}
.mce-content-body:not([dir=rtl]) blockquote {
border-left: 2px solid #ccc;
margin-left: 1.5rem;
padding-left: 1rem;
}
.mce-content-body[dir=rtl] blockquote {
border-right: 2px solid #ccc;
margin-right: 1.5rem;
padding-right: 1rem;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 1.4;
margin: 1rem;
}
table {
border-collapse: collapse;
}
/* Apply a default padding if legacy cellpadding attribute is missing */
table:not([cellpadding]) th,
table:not([cellpadding]) td {
padding: 0.4rem;
}
/* Set default table styles if a table has a positive border attribute
and no inline css */
table[border]:not([border="0"]):not([style*="border-width"]) th,
table[border]:not([border="0"]):not([style*="border-width"]) td {
border-width: 1px;
}
/* Set default table styles if a table has a positive border attribute
and no inline css */
table[border]:not([border="0"]):not([style*="border-style"]) th,
table[border]:not([border="0"]):not([style*="border-style"]) td {
border-style: solid;
}
/* Set default table styles if a table has a positive border attribute
and no inline css */
table[border]:not([border="0"]):not([style*="border-color"]) th,
table[border]:not([border="0"]):not([style*="border-color"]) td {
border-color: #ccc;
}
figure {
display: table;
margin: 1rem auto;
}
figure figcaption {
color: #999;
display: block;
margin-top: 0.25rem;
text-align: center;
}
hr {
border-color: #ccc;
border-style: solid;
border-width: 1px 0 0 0;
}
code {
background-color: #e8e8e8;
border-radius: 3px;
padding: 0.1rem 0.2rem;
}
.mce-content-body:not([dir=rtl]) blockquote {
border-left: 2px solid #ccc;
margin-left: 1.5rem;
padding-left: 1rem;
}
.mce-content-body[dir=rtl] blockquote {
border-right: 2px solid #ccc;
margin-right: 1.5rem;
padding-right: 1rem;
}

View File

@@ -1 +1 @@
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,211 +1,211 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>axupimgs</title>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="format-detection" content="telephone=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<style>
html,body{height:100%;margin:0;padding:0;background:#fff;}
ul{margin:0;padding:0;list-style:none;}
#wrap{padding:10px;}
#topbar{padding:10px 0;border-bottom:1px solid #ccc;text-align:right;}
#topbar button {margin:0;margin-left:5px;outline:none;padding: 4px 16px;box-sizing: border-box;
display:inline-block;border:none;border-radius:3px;text-align:center;cursor:pointer;
font-size:14px;line-height:1.5;background-color:#f0f0f0;color:#223;
}
#topbar button.primary{background-color:#3d97d4;color:#fff;}
#topbar button:hover{background-color:#207ab7;color:#fff;}
#topbar button.removeall{float:left}
#file_list {display:grid;grid-gap:10px;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));padding-top:10px;}
#file_list:empty:after{content:'可以直接拖拽文件到这里';color:#777;font-size:0.8em;}
#file_list li{position:relative;display:block;vertical-align:top;padding:5px 5px;border-radius:5px;}
#file_list li.up-over {}
#file_list li.up-now {}
#file_list li.up-now:after{content:'';position:absolute;top:0;left:0;display:block;width:100%;height:100%;background:rgba(255,255,255,0.8) url(loading.gif) center center no-repeat;border-radius:5px;z-index:999;}
#file_list li:hover{background-color:#ddd;}
#file_list li .picbox {display:flex;flex:0 0 auto;justify-content:center;overflow:hidden;position:relative;width:100%;padding-top:100%;align-items:center;}
#file_list li .picbox img {display:block;max-width:100%;max-height:100%;position:absolute;
top:50%;left:50%;transform:translateX(-50%) translateY(-50%);}
#file_list li.up-over .picbox:after{content:url('data:image/svg+xml;%20charset=utf8,%3Csvg%20viewBox%3D%220%200%201024%201024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M512%200C229.376%200%200%20229.376%200%20512s229.376%20512%20512%20512%20512-229.376%20512-512S794.624%200%20512%200z%22%20fill%3D%22%234AC711%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M855.552%20394.752l-358.4%20358.4a50.9952%2050.9952%200%200%201-72.192%200l-204.8-204.8c-18.944-19.968-18.944-51.2%200-71.168a50.5344%2050.5344%200%200%201%2072.192-1.024L460.8%20644.608l322.048-322.048c19.968-18.944%2051.2-18.944%2071.168%200%2020.48%2019.456%2020.992%2051.712%201.536%2072.192z%22%20fill%3D%22%23FFFFFF%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');position:absolute;bottom:2px;right:2px;z-index:9;}
#file_list li .tools {display:none;position:absolute;bottom:5px;right:5px;z-index:99;}
#file_list li:hover .tools {display:block;}
#file_list li .tools .remove{cursor:pointer;}
#file_list li .tools .remove:after{content:url('data:image/svg+xml;%20charset=utf8,%3Csvg%20width=%2224%22%20height=%2224%22%20viewBox=%220%200%2024%2024%22%20xmlns=%22http://www.w3.org/2000/svg%22%3E%3Cpath%20d=%22M17%206h3a1%201%200%200%201%200%202h-1v11a3%203%200%200%201-3%203H8a3%203%200%200%201-3-3V8H4a1%201%200%201%201%200-2h3V5a3%203%200%200%201%203-3h4a3%203%200%200%201%203%203v1zm-2%200V5a1%201%200%200%200-1-1h-4a1%201%200%200%200-1%201v1h6zm2%202H7v11a1%201%200%200%200%201%201h8a1%201%200%200%200%201-1V8zm-8%203a1%201%200%200%201%202%200v6a1%201%200%200%201-2%200v-6zm4%200a1%201%200%200%201%202%200v6a1%201%200%200%201-2%200v-6z%22%3E%3C/path%3E%3C/svg%3E');}
#file_list li .namebox {font-size:14px;line-height:20px;max-height:40px;overflow:hidden;padding:5px 10px;text-align:center;display:flex;justify-content:center;align-items:flex-start;}
#file_list li .namebox span{word-break:break-all;vertical-align:top;}
</style>
</head>
<body>
<div id="wrap">
<div id="topbar"><button class="addfile primary">+ 添加文件</button><button class="removeall">清空列表</button></div>
<ul id="file_list"></ul>
</div>
<script>
var editor=parent.tinymce.activeEditor;
var axupimgs=parent.axupimgs;
axupimgs.res = []; //存放本地文件的数组
var blobInfo = {file:null}
blobInfo.blob = function(){return this.file;}
var upload_handler = axupimgs.images_upload_handler;
var upload_base_path = axupimgs.images_upload_base_path;
//为列表添加排序
function reSort(){
document.querySelectorAll('#file_list li').forEach((el,i)=>{
el.setAttribute('data-num',i);
});
}
function addList(files){
var files_sum = files.length;
var vDom = document.createDocumentFragment();
for(let i=0;i<files_sum;i++){
let file = files[i];
let blobUrl = window.URL.createObjectURL(file)
axupimgs.res.push({file:file,blobUrl:blobUrl,url:''});
let li = document.createElement('li');
li.setAttribute('class','up-no');
li.setAttribute('data-time',file.lastModified);
li.innerHTML='<div class="picbox"><img src="'+blobUrl+'"></div><div class="namebox"><span>'+file.name+'</span></div><div class="tools"><a class="remove"></a></div>';
vDom.appendChild(li);
}
document.querySelector('#file_list').appendChild(vDom);
if(axupimgs.res.length>0){
document.querySelectorAll('#file_list li.up-no').forEach((el,i)=>{
el.classList ? el.classList.add('up-now') : el.className+=' up-now';
});
upAllFiles(0);
}
//reSort();
}
//清空列表
document.querySelector('#topbar .removeall').addEventListener('click',()=>{
axupimgs.res=[]
document.querySelectorAll('#file_list li').forEach((el,i)=>{
el.parentNode.removeChild(el)
});
});
//拖拽添加
document.addEventListener('dragover', (e)=>{
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
});
document.addEventListener('drop', (e)=>{
e.stopPropagation();
e.preventDefault();
if(!e.dataTransfer.files){return false;}
var dropfiles = e.dataTransfer.files;
if(!(dropfiles.length>0)){return false;}
var exts=axupimgs.axupimgs_filetype.replace(/(\s)+/g,'').toLowerCase().split(',');
var files=[];
for( let file of dropfiles ){
ext = file.name.split('.');
ext = '.'+ext[ext.length-1];
for(let s of exts){
if(s==ext){
files.push(file);
break;
}
}
}
if(files.length>0){ addList(files) }
});
//添加文件
document.querySelector('#topbar .addfile').addEventListener('click',()=>{
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('multiple', 'multiple');
input.setAttribute('accept', axupimgs.axupimgs_filetype);
input.click();
input.onchange = function() {
var files = this.files;
addList(files);
}
});
var file_i = 0;
function upAllFiles(n){
var len = axupimgs.res.length;
file_i = n;
if(len == n){
file_i=0;
// document.querySelector('#topbar .upall').innerText='全部上传';
return true;
}
if( axupimgs.res[n].url!='' ){
n++;
upAllFiles(n)
}else{
blobInfo.file=axupimgs.res[n].file;
upload_handler(blobInfo,function(url,name){
if(upload_base_path){
if(upload_base_path.slice(-1)=='/' && url.substr(0,1)=='/' ){
url = upload_base_path + url.slice(1);
}else if(upload_base_path.slice(-1)!='/' && url.substr(0,1)!='/' ){
url = upload_base_path + '/' + url;
}else{
url = upload_base_path + url;
}
}
axupimgs.res[file_i].url = url;
// filename = url.split('/').pop();
filename = name
var li = document.querySelectorAll('#file_list li')[file_i];
li.setAttribute('class','up-over');
li.querySelector('.namebox span').innerText = filename;
n++
upAllFiles(n);
},function(err){
// document.querySelector('#topbar .upall').innerText='全部上传';
// document.querySelectorAll('#file_list li.up-now').forEach((el,i)=>{
// el.setAttribute('class','up-no');
// });
// alert(err);
});
}
}
//
// document.querySelector('#topbar .upall').addEventListener('click',(e)=>{
// if(e.target.innerText!='全部上传'){return false;}
// if(axupimgs.res.length>0){
// document.querySelectorAll('#file_list li.up-no').forEach((el,i)=>{
// el.classList ? el.classList.add('up-now') : el.className+=' up-now';
// });
// e.target.innerText='上传中...';
// upAllFiles(0);
// }
// });
var observ_flist = new MutationObserver( (muList,observe)=>{
if(muList[0].addedNodes.length>0){
muList[0].addedNodes.forEach((el)=>{
el.querySelector('.remove').addEventListener('click',(e)=>{
var li = e.target.parentNode.parentNode;
var n = li.getAttribute('data-num');
var el = document.querySelectorAll('#file_list li')[n];
el.parentNode.removeChild(el);
axupimgs.res.splice(n,1);
});
});
}
reSort();
});
observ_flist.observe(document.querySelector('#file_list'),{childList:true});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>axupimgs</title>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="format-detection" content="telephone=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<style>
html,body{height:100%;margin:0;padding:0;background:#fff;}
ul{margin:0;padding:0;list-style:none;}
#wrap{padding:10px;}
#topbar{padding:10px 0;border-bottom:1px solid #ccc;text-align:right;}
#topbar button {margin:0;margin-left:5px;outline:none;padding: 4px 16px;box-sizing: border-box;
display:inline-block;border:none;border-radius:3px;text-align:center;cursor:pointer;
font-size:14px;line-height:1.5;background-color:#f0f0f0;color:#223;
}
#topbar button.primary{background-color:#3d97d4;color:#fff;}
#topbar button:hover{background-color:#207ab7;color:#fff;}
#topbar button.removeall{float:left}
#file_list {display:grid;grid-gap:10px;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));padding-top:10px;}
#file_list:empty:after{content:'可以直接拖拽文件到这里';color:#777;font-size:0.8em;}
#file_list li{position:relative;display:block;vertical-align:top;padding:5px 5px;border-radius:5px;}
#file_list li.up-over {}
#file_list li.up-now {}
#file_list li.up-now:after{content:'';position:absolute;top:0;left:0;display:block;width:100%;height:100%;background:rgba(255,255,255,0.8) url(loading.gif) center center no-repeat;border-radius:5px;z-index:999;}
#file_list li:hover{background-color:#ddd;}
#file_list li .picbox {display:flex;flex:0 0 auto;justify-content:center;overflow:hidden;position:relative;width:100%;padding-top:100%;align-items:center;}
#file_list li .picbox img {display:block;max-width:100%;max-height:100%;position:absolute;
top:50%;left:50%;transform:translateX(-50%) translateY(-50%);}
#file_list li.up-over .picbox:after{content:url('data:image/svg+xml;%20charset=utf8,%3Csvg%20viewBox%3D%220%200%201024%201024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M512%200C229.376%200%200%20229.376%200%20512s229.376%20512%20512%20512%20512-229.376%20512-512S794.624%200%20512%200z%22%20fill%3D%22%234AC711%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M855.552%20394.752l-358.4%20358.4a50.9952%2050.9952%200%200%201-72.192%200l-204.8-204.8c-18.944-19.968-18.944-51.2%200-71.168a50.5344%2050.5344%200%200%201%2072.192-1.024L460.8%20644.608l322.048-322.048c19.968-18.944%2051.2-18.944%2071.168%200%2020.48%2019.456%2020.992%2051.712%201.536%2072.192z%22%20fill%3D%22%23FFFFFF%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');position:absolute;bottom:2px;right:2px;z-index:9;}
#file_list li .tools {display:none;position:absolute;bottom:5px;right:5px;z-index:99;}
#file_list li:hover .tools {display:block;}
#file_list li .tools .remove{cursor:pointer;}
#file_list li .tools .remove:after{content:url('data:image/svg+xml;%20charset=utf8,%3Csvg%20width=%2224%22%20height=%2224%22%20viewBox=%220%200%2024%2024%22%20xmlns=%22http://www.w3.org/2000/svg%22%3E%3Cpath%20d=%22M17%206h3a1%201%200%200%201%200%202h-1v11a3%203%200%200%201-3%203H8a3%203%200%200%201-3-3V8H4a1%201%200%201%201%200-2h3V5a3%203%200%200%201%203-3h4a3%203%200%200%201%203%203v1zm-2%200V5a1%201%200%200%200-1-1h-4a1%201%200%200%200-1%201v1h6zm2%202H7v11a1%201%200%200%200%201%201h8a1%201%200%200%200%201-1V8zm-8%203a1%201%200%200%201%202%200v6a1%201%200%200%201-2%200v-6zm4%200a1%201%200%200%201%202%200v6a1%201%200%200%201-2%200v-6z%22%3E%3C/path%3E%3C/svg%3E');}
#file_list li .namebox {font-size:14px;line-height:20px;max-height:40px;overflow:hidden;padding:5px 10px;text-align:center;display:flex;justify-content:center;align-items:flex-start;}
#file_list li .namebox span{word-break:break-all;vertical-align:top;}
</style>
</head>
<body>
<div id="wrap">
<div id="topbar"><button class="addfile primary">+ 添加文件</button><button class="removeall">清空列表</button></div>
<ul id="file_list"></ul>
</div>
<script>
var editor=parent.tinymce.activeEditor;
var axupimgs=parent.axupimgs;
axupimgs.res = []; //存放本地文件的数组
var blobInfo = {file:null}
blobInfo.blob = function(){return this.file;}
var upload_handler = axupimgs.images_upload_handler;
var upload_base_path = axupimgs.images_upload_base_path;
//为列表添加排序
function reSort(){
document.querySelectorAll('#file_list li').forEach((el,i)=>{
el.setAttribute('data-num',i);
});
}
function addList(files){
var files_sum = files.length;
var vDom = document.createDocumentFragment();
for(let i=0;i<files_sum;i++){
let file = files[i];
let blobUrl = window.URL.createObjectURL(file)
axupimgs.res.push({file:file,blobUrl:blobUrl,url:''});
let li = document.createElement('li');
li.setAttribute('class','up-no');
li.setAttribute('data-time',file.lastModified);
li.innerHTML='<div class="picbox"><img src="'+blobUrl+'"></div><div class="namebox"><span>'+file.name+'</span></div><div class="tools"><a class="remove"></a></div>';
vDom.appendChild(li);
}
document.querySelector('#file_list').appendChild(vDom);
if(axupimgs.res.length>0){
document.querySelectorAll('#file_list li.up-no').forEach((el,i)=>{
el.classList ? el.classList.add('up-now') : el.className+=' up-now';
});
upAllFiles(0);
}
//reSort();
}
//清空列表
document.querySelector('#topbar .removeall').addEventListener('click',()=>{
axupimgs.res=[]
document.querySelectorAll('#file_list li').forEach((el,i)=>{
el.parentNode.removeChild(el)
});
});
//拖拽添加
document.addEventListener('dragover', (e)=>{
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
});
document.addEventListener('drop', (e)=>{
e.stopPropagation();
e.preventDefault();
if(!e.dataTransfer.files){return false;}
var dropfiles = e.dataTransfer.files;
if(!(dropfiles.length>0)){return false;}
var exts=axupimgs.axupimgs_filetype.replace(/(\s)+/g,'').toLowerCase().split(',');
var files=[];
for( let file of dropfiles ){
ext = file.name.split('.');
ext = '.'+ext[ext.length-1];
for(let s of exts){
if(s==ext){
files.push(file);
break;
}
}
}
if(files.length>0){ addList(files) }
});
//添加文件
document.querySelector('#topbar .addfile').addEventListener('click',()=>{
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('multiple', 'multiple');
input.setAttribute('accept', axupimgs.axupimgs_filetype);
input.click();
input.onchange = function() {
var files = this.files;
addList(files);
}
});
var file_i = 0;
function upAllFiles(n){
var len = axupimgs.res.length;
file_i = n;
if(len == n){
file_i=0;
// document.querySelector('#topbar .upall').innerText='全部上传';
return true;
}
if( axupimgs.res[n].url!='' ){
n++;
upAllFiles(n)
}else{
blobInfo.file=axupimgs.res[n].file;
upload_handler(blobInfo,function(url,name){
if(upload_base_path){
if(upload_base_path.slice(-1)=='/' && url.substr(0,1)=='/' ){
url = upload_base_path + url.slice(1);
}else if(upload_base_path.slice(-1)!='/' && url.substr(0,1)!='/' ){
url = upload_base_path + '/' + url;
}else{
url = upload_base_path + url;
}
}
axupimgs.res[file_i].url = url;
// filename = url.split('/').pop();
filename = name
var li = document.querySelectorAll('#file_list li')[file_i];
li.setAttribute('class','up-over');
li.querySelector('.namebox span').innerText = filename;
n++
upAllFiles(n);
},function(err){
// document.querySelector('#topbar .upall').innerText='全部上传';
// document.querySelectorAll('#file_list li.up-now').forEach((el,i)=>{
// el.setAttribute('class','up-no');
// });
// alert(err);
});
}
}
//
// document.querySelector('#topbar .upall').addEventListener('click',(e)=>{
// if(e.target.innerText!='全部上传'){return false;}
// if(axupimgs.res.length>0){
// document.querySelectorAll('#file_list li.up-no').forEach((el,i)=>{
// el.classList ? el.classList.add('up-now') : el.className+=' up-now';
// });
// e.target.innerText='上传中...';
// upAllFiles(0);
// }
// });
var observ_flist = new MutationObserver( (muList,observe)=>{
if(muList[0].addedNodes.length>0){
muList[0].addedNodes.forEach((el)=>{
el.querySelector('.remove').addEventListener('click',(e)=>{
var li = e.target.parentNode.parentNode;
var n = li.getAttribute('data-num');
var el = document.querySelectorAll('#file_list li')[n];
el.parentNode.removeChild(el);
axupimgs.res.splice(n,1);
});
});
}
reSort();
});
observ_flist.observe(document.querySelector('#file_list'),{childList:true});
</script>
</body>
</html>

View File

@@ -1,13 +1,13 @@
<template>
<RouterView />
</template>
<script setup>
import {usePermisstionStroe} from '@/stores/permisstion.js'
window.addEventListener('beforeunload', e=>beforeunload(e))
const beforeunload = (()=>{
const permisstionStore = usePermisstionStroe()
permisstionStore.setIsLoadRoutes(true)
permisstionStore.setIsSuccessReq()
})
</script>
<template>
<RouterView />
</template>
<script setup>
import {usePermisstionStroe} from '@/stores/permisstion.js'
window.addEventListener('beforeunload', e=>beforeunload(e))
const beforeunload = (()=>{
const permisstionStore = usePermisstionStroe()
permisstionStore.setIsLoadRoutes(true)
permisstionStore.setIsSuccessReq()
})
</script>

View File

@@ -1,36 +1,36 @@
import request from '@/utils/request.js'
export const getArticle = (params) => {
return request({
url: '/workflow/mosr/article/list',
method: "get",
params
});
};
export const getArticleDetail = (articleId) => {
return request({
url: `/workflow/mosr/article/${articleId}`,
method: "get"
});
};
export const addArticle= (data) => {
return request({
url: '/workflow/mosr/article/add',
method: "post",
data
});
};
export const editArticle= (data) => {
return request({
url: '/workflow/mosr/article/update',
method: "post",
data
});
};
export const deleteArticle = (articleIds) => {
return request({
url: `/workflow/mosr/article/${articleIds}`,
method: "delete"
});
};
import request from '@/utils/request.js'
export const getArticle = (params) => {
return request({
url: '/workflow/mosr/article/list',
method: "get",
params
});
};
export const getArticleDetail = (articleId) => {
return request({
url: `/workflow/mosr/article/${articleId}`,
method: "get"
});
};
export const addArticle= (data) => {
return request({
url: '/workflow/mosr/article/add',
method: "post",
data
});
};
export const editArticle= (data) => {
return request({
url: '/workflow/mosr/article/update',
method: "post",
data
});
};
export const deleteArticle = (articleIds) => {
return request({
url: `/workflow/mosr/article/${articleIds}`,
method: "delete"
});
};

View File

@@ -1,31 +1,31 @@
import request from "@/utils/request.js";
export const initPassword=(data)=>{
return request({
url:'/admin/mosr/user/init/password',
method:'post',
data
})
}
export const editPassword=(data)=>{
return request({
url:'/admin/mosr/user/update/password',
method:'post',
data
})
}
export const getAgentInfo=()=>{
return request({
url:'/admin/mosr/user/self/approval/agent',
method:'get'
})
}
export const editAgentInfo=(data)=>{
return request({
url:'/admin/mosr/user/self/approval/agent',
method:'post',
data
})
}
import request from "@/utils/request.js";
export const initPassword=(data)=>{
return request({
url:'/admin/mosr/user/init/password',
method:'post',
data
})
}
export const editPassword=(data)=>{
return request({
url:'/admin/mosr/user/update/password',
method:'post',
data
})
}
export const getAgentInfo=()=>{
return request({
url:'/admin/mosr/user/self/approval/agent',
method:'get'
})
}
export const editAgentInfo=(data)=>{
return request({
url:'/admin/mosr/user/self/approval/agent',
method:'post',
data
})
}

View File

@@ -1,15 +1,15 @@
import request from '@/utils/request.js'
export const getCacheOpt = (cacheKey) => {
return request({
url: '/admin/dict/data/option/'+ cacheKey,
method: 'get',
})
}
export const getCacheType = (cacheKey) => {
return request({
url: '/admin/dict/data/type/'+ cacheKey,
method: 'get',
})
import request from '@/utils/request.js'
export const getCacheOpt = (cacheKey) => {
return request({
url: '/admin/dict/data/option/'+ cacheKey,
method: 'get',
})
}
export const getCacheType = (cacheKey) => {
return request({
url: '/admin/dict/data/type/'+ cacheKey,
method: 'get',
})
}

View File

@@ -1,9 +1,9 @@
import request from '@/utils/request.js'
export const requestList = ( api, params, method = 'get' ) => {
return request({
url: api,
method,
params
})
import request from '@/utils/request.js'
export const requestList = ( api, params, method = 'get' ) => {
return request({
url: api,
method,
params
})
}

View File

@@ -1,54 +1,54 @@
import request from '@/utils/request.js'
//获取部门信息
export const getDeptList = (params) => {
return request({
url: '/admin/dept',
method: 'get',
params
})
}
//获取增加时的部门列表
export const getDeptOption = () => {
return request({
url: '/admin/dept/option',
method: 'get'
})
}
//获取修改时的部门列表
export const getDeptExcludeOption = (deptId) => {
return request({
url: `/admin/dept/option/exclude/${deptId}`,
method: 'get'
})
}
//新增部门
export const addDept = (data) => {
return request({
url: '/admin/dept',
method: 'post',
data
})
}
//编辑部门
export const editDept = (data) => {
return request({
url: '/admin/dept',
method: 'put',
data
})
}
//查询部门详情
export const getDeptDetail = (deptId) => {
return request({
url: `/admin/dept/${deptId}`,
method: "get"
});
};
//删除部门
export const deleteDept = (deptId) => {
return request({
url: `/admin/dept/${deptId}`,
method: "delete"
});
};
import request from '@/utils/request.js'
//获取部门信息
export const getDeptList = (params) => {
return request({
url: '/admin/dept',
method: 'get',
params
})
}
//获取增加时的部门列表
export const getDeptOption = () => {
return request({
url: '/admin/dept/option',
method: 'get'
})
}
//获取修改时的部门列表
export const getDeptExcludeOption = (deptId) => {
return request({
url: `/admin/dept/option/exclude/${deptId}`,
method: 'get'
})
}
//新增部门
export const addDept = (data) => {
return request({
url: '/admin/dept',
method: 'post',
data
})
}
//编辑部门
export const editDept = (data) => {
return request({
url: '/admin/dept',
method: 'put',
data
})
}
//查询部门详情
export const getDeptDetail = (deptId) => {
return request({
url: `/admin/dept/${deptId}`,
method: "get"
});
};
//删除部门
export const deleteDept = (deptId) => {
return request({
url: `/admin/dept/${deptId}`,
method: "delete"
});
};

View File

@@ -1,81 +1,107 @@
import request from '@/utils/request.js'
import axios from "axios";
import {getToken} from "@/utils/auth";
export const addAllocation = (data) => {
return request({
url:'/workflow/mosr/cost/allocation',
method: "post",
data
});
};
export const getAllocationDetail = (allocationId) => {
return request({
url: `/workflow/mosr/cost/allocation/info/${allocationId}`,
method: "get"
});
};
export const getAllocationDetails = (allocationId) => {
return request({
url: `/workflow/mosr/cost/allocation/usr/detail/${allocationId}`,
method: "get"
});
};
export const getAllocationSummaryDetails = (params) => {
return request({
url: '/workflow/mosr/cost/allocation/collect',
method: "get",
params:params
});
};
export const getAllocationProcess = () => {
return request({
url: '/workflow/mosr/cost/allocation/process',
method: "get"
});
};
export const getAllocationDetailList = (params) => {
return request({
url: '/workflow/mosr/cost/allocation/usr',
method: "get",
params:params
});
};
export const getResearchUser = () => {
return request({
url: '/admin/mosr/user/research',
method: "get"
});
};
export const getProjectOption = () => {
return request({
url: '/workflow/mosr/project/implementation/in/implementation/option',
method: "get"
});
};
export const editAllocation = (data) => {
return request({
url: '/workflow/mosr/cost/allocation/edit',
method: "post",
data
});
};
export const deleteAllocation = (id) => {
return request({
url: `/workflow/mosr/cost/allocation/${id}`,
method: "delete"
});
};
export const shareExportExcel = (allocationId) => {
return axios.get(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/cost/allocation/collect/${allocationId}`,
{
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};
import request from '@/utils/request.js'
import axios from "axios";
import {getToken} from "@/utils/auth";
export const addAllocation = (data) => {
return request({
url:'/workflow/mosr/cost/allocation',
method: "post",
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}`,
method: "get"
});
};
export const getAllocationDetails = (allocationId) => {
return request({
url: `/workflow/mosr/cost/allocation/usr/detail/${allocationId}`,
method: "get"
});
};
export const getAllocationSummaryDetails = (params) => {
return request({
url: '/workflow/mosr/cost/allocation/collect',
method: "get",
params:params
});
};
export const getAllocationProcess = () => {
return request({
url: '/workflow/mosr/cost/allocation/process',
method: "get"
});
};
export const getAllocationDetailList = (params) => {
return request({
url: '/workflow/mosr/cost/allocation/usr',
method: "get",
params:params
});
};
export const getResearchUser = () => {
return request({
url: '/admin/mosr/user/research',
method: "get"
});
};
export const getProjectOption = () => {
return request({
url: '/workflow/mosr/project/implementation/in/implementation/option',
method: "get"
});
};
export const editAllocation = (data) => {
return request({
url: '/workflow/mosr/cost/allocation/edit',
method: "post",
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}`,
method: "delete"
});
};
export const shareExportExcel = (allocationId) => {
return axios.get(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/cost/allocation/collect/${allocationId}`,
{
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};
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

@@ -1,31 +1,31 @@
import request from '@/utils/request.js'
export const getHomeTaskInfo = () => {
return request({
url: '/workflow/mosr/process/task',
method: "get"
});
};
//获取已办数据
export const getDoneTaskInfo = () => {
return request({
url: '/workflow/mosr/process/task/about',
method: "get"
});
};
//获取专项资金饼图数据
export const getSpecialFundChart = () => {
return request({
url: '/workflow/home/page/statistic',
method: "get"
});
};
//获取首页四个统计数量
export const getHomeStatistics = () => {
return request({
url: '/workflow/mosr/process/task/statistics',
method: "get"
});
};
import request from '@/utils/request.js'
export const getHomeTaskInfo = () => {
return request({
url: '/workflow/mosr/process/task',
method: "get"
});
};
//获取已办数据
export const getDoneTaskInfo = () => {
return request({
url: '/workflow/mosr/process/task/about',
method: "get"
});
};
//获取专项资金饼图数据
export const getSpecialFundChart = () => {
return request({
url: '/workflow/home/page/statistic',
method: "get"
});
};
//获取首页四个统计数量
export const getHomeStatistics = () => {
return request({
url: '/workflow/mosr/process/task/statistics',
method: "get"
});
};

View File

@@ -1,44 +1,44 @@
import request from '@/utils/request.js'
// 获取list
export const getIPBlackList = (params) => {
return request({
url: '/admin/ip/back',
method: 'get',
params
})
}
// 新增
export const addIPBlack = (data) => {
return request({
url: '/admin/ip/back',
method: 'post',
data
})
}
// 修改
export const editIPBlack = (data) => {
return request({
url: '/admin/ip/back',
method: 'put',
data
})
}
// 删除
export const delIPBlack = (ids) => {
return request({
url: '/admin/ip/back/'+ids,
method: 'delete'
})
}
// 详情
export const getIPBlackDetail = (id) => {
return request({
url: '/admin/ip/back/'+id,
method: 'get'
})
import request from '@/utils/request.js'
// 获取list
export const getIPBlackList = (params) => {
return request({
url: '/admin/ip/back',
method: 'get',
params
})
}
// 新增
export const addIPBlack = (data) => {
return request({
url: '/admin/ip/back',
method: 'post',
data
})
}
// 修改
export const editIPBlack = (data) => {
return request({
url: '/admin/ip/back',
method: 'put',
data
})
}
// 删除
export const delIPBlack = (ids) => {
return request({
url: '/admin/ip/back/'+ids,
method: 'delete'
})
}
// 详情
export const getIPBlackDetail = (id) => {
return request({
url: '/admin/ip/back/'+id,
method: 'get'
})
}

View File

@@ -1,24 +1,24 @@
import request from "@/utils/request.js";
//查询登录日志
export const getLoginLogList = (params) => {
return request({
url: "/log/login-info/list",
method: "get",
params
});
};
//查询登录日志详情
export const getLoginLogDetail = (infoId) => {
return request({
url: `/log/login-info/${infoId}`,
method: "get"
});
};
//删除登录日志
export const deleteLoginLog = (infoIds) => {
return request({
url: `/log/login-info/${infoIds}`,
method: "delete"
});
};
import request from "@/utils/request.js";
//查询登录日志
export const getLoginLogList = (params) => {
return request({
url: "/log/login-info/list",
method: "get",
params
});
};
//查询登录日志详情
export const getLoginLogDetail = (infoId) => {
return request({
url: `/log/login-info/${infoId}`,
method: "get"
});
};
//删除登录日志
export const deleteLoginLog = (infoIds) => {
return request({
url: `/log/login-info/${infoIds}`,
method: "delete"
});
};

View File

@@ -1,24 +1,24 @@
import request from "@/utils/request.js";
//查询操作日志
export const getOperateLog = (params) => {
return request({
url: "/log/log/list",
method: "get",
params
});
};
//查询操作日志详情
export const getOperateLogDetail = (operId) => {
return request({
url: `/log/log/${operId}`,
method: "get"
});
};
//删除操作日志
export const deleteOperateLog = (operIds) => {
return request({
url: `/log/log/${operIds}`,
method: "delete"
});
};
import request from "@/utils/request.js";
//查询操作日志
export const getOperateLog = (params) => {
return request({
url: "/log/log/list",
method: "get",
params
});
};
//查询操作日志详情
export const getOperateLogDetail = (operId) => {
return request({
url: `/log/log/${operId}`,
method: "get"
});
};
//删除操作日志
export const deleteOperateLog = (operIds) => {
return request({
url: `/log/log/${operIds}`,
method: "delete"
});
};

View File

@@ -1,36 +1,36 @@
import request from '@/utils/request.js'
export const getCodeImg = () => {
return request({
url: '/auth/captchaImage',
method: 'get'
})
}
export const login = (data) => {
return request({
url: '/auth/login',
method: 'post',
data
})
}
export const switchAccount = (userId) => {
return request({
url: `/auth/switch/account/${userId}`,
method: 'post',
})
}
export const getUserInfo = () => {
return request({
url: '/auth/info',
method: 'get',
})
}
export const getAuthInfo = () => {
return request({
url: '/admin/mosr/user/detail/info',
method: 'get',
})
}
import request from '@/utils/request.js'
export const getCodeImg = () => {
return request({
url: '/auth/captchaImage',
method: 'get'
})
}
export const login = (data) => {
return request({
url: '/auth/login',
method: 'post',
data
})
}
export const switchAccount = (userId) => {
return request({
url: `/auth/switch/account/${userId}`,
method: 'post',
})
}
export const getUserInfo = () => {
return request({
url: '/auth/info',
method: 'get',
})
}
export const getAuthInfo = () => {
return request({
url: '/admin/mosr/user/detail/info',
method: 'get',
})
}

View File

@@ -1,30 +1,30 @@
import request from '@/utils/request.js'
export const getNoticeList = (params) => {
return request({
url: '/notice/notice',
method: 'get',
params
})
}
export const getNoticeDetail = (noticeId) => {
return request({
url: '/notice/notice/'+noticeId,
method: "get"
});
};
export const addNotice = (data) => {
return request({
url: '/notice/notice',
method: 'post',
data
})
}
export const deleteNotice = (noticeId) => {
return request({
url: `/notice/notice/${noticeId}`,
method: "delete"
});
};
import request from '@/utils/request.js'
export const getNoticeList = (params) => {
return request({
url: '/notice/notice',
method: 'get',
params
})
}
export const getNoticeDetail = (noticeId) => {
return request({
url: '/notice/notice/'+noticeId,
method: "get"
});
};
export const addNotice = (data) => {
return request({
url: '/notice/notice',
method: 'post',
data
})
}
export const deleteNotice = (noticeId) => {
return request({
url: `/notice/notice/${noticeId}`,
method: "delete"
});
};

View File

@@ -1,43 +1,43 @@
import request from '@/utils/request.js'
export const getNotifyList = (params) => {
return request({
url: '/notice/notify',
method: 'get',
params
})
}
export const getNotifyDetail = (noticeId) => {
return request({
url: '/notice/notify/'+noticeId,
method: "get"
});
};
//已读单个消息
export const readSingleNotify = (noticeId) => {
return request({
url: '/notice/notify/read/'+noticeId,
method: 'put'
})
}
//已读全部消息
export const readAllNotify = () => {
return request({
url: '/notice/notify/read/all',
method: 'put'
})
}
//删除单个消息
export const deleteSingleNotify = (noticeId) => {
return request({
url: '/notice/notify/'+noticeId,
method: "delete"
});
};
//删除多个消息
export const deleteMoreNotify = (noticeIds) => {
return request({
url: '/notice/notify/batch/'+noticeIds,
method: "delete"
});
};
import request from '@/utils/request.js'
export const getNotifyList = (params) => {
return request({
url: '/notice/notify',
method: 'get',
params
})
}
export const getNotifyDetail = (noticeId) => {
return request({
url: '/notice/notify/'+noticeId,
method: "get"
});
};
//已读单个消息
export const readSingleNotify = (noticeId) => {
return request({
url: '/notice/notify/read/'+noticeId,
method: 'put'
})
}
//已读全部消息
export const readAllNotify = () => {
return request({
url: '/notice/notify/read/all',
method: 'put'
})
}
//删除单个消息
export const deleteSingleNotify = (noticeId) => {
return request({
url: '/notice/notify/'+noticeId,
method: "delete"
});
};
//删除多个消息
export const deleteMoreNotify = (noticeIds) => {
return request({
url: '/notice/notify/batch/'+noticeIds,
method: "delete"
});
};

View File

@@ -1,17 +1,17 @@
import request from "@/utils/request.js";
//查询在线用户
export const getOnlineList = (params) => {
return request({
url: "/admin/online/user",
method: "get",
params
});
};
//强制退出用户
export const deleteOnlineUser= (tokenId) => {
return request({
url: '/admin/online/user/'+tokenId,
method: "delete"
});
};
import request from "@/utils/request.js";
//查询在线用户
export const getOnlineList = (params) => {
return request({
url: "/admin/online/user",
method: "get",
params
});
};
//强制退出用户
export const deleteOnlineUser= (tokenId) => {
return request({
url: '/admin/online/user/'+tokenId,
method: "delete"
});
};

View File

@@ -1,48 +1,48 @@
import request from '@/utils/request.js'
//获取岗位信息
export const getPostList = (params) => {
return request({
url: '/admin/post',
method: 'get',
params
})
}
//查询岗位详情
export const getPostDetail = (postId) => {
return request({
url: `/admin/post/info/${postId}`,
method: "get"
});
};
//新增岗位
export const addPost = (data) => {
return request({
url: '/admin/post',
method: 'post',
data
})
}
//编辑岗位
export const editPost = (data) => {
return request({
url: '/admin/post',
method: 'put',
data
})
}
//获取select下拉框数据
export const getSelectOption = () => {
return request({
url: '/admin/post/option',
method: 'get'
})
}
//删除角色信息
export const deletePost = (postId) => {
return request({
url: `/admin/post/${postId}`,
method: "delete"
});
};
import request from '@/utils/request.js'
//获取岗位信息
export const getPostList = (params) => {
return request({
url: '/admin/post',
method: 'get',
params
})
}
//查询岗位详情
export const getPostDetail = (postId) => {
return request({
url: `/admin/post/info/${postId}`,
method: "get"
});
};
//新增岗位
export const addPost = (data) => {
return request({
url: '/admin/post',
method: 'post',
data
})
}
//编辑岗位
export const editPost = (data) => {
return request({
url: '/admin/post',
method: 'put',
data
})
}
//获取select下拉框数据
export const getSelectOption = () => {
return request({
url: '/admin/post/option',
method: 'get'
})
}
//删除角色信息
export const deletePost = (postId) => {
return request({
url: `/admin/post/${postId}`,
method: "delete"
});
};

View File

@@ -1,128 +1,128 @@
import request from '@/utils/request.js'
import axios from "axios";
import {getToken} from "@/utils/auth";
//需求征集
export const getDemandInfo = (param) => {
return request({
url: '/workflow/mosr/requirement',
method: "get",
params: param
});
};
export const filterRequirementName = (requirementName) => {
return request({
url: `/workflow/mosr/requirement/match/${requirementName}`,
method: "get"
});
};
export const getWorkflowInfo = () => {
return request({
url: '/workflow/mosr/requirement/process',
method: "get"
});
};
export const getInfo = (requirementId) => {
return request({
url: `/workflow/mosr/requirement/info/${requirementId}`,
method: "get"
});
};
export const getFormInfo = (requirementId) => {
return request({
url: `/workflow/mosr/requirement/form/${requirementId}`,
method: "get"
});
};
export const agreeTask = (data) => {
return request({
url: `/workflow/mosr/process/task/agree`,
method: "post",
data: data
});
};
export const rejectTask = (data) => {
return request({
url: `/workflow/mosr/process/task/reject`,
method: "post",
data: data
});
};
export const addRequirement = (data) => {
return request({
url: '/workflow/mosr/requirement',
method: "post",
data: data
});
};
export const resubmit = (data) => {
return request({
url: '/workflow/mosr/requirement/resubmit',
method: "post",
data: data
});
};
export const deleteFile = (fileId) => {
return request({
url: `/workflow/process/file/delete/${fileId}`,
method: "delete"
});
};
export const downloadFile = (fileId) => {
return request({
url: '/workflow/process/file/download',
method: "get",
responseType:'blob',
params:{
fileId:fileId
}
});
};
export const getCompanyOption = () => {
return request({
url: '/admin/mosr/sub/company/companyOption',
method: "get"
});
};
export const deleteDemand = (id) => {
return request({
url: `/workflow/mosr/requirement/${id}`,
method: "delete"
});
};
export const getRequirementStatePerm = () => {
return request({
url: '/workflow/mosr/requirement/prem/state',
method: "get"
});
};
export const downloadTemplate = (type) => {
return request({
url: '/workflow/mosr/attachment/download/template',
method: "get",
responseType:'blob',
params:{
type:type
}
});
};
export const downloadTemplateZip = (typeList) => {
return axios.get(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/attachment/download/pack?typeList=${typeList}`,
{
responseType: 'blob',
headers: {
Authorization: getToken()
},
}
);
// return request({
// url: '/workflow/mosr/attachment/download/pack',
// method: "get",
// responseType:'blob',
// params:{
// typeList:typeList
// }
// });
};
import request from '@/utils/request.js'
import axios from "axios";
import {getToken} from "@/utils/auth";
//需求征集
export const getDemandInfo = (param) => {
return request({
url: '/workflow/mosr/requirement',
method: "get",
params: param
});
};
export const filterRequirementName = (requirementName) => {
return request({
url: `/workflow/mosr/requirement/match/${requirementName}`,
method: "get"
});
};
export const getWorkflowInfo = () => {
return request({
url: '/workflow/mosr/requirement/process',
method: "get"
});
};
export const getInfo = (requirementId) => {
return request({
url: `/workflow/mosr/requirement/info/${requirementId}`,
method: "get"
});
};
export const getFormInfo = (requirementId) => {
return request({
url: `/workflow/mosr/requirement/form/${requirementId}`,
method: "get"
});
};
export const agreeTask = (data) => {
return request({
url: `/workflow/mosr/process/task/agree`,
method: "post",
data: data
});
};
export const rejectTask = (data) => {
return request({
url: `/workflow/mosr/process/task/reject`,
method: "post",
data: data
});
};
export const addRequirement = (data) => {
return request({
url: '/workflow/mosr/requirement',
method: "post",
data: data
});
};
export const resubmit = (data) => {
return request({
url: '/workflow/mosr/requirement/resubmit',
method: "post",
data: data
});
};
export const deleteFile = (fileId) => {
return request({
url: `/workflow/process/file/delete/${fileId}`,
method: "delete"
});
};
export const downloadFile = (fileId) => {
return request({
url: '/workflow/process/file/download',
method: "get",
responseType:'blob',
params:{
fileId:fileId
}
});
};
export const getCompanyOption = () => {
return request({
url: '/admin/mosr/sub/company/companyOption',
method: "get"
});
};
export const deleteDemand = (id) => {
return request({
url: `/workflow/mosr/requirement/${id}`,
method: "delete"
});
};
export const getRequirementStatePerm = () => {
return request({
url: '/workflow/mosr/requirement/prem/state',
method: "get"
});
};
export const downloadTemplate = (type) => {
return request({
url: '/workflow/mosr/attachment/download/template',
method: "get",
responseType:'blob',
params:{
type:type
}
});
};
export const downloadTemplateZip = (typeList) => {
return axios.get(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/attachment/download/pack?typeList=${typeList}`,
{
responseType: 'blob',
headers: {
Authorization: getToken()
},
}
);
// return request({
// url: '/workflow/mosr/attachment/download/pack',
// method: "get",
// responseType:'blob',
// params:{
// typeList:typeList
// }
// });
};

View File

@@ -1,113 +1,185 @@
import request from '@/utils/request'
export const fileUp = (url, data) => {
return request({
url,
method: 'post',
data,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
export const requirementReported = (data) => {
return request({
url: '/workflow/mosr/requirement/reported',
method: "post",
data: data
});
};
//需求汇总-征集名称关键词匹配
export const getRequirementName = (requirementName) => {
return request({
url: `/workflow/mosr/requirement/collect/project/match/${requirementName}`,
method: "get"
});
};
//获取需求上报 流程信息
export const getProcessInfo = (specialFund) => {
return request({
url: `/workflow/mosr/requirement/collect/process/${specialFund}`,
method: "get"
});
};
export const getDetail = (projectId) => {
return request({
url: `/workflow/mosr/requirement/collect/info/${projectId}`,
method: "get"
});
};
export const resubmitReported = (data) => {
return request({
url: '/workflow/mosr/requirement/collect/resubmit',
method: "post",
data: data
});
};
export const getCollectAttachment = (params) => {
return request({
url: '/workflow/mosr/requirement/collect/attachments',
method: "get",
params:params
});
};
export const uploadCollectAttachment= (data) => {
return request({
url: '/workflow/mosr/requirement/collect/upload',
method: "post",
data: data
});
};
// 年度计划
export const addPlan= (data) => {
return request({
url: '/workflow/annual/plan',
method: "post",
data: data
});
};
export const editPlan= (data) => {
return request({
url: '/workflow/annual/plan',
method: "put",
data: data
});
};
export const getPlan= (annualPlanId) => {
return request({
url: `/workflow/annual/plan/info/${annualPlanId}`,
method: "get"
});
};
export const deletePlan= (annualPlanId) => {
return request({
url: `/workflow/annual/plan/${annualPlanId}`,
method: "delete"
});
};
export const approvePlan= (data) => {
return request({
url: '/workflow/annual/plan/approve',
method: "post",
data: data
});
};
export const getProjectOption = () => {
return request({
url: '/workflow/mosr/requirement/master',
method: "get"
});
};
export const getRequirementOption = () => {
return request({
url: '/workflow/mosr/requirement/option',
method: "get"
});
};
import request from '@/utils/request'
export const fileUp = (url, data) => {
return request({
url,
method: 'post',
data,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
export const requirementReported = (data) => {
return request({
url: '/workflow/mosr/requirement/reported',
method: "post",
data: data
});
};
//需求汇总-征集名称关键词匹配
export const getRequirementName = (requirementName) => {
return request({
url: `/workflow/mosr/requirement/collect/project/match/${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({
url: `/workflow/mosr/requirement/collect/process/${specialFund}`,
method: "get"
});
};
export const getDetail = (projectId) => {
return request({
url: `/workflow/mosr/requirement/collect/info/${projectId}`,
method: "get"
});
};
export const resubmitReported = (data) => {
return request({
url: '/workflow/mosr/requirement/collect/resubmit',
method: "post",
data: data
});
};
export const getCollectAttachment = (params) => {
return request({
url: '/workflow/mosr/requirement/collect/attachments',
method: "get",
params:params
});
};
export const uploadCollectAttachment= (data) => {
return request({
url: '/workflow/mosr/requirement/collect/upload',
method: "post",
data: data
});
};
// 项目计划
export const addPlan= (data) => {
return request({
url: '/workflow/annual/plan',
method: "post",
data: data
});
};
export const editPlan= (data) => {
return request({
url: '/workflow/annual/plan',
method: "put",
data: data
});
};
export const getPlan= (annualPlanId) => {
return request({
url: `/workflow/annual/plan/info/${annualPlanId}`,
method: "get"
});
};
export const deletePlan= (annualPlanId) => {
return request({
url: `/workflow/annual/plan/${annualPlanId}`,
method: "delete"
});
};
export const approvePlan= (data) => {
return request({
url: '/workflow/annual/plan/approve',
method: "post",
data: data
});
};
export const getProjectOption = (projectName) => {
return request({
url: '/workflow/mosr/requirement/master',
method: "get",
params:{
projectName:projectName
}
});
};
export const getMasterProjectNameOption = (masterProjectName) => {
return request({
url: '/workflow/mosr/payment/master/option',
method: "get",
params:{
masterProjectName:masterProjectName
}
});
};
export const getSubprojectNameOption = (subProjectName) => {
return request({
url: '/workflow/mosr/payment/sub/option',
method: "get",
params:{
subProjectName:subProjectName
}
});
};
export const getExpenseMasterProjectNameOption = (masterProjectName) => {
return request({
url: '/workflow/mosr/rd/expense/master/option',
method: "get",
params:{
masterProjectName:masterProjectName
}
});
};
export const getExpenseSubprojectNameOption = (subProjectName) => {
return request({
url: '/workflow/mosr/rd/expense/sub/option',
method: "get",
params:{
subProjectName:subProjectName
}
});
};
export const getCostMasterProjectNameOption = (masterProjectName) => {
return request({
url: '/workflow/mosr/cost/share/master/option',
method: "get",
params:{
masterProjectName:masterProjectName
}
});
};
export const getCostSubprojectNameOption = (subProjectName) => {
return request({
url: '/workflow/mosr/cost/share/sub/option',
method: "get",
params:{
subProjectName:subProjectName
}
});
};
export const getRequirementOption = () => {
return request({
url: '/workflow/mosr/requirement/option',
method: "get"
});
};

View File

@@ -1,38 +1,38 @@
import request from '@/utils/request.js'
export const searchFileList = (params) => {
return request({
url: `/workflow/mosr/attachment/list`,
method: "get",
params: params
});
};
export const searchAllFileList = (params) => {
return request({
url: '/workflow/mosr/attachment/all',
method: "get",
params: params
});
};
export const uploadFileList = (data) => {
return request({
url: '/workflow/mosr/attachment/upload',
method: "post",
data: data
});
};
export const searchImplementationFileList = (params) => {
return request({
url: '/workflow/mosr/attachment/implementation/list',
method: "get",
params: params
});
};
export const switchAttachmentState = (data) => {
return request({
url: '/workflow/mosr/project/filing/attachment/switch',
method: "post",
data
});
};
import request from '@/utils/request.js'
export const searchFileList = (params) => {
return request({
url: `/workflow/mosr/attachment/list`,
method: "get",
params: params
});
};
export const searchAllFileList = (params) => {
return request({
url: '/workflow/mosr/attachment/all',
method: "get",
params: params
});
};
export const uploadFileList = (data) => {
return request({
url: '/workflow/mosr/attachment/upload',
method: "post",
data: data
});
};
export const searchImplementationFileList = (params) => {
return request({
url: '/workflow/mosr/attachment/implementation/list',
method: "get",
params: params
});
};
export const switchAttachmentState = (data) => {
return request({
url: '/workflow/mosr/project/filing/attachment/switch',
method: "post",
data
});
};

View File

@@ -1,199 +1,240 @@
import request from '@/utils/request.js'
import axios from "axios";
import {getToken} from "@/utils/auth";
//项目立项
export const getApplyProcess = (projectId) => {
return request({
url: `/workflow/mosr/project/approval/initiation/process/${projectId}`,
method: "get"
});
};
export const filterProjectName = (projectName,targetState) => {
return request({
url: `/workflow/mosr/project/approval/match/${projectName}/${targetState}`,
method: "get"
});
};
export const projectApply = (data) => {
return request({
url: '/workflow/mosr/project/approval/initiation/apply',
method: "post",
data: data
});
};
export const getApplyDetail = (ProjectId) => {
return request({
url: `/workflow/mosr/project/approval/info/${ProjectId}`,
method: "get"
});
};
export const resubmitApply = (data) => {
return request({
url: '/workflow/mosr/project/approval/initiation/resubmit',
method: "post",
data: data
});
};
export const getInitiationAttachment = (params) => {
return request({
url: '/workflow/mosr/project/approval/attachments',
method: "get",
params: params
});
};
//项目实施
export const getCheckDetail = (projectId) => {
return request({
url: `/workflow/mosr/project/implementation/info/${projectId}`,
method: "get"
});
};
export const resubmitCheck = (data) => {
return request({
url: '/workflow/mosr/project/implementation/resubmit',
method: "post",
data: data
});
};
export const projectCheck = (data) => {
return request({
url: '/workflow/mosr/project/implementation/initiation/check',
method: "post",
data: data
});
};
export const getProjectCheckProcess = (projectId) => {
return request({
url: `/workflow/mosr/project/implementation/process/${projectId}`,
method: "get"
});
};
export const addLedger = (data) => {
return request({
url: '/workflow/mosr/expense/ledger',
method: "post",
data: data
});
};
export const getTags = (projectId) => {
return request({
url: `/workflow/mosr/attachment/option/${projectId}`,
method: "get"
});
};
export const getPhaseProcess = () => {
return request({
url: '/workflow/phase/change/process',
method: "get"
});
};
export const submitPhaseChange = (data) => {
return request({
url: '/workflow/phase/change',
method: "post",
data: data
});
};
export const getPhaseDetail = (projectId) => {
return request({
url: `/workflow/phase/change/info/${projectId}`,
method: "get"
});
};
export const getPhaseForm = (projectId) => {
return request({
url: `/workflow/phase/change/from/${projectId}`,
method: "get"
});
};
export const resubmitPhaseForm = (data) => {
return request({
url: '/workflow/phase/change/resubmit',
method: "post",
data: data
});
};
//项目归档
export const getConclusionDetail = (ProjectId) => {
return request({
url: `/workflow/mosr/project/filing/info/${ProjectId}`,
method: "get"
});
};
export const resubmitConclusion = (data) => {
return request({
url: '/workflow/mosr/project/filing/resubmit',
method: "post",
data: data
});
};
export const projectConclusion = (data) => {
return request({
url: '/workflow/mosr/project/filing/project/entry',
method: "post",
data: data
});
};
export const getProjectConclusionProcess = () => {
return request({
url: '/workflow/mosr/project/filing/process',
method: "get"
});
};
//获取前置流程
export const getPreProcess = () => {
return request({
url: '/workflow/details/pre/process',
method: "get"
});
};
export const updateLedger = (data) => {
return request({
url: '/workflow/mosr/expense/ledger/replenishment',
method: "post",
data: data
});
};
export const searchUpdateLedgerData = (projectId) => {
return request({
url: `/workflow/mosr/expense/ledger/${projectId}`,
method: "get"
});
};
//
// export const searchUpdateLedgerData = (projectId) => {
// return request({
// url: '/workflow/mosr/expense/ledger/import',
// method: "get"
// });
// };
export const exportExcel = (data) => {
return axios.post(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/project/implementation/export`,
data, {
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};
//台账模板下载
export const ledgerTemplateDownload = () => {
return axios.get(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/project/implementation/download/template`,
{
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};
import request from '@/utils/request.js'
import axios from "axios";
import {getToken} from "@/utils/auth";
//项目立项
export const getApplyProcess = (projectId) => {
return request({
url: `/workflow/mosr/project/approval/initiation/process/${projectId}`,
method: "get"
});
};
export const filterProjectName = (projectName,targetState) => {
return request({
url: `/workflow/mosr/project/approval/match/${projectName}/${targetState}`,
method: "get"
});
};
export const projectApply = (data) => {
return request({
url: '/workflow/mosr/project/approval/initiation/apply',
method: "post",
data: data
});
};
export const getApplyDetail = (ProjectId) => {
return request({
url: `/workflow/mosr/project/approval/info/${ProjectId}`,
method: "get"
});
};
export const resubmitApply = (data) => {
return request({
url: '/workflow/mosr/project/approval/initiation/resubmit',
method: "post",
data: data
});
};
export const getInitiationAttachment = (params) => {
return request({
url: '/workflow/mosr/project/approval/attachments',
method: "get",
params: params
});
};
//项目实施
export const getCheckDetail = (projectId) => {
return request({
url: `/workflow/mosr/project/implementation/info/${projectId}`,
method: "get"
});
};
export const resubmitCheck = (data) => {
return request({
url: '/workflow/mosr/project/implementation/resubmit',
method: "post",
data: data
});
};
export const projectCheck = (data) => {
return request({
url: '/workflow/mosr/project/implementation/initiation/check',
method: "post",
data: data
});
};
export const getProjectCheckProcess = (projectId) => {
return request({
url: `/workflow/mosr/project/implementation/process/${projectId}`,
method: "get"
});
};
export const addLedger = (data) => {
return request({
url: '/workflow/mosr/expense/ledger',
method: "post",
data: data
});
};
export const getTags = (projectId) => {
return request({
url: `/workflow/mosr/attachment/option/${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',
method: "get"
});
};
export const submitPhaseChange = (data) => {
return request({
url: '/workflow/phase/change',
method: "post",
data: data
});
};
export const getPhaseDetail = (projectId) => {
return request({
url: `/workflow/phase/change/info/${projectId}`,
method: "get"
});
};
export const getPhaseForm = (projectId) => {
return request({
url: `/workflow/phase/change/from/${projectId}`,
method: "get"
});
};
export const resubmitPhaseForm = (data) => {
return request({
url: '/workflow/phase/change/resubmit',
method: "post",
data: data
});
};
//项目归档
export const getConclusionDetail = (ProjectId) => {
return request({
url: `/workflow/mosr/project/filing/info/${ProjectId}`,
method: "get"
});
};
export const resubmitConclusion = (data) => {
return request({
url: '/workflow/mosr/project/filing/resubmit',
method: "post",
data: data
});
};
export const projectConclusion = (data) => {
return request({
url: '/workflow/mosr/project/filing/project/entry',
method: "post",
data: data
});
};
export const getProjectConclusionProcess = () => {
return request({
url: '/workflow/mosr/project/filing/process',
method: "get"
});
};
//获取前置流程
export const getPreProcess = () => {
return request({
url: '/workflow/details/pre/process',
method: "get"
});
};
export const updateLedger = (data) => {
return request({
url: '/workflow/mosr/expense/ledger/replenishment',
method: "post",
data: data
});
};
export const searchUpdateLedgerData = (projectId) => {
return request({
url: `/workflow/mosr/expense/ledger/${projectId}`,
method: "get"
});
};
//
// export const searchUpdateLedgerData = (projectId) => {
// return request({
// url: '/workflow/mosr/expense/ledger/import',
// method: "get"
// });
// };
export const exportExcel = (data) => {
return axios.post(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/project/implementation/export`,
data, {
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};
//台账模板下载
export const ledgerTemplateDownload = () => {
return axios.get(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/project/implementation/download/template`,
{
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};
//费用明细模板下载
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

@@ -1,68 +1,68 @@
import request from '@/utils/request.js'
export const getTableList = (params) => {
return request({
url: '/code-gen/table',
method: 'get',
params
})
}
export const getDynamicTable = (params) => {
return request({
url: '/code-gen/dynamic-table',
method: 'get',
params
})
}
export const getTableDetail = (tableId) => {
return request({
url: `/code-gen/table/${tableId}`,
method: 'get',
})
}
export const previewCode = (tableId) => {
return request({
url: `/code-gen/table/preview/${tableId}`,
method: 'get',
})
}
export const deleteMoreTable = (params) => {
return request({
url: '/code-gen/table',
method: 'delete',
params
})
}
export const deleteTable = (tableId) => {
return request({
url: `/code-gen/table/${tableId}`,
method: 'delete',
})
}
export const importTable = (data) => {
return request({
url: "/code-gen/table/import-table",
method: 'post',
data
})
}
export const editCodeGen = (data) => {
return request({
url: '/code-gen/table',
method: 'put',
data
})
}
export const syncDatabase = (tableId) => {
return request({
url: '/code-gen/table/sync/'+tableId,
method: 'put'
})
}
import request from '@/utils/request.js'
export const getTableList = (params) => {
return request({
url: '/code-gen/table',
method: 'get',
params
})
}
export const getDynamicTable = (params) => {
return request({
url: '/code-gen/dynamic-table',
method: 'get',
params
})
}
export const getTableDetail = (tableId) => {
return request({
url: `/code-gen/table/${tableId}`,
method: 'get',
})
}
export const previewCode = (tableId) => {
return request({
url: `/code-gen/table/preview/${tableId}`,
method: 'get',
})
}
export const deleteMoreTable = (params) => {
return request({
url: '/code-gen/table',
method: 'delete',
params
})
}
export const deleteTable = (tableId) => {
return request({
url: `/code-gen/table/${tableId}`,
method: 'delete',
})
}
export const importTable = (data) => {
return request({
url: "/code-gen/table/import-table",
method: 'post',
data
})
}
export const editCodeGen = (data) => {
return request({
url: '/code-gen/table',
method: 'put',
data
})
}
export const syncDatabase = (tableId) => {
return request({
url: '/code-gen/table/sync/'+tableId,
method: 'put'
})
}

View File

@@ -1,54 +1,54 @@
import request from '@/utils/request.js'
export const getDataSourceList = (params) => {
return request({
url: '/code-gen/data-source',
method: 'get',
params
})
}
export const getDataSourceOption = () => {
return request({
url: '/code-gen/data-source/option',
method: 'get'
})
}
export const getDataSourceOptionType=()=>{
return request({
url:'/code-gen/data-source/option/type',
method:'get'
})
}
export const getDataSource = (dsId) => {
return request({
url: `/code-gen/data-source/${dsId}`,
method: 'get'
})
}
export const addDataSource = (data) => {
return request({
url: '/code-gen/data-source',
method: 'post',
data
})
}
export const editDataSource = (data) => {
return request({
url: '/code-gen/data-source',
method: 'put',
data
})
}
export const deleteDataSource = (dsId) => {
return request({
url: `/code-gen/data-source/${dsId}`,
method: 'delete'
})
}
import request from '@/utils/request.js'
export const getDataSourceList = (params) => {
return request({
url: '/code-gen/data-source',
method: 'get',
params
})
}
export const getDataSourceOption = () => {
return request({
url: '/code-gen/data-source/option',
method: 'get'
})
}
export const getDataSourceOptionType=()=>{
return request({
url:'/code-gen/data-source/option/type',
method:'get'
})
}
export const getDataSource = (dsId) => {
return request({
url: `/code-gen/data-source/${dsId}`,
method: 'get'
})
}
export const addDataSource = (data) => {
return request({
url: '/code-gen/data-source',
method: 'post',
data
})
}
export const editDataSource = (data) => {
return request({
url: '/code-gen/data-source',
method: 'put',
data
})
}
export const deleteDataSource = (dsId) => {
return request({
url: `/code-gen/data-source/${dsId}`,
method: 'delete'
})
}

View File

@@ -1,52 +1,52 @@
import request from '@/utils/request.js'
// 请求校验规则表list
export const getRegularList = (params) => {
return request({
url: '/code-gen/rapid/regular',
method: 'get',
params
})
}
// 获取校验规则表详情
export const getRegularDetails = (regularId) => {
return request({
url: '/code-gen/rapid/regular/' + regularId,
method: 'get'
})
}
// 获取校验规则选项列表
export const getRegularOpt = (regularId) => {
return request({
url: '/code-gen/rapid/regular/option',
method: 'get'
})
}
// 新增校验规则表
export const addRegular = (data) => {
return request({
url: '/code-gen/rapid/regular',
method: 'post',
data
})
}
// 修改校验规则表
export const editRegular = (data) => {
return request({
url: '/code-gen/rapid/regular',
method: 'put',
data
})
}
// 删除校验规则表
export const delRegular =(regularId) => {
return request({
url: '/code-gen/rapid/regular/' + regularId,
method: 'delete'
})
import request from '@/utils/request.js'
// 请求校验规则表list
export const getRegularList = (params) => {
return request({
url: '/code-gen/rapid/regular',
method: 'get',
params
})
}
// 获取校验规则表详情
export const getRegularDetails = (regularId) => {
return request({
url: '/code-gen/rapid/regular/' + regularId,
method: 'get'
})
}
// 获取校验规则选项列表
export const getRegularOpt = (regularId) => {
return request({
url: '/code-gen/rapid/regular/option',
method: 'get'
})
}
// 新增校验规则表
export const addRegular = (data) => {
return request({
url: '/code-gen/rapid/regular',
method: 'post',
data
})
}
// 修改校验规则表
export const editRegular = (data) => {
return request({
url: '/code-gen/rapid/regular',
method: 'put',
data
})
}
// 删除校验规则表
export const delRegular =(regularId) => {
return request({
url: '/code-gen/rapid/regular/' + regularId,
method: 'delete'
})
}

View File

@@ -1,36 +1,36 @@
import request from '@/utils/request.js'
export const getResearchFundChart = (year) => {
return request({
url: '/workflow/mosr/rd/home',
method: 'get',
params: {year:year}
})
}
export const getResearchFundDetail = (rdFundId) => {
return request({
url: `/workflow/mosr/rd/${rdFundId}`,
method: "get"
});
};
export const addResearchFund= (data) => {
return request({
url: '/workflow/mosr/rd/add',
method: "post",
data
});
};
export const editResearchFund= (data) => {
return request({
url: '/workflow/mosr/rd/update',
method: "post",
data
});
};
export const deleteResearchFund = (rdFundIds) => {
return request({
url: `/workflow/mosr/rd/${rdFundIds}`,
method: "delete"
});
};
import request from '@/utils/request.js'
export const getResearchFundChart = (year) => {
return request({
url: '/workflow/mosr/rd/home',
method: 'get',
params: {year:year}
})
}
export const getResearchFundDetail = (rdFundId) => {
return request({
url: `/workflow/mosr/rd/${rdFundId}`,
method: "get"
});
};
export const addResearchFund= (data) => {
return request({
url: '/workflow/mosr/rd/add',
method: "post",
data
});
};
export const editResearchFund= (data) => {
return request({
url: '/workflow/mosr/rd/update',
method: "post",
data
});
};
export const deleteResearchFund = (rdFundIds) => {
return request({
url: `/workflow/mosr/rd/${rdFundIds}`,
method: "delete"
});
};

View File

@@ -1,110 +1,110 @@
import request from '@/utils/request.js'
export const getRoleList = (params) => {
return request({
url: '/admin/role',
method: 'get',
params
})
}
//查询角色option
export const getRoleOption = () => {
return request({
url: '/admin/role/option',
method: "get"
});
};
export const getTemRoleOption = () => {
return request({
url: '/admin/role/option/template',
method: "get"
});
};
//查询角色信息
export const getRoleDetail = (roleId) => {
return request({
url: `/admin/role/${roleId}`,
method: "get"
});
};
//根据菜单id获取分配的角色信息
export const getRoleInfoByMenuId = (params) => {
return request({
url: '/admin/role/menu',
method: 'get',
params
})
}
//获取排除在外的角色
export const getRoleExcludeMenuId = (params) => {
return request({
url: '/admin/role/menu/list',
method: "get",
params
});
};
// 新增修改
export const operate = (data) => {
if(data.roleId) return editRole(data)
return addRole(data)
}
// 新增角色
export const addRole = (data) => {
return request({
url: '/admin/role',
method: 'post',
data
})
}
// 修改角色
export const editRole = (data) => {
return request({
url: '/admin/role',
method: 'put',
data
})
}
//解除当前角色对应的所有菜单的绑定关系
export const unbindAllRole = (menuId) => {
return request({
url: '/admin/role/all/unbind/menu',
method: 'put',
data: {
id: menuId
}
})
}
// 解除角色与菜单之间的绑定状态
export const cancelAuthorization = (menuId, roleIds) => {
return request({
url: '/admin/role/unbind/menu',
method: 'put',
data: {
id: menuId,
ids: roleIds
}
})
}
//建立角色用户绑定关系
export const bindRoleAndMenu = (menuId, roleIds) => {
return request({
url: '/admin/role/bind/menu',
method: 'put',
data: {
id: menuId,
ids: roleIds
}
})
}
//删除角色信息
export const deleteRole = (roleId) => {
return request({
url: `/admin/role/${roleId}`,
method: "delete"
});
};
import request from '@/utils/request.js'
export const getRoleList = (params) => {
return request({
url: '/admin/role',
method: 'get',
params
})
}
//查询角色option
export const getRoleOption = () => {
return request({
url: '/admin/role/option',
method: "get"
});
};
export const getTemRoleOption = () => {
return request({
url: '/admin/role/option/template',
method: "get"
});
};
//查询角色信息
export const getRoleDetail = (roleId) => {
return request({
url: `/admin/role/${roleId}`,
method: "get"
});
};
//根据菜单id获取分配的角色信息
export const getRoleInfoByMenuId = (params) => {
return request({
url: '/admin/role/menu',
method: 'get',
params
})
}
//获取排除在外的角色
export const getRoleExcludeMenuId = (params) => {
return request({
url: '/admin/role/menu/list',
method: "get",
params
});
};
// 新增修改
export const operate = (data) => {
if(data.roleId) return editRole(data)
return addRole(data)
}
// 新增角色
export const addRole = (data) => {
return request({
url: '/admin/role',
method: 'post',
data
})
}
// 修改角色
export const editRole = (data) => {
return request({
url: '/admin/role',
method: 'put',
data
})
}
//解除当前角色对应的所有菜单的绑定关系
export const unbindAllRole = (menuId) => {
return request({
url: '/admin/role/all/unbind/menu',
method: 'put',
data: {
id: menuId
}
})
}
// 解除角色与菜单之间的绑定状态
export const cancelAuthorization = (menuId, roleIds) => {
return request({
url: '/admin/role/unbind/menu',
method: 'put',
data: {
id: menuId,
ids: roleIds
}
})
}
//建立角色用户绑定关系
export const bindRoleAndMenu = (menuId, roleIds) => {
return request({
url: '/admin/role/bind/menu',
method: 'put',
data: {
id: menuId,
ids: roleIds
}
})
}
//删除角色信息
export const deleteRole = (roleId) => {
return request({
url: `/admin/role/${roleId}`,
method: "delete"
});
};

View File

@@ -1,46 +1,46 @@
import request from '@/utils/request.js'
export const getFundDetail = (specialFundId) => {
return request({
url: `/workflow/mosr/special/fund/from/${specialFundId}`,
method: "get"
});
};
export const getFundDetailProcess = (specialFundId) => {
return request({
url: `/workflow/mosr/special/fund/info/${specialFundId}`,
method: "get"
});
};
export const getFundOption = () => {
return request({
url: '/workflow/mosr/special/fund/option',
method: "get"
});
};
export const getFundProcess = (specialFundId) => {
return request({
url: '/workflow/mosr/special/fund/process',
method: "get"
});
};
export const addFund= (data) => {
return request({
url: '/workflow/mosr/special/fund',
method: "post",
data
});
};
export const resubmitFund= (data) => {
return request({
url: '/workflow/mosr/special/fund/resubmit',
method: "post",
data
});
};
export const deleteFund = (id) => {
return request({
url: `/workflow/mosr/special/fund/${id}`,
method: "delete"
});
};
import request from '@/utils/request.js'
export const getFundDetail = (specialFundId) => {
return request({
url: `/workflow/mosr/special/fund/from/${specialFundId}`,
method: "get"
});
};
export const getFundDetailProcess = (specialFundId) => {
return request({
url: `/workflow/mosr/special/fund/info/${specialFundId}`,
method: "get"
});
};
export const getFundOption = () => {
return request({
url: '/workflow/mosr/special/fund/option',
method: "get"
});
};
export const getFundProcess = (specialFundId) => {
return request({
url: '/workflow/mosr/special/fund/process',
method: "get"
});
};
export const addFund= (data) => {
return request({
url: '/workflow/mosr/special/fund',
method: "post",
data
});
};
export const resubmitFund= (data) => {
return request({
url: '/workflow/mosr/special/fund/resubmit',
method: "post",
data
});
};
export const deleteFund = (id) => {
return request({
url: `/workflow/mosr/special/fund/${id}`,
method: "delete"
});
};

View File

@@ -1,30 +1,30 @@
import request from "@/utils/request.js";
export const getSubCompanyList=(params)=>{
return request({
url:'/admin/mosr/sub/company',
method:'get',
params
})
}
export const getDepartmentList=(params)=>{
return request({
url:'/admin/mosr/department',
method:'get',
params
})
}
export const getCompanyDetail=(companyId)=>{
return request({
url:`/admin/mosr/sub/company/info/${companyId}`,
method:'get'
})
}
export const setCompanyLeader=(data)=>{
return request({
url:'/admin/mosr/sub/company/leader',
method:'post',
data:data
})
}
import request from "@/utils/request.js";
export const getSubCompanyList=(params)=>{
return request({
url:'/admin/mosr/sub/company',
method:'get',
params
})
}
export const getDepartmentList=(params)=>{
return request({
url:'/admin/mosr/department',
method:'get',
params
})
}
export const getCompanyDetail=(companyId)=>{
return request({
url:`/admin/mosr/sub/company/info/${companyId}`,
method:'get'
})
}
export const setCompanyLeader=(data)=>{
return request({
url:'/admin/mosr/sub/company/leader',
method:'post',
data:data
})
}

View File

@@ -1,54 +1,54 @@
import request from '@/utils/request.js'
// 请求参数配置表list
export const getConfigList = (params) => {
return request({
url: '/admin/config',
method: 'get',
params
})
}
//获取到option列表
// 获取参数配置表详情
export const getConfigDetails = (configId) => {
return request({
url: '/admin/config/' + configId,
method: 'get'
})
}
// 获取参数配置表详情
export const getConfigByKey = (configKey) => {
return request({
url: '/admin/config/key/' + configKey,
method: 'get'
})
}
// 新增参数配置表
export const addConfig = (data) => {
return request({
url: '/admin/config',
method: 'post',
data
})
}
// 修改参数配置表
export const editConfig = (data) => {
return request({
url: '/admin/config',
method: 'put',
data
})
}
// 删除参数配置表
export const delConfig =(configId) => {
return request({
url: '/admin/config/' + configId,
method: 'delete'
})
}
import request from '@/utils/request.js'
// 请求参数配置表list
export const getConfigList = (params) => {
return request({
url: '/admin/config',
method: 'get',
params
})
}
//获取到option列表
// 获取参数配置表详情
export const getConfigDetails = (configId) => {
return request({
url: '/admin/config/' + configId,
method: 'get'
})
}
// 获取参数配置表详情
export const getConfigByKey = (configKey) => {
return request({
url: '/admin/config/key/' + configKey,
method: 'get'
})
}
// 新增参数配置表
export const addConfig = (data) => {
return request({
url: '/admin/config',
method: 'post',
data
})
}
// 修改参数配置表
export const editConfig = (data) => {
return request({
url: '/admin/config',
method: 'put',
data
})
}
// 删除参数配置表
export const delConfig =(configId) => {
return request({
url: '/admin/config/' + configId,
method: 'delete'
})
}

View File

@@ -1,44 +1,44 @@
import request from '@/utils/request.js'
// 请求字典类型表list
export const getDictDataList = (params) => {
return request({
url: '/admin/dict/data',
method: 'get',
params
})
}
// 获取字典数据表详情
export const getDictDataDetails = (dictCode) => {
return request({
url: '/admin/dict/data/' + dictCode,
method: 'get'
})
}
// 新增字典数据表
export const addDictData = (data) => {
return request({
url: '/admin/dict/data',
method: 'post',
data
})
}
// 修改字典类型表
export const editDictData = (data) => {
return request({
url: '/admin/dict/data',
method: 'put',
data
})
}
// 删除字典类型表
export const delDictData = (dictCode) => {
return request({
url: `/admin/dict/data/${dictCode}`,
method: 'delete'
})
}
import request from '@/utils/request.js'
// 请求字典类型表list
export const getDictDataList = (params) => {
return request({
url: '/admin/dict/data',
method: 'get',
params
})
}
// 获取字典数据表详情
export const getDictDataDetails = (dictCode) => {
return request({
url: '/admin/dict/data/' + dictCode,
method: 'get'
})
}
// 新增字典数据表
export const addDictData = (data) => {
return request({
url: '/admin/dict/data',
method: 'post',
data
})
}
// 修改字典类型表
export const editDictData = (data) => {
return request({
url: '/admin/dict/data',
method: 'put',
data
})
}
// 删除字典类型表
export const delDictData = (dictCode) => {
return request({
url: `/admin/dict/data/${dictCode}`,
method: 'delete'
})
}

View File

@@ -1,58 +1,58 @@
import request from '@/utils/request.js'
export const getDictOption = () => {
return request({
url: '/admin/dict/type/option',
method: 'get'
})
}
// 请求字典类型表list
export const getDictTypeList = (params) => {
return request({
url: '/admin/dict/type',
method: 'get',
params
})
}
// 获取字典类型表详情
export const getDictTypeDetails = (dictTypeId) => {
return request({
url: '/admin/dict/type/' + dictTypeId,
method: 'get'
})
}
// 新增字典类型表
export const addDictType = (data) => {
return request({
url: '/admin/dict/type',
method: 'post',
data
})
}
// 修改字典类型表
export const editDictType = (data) => {
return request({
url: '/admin/dict/type',
method: 'put',
data
})
}
// 删除字典类型表
export const delDictType =(dictTypeId) => {
return request({
url: '/admin/dict/type/' + dictTypeId,
method: 'delete'
})
}
//字典刷新缓存
export const refreshDict =() => {
return request({
url: 'admin/dict/type/refresh',
method: 'post'
})
}
import request from '@/utils/request.js'
export const getDictOption = () => {
return request({
url: '/admin/dict/type/option',
method: 'get'
})
}
// 请求字典类型表list
export const getDictTypeList = (params) => {
return request({
url: '/admin/dict/type',
method: 'get',
params
})
}
// 获取字典类型表详情
export const getDictTypeDetails = (dictTypeId) => {
return request({
url: '/admin/dict/type/' + dictTypeId,
method: 'get'
})
}
// 新增字典类型表
export const addDictType = (data) => {
return request({
url: '/admin/dict/type',
method: 'post',
data
})
}
// 修改字典类型表
export const editDictType = (data) => {
return request({
url: '/admin/dict/type',
method: 'put',
data
})
}
// 删除字典类型表
export const delDictType =(dictTypeId) => {
return request({
url: '/admin/dict/type/' + dictTypeId,
method: 'delete'
})
}
//字典刷新缓存
export const refreshDict =() => {
return request({
url: 'admin/dict/type/refresh',
method: 'post'
})
}

View File

@@ -1,16 +1,16 @@
import request from '@/utils/request.js'
export const getMappingList = (params) => {
return request({
url: '/admin/mapping/switch',
method: 'get',
params
})
}
export const editMappingSwitch = (data) => {
return request({
url: '/admin/mapping/switch',
method: 'put',
data
})
}
import request from '@/utils/request.js'
export const getMappingList = (params) => {
return request({
url: '/admin/mapping/switch',
method: 'get',
params
})
}
export const editMappingSwitch = (data) => {
return request({
url: '/admin/mapping/switch',
method: 'put',
data
})
}

View File

@@ -1,8 +1,8 @@
import request from '@/utils/request'
export const getRouters = () => {
return request({
url: '/auth/router',
method: 'get'
})
import request from '@/utils/request'
export const getRouters = () => {
return request({
url: '/auth/router',
method: 'get'
})
}

View File

@@ -1,53 +1,53 @@
import request from '@/utils/request.js'
export const getMenuList = (params) => {
return request({
url: '/admin/menu',
method: 'get',
params
})
}
export const editMenu = (data) => {
return request({
url: '/admin/menu',
method: 'put',
data
})
}
export const addMenu = (data) => {
return request({
url: '/admin/menu',
method: 'post',
data
})
}
export const delMenu = (menuId) => {
return request({
url: '/admin/menu/'+menuId,
method: 'delete'
})
}
export const getMenuInfo = (menuId) => {
return request({
url: '/admin/menu/info/'+menuId,
method: 'get'
})
}
export const getMenuOpt = (excludeId=0) => {
return request({
url: '/admin/menu/option/'+excludeId,
method: 'get'
})
}
export const getMenuOptRole = (roleId) => {
return request({
url: '/admin/menu/option/role/'+roleId,
method: 'get'
})
}
import request from '@/utils/request.js'
export const getMenuList = (params) => {
return request({
url: '/admin/menu',
method: 'get',
params
})
}
export const editMenu = (data) => {
return request({
url: '/admin/menu',
method: 'put',
data
})
}
export const addMenu = (data) => {
return request({
url: '/admin/menu',
method: 'post',
data
})
}
export const delMenu = (menuId) => {
return request({
url: '/admin/menu/'+menuId,
method: 'delete'
})
}
export const getMenuInfo = (menuId) => {
return request({
url: '/admin/menu/info/'+menuId,
method: 'get'
})
}
export const getMenuOpt = (excludeId=0) => {
return request({
url: '/admin/menu/option/'+excludeId,
method: 'get'
})
}
export const getMenuOptRole = (roleId) => {
return request({
url: '/admin/menu/option/role/'+roleId,
method: 'get'
})
}

View File

@@ -1,251 +1,251 @@
import request from '@/utils/request.js'
// 根据角色或者部门id获取对应数据
export const getDeptOpt = (params = {}) => {
return request({
url: `/admin/mosr/department/option`,
method: 'get',
params
})
}
export const getSubCompOpt = () => {
return request({
url: `/admin/mosr/sub/company/option`,
method: 'get'
})
}
export const getUserAccount = () => {
return request({
url: `/admin/mosr/user/account/list`,
method: 'get'
})
}
export const judgeIsSameRole = (userId) => {
return request({
url: `/admin/mosr/user/company/same/${userId}`,
method: 'get'
})
}
// 查询角色信息
export const getRolesOpt = () => {
return request({
url: '/admin/role/option',
method: 'get',
})
}
// 获取岗位下拉
export const getJobOpt = () => {
return request({
url: '/admin/job/option',
method: 'get',
})
}
export const getMosrUserList = (params) => {
return request({
url: '/admin/mosr/user',
method: 'get',
params
})
}
export const getUserList = (params) => {
return request({
url: '/admin/user',
method: 'get',
params
})
}
//获取用户详情
export const getUserDetail = (userId) => {
return request({
url: `/admin/mosr/user/info/${userId}`,
method: "get"
});
};
// 操作
export const operate = (data, type) => {
// console.log(type ,'type');
if (data.userId && type !== '0') return editUser(data)
else if (type == '0') return editUserOA(data)
return addUser(data)
}
// 新增用户
export const addUser = (data) => {
return request({
url: '/admin/mosr/user',
method: 'post',
data
})
}
// 修改用户
export const editUser = (data) => {
return request({
url: '/admin/mosr/user',
method: 'put',
data
})
}
// 修改OA用户
export const editUserOA = (data) => {
return request({
url: '/admin/mosr/user/oa',
method: 'put',
data
})
}
//删除用户信息
export const deleteUser = (userId) => {
return request({
url: `/admin/user/${userId}`,
method: "delete"
});
};
//根据roleId获取用户信息
export const getUserByRoleId = (roleId, params) => {
return request({
url: `/admin/user/role/${roleId}`,
method: "get",
params
});
};
//排除角色id获取用户信息
export const getUserExcludeRoleId = (roleId, params) => {
return request({
url: `/admin/user/role/exclude/${roleId}`,
method: "get",
params
});
};
//建立角色用户绑定关系
export const roleBindUser = (data) => {
return request({
url: '/admin/user/bind/role',
method: 'put',
data
})
}
// 解除角色与用户之间的绑定状态
export const cancelAuthorization = (data) => {
return request({
url: '/admin/user/unbind/role',
method: 'put',
data
})
}
//解除当前角色对应的所有用户的绑定关系
export const unbindAllUser = (roleId) => {
return request({
url: '/admin/user/all/unbind/role',
method: 'put',
data: {
id: roleId
}
})
}
//根据岗位id获取分配的用户信息
export const getUserInfoByPostId = (postId, params) => {
return request({
url: `/admin/user/post/${postId}`,
method: 'get',
params
})
}
//排除岗位id获取用户信息
export const getUserExcludePostId = (postId, params) => {
return request({
url: `/admin/user/post/exclude/${postId}`,
method: "get",
params
});
};
//建立岗位与用户绑定关系
export const postBindUser = (userIds, postId) => {
return request({
url: '/admin/user/bind/post',
method: 'put',
data: {
ids: userIds,
id: postId
}
})
}
// 解除岗位与用户之间的绑定状态
export const cancelPostAndUserAuthorization = (userIds, postId) => {
return request({
url: '/admin/user/unbind/post',
method: 'put',
data: {
ids: userIds,
id: postId
}
})
}
//解除当前岗位对应的所有用户的绑定关系
export const unbindAllUserByPost = (postId) => {
return request({
url: '/admin/user/all/unbind/post',
method: 'put',
data: {
id: postId
}
})
}
export const bindAccount = (data) => {
return request({
url: '/admin/mosr/user/bind/account',
method: 'post',
data
})
}
export const getBindAccount = (userId) => {
return request({
url: `/admin/mosr/user/bind/account/info/${userId}`,
method: 'get'
})
}
export const checkMatrix = (userId) => {
return request({
url: `/admin/mosr/user/matrix?userId=` + userId,
method: 'get'
})
}
export const getAgentInfo=(userId)=>{
return request({
url: `/admin/mosr/user/approval/agent/${userId}`,
method:'get'
})
}
export const editAgentInfo=(data)=>{
return request({
url:'/admin/mosr/user/approval/agent',
method:'post',
data
})
}
export const addWhiteUser=(data)=>{
return request({
url:'/admin/approve/white',
method:'post',
data
})
}
export const delWhiteUser=(data)=>{
return request({
url:'/admin/approve/white',
method:'delete',
data
})
}
import request from '@/utils/request.js'
// 根据角色或者部门id获取对应数据
export const getDeptOpt = (params = {}) => {
return request({
url: `/admin/mosr/department/option`,
method: 'get',
params
})
}
export const getSubCompOpt = () => {
return request({
url: `/admin/mosr/sub/company/option`,
method: 'get'
})
}
export const getUserAccount = () => {
return request({
url: `/admin/mosr/user/account/list`,
method: 'get'
})
}
export const judgeIsSameRole = (userId) => {
return request({
url: `/admin/mosr/user/company/same/${userId}`,
method: 'get'
})
}
// 查询角色信息
export const getRolesOpt = () => {
return request({
url: '/admin/role/option',
method: 'get',
})
}
// 获取岗位下拉
export const getJobOpt = () => {
return request({
url: '/admin/job/option',
method: 'get',
})
}
export const getMosrUserList = (params) => {
return request({
url: '/admin/mosr/user',
method: 'get',
params
})
}
export const getUserList = (params) => {
return request({
url: '/admin/user',
method: 'get',
params
})
}
//获取用户详情
export const getUserDetail = (userId) => {
return request({
url: `/admin/mosr/user/info/${userId}`,
method: "get"
});
};
// 操作
export const operate = (data, type) => {
// console.log(type ,'type');
if (data.userId && type !== '0') return editUser(data)
else if (type == '0') return editUserOA(data)
return addUser(data)
}
// 新增用户
export const addUser = (data) => {
return request({
url: '/admin/mosr/user',
method: 'post',
data
})
}
// 修改用户
export const editUser = (data) => {
return request({
url: '/admin/mosr/user',
method: 'put',
data
})
}
// 修改OA用户
export const editUserOA = (data) => {
return request({
url: '/admin/mosr/user/oa',
method: 'put',
data
})
}
//删除用户信息
export const deleteUser = (userId) => {
return request({
url: `/admin/user/${userId}`,
method: "delete"
});
};
//根据roleId获取用户信息
export const getUserByRoleId = (roleId, params) => {
return request({
url: `/admin/user/role/${roleId}`,
method: "get",
params
});
};
//排除角色id获取用户信息
export const getUserExcludeRoleId = (roleId, params) => {
return request({
url: `/admin/user/role/exclude/${roleId}`,
method: "get",
params
});
};
//建立角色用户绑定关系
export const roleBindUser = (data) => {
return request({
url: '/admin/user/bind/role',
method: 'put',
data
})
}
// 解除角色与用户之间的绑定状态
export const cancelAuthorization = (data) => {
return request({
url: '/admin/user/unbind/role',
method: 'put',
data
})
}
//解除当前角色对应的所有用户的绑定关系
export const unbindAllUser = (roleId) => {
return request({
url: '/admin/user/all/unbind/role',
method: 'put',
data: {
id: roleId
}
})
}
//根据岗位id获取分配的用户信息
export const getUserInfoByPostId = (postId, params) => {
return request({
url: `/admin/user/post/${postId}`,
method: 'get',
params
})
}
//排除岗位id获取用户信息
export const getUserExcludePostId = (postId, params) => {
return request({
url: `/admin/user/post/exclude/${postId}`,
method: "get",
params
});
};
//建立岗位与用户绑定关系
export const postBindUser = (userIds, postId) => {
return request({
url: '/admin/user/bind/post',
method: 'put',
data: {
ids: userIds,
id: postId
}
})
}
// 解除岗位与用户之间的绑定状态
export const cancelPostAndUserAuthorization = (userIds, postId) => {
return request({
url: '/admin/user/unbind/post',
method: 'put',
data: {
ids: userIds,
id: postId
}
})
}
//解除当前岗位对应的所有用户的绑定关系
export const unbindAllUserByPost = (postId) => {
return request({
url: '/admin/user/all/unbind/post',
method: 'put',
data: {
id: postId
}
})
}
export const bindAccount = (data) => {
return request({
url: '/admin/mosr/user/bind/account',
method: 'post',
data
})
}
export const getBindAccount = (userId) => {
return request({
url: `/admin/mosr/user/bind/account/info/${userId}`,
method: 'get'
})
}
export const checkMatrix = (userId) => {
return request({
url: `/admin/mosr/user/matrix?userId=` + userId,
method: 'get'
})
}
export const getAgentInfo=(userId)=>{
return request({
url: `/admin/mosr/user/approval/agent/${userId}`,
method:'get'
})
}
export const editAgentInfo=(data)=>{
return request({
url:'/admin/mosr/user/approval/agent',
method:'post',
data
})
}
export const addWhiteUser=(data)=>{
return request({
url:'/admin/approve/white',
method:'post',
data
})
}
export const delWhiteUser=(data)=>{
return request({
url:'/admin/approve/white',
method:'delete',
data
})
}

View File

@@ -1,78 +1,78 @@
import request from '@/utils/request.js'
export function getProcessDefinitionList(param) {
return request({
url: "/workflow/process/definition",
method: "get",
params: param
})
}
export function getProcessDefinitionInfo(deploymentId) {
return request({
url: "/workflow/process/definition/" + deploymentId,
method: "get",
})
}
export function getInitiateInfo(processDefinitionKey) {
return request({
url: "/workflow/process/definition/key/" + processDefinitionKey,
method: "get",
})
}
export function getHistoryVersion(processDefinitionKey) {
return request({
url: "/workflow/process/definition/history/" + processDefinitionKey,
method: "get",
})
}
export function deleteHistoryVersion(deploymentId) {
return request({
url: "/workflow/process/definition/" + deploymentId,
method: "delete",
})
}
export function suspendProcessDefinition(processDefinitionId) {
return request({
url: "/workflow/process/definition/suspend",
method: "put",
data: processDefinitionId
})
}
export function activateProcessDefinition(processDefinitionId) {
return request({
url: "/workflow/process/definition/activate",
method: "put",
data: processDefinitionId
})
}
export function addProcessDefinition(param) {
return request({
url: "/workflow/process/definition",
method: "post",
data: param
})
}
export function getTypeOption() {
return request({
url: "/workflow/process/definition/type/option",
method: "get",
})
}
export function getFromPerm(processKey) {
return request({
url: "/workflow/process/definition/from/perm/"+processKey,
method: "get",
})
}
import request from '@/utils/request.js'
export function getProcessDefinitionList(param) {
return request({
url: "/workflow/process/definition",
method: "get",
params: param
})
}
export function getProcessDefinitionInfo(deploymentId) {
return request({
url: "/workflow/process/definition/" + deploymentId,
method: "get",
})
}
export function getInitiateInfo(processDefinitionKey) {
return request({
url: "/workflow/process/definition/key/" + processDefinitionKey,
method: "get",
})
}
export function getHistoryVersion(processDefinitionKey) {
return request({
url: "/workflow/process/definition/history/" + processDefinitionKey,
method: "get",
})
}
export function deleteHistoryVersion(deploymentId) {
return request({
url: "/workflow/process/definition/" + deploymentId,
method: "delete",
})
}
export function suspendProcessDefinition(processDefinitionId) {
return request({
url: "/workflow/process/definition/suspend",
method: "put",
data: processDefinitionId
})
}
export function activateProcessDefinition(processDefinitionId) {
return request({
url: "/workflow/process/definition/activate",
method: "put",
data: processDefinitionId
})
}
export function addProcessDefinition(param) {
return request({
url: "/workflow/process/definition",
method: "post",
data: param
})
}
export function getTypeOption() {
return request({
url: "/workflow/process/definition/type/option",
method: "get",
})
}
export function getFromPerm(processKey) {
return request({
url: "/workflow/process/definition/from/perm/"+processKey,
method: "get",
})
}

View File

@@ -1,9 +1,9 @@
import request from '@/utils/request.js'
export function deleteFile(fileId) {
// 删除文件
return request({
url: '/workflow/process/file/' + fileId,
method: 'delete',
})
}
import request from '@/utils/request.js'
export function deleteFile(fileId) {
// 删除文件
return request({
url: '/workflow/process/file/' + fileId,
method: 'delete',
})
}

View File

@@ -1,53 +1,53 @@
import request from '@/utils/request.js'
/**
* 开始实例流程
* @param param
* @returns {*}
*/
export function startProcessInstance(param) {
return request({
url: "/workflow/process/instance/start",
method: "post",
data: param
})
}
export function restartProcessInstance(param) {
return request({
url: "/workflow/process/instance/restart",
method: "post",
data: param
})
}
export function getAboutInstanceList(param) {
return request({
url: "/workflow/process/instance/about",
method: "get",
params: param
})
}
export function getInitiatedInstanceList(param) {
return request({
url: "/workflow/process/instance/self",
method: "get",
params: param
})
}
export function getInitiatedInstanceInfo(processInstanceId) {
return request({
url: "/workflow/process/instance/info/"+processInstanceId,
method: "get",
})
}
export function getInitiatedInstanceReInfo(instanceId) {
return request({
url: "/workflow/process/instance/re/info/"+instanceId,
method: "get",
})
}
import request from '@/utils/request.js'
/**
* 开始实例流程
* @param param
* @returns {*}
*/
export function startProcessInstance(param) {
return request({
url: "/workflow/process/instance/start",
method: "post",
data: param
})
}
export function restartProcessInstance(param) {
return request({
url: "/workflow/process/instance/restart",
method: "post",
data: param
})
}
export function getAboutInstanceList(param) {
return request({
url: "/workflow/process/instance/about",
method: "get",
params: param
})
}
export function getInitiatedInstanceList(param) {
return request({
url: "/workflow/process/instance/self",
method: "get",
params: param
})
}
export function getInitiatedInstanceInfo(processInstanceId) {
return request({
url: "/workflow/process/instance/info/"+processInstanceId,
method: "get",
})
}
export function getInitiatedInstanceReInfo(instanceId) {
return request({
url: "/workflow/process/instance/re/info/"+instanceId,
method: "get",
})
}

View File

@@ -1,46 +1,46 @@
import request from '@/utils/request.js'
// 请求系统内置监听器list
export const getProcessListenerList = (params) => {
return request({
url: '/workflow/process/listener',
method: 'get',
params
})
}
//获取到option列表
// 获取系统内置监听器详情
export const getProcessListenerDetails = (processListenerId) => {
return request({
url: '/workflow/process/listener/' + processListenerId,
method: 'get'
})
}
// 新增系统内置监听器
export const addProcessListener = (data) => {
return request({
url: '/workflow/process/listener',
method: 'post',
data
})
}
// 修改系统内置监听器
export const editProcessListener = (data) => {
return request({
url: '/workflow/process/listener',
method: 'put',
data
})
}
// 删除系统内置监听器
export const delProcessListener =(processListenerId) => {
return request({
url: '/workflow/process/listener/' + processListenerId,
method: 'delete'
})
}
import request from '@/utils/request.js'
// 请求系统内置监听器list
export const getProcessListenerList = (params) => {
return request({
url: '/workflow/process/listener',
method: 'get',
params
})
}
//获取到option列表
// 获取系统内置监听器详情
export const getProcessListenerDetails = (processListenerId) => {
return request({
url: '/workflow/process/listener/' + processListenerId,
method: 'get'
})
}
// 新增系统内置监听器
export const addProcessListener = (data) => {
return request({
url: '/workflow/process/listener',
method: 'post',
data
})
}
// 修改系统内置监听器
export const editProcessListener = (data) => {
return request({
url: '/workflow/process/listener',
method: 'put',
data
})
}
// 删除系统内置监听器
export const delProcessListener =(processListenerId) => {
return request({
url: '/workflow/process/listener/' + processListenerId,
method: 'delete'
})
}

View File

@@ -1,45 +1,45 @@
import request from '@/utils/request.js'
export function getTaskList() {
return request({
url: "/workflow/process/task",
method: "get",
})
}
export function getTaskInfo(taskId) {
return request({
url: "/workflow/process/task/"+taskId,
method: "get",
})
}
export function completeTask(params) {
return request({
url: "/workflow/process/task/complete",
method: "put",
data: params
})
}
export function refuseTask(params) {
return request({
url: "/workflow/process/task/refuse",
method: "put",
data: params
})
}
export function rollBackTask(params) {
return request({
url: "/workflow/process/task/rollback",
method: "put",
data: params
})
}
export function addComment(params) {
return request({
url: "/workflow/process/task/comment",
method: "post",
data: params
})
}
import request from '@/utils/request.js'
export function getTaskList() {
return request({
url: "/workflow/process/task",
method: "get",
})
}
export function getTaskInfo(taskId) {
return request({
url: "/workflow/process/task/"+taskId,
method: "get",
})
}
export function completeTask(params) {
return request({
url: "/workflow/process/task/complete",
method: "put",
data: params
})
}
export function refuseTask(params) {
return request({
url: "/workflow/process/task/refuse",
method: "put",
data: params
})
}
export function rollBackTask(params) {
return request({
url: "/workflow/process/task/rollback",
method: "put",
data: params
})
}
export function addComment(params) {
return request({
url: "/workflow/process/task/comment",
method: "post",
data: params
})
}

View File

@@ -1,47 +1,47 @@
import request from '@/utils/request.js'
//根据角色或者部门获取到对应的数据
export function getUserTree(type,chooseId){
return request({
url:`/admin/user/choose/${type}/${chooseId}`,
method:'get'
})
}
// 查询系统角色
export function getRole() {
return request({
url: 'admin/role/option',
method: 'get'
})
}
//获取采取树形控件的部门option
export function getDepartmentTree() {
return request({
url: 'admin/dept/option',
method: 'get'
})
}
export function getMosrUser(params) {
return request({
url: '/admin/mosr/user/choose',
method: 'get',
params:params
})
}
export function getOrganizationStructure(params) {
return request({
url: '/admin/organizational/structure/choose',
method: 'get',
params:params
})
}
export function getOrganizationStructureTree(params) {
return request({
url: '/admin/organizational/structure/tree',
method: 'get',
params: params
})
}
import request from '@/utils/request.js'
//根据角色或者部门获取到对应的数据
export function getUserTree(type,chooseId){
return request({
url:`/admin/user/choose/${type}/${chooseId}`,
method:'get'
})
}
// 查询系统角色
export function getRole() {
return request({
url: 'admin/role/option',
method: 'get'
})
}
//获取采取树形控件的部门option
export function getDepartmentTree() {
return request({
url: 'admin/dept/option',
method: 'get'
})
}
export function getMosrUser(params) {
return request({
url: '/admin/mosr/user/choose',
method: 'get',
params:params
})
}
export function getOrganizationStructure(params) {
return request({
url: '/admin/organizational/structure/choose',
method: 'get',
params:params
})
}
export function getOrganizationStructureTree(params) {
return request({
url: '/admin/organizational/structure/tree',
method: 'get',
params: params
})
}

View File

@@ -1,77 +1,77 @@
tinymce.PluginManager.add('axupimgs', function (editor, url) {
var pluginName = '多图片上传';
window.axupimgs = {}; //扔外部公共变量,也可以扔一个自定义的位置
const baseURL = import.meta.env.VITE_BASE_URL
// var baseURL=tinymce.baseURL;
var iframe1 = '/upfiles.html';
console.log('editor',editor)
axupimgs.images_upload_handler = editor.getParam('images_upload_handler_not_loading', undefined, 'function');
axupimgs.images_upload_base_path = editor.getParam('images_upload_base_path', '', 'string');
axupimgs.axupimgs_filetype = editor.getParam('axupimgs_filetype', '.png,.gif,.jpg,.jpeg', 'string');
axupimgs.res = [];
var openDialog = function () {
return editor.windowManager.openUrl({
title: pluginName,
size: 'large',
url: iframe1,
buttons: [
{
type: 'cancel',
text: 'Close'
},
{
type: 'custom',
text: 'Save',
name: 'save',
primary: true
},
],
onAction: function (api, details) {
switch (details.name) {
case 'save':
var html = '';
var imgs = axupimgs.res;
var len = imgs.length;
for (let i = 0; i < len; i++) {
if (imgs[i].url) {
html += '<img src="' + imgs[i].url + '" />';
}
}
editor.insertContent(html);
axupimgs.res = [];
api.close();
break;
default:
break;
}
}
});
};
editor.ui.registry.getAll().icons.axupimgs || editor.ui.registry.addIcon('axupimgs', '<svg viewBox="0 0 1280 1024" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M1126.2,779.8V87.6c0-24-22.6-86.9-83.5-86.9H83.5C14.7,0.7,0,63.7,0,87.7v692c0,36.2,29.2,89.7,83.5,89.7l959.3-1.3c51.7,0,83.5-42.5,83.5-88.3zm-1044,4V86.3h961.6V783.7H82.2v0.1z" fill="#53565A"/><path d="M603,461.6L521.1,366.3,313,629.8,227.2,546.8,102.4,716.8H972.8v-170L768.2,235.2,603.1,461.6zM284.6,358.4a105.4,105.4,0,0,0,73.5-30c19.5-19.1,30.3-45,30.2-71.8,0-56.8-45.9-103-102.4-103-56.6,0-102.4,46.1-102.4,103C183.4,313.5,228,358.4,284.6,358.4z" fill="#9598A0"/><path d="M1197.7,153.6l-0.3,669.3s13.5,113.9-67.4,113.9H153.6c0,24.1,23.9,87.2,83.5,87.2h959.3c58.3,0,83.6-49.5,83.6-89.9V240.8c-0.1-41.8-44.9-87.2-82.3-87.2z" fill="#53565A"/></svg>');
editor.ui.registry.addButton('axupimgs', {
icon: 'axupimgs',
tooltip: pluginName,
onAction: function () {
openDialog();
}
});
editor.ui.registry.addMenuItem('axupimgs', {
icon: 'axupimgs',
text: '图片批量上传...',
onAction: function () {
openDialog();
}
});
return {
getMetadata: function () {
return {
name: pluginName,
url: "http://tinymce.ax-z.cn/more-plugins/axupimgs.php",
};
}
};
});
tinymce.PluginManager.add('axupimgs', function (editor, url) {
var pluginName = '多图片上传';
window.axupimgs = {}; //扔外部公共变量,也可以扔一个自定义的位置
const baseURL = import.meta.env.VITE_BASE_URL
// var baseURL=tinymce.baseURL;
var iframe1 = '/upfiles.html';
console.log('editor',editor)
axupimgs.images_upload_handler = editor.getParam('images_upload_handler_not_loading', undefined, 'function');
axupimgs.images_upload_base_path = editor.getParam('images_upload_base_path', '', 'string');
axupimgs.axupimgs_filetype = editor.getParam('axupimgs_filetype', '.png,.gif,.jpg,.jpeg', 'string');
axupimgs.res = [];
var openDialog = function () {
return editor.windowManager.openUrl({
title: pluginName,
size: 'large',
url: iframe1,
buttons: [
{
type: 'cancel',
text: 'Close'
},
{
type: 'custom',
text: 'Save',
name: 'save',
primary: true
},
],
onAction: function (api, details) {
switch (details.name) {
case 'save':
var html = '';
var imgs = axupimgs.res;
var len = imgs.length;
for (let i = 0; i < len; i++) {
if (imgs[i].url) {
html += '<img src="' + imgs[i].url + '" />';
}
}
editor.insertContent(html);
axupimgs.res = [];
api.close();
break;
default:
break;
}
}
});
};
editor.ui.registry.getAll().icons.axupimgs || editor.ui.registry.addIcon('axupimgs', '<svg viewBox="0 0 1280 1024" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M1126.2,779.8V87.6c0-24-22.6-86.9-83.5-86.9H83.5C14.7,0.7,0,63.7,0,87.7v692c0,36.2,29.2,89.7,83.5,89.7l959.3-1.3c51.7,0,83.5-42.5,83.5-88.3zm-1044,4V86.3h961.6V783.7H82.2v0.1z" fill="#53565A"/><path d="M603,461.6L521.1,366.3,313,629.8,227.2,546.8,102.4,716.8H972.8v-170L768.2,235.2,603.1,461.6zM284.6,358.4a105.4,105.4,0,0,0,73.5-30c19.5-19.1,30.3-45,30.2-71.8,0-56.8-45.9-103-102.4-103-56.6,0-102.4,46.1-102.4,103C183.4,313.5,228,358.4,284.6,358.4z" fill="#9598A0"/><path d="M1197.7,153.6l-0.3,669.3s13.5,113.9-67.4,113.9H153.6c0,24.1,23.9,87.2,83.5,87.2h959.3c58.3,0,83.6-49.5,83.6-89.9V240.8c-0.1-41.8-44.9-87.2-82.3-87.2z" fill="#53565A"/></svg>');
editor.ui.registry.addButton('axupimgs', {
icon: 'axupimgs',
tooltip: pluginName,
onAction: function () {
openDialog();
}
});
editor.ui.registry.addMenuItem('axupimgs', {
icon: 'axupimgs',
text: '图片批量上传...',
onAction: function () {
openDialog();
}
});
return {
getMetadata: function () {
return {
name: pluginName,
url: "http://tinymce.ax-z.cn/more-plugins/axupimgs.php",
};
}
};
});

View File

@@ -1,75 +1,75 @@
tinymce.PluginManager.add('axupimgs', function(editor, url) {
var pluginName='Ax多图片上传';
window.axupimgs={}; //扔外部公共变量,也可以扔一个自定义的位置
var baseURL=tinymce.baseURL;
var iframe1 = baseURL+'/plugins/axupimgs/upfiles.html';
axupimgs.images_upload_handler = editor.getParam('images_upload_handler', undefined, 'function');
axupimgs.images_upload_base_path = editor.getParam('images_upload_base_path', '', 'string');
axupimgs.axupimgs_filetype = editor.getParam('axupimgs_filetype', '.png,.gif,.jpg,.jpeg', 'string');
axupimgs.res=[];
var openDialog = function() {
return editor.windowManager.openUrl({
title: pluginName,
size: 'large',
url:iframe1,
buttons: [
{
type: 'cancel',
text: 'Close'
},
{
type: 'custom',
text: 'Save',
name: 'save',
primary: true
},
],
onAction: function (api, details) {
switch (details.name) {
case 'save':
var html = '';
var imgs = axupimgs.res;
var len = imgs.length;
for(let i=0;i<len;i++){
if( imgs[i].url ){
html += '<img src="'+imgs[i].url+'" />';
}
}
editor.insertContent(html);
axupimgs.res=[];
api.close();
break;
default:
break;
}
}
});
};
editor.ui.registry.getAll().icons.axupimgs || editor.ui.registry.addIcon('axupimgs','<svg viewBox="0 0 1280 1024" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M1126.2,779.8V87.6c0-24-22.6-86.9-83.5-86.9H83.5C14.7,0.7,0,63.7,0,87.7v692c0,36.2,29.2,89.7,83.5,89.7l959.3-1.3c51.7,0,83.5-42.5,83.5-88.3zm-1044,4V86.3h961.6V783.7H82.2v0.1z" fill="#53565A"/><path d="M603,461.6L521.1,366.3,313,629.8,227.2,546.8,102.4,716.8H972.8v-170L768.2,235.2,603.1,461.6zM284.6,358.4a105.4,105.4,0,0,0,73.5-30c19.5-19.1,30.3-45,30.2-71.8,0-56.8-45.9-103-102.4-103-56.6,0-102.4,46.1-102.4,103C183.4,313.5,228,358.4,284.6,358.4z" fill="#9598A0"/><path d="M1197.7,153.6l-0.3,669.3s13.5,113.9-67.4,113.9H153.6c0,24.1,23.9,87.2,83.5,87.2h959.3c58.3,0,83.6-49.5,83.6-89.9V240.8c-0.1-41.8-44.9-87.2-82.3-87.2z" fill="#53565A"/></svg>');
editor.ui.registry.addButton('axupimgs', {
icon: 'axupimgs',
tooltip: pluginName,
onAction: function() {
openDialog();
}
});
editor.ui.registry.addMenuItem('axupimgs', {
icon: 'axupimgs',
text: '图片批量上传...',
onAction: function() {
openDialog();
}
});
return {
getMetadata: function() {
return {
name: pluginName,
url: "http://tinymce.ax-z.cn/more-plugins/axupimgs.php",
};
}
};
});
tinymce.PluginManager.add('axupimgs', function(editor, url) {
var pluginName='Ax多图片上传';
window.axupimgs={}; //扔外部公共变量,也可以扔一个自定义的位置
var baseURL=tinymce.baseURL;
var iframe1 = baseURL+'/plugins/axupimgs/upfiles.html';
axupimgs.images_upload_handler = editor.getParam('images_upload_handler', undefined, 'function');
axupimgs.images_upload_base_path = editor.getParam('images_upload_base_path', '', 'string');
axupimgs.axupimgs_filetype = editor.getParam('axupimgs_filetype', '.png,.gif,.jpg,.jpeg', 'string');
axupimgs.res=[];
var openDialog = function() {
return editor.windowManager.openUrl({
title: pluginName,
size: 'large',
url:iframe1,
buttons: [
{
type: 'cancel',
text: 'Close'
},
{
type: 'custom',
text: 'Save',
name: 'save',
primary: true
},
],
onAction: function (api, details) {
switch (details.name) {
case 'save':
var html = '';
var imgs = axupimgs.res;
var len = imgs.length;
for(let i=0;i<len;i++){
if( imgs[i].url ){
html += '<img src="'+imgs[i].url+'" />';
}
}
editor.insertContent(html);
axupimgs.res=[];
api.close();
break;
default:
break;
}
}
});
};
editor.ui.registry.getAll().icons.axupimgs || editor.ui.registry.addIcon('axupimgs','<svg viewBox="0 0 1280 1024" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M1126.2,779.8V87.6c0-24-22.6-86.9-83.5-86.9H83.5C14.7,0.7,0,63.7,0,87.7v692c0,36.2,29.2,89.7,83.5,89.7l959.3-1.3c51.7,0,83.5-42.5,83.5-88.3zm-1044,4V86.3h961.6V783.7H82.2v0.1z" fill="#53565A"/><path d="M603,461.6L521.1,366.3,313,629.8,227.2,546.8,102.4,716.8H972.8v-170L768.2,235.2,603.1,461.6zM284.6,358.4a105.4,105.4,0,0,0,73.5-30c19.5-19.1,30.3-45,30.2-71.8,0-56.8-45.9-103-102.4-103-56.6,0-102.4,46.1-102.4,103C183.4,313.5,228,358.4,284.6,358.4z" fill="#9598A0"/><path d="M1197.7,153.6l-0.3,669.3s13.5,113.9-67.4,113.9H153.6c0,24.1,23.9,87.2,83.5,87.2h959.3c58.3,0,83.6-49.5,83.6-89.9V240.8c-0.1-41.8-44.9-87.2-82.3-87.2z" fill="#53565A"/></svg>');
editor.ui.registry.addButton('axupimgs', {
icon: 'axupimgs',
tooltip: pluginName,
onAction: function() {
openDialog();
}
});
editor.ui.registry.addMenuItem('axupimgs', {
icon: 'axupimgs',
text: '图片批量上传...',
onAction: function() {
openDialog();
}
});
return {
getMetadata: function() {
return {
name: pluginName,
url: "http://tinymce.ax-z.cn/more-plugins/axupimgs.php",
};
}
};
});

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>

Before

Width:  |  Height:  |  Size: 276 B

After

Width:  |  Height:  |  Size: 277 B

View File

@@ -1,144 +1,144 @@
* {
margin: 0;
padding: 0;
list-style: none;
box-sizing: border-box;
}
/* ==============X轴/Y轴区域样式=============*/
.box-card-h {
height: 390px !important;
}
.box-card::-webkit-scrollbar {
width: 6px;
}
// 滚动条轨道
.box-card::-webkit-scrollbar-track {
background: rgb(239, 239, 239);
border-radius: 2px;
}
// 小滑块
.box-card::-webkit-scrollbar-thumb {
background: rgba(80, 81, 82, 0.29);
border-radius: 10px;
}
.box-card {
font-size: 15px;
height: 350px;
overflow-y: auto;
.el-card__body {
padding: 15px;
}
.x-y-axis {
margin-bottom: 10px;
}
.list-group {
height: 100%;
}
.cards {
margin-bottom: 10px;
span:last-child {
color: #2a99ff;
}
.update-color {
display: flex;
align-items: center;
justify-content: space-around;
> span{
white-space: pre
}
}
}
.card-active {
outline: none; /* 隐藏默认的蓝色外边框 */
box-shadow: 0 0 5px blue; /* 添加阴影效果,颜色为蓝色 */
}
.x-y-cards {
.el-card__body {
display: flex;
justify-content: space-around;
align-items: center;
height: 50px;
}
.cards-right {
display: flex;
align-items: center;
justify-content: flex-end;
> span:first-child {
color: #2a99ff;
}
}
}
}
//扩大拖拽区域
.drag-block {
height: 329px;
}
.red-bgc {
background-color: red;
}
.yellow-bgc {
background-color: yellow;
}
/* ==============基础设置样式=============*/
.basic-setup {
font-weight: bold;
font-size: 18px;
margin-bottom: 10px;
}
.setting {
display: flex;
flex-direction: column;
margin-bottom: 10px;
.setting-title {
font-weight: bold;
font-size: 16px;
margin-bottom: 5px;
}
.setting-item {
margin-bottom: 10px;
}
}
/* ==============高级设置样式=============*/
.advanced-setting{
.el-form-item {
display: block;
.el-form-item__label {
font-weight: bold;
font-size: 18px;
}
.el-form-item__content {
display: flex;
flex-direction: column;
align-items: flex-start;
font-size: 15px;
}
}
}
/* ==============echarts样式=============*/
#container {
box-sizing: border-box;
height: 450px;
width: 80%;
margin: 0 auto;
}
* {
margin: 0;
padding: 0;
list-style: none;
box-sizing: border-box;
}
/* ==============X轴/Y轴区域样式=============*/
.box-card-h {
height: 390px !important;
}
.box-card::-webkit-scrollbar {
width: 6px;
}
// 滚动条轨道
.box-card::-webkit-scrollbar-track {
background: rgb(239, 239, 239);
border-radius: 2px;
}
// 小滑块
.box-card::-webkit-scrollbar-thumb {
background: rgba(80, 81, 82, 0.29);
border-radius: 10px;
}
.box-card {
font-size: 15px;
height: 350px;
overflow-y: auto;
.el-card__body {
padding: 15px;
}
.x-y-axis {
margin-bottom: 10px;
}
.list-group {
height: 100%;
}
.cards {
margin-bottom: 10px;
span:last-child {
color: #2a99ff;
}
.update-color {
display: flex;
align-items: center;
justify-content: space-around;
> span{
white-space: pre
}
}
}
.card-active {
outline: none; /* 隐藏默认的蓝色外边框 */
box-shadow: 0 0 5px blue; /* 添加阴影效果,颜色为蓝色 */
}
.x-y-cards {
.el-card__body {
display: flex;
justify-content: space-around;
align-items: center;
height: 50px;
}
.cards-right {
display: flex;
align-items: center;
justify-content: flex-end;
> span:first-child {
color: #2a99ff;
}
}
}
}
//扩大拖拽区域
.drag-block {
height: 329px;
}
.red-bgc {
background-color: red;
}
.yellow-bgc {
background-color: yellow;
}
/* ==============基础设置样式=============*/
.basic-setup {
font-weight: bold;
font-size: 18px;
margin-bottom: 10px;
}
.setting {
display: flex;
flex-direction: column;
margin-bottom: 10px;
.setting-title {
font-weight: bold;
font-size: 16px;
margin-bottom: 5px;
}
.setting-item {
margin-bottom: 10px;
}
}
/* ==============高级设置样式=============*/
.advanced-setting{
.el-form-item {
display: block;
.el-form-item__label {
font-weight: bold;
font-size: 18px;
}
.el-form-item__content {
display: flex;
flex-direction: column;
align-items: flex-start;
font-size: 15px;
}
}
}
/* ==============echarts样式=============*/
#container {
box-sizing: border-box;
height: 450px;
width: 80%;
margin: 0 auto;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,53 +1,53 @@
.el-side {
border-radius: 10px;
}
.logo {
height: 65px;
background-color: #BEA266;
color: #ffffff;
font-weight: bold;
font-size: 26px;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
padding: 10px;
& > img {
object-fit: scale-down;
width: 100%;
height: 40px;
}
}
.port-link{
display: block;
width: 200px;
height: 50px;
margin-left: -40px;
padding-left: 40px;
}
.el-menu {
border: none !important;
.el-sub-menu {
.el-sub-menu__title {
display: block;
font-size: 14px;
&:hover{
//background-color: #1F315F;
}
}
.el-menu-item {
font-size: 14px;
justify-content: flex-start;
align-items: center;
&:hover {
//background-color: #373350 !important;
//color: #EDC49A;
}
}
.el-menu-item.is-active {
background: rgba(190,162,102,0.5);
//background-color: #373350 !important;
}
}
}
.el-side {
border-radius: 10px;
}
.logo {
height: 65px;
background-color: #BEA266;
color: #ffffff;
font-weight: bold;
font-size: 26px;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
padding: 10px;
& > img {
object-fit: scale-down;
width: 100%;
height: 40px;
}
}
.port-link{
display: block;
width: 200px;
height: 50px;
margin-left: -40px;
padding-left: 40px;
}
.el-menu {
border: none !important;
.el-sub-menu {
.el-sub-menu__title {
display: block;
font-size: 14px;
&:hover{
//background-color: #1F315F;
}
}
.el-menu-item {
font-size: 14px;
justify-content: flex-start;
align-items: center;
&:hover {
//background-color: #373350 !important;
//color: #EDC49A;
}
}
.el-menu-item.is-active {
background: rgba(190,162,102,0.5);
//background-color: #373350 !important;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,110 +1,110 @@
<template>
<el-button color="#DED0B2" style="float: right;margin: 0 10px 10px 0" @click="exportExcelHandler">导出</el-button>
<el-table ref="table" :data="tableData" style="width: 100%;height: 479px" :show-summary="true" border
:summary-method="getSummaries" v-loading="loading" :header-cell-style="{background:'#f5f7fa'}">
<el-table-column type="index" label="序号" align="center" width="60"/>
<el-table-column prop="projectName" label="项目名称" align="center"/>
<el-table-column prop="projectCost" label="费用性质" align="center">
<template #default="scope">
<div v-if="scope.row.projectCost !== null">
<Tag dictType="project_cost" :value="scope.row.projectCost"/>
</div>
<div v-else>--</div>
</template>
</el-table-column>
<el-table-column prop="researchStage" label="研发阶段" align="center">
<template #default="scope">
<div v-if="scope.row.researchStage !== null && scope.row.researchStage !== null && scope.row.researchStage !== undefined">
<el-tag effect="plain">{{scope.row.researchStage==1?'开发阶段':'研究阶段'}}</el-tag>
</div>
<div v-else>--</div>
</template>
</el-table-column>
<el-table-column prop="afterTax" label="分摊金额" align="center">
<template #default="scope">
<div v-if="scope.row.afterTax !== null">
<!-- {{ toThousands(scope.row.afterTax) }}-->
{{ scope.row.afterTax }}
</div>
</template>
</el-table-column>
</el-table>
<!-- <Tag dictType="research_stage" :value="scope.row.researchStage"/>-->
</template>
<script setup>
import {getAllocationSummaryDetails} from "@/api/expense-manage";
import {shareExportExcel} from "@/api/expense-manage";
const props = defineProps({
allocationName :{
type: String,
default: ''
}
})
const tableData = ref()
const loading = ref(false)
const table = ref()
const route = useRoute()
const getSummaries = (param) => {
const {columns, data} = param
const sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '小计'
} else if (index === 4) {
const values = data.map((item) => Number(item[column.property]))
if (!values.every((value) => Number.isNaN(value))) {
sums[index] = `${values.reduce((prev, curr) => {
const value = Number(curr)
if (!Number.isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)}`
sums[index] = parseFloat(sums[index]).toFixed(2)
// sums[index] = toThousands(sums[index])
} else {
sums[index] = '-'
}
}
})
return sums
}
// const exportTable = () => {
// const $e = table.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 exportExcelHandler = () => {
shareExportExcel(route.query.id).then(res => {
let fileName = `科技创新项目费用分摊表-${props.allocationName}.zip`
const blob = new Blob([res.data])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = fileName
a.click()
})
}
const init = () => {
loading.value = true
let params = {
allocationId: route.query.id
}
getAllocationSummaryDetails(params).then(res => {
tableData.value = res.data
loading.value = false
})
}
init()
</script>
<style scoped>
</style>
<template>
<el-button color="#DED0B2" style="float: right;margin: 0 10px 10px 0" @click="exportExcelHandler">导出</el-button>
<el-table ref="table" :data="tableData" style="width: 100%;height: 479px" :show-summary="true" border
:summary-method="getSummaries" v-loading="loading" :header-cell-style="{background:'#f5f7fa'}">
<el-table-column type="index" label="序号" align="center" width="60"/>
<el-table-column prop="projectName" label="项目名称" align="center"/>
<el-table-column prop="projectCost" label="费用性质" align="center">
<template #default="scope">
<div v-if="scope.row.projectCost !== null">
<Tag dictType="project_cost" :value="scope.row.projectCost"/>
</div>
<div v-else>--</div>
</template>
</el-table-column>
<el-table-column prop="researchStage" label="研发阶段" align="center">
<template #default="scope">
<div v-if="scope.row.researchStage !== null && scope.row.researchStage !== null && scope.row.researchStage !== undefined">
<el-tag effect="plain">{{scope.row.researchStage==1?'开发阶段':'研究阶段'}}</el-tag>
</div>
<div v-else>--</div>
</template>
</el-table-column>
<el-table-column prop="afterTax" label="分摊金额" align="center">
<template #default="scope">
<div v-if="scope.row.afterTax !== null">
<!-- {{ toThousands(scope.row.afterTax) }}-->
{{ scope.row.afterTax }}
</div>
</template>
</el-table-column>
</el-table>
<!-- <Tag dictType="research_stage" :value="scope.row.researchStage"/>-->
</template>
<script setup>
import {getAllocationSummaryDetails} from "@/api/expense-manage";
import {shareExportExcel} from "@/api/expense-manage";
const props = defineProps({
allocationName :{
type: String,
default: ''
}
})
const tableData = ref()
const loading = ref(false)
const table = ref()
const route = useRoute()
const getSummaries = (param) => {
const {columns, data} = param
const sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '小计'
} else if (index === 4) {
const values = data.map((item) => Number(item[column.property]))
if (!values.every((value) => Number.isNaN(value))) {
sums[index] = `${values.reduce((prev, curr) => {
const value = Number(curr)
if (!Number.isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)}`
sums[index] = parseFloat(sums[index]).toFixed(2)
// sums[index] = toThousands(sums[index])
} else {
sums[index] = '-'
}
}
})
return sums
}
// const exportTable = () => {
// const $e = table.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 exportExcelHandler = () => {
shareExportExcel(route.query.id).then(res => {
let fileName = `科技创新项目费用分摊表-${props.allocationName}.zip`
const blob = new Blob([res.data])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = fileName
a.click()
})
}
const init = () => {
loading.value = true
let params = {
allocationId: route.query.id
}
getAllocationSummaryDetails(params).then(res => {
tableData.value = res.data
loading.value = false
})
}
init()
</script>
<style scoped>
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,208 +1,208 @@
<template>
<div v-loading="loading" :style="type==='singleDetail'?'padding: 0 30px':''">
<baseTitle title="需求征集信息" v-if="type!=='singleDetail'"></baseTitle>
<el-form :model="formData" >
<el-row gutter="20" style="margin-left: 5px">
<el-col :span="6">
<el-form-item label="征集名称">
<span>{{ formData.requirementName }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="征集类型">
<span>{{ formData.collectType }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="需求上报截止时间">
<span>{{ formData.deadline }}</span>
</el-form-item>
</el-col>
<el-col :span="6" v-if="formData.isSpecialFund">
<el-form-item label="专项资金名称">
<span>{{ formData.specialFund }}</span>
</el-form-item>
</el-col>
<el-col :span="24" v-if="type==='singleDetail'">
<el-form-item label="征集公司">
<span :class="showExpendClass(showMoreCompany,formData.companyIds)">{{
getCompanyName(formData.companyIds)
}}</span>
<div style="color: #2a99ff;text-align: center;width: 100%;font-size: 15px;cursor: pointer"
@click="handleExpend">{{ showExpendText }}
</div>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-bottom: -15px">
<el-form-item label="征集说明">
<div v-if="formData.collectExplain" v-html="formData.collectExplain" style="white-space: pre-wrap;">
</div>
<div v-else>--</div>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<baseTitle v-if="fileListShow === 'READ' || fileListShow === 'EDIT'" title="附件文件" style="margin-bottom: 0"></baseTitle>
<file-component title="" tag="需求征集"
v-model:value="formData.fileList" :processViewer="processViewer"
:file-list-show="fileListShow"/>
</el-col>
<el-col :span="24" style="margin-top: -15px">
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
v-model="_value"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
</el-col>
</el-row>
<div class="approval-record" style="margin-top: -15px">
<div class="approval-title">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color:#BEA266; --el-switch-off-color:#cecdcd"
/>
</div>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="collectionProcess"/>
</div>
</div>
</el-form>
</div>
</template>
<script setup lang="jsx">
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {downloadFile} from "@/api/project-demand";
const emit = defineEmits(['update:value'])
const showExpendText = ref('')
const showMoreCompany = ref(false)
const props = defineProps({
formData: {
type: Array,
default: []
},
data: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
},
companyOption: {
type: Array,
default: []
},
loading: {
type: Boolean,
default: false
},
fileListShow: {
type: String,
default: ''
},
type: {
type: String,
default: ''
},
value: {
type: String,
default: ''
}
})
const changeDiagram = ref(false)
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const getCompanyName = (data) => {
if (data) {
return data.join('')
}
}
const handleExpend = () => {
showMoreCompany.value = !showMoreCompany.value;
showExpendClass(showMoreCompany.value, props.formData.companyIds)
}
const showExpendClass = (showMoreCompany, data) => {
if (!showMoreCompany) {
if (data && data.length > 14) {
showExpendText.value = '展开'
return 'company-style'
}
} else {
showExpendText.value = '收缩'
return ''
}
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
:deep(.el-empty__description) {
margin-top: 0;
}
.company-style {
//width: 98%;
min-height: 30px;
max-height: 60px;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
}
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: -53px !important;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: -26px !important;
}
}
}
</style>
<template>
<div v-loading="loading" :style="type==='singleDetail'?'padding: 0 30px':''">
<baseTitle title="需求征集信息" v-if="type!=='singleDetail'"></baseTitle>
<el-form :model="formData" >
<el-row gutter="20" style="margin-left: 5px">
<el-col :span="6">
<el-form-item label="征集名称">
<span>{{ formData.requirementName }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="征集类型">
<span>{{ formData.collectType }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="需求上报截止时间">
<span>{{ formData.deadline }}</span>
</el-form-item>
</el-col>
<el-col :span="6" v-if="formData.isSpecialFund">
<el-form-item label="专项资金名称">
<span>{{ formData.specialFund }}</span>
</el-form-item>
</el-col>
<el-col :span="24" v-if="type==='singleDetail'">
<el-form-item label="征集公司">
<span :class="showExpendClass(showMoreCompany,formData.companyIds)">{{
getCompanyName(formData.companyIds)
}}</span>
<div style="color: #2a99ff;text-align: center;width: 100%;font-size: 15px;cursor: pointer"
@click="handleExpend">{{ showExpendText }}
</div>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-bottom: -15px">
<el-form-item label="征集说明">
<div v-if="formData.collectExplain" v-html="formData.collectExplain" style="white-space: pre-wrap;">
</div>
<div v-else>--</div>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<baseTitle v-if="fileListShow === 'READ' || fileListShow === 'EDIT'" title="附件文件" style="margin-bottom: 0"></baseTitle>
<file-component title="" tag="需求征集"
v-model:value="formData.fileList" :processViewer="processViewer"
:file-list-show="fileListShow"/>
</el-col>
<el-col :span="24" style="margin-top: -15px">
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
v-model="_value"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
</el-col>
</el-row>
<div class="approval-record" style="margin-top: -15px">
<div class="approval-title">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color:#BEA266; --el-switch-off-color:#cecdcd"
/>
</div>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="collectionProcess"/>
</div>
</div>
</el-form>
</div>
</template>
<script setup lang="jsx">
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {downloadFile} from "@/api/project-demand";
const emit = defineEmits(['update:value'])
const showExpendText = ref('')
const showMoreCompany = ref(false)
const props = defineProps({
formData: {
type: Array,
default: []
},
data: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
},
companyOption: {
type: Array,
default: []
},
loading: {
type: Boolean,
default: false
},
fileListShow: {
type: String,
default: ''
},
type: {
type: String,
default: ''
},
value: {
type: String,
default: ''
}
})
const changeDiagram = ref(false)
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const getCompanyName = (data) => {
if (data) {
return data.join('')
}
}
const handleExpend = () => {
showMoreCompany.value = !showMoreCompany.value;
showExpendClass(showMoreCompany.value, props.formData.companyIds)
}
const showExpendClass = (showMoreCompany, data) => {
if (!showMoreCompany) {
if (data && data.length > 14) {
showExpendText.value = '展开'
return 'company-style'
}
} else {
showExpendText.value = '收缩'
return ''
}
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
:deep(.el-empty__description) {
margin-top: 0;
}
.company-style {
//width: 98%;
min-height: 30px;
max-height: 60px;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
}
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: -53px !important;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: -26px !important;
}
}
}
</style>

View File

@@ -1,424 +1,424 @@
<template>
<el-dialog custom-class="custom-dialog" class="border" :border="false" width="1000px" style="height: 676px"
:title="title" :show-close="false" :visible.sync="visible" v-model="visible" append-to-body :close-on-click-modal="false" @close="closeDialog">
<div class="picker">
<div class="candidate" v-loading="loading">
<el-input v-model="filterText"
clearable placeholder="输入公司进行搜索">
<template #append>
<el-button @click="getList()">搜索</el-button>
</template>
</el-input>
<fvCheckbox style="margin-left: 10px" :options="checkOptions" v-model="checkList" @change="checkBoxChange"/>
<!-- 人员选择 -->
<el-empty :image-size="100" description="似乎没有数据" v-show="dataList.length === 0"/>
<el-scrollbar style="height:87%;">
<div class="tree">
<el-tree :data="dataList" ref="tree" :props="defaultProps" empty-text="" node-key="value"
:show-checkbox="showCheckbox" highlight-current default-expand-all
:default-checked-keys="defaultChecked" :disabled="disabled"
:check-strictly="!checkStrictly" @node-click="(node,check)=>handleNodeClick(node,check)"
@check-change="handleCheckClick" :filter-node-method="filterNode">
<template #default="{ node, data }">
<div class="tree-node">
<div style="display: flex;align-items: center;padding: 3px 0">
{{ node.label }}
</div>
</div>
</template>
</el-tree>
</div>
</el-scrollbar>
</div>
<div class="selected">
<div class="count">
<span>已选 {{ selectList.length }} 项</span>
<span @click="clearSelected">清空</span>
</div>
<div class="org-items">
<el-empty :image-size="100" description="请点击左侧列表选择数据" v-show="selectList.length === 0"/>
<div v-for="(selectItem, selectIndex) in selectList" :key="selectIndex" class="org-item">
{{ selectItem.label }}
<el-icon @click="removeSingleSelected(selectItem)" size="20" style="margin-left: 10px;cursor: pointer;">
<CircleClose/>
</el-icon>
</div>
</div>
</div>
</div>
<div class="footer">
<el-button size="mini" @click="cancelUserPicker">取 消</el-button>
<el-button size="mini" color="#DED0B2" @click="selectConfirm">确 定</el-button>
</div>
</el-dialog>
</template>
<script setup>
import {ElMessageBox} from "element-plus";
import {getSubCompOpt} from "@/api/user/user";
const checkList = ref(['1'])
const checkStrictly = ref(false)
const isExpand = ref('展开')
const expandedKeys = ref(['-1']);
const checkOptions = ref([
{
label: isExpand.value,
value: '1'
},
// {
// label: '父子联动',
// value: '2'
// },
])
const props = defineProps({
value: {
type: Array,
default: () => {
return [];
}
},
multiple: { //是否多选
default: true,
type: Boolean
},
showCheckbox: { //是否显示左侧选择框
default: true,
type: Boolean
}
});
let selectItem = reactive({
type: -1,
value: "0"
});
const visible = ref(false);
const loading = ref(false);
const title = ref("请选择");
const selectList = ref([]);
const filterText = ref("");
const dataList = ref([]);
const defaultChecked = ref([]);
const tree = ref([]);
const defaultProps = {
value: "value",
label: "label",
children: "children",
disabled: "disabled",
};
const isRemoveSingleSelected = ref(false);
const emit = defineEmits(['update:modelValue'])
const _value = computed({
get() {
return props.value;
},
set(value) {
emit('update:modelValue', value)
}
});
watch(() => filterText.value, (newVal) => {
tree.value.filter(newVal);
});
const closeDialog=()=>{
console.log('关闭')
visible.value=false
filterText.value=''
}
const checkBoxChange = (val) => {
checkStrictly.value = val.includes('2')
let nodes = tree.value.store.nodesMap
if (val.includes('1')) {
for (const node in nodes) {
nodes[node].expanded = true;
}
isExpand.value = '折叠'
} else {
for (const node in nodes) {
nodes[node].expanded = false;
}
isExpand.value = '展开'
}
}
const getList = () => {
getSubCompOpt().then(res => {
dataList.value = [
{
label: "所有公司",
value: -1,
},
...res.data
]
});
};
//通过关键字过滤树节点
const filterNode = (value, data) => {
//通过关键字过滤树节点
if (!value) return true;
return data.label.indexOf(value) !== -1;
};
//用于用户选择
const show = () => {
//用于弹开部门选择
visible.value = true;
selectList.value = _value.value
defaultChecked.value = _value.value.map(item => item.value)
getList()
};
const updateTreeCheck = (list, flag) => {
list.forEach(item => {
if (item.value !== -1) {
tree.value.setChecked(item, flag)
if (item.children !== undefined) {
updateTreeCheck(item.children, flag)
}
}
})
}
const handleCheckClick = (data, checked) => {
if (data.value == -1) {
if(checked){
updateTreeCheck(dataList.value, false)
tree.value.setChecked(data,true);
}
}
if(tree.value.getCheckedKeys().length>1&&tree.value.getCheckedKeys().indexOf(-1)!==-1){
tree.value.setChecked(-1,false);
}
// 左侧有选择框 + 多选
if (props.multiple) {
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === data.value) {
selectList.value.splice(i, 1);
break;
}
}
if (checked) {
// if (data.children === undefined) {
selectList.value.push(data);
// }
} else if (data === "1") {
tree.value.setCheckedKeys([]);
selectList.value = [];
}
} else {// 左侧有选择框 + 单选
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === data.value) {
selectList.value.splice(i, 1);
break;
}
}
if (checked) {
tree.value.setCheckedNodes([data]);
selectList.value = [data];
} else if (data === "1") {
selectList.value = [];
tree.value.setCheckedKeys([]);
}
}
};
const handleNodeClick = (node, check) => {
if (check.isLeaf !== false) {
if (props.multiple) {
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === node.value) {
selectList.value.splice(i, 1);
break;
}
}
check.checked = true;
selectList.value.push(node);
} else {
check.checked = true;
selectList.value = [node];
}
}
// _value.value = selectList.value
};
const removeSingleSelected = (selectItem) => {
//左侧无选择框时,右侧显示×
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === selectItem.value) {
tree.value.setChecked(selectList.value[i].value, false);
selectList.value.splice(i, 1);
break;
}
}
if (props.showCheckbox) {
// 左侧有选择框 + 单选
if (props.multiple === false) {
tree.value.setCheckedKeys([]);
}
}
// isRemoveSingleSelected.value = true
};
const clearSelected = () => {
//清空
ElMessageBox.confirm("您确定要清空已选中的项?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
// isRemoveSingleSelected.value = true
if (!props.showCheckbox) {
selectList.value = [];
} else {
handleCheckClick("1");
}
});
};
const cancelUserPicker = () => {
if (localStorage.getItem('originallyCompanySelectedList')) {
selectList.value = JSON.parse(localStorage.getItem('originallyCompanySelectedList'))
}else{
selectList.value=[]
handleCheckClick("1");
}
emit("cancelOrClear", selectList.value);
visible.value = false;
// nextTick(()=>{
// isRemoveSingleSelected.value=false
// })
}
const selectConfirm = () => {
//确定按钮
emit("ok", selectList.value);
dataList.value = []
visible.value = false;
localStorage.setItem('originallyCompanySelectedList', JSON.stringify(selectList.value))
};
defineExpose({
show
});
getList()
</script>
<style lang="scss" scoped>
$containWidth: 480px;
:deep(.tree) {
.el-tree-node__content {
height: 34px;
.tree-node {
font-size: 18px;
}
}
//.el-tree-node {
// .is-leaf + .el-checkbox .el-checkbox__inner {
// display: inline-block;
// }
//
// .el-checkbox .el-checkbox__inner {
// display: none;
// }
//}
}
.footer {
float: right;
margin-top: 10px;
}
.picker {
height: 560px;
position: relative;
text-align: left;
.candidate {
position: absolute;
display: block;
width: $containWidth;
height: 100%;
border: 1px solid #e8e8e8;
:deep(.el-input) {
height: 40px;
.el-input__inner, .el-input-group__append {
font-size: 16px;
}
}
}
.selected {
right: 0;
top: 0;
position: absolute;
display: inline-block;
width: 450px;
height: 100%;
border: 1px solid #e8e8e8;
.count {
width: 100%;
padding: 10px;
display: inline-block;
border-bottom: 1px solid #e8e8e8;
margin-bottom: 5px;
font-size: 16px;
> span:nth-child(2) {
float: right;
color: #c75450;
cursor: pointer;
margin-left: 10px;
}
}
.org-items {
overflow-y: auto;
height: 90%;
.el-icon-close {
position: absolute;
right: 5px;
cursor: pointer;
font-size: larger;
}
.org-item {
margin: 0 5px;
border-radius: 5px;
position: relative;
padding: 7px 5px;
display: flex;
align-items: center;
font-size: 16px;
&:hover {
background: #f1f1f1;
}
> span {
margin-left: 5px;
}
}
}
}
}
.el-scrollbar .el-scrollbar__wrap {
overflow-x: hidden;
}
::-webkit-scrollbar {
float: right;
width: 4px;
height: 4px;
background-color: white;
}
::-webkit-scrollbar-thumb {
border-radius: 16px;
background-color: #efefef;
}
</style>
<template>
<el-dialog custom-class="custom-dialog" class="border" :border="false" width="1000px" style="height: 676px"
:title="title" :show-close="false" :visible.sync="visible" v-model="visible" append-to-body :close-on-click-modal="false" @close="closeDialog">
<div class="picker">
<div class="candidate" v-loading="loading">
<el-input v-model="filterText"
clearable placeholder="输入公司进行搜索">
<template #append>
<el-button @click="getList()">搜索</el-button>
</template>
</el-input>
<fvCheckbox style="margin-left: 10px" :options="checkOptions" v-model="checkList" @change="checkBoxChange"/>
<!-- 人员选择 -->
<el-empty :image-size="100" description="似乎没有数据" v-show="dataList.length === 0"/>
<el-scrollbar style="height:87%;">
<div class="tree">
<el-tree :data="dataList" ref="tree" :props="defaultProps" empty-text="" node-key="value"
:show-checkbox="showCheckbox" highlight-current default-expand-all
:default-checked-keys="defaultChecked" :disabled="disabled"
:check-strictly="!checkStrictly" @node-click="(node,check)=>handleNodeClick(node,check)"
@check-change="handleCheckClick" :filter-node-method="filterNode">
<template #default="{ node, data }">
<div class="tree-node">
<div style="display: flex;align-items: center;padding: 3px 0">
{{ node.label }}
</div>
</div>
</template>
</el-tree>
</div>
</el-scrollbar>
</div>
<div class="selected">
<div class="count">
<span>已选 {{ selectList.length }} 项</span>
<span @click="clearSelected">清空</span>
</div>
<div class="org-items">
<el-empty :image-size="100" description="请点击左侧列表选择数据" v-show="selectList.length === 0"/>
<div v-for="(selectItem, selectIndex) in selectList" :key="selectIndex" class="org-item">
{{ selectItem.label }}
<el-icon @click="removeSingleSelected(selectItem)" size="20" style="margin-left: 10px;cursor: pointer;">
<CircleClose/>
</el-icon>
</div>
</div>
</div>
</div>
<div class="footer">
<el-button size="mini" @click="cancelUserPicker">取 消</el-button>
<el-button size="mini" color="#DED0B2" @click="selectConfirm">确 定</el-button>
</div>
</el-dialog>
</template>
<script setup>
import {ElMessageBox} from "element-plus";
import {getSubCompOpt} from "@/api/user/user";
const checkList = ref(['1'])
const checkStrictly = ref(false)
const isExpand = ref('展开')
const expandedKeys = ref(['-1']);
const checkOptions = ref([
{
label: isExpand.value,
value: '1'
},
// {
// label: '父子联动',
// value: '2'
// },
])
const props = defineProps({
value: {
type: Array,
default: () => {
return [];
}
},
multiple: { //是否多选
default: true,
type: Boolean
},
showCheckbox: { //是否显示左侧选择框
default: true,
type: Boolean
}
});
let selectItem = reactive({
type: -1,
value: "0"
});
const visible = ref(false);
const loading = ref(false);
const title = ref("请选择");
const selectList = ref([]);
const filterText = ref("");
const dataList = ref([]);
const defaultChecked = ref([]);
const tree = ref([]);
const defaultProps = {
value: "value",
label: "label",
children: "children",
disabled: "disabled",
};
const isRemoveSingleSelected = ref(false);
const emit = defineEmits(['update:modelValue'])
const _value = computed({
get() {
return props.value;
},
set(value) {
emit('update:modelValue', value)
}
});
watch(() => filterText.value, (newVal) => {
tree.value.filter(newVal);
});
const closeDialog=()=>{
console.log('关闭')
visible.value=false
filterText.value=''
}
const checkBoxChange = (val) => {
checkStrictly.value = val.includes('2')
let nodes = tree.value.store.nodesMap
if (val.includes('1')) {
for (const node in nodes) {
nodes[node].expanded = true;
}
isExpand.value = '折叠'
} else {
for (const node in nodes) {
nodes[node].expanded = false;
}
isExpand.value = '展开'
}
}
const getList = () => {
getSubCompOpt().then(res => {
dataList.value = [
{
label: "所有公司",
value: -1,
},
...res.data
]
});
};
//通过关键字过滤树节点
const filterNode = (value, data) => {
//通过关键字过滤树节点
if (!value) return true;
return data.label.indexOf(value) !== -1;
};
//用于用户选择
const show = () => {
//用于弹开部门选择
visible.value = true;
selectList.value = _value.value
defaultChecked.value = _value.value.map(item => item.value)
getList()
};
const updateTreeCheck = (list, flag) => {
list.forEach(item => {
if (item.value !== -1) {
tree.value.setChecked(item, flag)
if (item.children !== undefined) {
updateTreeCheck(item.children, flag)
}
}
})
}
const handleCheckClick = (data, checked) => {
if (data.value == -1) {
if(checked){
updateTreeCheck(dataList.value, false)
tree.value.setChecked(data,true);
}
}
if(tree.value.getCheckedKeys().length>1&&tree.value.getCheckedKeys().indexOf(-1)!==-1){
tree.value.setChecked(-1,false);
}
// 左侧有选择框 + 多选
if (props.multiple) {
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === data.value) {
selectList.value.splice(i, 1);
break;
}
}
if (checked) {
// if (data.children === undefined) {
selectList.value.push(data);
// }
} else if (data === "1") {
tree.value.setCheckedKeys([]);
selectList.value = [];
}
} else {// 左侧有选择框 + 单选
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === data.value) {
selectList.value.splice(i, 1);
break;
}
}
if (checked) {
tree.value.setCheckedNodes([data]);
selectList.value = [data];
} else if (data === "1") {
selectList.value = [];
tree.value.setCheckedKeys([]);
}
}
};
const handleNodeClick = (node, check) => {
if (check.isLeaf !== false) {
if (props.multiple) {
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === node.value) {
selectList.value.splice(i, 1);
break;
}
}
check.checked = true;
selectList.value.push(node);
} else {
check.checked = true;
selectList.value = [node];
}
}
// _value.value = selectList.value
};
const removeSingleSelected = (selectItem) => {
//左侧无选择框时,右侧显示×
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === selectItem.value) {
tree.value.setChecked(selectList.value[i].value, false);
selectList.value.splice(i, 1);
break;
}
}
if (props.showCheckbox) {
// 左侧有选择框 + 单选
if (props.multiple === false) {
tree.value.setCheckedKeys([]);
}
}
// isRemoveSingleSelected.value = true
};
const clearSelected = () => {
//清空
ElMessageBox.confirm("您确定要清空已选中的项?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
// isRemoveSingleSelected.value = true
if (!props.showCheckbox) {
selectList.value = [];
} else {
handleCheckClick("1");
}
});
};
const cancelUserPicker = () => {
if (localStorage.getItem('originallyCompanySelectedList')) {
selectList.value = JSON.parse(localStorage.getItem('originallyCompanySelectedList'))
}else{
selectList.value=[]
handleCheckClick("1");
}
emit("cancelOrClear", selectList.value);
visible.value = false;
// nextTick(()=>{
// isRemoveSingleSelected.value=false
// })
}
const selectConfirm = () => {
//确定按钮
emit("ok", selectList.value);
dataList.value = []
visible.value = false;
localStorage.setItem('originallyCompanySelectedList', JSON.stringify(selectList.value))
};
defineExpose({
show
});
getList()
</script>
<style lang="scss" scoped>
$containWidth: 480px;
:deep(.tree) {
.el-tree-node__content {
height: 34px;
.tree-node {
font-size: 18px;
}
}
//.el-tree-node {
// .is-leaf + .el-checkbox .el-checkbox__inner {
// display: inline-block;
// }
//
// .el-checkbox .el-checkbox__inner {
// display: none;
// }
//}
}
.footer {
float: right;
margin-top: 10px;
}
.picker {
height: 560px;
position: relative;
text-align: left;
.candidate {
position: absolute;
display: block;
width: $containWidth;
height: 100%;
border: 1px solid #e8e8e8;
:deep(.el-input) {
height: 40px;
.el-input__inner, .el-input-group__append {
font-size: 16px;
}
}
}
.selected {
right: 0;
top: 0;
position: absolute;
display: inline-block;
width: 450px;
height: 100%;
border: 1px solid #e8e8e8;
.count {
width: 100%;
padding: 10px;
display: inline-block;
border-bottom: 1px solid #e8e8e8;
margin-bottom: 5px;
font-size: 16px;
> span:nth-child(2) {
float: right;
color: #c75450;
cursor: pointer;
margin-left: 10px;
}
}
.org-items {
overflow-y: auto;
height: 90%;
.el-icon-close {
position: absolute;
right: 5px;
cursor: pointer;
font-size: larger;
}
.org-item {
margin: 0 5px;
border-radius: 5px;
position: relative;
padding: 7px 5px;
display: flex;
align-items: center;
font-size: 16px;
&:hover {
background: #f1f1f1;
}
> span {
margin-left: 5px;
}
}
}
}
}
.el-scrollbar .el-scrollbar__wrap {
overflow-x: hidden;
}
::-webkit-scrollbar {
float: right;
width: 4px;
height: 4px;
background-color: white;
}
::-webkit-scrollbar-thumb {
border-radius: 16px;
background-color: #efefef;
}
</style>

View File

@@ -1,255 +1,255 @@
<template>
<el-button color="#DED0B2" style="float: right;margin: 0 10px 10px 0" @click="exportTable">导出</el-button>
<el-table ref="reportTable" :data="tableData" style="width: 100%;height: 479px"
:span-method="objectSpanMethod" v-loading="loading">
<el-table-column label="四川省国有资产经营投资管理有限责任公司科技创新项目人工成本分摊明细表" align="center">
<el-table-column v-for="column in columnInfo" :prop="column.prop" :label="column.label" align="center"
:fixed="(!column.children) ? ((column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') ? 'right' : 'left') : false"
:width="(column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') ? 160:130">
<template #default="scope">
<template v-if="column.children">
<el-table-column v-for="childColumn in column.children"
:prop="column.prop + '.'+ childColumn.prop"
:label="childColumn.label"
:width="childColumn.prop === 'subtotal' ? 160 : 130">
<template #default="columnScope">
<template v-if="(tableData.length -1) !== columnScope.$index">
{{
columnScope.row[column.prop][childColumn.prop] ? columnScope.row[column.prop][childColumn.prop] : '/'
}}
</template>
<template v-else>
{{ columnScope.row[column.prop][childColumn.prop] }}
</template>
</template>
</el-table-column>
</template>
<template v-else>
<!--分摊金额合计与分摊金额总计计算-->
<template
v-if="(column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') && (tableData.length -1) !== scope.$index">
{{ getTotalSeparation(scope.row, column.prop) }}
</template>
<template
v-else-if="(tableData.length -1) === scope.$index && (column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost')">
{{ getTotalSummary(scope.row, column.prop) }}
</template>
<template v-else>
{{ scope.row[column.prop] }}
</template>
</template>
</template>
</el-table-column>
</el-table-column>
</el-table>
</template>
<script setup lang="jsx">
import {getResearchUser, getAllocationDetails} from "@/api/expense-manage";
import {exportExcel} from "@/utils/export-excel";
import {ElNotification} from "element-plus";
const route = useRoute()
const tableIns = ref()
const reportTable = ref({});
const columnInfo = ref([])
const monthConcat = new Map()
const tableData = ref([])
const loading = ref(false)
const researchOptions = ref([])
const objectSpanMethod = ({row, column, rowIndex, columnIndex}) => {
if (columnIndex === 0) {
if (monthConcat.has(rowIndex)) {
return {
rowspan: monthConcat.get(rowIndex),
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
} else {
let length = Object.keys(row).length
// console.log(length)
if (length > 5) {
if (concatColumn(columnIndex, length, rowIndex)) {
if (rowIndex % 5 === 0) {
return {
rowspan: 5,
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
}
}
}
}
const getTotalSeparation = (row, prop) => {
let totalSeparation = 0.00
for (let key of Object.keys(row)) {
if (key.startsWith('personInfo')) {
let value = prop === 'totalSeparation' ? (row[key].separationAmount ? row[key].separationAmount : 0) : row[key].subtotal
if ("/" !== value) {
try {
totalSeparation += parseFloat(value)
} catch (e) {
}
}
}
}
if (totalSeparation !== 0) {
return totalSeparation.toFixed(2);
} else {
return "/"
}
}
const getTotalSummary = (row, prop) => {
let key;
if (prop === 'totalSeparation') {
key = 'separationAmount'
} else {
key = 'subtotal'
}
let result = 0
for (const rowKey of Object.keys(row)) {
if (rowKey.startsWith('personInfo')) {
let value = row[rowKey][key]
if (value && "/" !== value) {
try {
result += parseFloat(value)
} catch (e) {
}
}
}
}
return result.toFixed(2);
}
const concatColumn = (columnIndex, length, rowIndex) => {
if (rowIndex === tableData.value.length - 1) {
return false
}
let columnLength = 5 + (length - 5) * 5
if (columnIndex === 1
|| columnIndex === columnLength - 1) {
return true;
}
for (let i = 0; i < length - 5; i++) {
if (columnIndex === 4 + (i * 5)
|| columnIndex === 5 + (i * 5)
|| columnIndex === 7 + (i * 5)) {
return true
}
}
return false
}
const init = () => {
loading.value = true
getAllocationDetails(route.query.id).then(res => {
if (res.code !== 1000) {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
columnInfo.value = res.data.columns
let tableDataLet = res.data.tableData;
let personInfoKey = []
columnInfo.value.forEach(item => {
if (item.prop.startsWith('personInfo')) {
personInfoKey.push(item.prop)
}
})
tableData.value = []
let rowIndex = 0;
let summary = {
month: "",
salaryType: '',
projectName: "合计",
totalSeparation: 10,
totalSeparationCost: 10
}
for (const key of personInfoKey) {
summary[key] = {
researchDuration: "",
separationAmount: 0,
subtotal: 0,
wagesPayable: "",
workday: "",
}
}
tableDataLet.forEach((tableDatum) => {
let rowspan = tableDatum.rows.length * 5
monthConcat.set(rowIndex, rowspan)
rowIndex += rowspan
for (const tableDatumElement of tableDatum.rows) {
tableData.value = tableData.value.concat(tableDatumElement)
let row = tableDatumElement[0]
for (const key of personInfoKey) {
try {
if (row[key].subtotal && '/' !== row[key].subtotal) {
summary[key].subtotal += parseFloat(row[key].subtotal)
}
} catch (e) {
}
}
}
})
for (const row of tableData.value) {
for (const key of personInfoKey) {
try {
if (row[key].separationAmount && '/' !== row[key].separationAmount) {
summary[key].separationAmount += parseFloat(row[key].separationAmount)
}
} catch (e) {
}
}
}
for (const key of personInfoKey) {
summary[key].subtotal = summary[key].subtotal.toFixed(2)
summary[key].separationAmount = summary[key].separationAmount.toFixed(2)
}
monthConcat.set(rowIndex, 1)
tableData.value.push(summary)
loading.value = false
})
}
const getResearchOptions = async () => {
const res = await getResearchUser()
researchOptions.value = res.data
}
const search = (val) => {
tableConfig.params = {
allocationId: route.query.id,
...val
}
tableIns.value.refresh()
}
getResearchOptions()
init()
const exportTable = () => {
const $e = reportTable.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)
}
</script>
<template>
<el-button color="#DED0B2" style="float: right;margin: 0 10px 10px 0" @click="exportTable">导出</el-button>
<el-table ref="reportTable" :data="tableData" style="width: 100%;height: 479px"
:span-method="objectSpanMethod" v-loading="loading">
<el-table-column label="四川省国有资产经营投资管理有限责任公司科技创新项目人工成本分摊明细表" align="center">
<el-table-column v-for="column in columnInfo" :prop="column.prop" :label="column.label" align="center"
:fixed="(!column.children) ? ((column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') ? 'right' : 'left') : false"
:width="(column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') ? 160:130">
<template #default="scope">
<template v-if="column.children">
<el-table-column v-for="childColumn in column.children"
:prop="column.prop + '.'+ childColumn.prop"
:label="childColumn.label"
:width="childColumn.prop === 'subtotal' ? 160 : 130">
<template #default="columnScope">
<template v-if="(tableData.length -1) !== columnScope.$index">
{{
columnScope.row[column.prop][childColumn.prop] ? columnScope.row[column.prop][childColumn.prop] : '/'
}}
</template>
<template v-else>
{{ columnScope.row[column.prop][childColumn.prop] }}
</template>
</template>
</el-table-column>
</template>
<template v-else>
<!--分摊金额合计与分摊金额总计计算-->
<template
v-if="(column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') && (tableData.length -1) !== scope.$index">
{{ getTotalSeparation(scope.row, column.prop) }}
</template>
<template
v-else-if="(tableData.length -1) === scope.$index && (column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost')">
{{ getTotalSummary(scope.row, column.prop) }}
</template>
<template v-else>
{{ scope.row[column.prop] }}
</template>
</template>
</template>
</el-table-column>
</el-table-column>
</el-table>
</template>
<script setup lang="jsx">
import {getResearchUser, getAllocationDetails} from "@/api/expense-manage";
import {exportExcel} from "@/utils/export-excel";
import {ElNotification} from "element-plus";
const route = useRoute()
const tableIns = ref()
const reportTable = ref({});
const columnInfo = ref([])
const monthConcat = new Map()
const tableData = ref([])
const loading = ref(false)
const researchOptions = ref([])
const objectSpanMethod = ({row, column, rowIndex, columnIndex}) => {
if (columnIndex === 0) {
if (monthConcat.has(rowIndex)) {
return {
rowspan: monthConcat.get(rowIndex),
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
} else {
let length = Object.keys(row).length
// console.log(length)
if (length > 5) {
if (concatColumn(columnIndex, length, rowIndex)) {
if (rowIndex % 5 === 0) {
return {
rowspan: 5,
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
}
}
}
}
const getTotalSeparation = (row, prop) => {
let totalSeparation = 0.00
for (let key of Object.keys(row)) {
if (key.startsWith('personInfo')) {
let value = prop === 'totalSeparation' ? (row[key].separationAmount ? row[key].separationAmount : 0) : row[key].subtotal
if ("/" !== value) {
try {
totalSeparation += parseFloat(value)
} catch (e) {
}
}
}
}
if (totalSeparation !== 0) {
return totalSeparation.toFixed(2);
} else {
return "/"
}
}
const getTotalSummary = (row, prop) => {
let key;
if (prop === 'totalSeparation') {
key = 'separationAmount'
} else {
key = 'subtotal'
}
let result = 0
for (const rowKey of Object.keys(row)) {
if (rowKey.startsWith('personInfo')) {
let value = row[rowKey][key]
if (value && "/" !== value) {
try {
result += parseFloat(value)
} catch (e) {
}
}
}
}
return result.toFixed(2);
}
const concatColumn = (columnIndex, length, rowIndex) => {
if (rowIndex === tableData.value.length - 1) {
return false
}
let columnLength = 5 + (length - 5) * 5
if (columnIndex === 1
|| columnIndex === columnLength - 1) {
return true;
}
for (let i = 0; i < length - 5; i++) {
if (columnIndex === 4 + (i * 5)
|| columnIndex === 5 + (i * 5)
|| columnIndex === 7 + (i * 5)) {
return true
}
}
return false
}
const init = () => {
loading.value = true
getAllocationDetails(route.query.id).then(res => {
if (res.code !== 1000) {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
columnInfo.value = res.data.columns
let tableDataLet = res.data.tableData;
let personInfoKey = []
columnInfo.value.forEach(item => {
if (item.prop.startsWith('personInfo')) {
personInfoKey.push(item.prop)
}
})
tableData.value = []
let rowIndex = 0;
let summary = {
month: "",
salaryType: '',
projectName: "合计",
totalSeparation: 10,
totalSeparationCost: 10
}
for (const key of personInfoKey) {
summary[key] = {
researchDuration: "",
separationAmount: 0,
subtotal: 0,
wagesPayable: "",
workday: "",
}
}
tableDataLet.forEach((tableDatum) => {
let rowspan = tableDatum.rows.length * 5
monthConcat.set(rowIndex, rowspan)
rowIndex += rowspan
for (const tableDatumElement of tableDatum.rows) {
tableData.value = tableData.value.concat(tableDatumElement)
let row = tableDatumElement[0]
for (const key of personInfoKey) {
try {
if (row[key].subtotal && '/' !== row[key].subtotal) {
summary[key].subtotal += parseFloat(row[key].subtotal)
}
} catch (e) {
}
}
}
})
for (const row of tableData.value) {
for (const key of personInfoKey) {
try {
if (row[key].separationAmount && '/' !== row[key].separationAmount) {
summary[key].separationAmount += parseFloat(row[key].separationAmount)
}
} catch (e) {
}
}
}
for (const key of personInfoKey) {
summary[key].subtotal = summary[key].subtotal.toFixed(2)
summary[key].separationAmount = summary[key].separationAmount.toFixed(2)
}
monthConcat.set(rowIndex, 1)
tableData.value.push(summary)
loading.value = false
})
}
const getResearchOptions = async () => {
const res = await getResearchUser()
researchOptions.value = res.data
}
const search = (val) => {
tableConfig.params = {
allocationId: route.query.id,
...val
}
tableIns.value.refresh()
}
getResearchOptions()
init()
const exportTable = () => {
const $e = reportTable.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)
}
</script>

View File

@@ -1,210 +1,212 @@
<template>
<el-form :label-position="labelAlign">
<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"
:data="_value" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-form>
<file-preview ref="filePreviewRef" :fullscreen="fullscreen" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</template>
<script setup lang="jsx">
import {downloadFile, deleteFile} from "@/api/project-demand";
import {ElNotification} from "element-plus";
import FilePreview from "../filePreview/index.vue";
const props = defineProps({
title: {
type: String,
default: ''
},
tag: {
type: String,
default: ''
},
fileNameTableWidth: {
type: String,
default: '400'
},
fileListShow: {
type: String,
default: 'READ'
},
value: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
},
labelAlign: {
type: String,
default: 'right'
},
//弹窗是否铺满全屏
fullscreen: {
type: Boolean,
default: false
},
//是否开始打印
isOpenPrint: {
type: Boolean,
default: false
},
})
const emit = defineEmits(['update:value'])
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: 85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: props.fileNameTableWidth,
showOverflowTooltip: false,
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
width: 150,
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
// if (row.newFile) {
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
// }
return (
<div style={{width: '100%'}}>
{
btn.map(item => (
<el-button
type={item.type}
onClick={() => item.func()}
link>
{item.label}
</el-button>
))
}
{
row.newFile ? <popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => handleDelete(row)}/>
: ''
}
</div>
)
}
}
]
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const getOtherFile = (val) => {
props.processViewer = false
let fileObj = compositeParam(val)
_value.value.push(fileObj)
nextTick(() => {
props.processViewer = true
})
}
const compositeParam = (item, type) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: props.tag
}
}
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 handleDelete = (row) => {
deleteFile(row.fileId).then(res => {
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
_value.value.splice(_value.value.findIndex((item) => item.fileId === row.fileId), 1);
}
});
}
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
:deep(.el-table--fit ) {
height: 160px !important;
}
@media print {
//#printTable{
// width: 400px!important;
//}
}
</style>
<template>
<el-form :label-position="labelAlign">
<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%;" :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"/>
</template>
</fvTable>
</el-form-item>
</el-form>
<file-preview ref="filePreviewRef" :fullscreen="fullscreen" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</template>
<script setup lang="jsx">
import {downloadFile, deleteFile} from "@/api/project-demand";
import {ElNotification} from "element-plus";
import FilePreview from "../filePreview/index.vue";
const props = defineProps({
title: {
type: String,
default: ''
},
tag: {
type: String,
default: ''
},
fileNameTableWidth: {
type: String,
default: '400'
},
fileListShow: {
type: String,
default: 'READ'
},
value: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
},
labelAlign: {
type: String,
default: 'right'
},
//弹窗是否铺满全屏
fullscreen: {
type: Boolean,
default: false
},
//是否开始打印
isOpenPrint: {
type: Boolean,
default: false
},
})
const emit = defineEmits(['update:value'])
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: 85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: props.fileNameTableWidth,
showOverflowTooltip: false,
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center',
showOverflowTooltip: false,
minWidth: props.fileNameTableWidth,
},
{
prop: 'size',
label: '文件大小',
align: 'center',
width: 150,
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
// if (row.newFile) {
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
// }
return (
<div style={{width: '100%'}}>
{
btn.map(item => (
<el-button
type={item.type}
onClick={() => item.func()}
link>
{item.label}
</el-button>
))
}
{
row.newFile ? <popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => handleDelete(row)}/>
: ''
}
</div>
)
}
}
]
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const getOtherFile = (val) => {
props.processViewer = false
let fileObj = compositeParam(val)
_value.value.push(fileObj)
nextTick(() => {
props.processViewer = true
})
}
const compositeParam = (item, type) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: props.tag
}
}
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 handleDelete = (row) => {
deleteFile(row.fileId).then(res => {
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
_value.value.splice(_value.value.findIndex((item) => item.fileId === row.fileId), 1);
}
});
}
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
:deep(.el-table--fit ) {
height: 160px !important;
}
@media print {
//#printTable{
// width: 400px!important;
//}
}
</style>

View File

@@ -1,234 +1,242 @@
<template>
<!-- <baseTitle title="审核意见"></baseTitle>-->
<!-- <fvForm :schema="schema" @getInstance="(e)=>form = e"></fvForm>-->
<div class="oper-page-btn" style="display: flex">
<el-button type="danger" @click="handleReject">驳回</el-button>
<el-button color="#DED0B2" @click="handleAgree">同意</el-button>
</div>
<div class="opinion-dialog">
<el-dialog v-model="showBackNode" title="请选择退回节点" width="400">
<el-table :data="taskUserOptionList" style="width: 100%"
:header-cell-style="{background:'#f5f7fa'}">
<el-table-column width="55">
<template #default="scope">
<el-radio
class="radio"
:label="scope.row"
v-model="backNode"
>&emsp;&emsp;&emsp;
</el-radio>
</template>
</el-table-column>
<el-table-column
prop="nodeName"
label="节点名称">
<!-- <template #default="scope">-->
<!-- {{scope.row.nodeId==-1?'发起节点':scope.row.nodeName}}-->
<!-- </template>-->
</el-table-column>
<el-table-column
prop="name"
label="操作者">
<template #default="scope">
<el-tag v-if="scope.row.userInfo" type="success">{{ scope.row.userInfo.name }}</el-tag>
</template>
</el-table-column>
</el-table>
<div class="oper" style="display: flex;justify-content: flex-end;margin-top: 10px">
<el-button type="danger" @click="rollbackHandler">确定</el-button>
<el-button @click="showBackNode=false">取消</el-button>
</div>
<!-- <el-select v-if="taskUserOptionList?.length>0" v-model="backNode" placeholder="请选择退回节点" clearable>-->
<!-- <el-option-->
<!-- v-for="item in taskUserOptionList"-->
<!-- :key="item.nodeId"-->
<!-- :label="item.nodeName + (item.userInfo ? ':' + item.userInfo.name : '')"-->
<!-- :value="item.nodeId">-->
<!-- </el-option>-->
<!-- </el-select>-->
<!-- <el-button type="danger" @click="rollbackHandler">确认</el-button>-->
</el-dialog>
</div>
</template>
<script setup lang="jsx">
import {ElNotification} from 'element-plus';
import {agreeTask, rejectTask} from "@/api/project-demand/index.js";
import {useTagsView} from '@/stores/tagsview.js'
const tagsViewStore = useTagsView()
const route = useRoute()
const router = useRouter()
const props = defineProps({
taskId: {
type: String,
default: ''
},
formData: {
type: Object,
default: {}
},
value: {
type: String,
default: ''
},
//退回节点选择框数据
taskUserOptionList: {
type: Array,
default: []
}
})
const form = ref()
const backNode = ref({})
const showBackNode = ref(false)
const schema = computed(() => {
return [
{
label: '',
prop: 'auditOpinion',
component: 'el-input',
colProps: {
span: 24
},
props: {
placeholder: '请输入审核意见',
type: 'textarea',
rows: 3
}
}
]
})
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const back = () => {
switch (route.name) {
case 'Initiation/detail':
router.push({name: 'Initiation'})
break;
case 'Filing/detail':
router.push({name: 'Filing'})
break;
case 'Implementation/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
if (route.query.step === '10') {
router.push({name: 'Summary'})
} else if (route.query.step === '20') {
router.push({name: 'Initiation'})
} else if (route.query.step === '40') {
router.push({name: 'Implementation'})
} else if (route.query.step === '50') {
router.push({name: 'Filing'})
} else if (route.query.step === '00') {
router.push({name: 'Requirement'})
}
}
break;
// case 'Summary/detail':
// if (route.query.source === 'home') {
// router.push('/home')
// } else {
// router.push({name: 'Summary'})
// }
// break;
case 'Requirement/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Requirement'})
}
break;
case 'Fund/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Fund'})
}
break;
case 'Share/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Expense/share'})
}
break;
case 'Phase/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Implementation'})
}
break;
}
}
// 驳回
const handleReject = async () => {
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
showBackNode.value = true
backNode.value = {}
}
//回退节点
const rollbackHandler = async () => {
// const values = form.value.getValues()
const params = {
taskId: props.taskId,
// ...values
auditOpinion: _value.value,
rollBackId: backNode.value.nodeId
}
// console.log('params', params)
const res = await rejectTask(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
back()
}
}
const handleAgree = async () => {
// const values = form.value.getValues()
const params = {
taskId: props.taskId,
formData: props.formData,
auditOpinion: _value.value
}
const res = await agreeTask(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
back()
}
}
</script>
<style lang="scss">
.opinion-dialog {
.el-dialog__body {
padding: 0 !important;
}
}
</style>
<template>
<!-- <baseTitle title="审核意见"></baseTitle>-->
<!-- <fvForm :schema="schema" @getInstance="(e)=>form = e"></fvForm>-->
<div class="oper-page-btn" style="display: flex">
<el-button type="danger" @click="handleReject">驳回</el-button>
<el-button color="#DED0B2" @click="handleAgree">同意</el-button>
</div>
<div class="opinion-dialog">
<el-dialog v-model="showBackNode" title="请选择退回节点" width="400">
<el-table :data="taskUserOptionList" style="width: 100%"
:header-cell-style="{background:'#f5f7fa'}">
<el-table-column width="55">
<template #default="scope">
<el-radio
class="radio"
:label="scope.row"
v-model="backNode"
>&emsp;&emsp;&emsp;
</el-radio>
</template>
</el-table-column>
<el-table-column
prop="nodeName"
label="节点名称">
<!-- <template #default="scope">-->
<!-- {{scope.row.nodeId==-1?'发起节点':scope.row.nodeName}}-->
<!-- </template>-->
</el-table-column>
<el-table-column
prop="name"
label="操作者">
<template #default="scope">
<el-tag v-if="scope.row.userInfo" type="success">{{ scope.row.userInfo.name }}</el-tag>
</template>
</el-table-column>
</el-table>
<div class="oper" style="display: flex;justify-content: flex-end;margin-top: 10px">
<el-button type="danger" @click="rollbackHandler">确定</el-button>
<el-button @click="showBackNode=false">取消</el-button>
</div>
<!-- <el-select v-if="taskUserOptionList?.length>0" v-model="backNode" placeholder="请选择退回节点" clearable>-->
<!-- <el-option-->
<!-- v-for="item in taskUserOptionList"-->
<!-- :key="item.nodeId"-->
<!-- :label="item.nodeName + (item.userInfo ? ':' + item.userInfo.name : '')"-->
<!-- :value="item.nodeId">-->
<!-- </el-option>-->
<!-- </el-select>-->
<!-- <el-button type="danger" @click="rollbackHandler">确认</el-button>-->
</el-dialog>
</div>
</template>
<script setup lang="jsx">
import {ElNotification} from 'element-plus';
import {agreeTask, rejectTask} from "@/api/project-demand/index.js";
import {useTagsView} from '@/stores/tagsview.js'
const tagsViewStore = useTagsView()
const route = useRoute()
const router = useRouter()
const props = defineProps({
taskId: {
type: String,
default: ''
},
formData: {
type: Object,
default: {}
},
value: {
type: String,
default: ''
},
//退回节点选择框数据
taskUserOptionList: {
type: Array,
default: []
}
})
const form = ref()
const backNode = ref({})
const showBackNode = ref(false)
const schema = computed(() => {
return [
{
label: '',
prop: 'auditOpinion',
component: 'el-input',
colProps: {
span: 24
},
props: {
placeholder: '请输入审核意见',
type: 'textarea',
rows: 3
}
}
]
})
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const back = () => {
switch (route.name) {
case 'Initiation/detail':
router.push({name: 'Initiation'})
break;
case 'Filing/detail':
router.push({name: 'Filing'})
break;
case 'Implementation/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
if (route.query.step === '10') {
router.push({name: 'Summary'})
} else if (route.query.step === '20') {
router.push({name: 'Initiation'})
} else if (route.query.step === '40') {
router.push({name: 'Implementation'})
} else if (route.query.step === '50') {
router.push({name: 'Filing'})
} else if (route.query.step === '00') {
router.push({name: 'Requirement'})
}
}
break;
// case 'Summary/detail':
// if (route.query.source === 'home') {
// router.push('/home')
// } else {
// router.push({name: 'Summary'})
// }
// break;
case 'Requirement/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Requirement'})
}
break;
case 'Fund/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Fund'})
}
break;
case 'Share/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Expense/share'})
}
break;
case 'Phase/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Implementation'})
}
break;
}
}
// 驳回
const handleReject = async () => {
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
showBackNode.value = true
backNode.value = {}
}
//回退节点
const rollbackHandler = async () => {
// const values = form.value.getValues()
const params = {
taskId: props.taskId,
// ...values
auditOpinion: _value.value,
rollBackId: backNode.value.nodeId
}
// console.log('params', params)
const res = await rejectTask(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
back()
}
}
const handleAgree = async () => {
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
// const values = form.value.getValues()
const params = {
taskId: props.taskId,
formData: props.formData,
auditOpinion: _value.value
}
const res = await agreeTask(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
back()
}
}
</script>
<style lang="scss">
.opinion-dialog {
.el-dialog__body {
padding: 0 !important;
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,224 +1,610 @@
<template>
<el-row style="padding-bottom: 20px">
<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-row>
<file-preview ref="filePreviewRef" :fullscreen="false" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</template>
<script setup lang="jsx">
import {getTags} from "@/api/project-manage";
import {ElLoading, ElNotification} from "element-plus";
import {searchImplementationFileList} from "@/api/project-manage/attachment";
const router = useRouter()
const route = useRoute()
const attachmentParam = reactive({
tag: ''
})
const uploadState = ref(false)
const tagsOption = ref([])
const showAttachmentTable = ref(true)
const props = defineProps({
fileNameTableWidth: {
type: String,
default: '400'
},
isLineBtn: {
type: Boolean,
default: false
},
})
const executeTableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: 85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: props.fileNameTableWidth,
currentRender: ({row, index}) => (
<div style="color: #2a99ff;cursor: pointer;" onClick={() => clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center',
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
return (
<div>
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
</div>
)
}
}
]
})
const otherAttachmentList = ref([])
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const handleSearch = () => {
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
}
searchImplementationFileList(params).then(res => {
showAttachmentTable.value = false
if (res.code === 1000) {
otherAttachmentList.value = res.data.fileList
uploadState.value = res.data.upload
nextTick(() => {
showAttachmentTable.value = true
})
loading.close()
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
loading.close()
}
})
}
const getTagsOption = () => {
if (!route.query.projectId) return
getTags(route.query.projectId).then(res => {
if (res.code === 1000) {
tagsOption.value = res.data
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
})
}
const handleUpload = () => {
router.push({
name: 'Implementation/upload',
query: {
id: route.query.id,
projectId: route.query.projectId,
state: route.query.state,
step: '30'
}
})
}
handleSearch()
getTagsOption()
onActivated(()=>{
handleSearch()
getTagsOption()
})
</script>
<style lang="scss">
.execute-apply-table {
//.el-table__header {
// .el-table__cell:last-child {
// .cell {
// margin-left: -108px !important;
// }
// }
//}
//.el-table__body {
// .el-table__cell:last-child {
// .cell {
// margin-left: -108px !important;
// }
// }
//}
.is-leaf:first-child {
.cell {
margin-left: -25px !important;
}
}
.el-table__body {
.el-table__cell:first-child {
.cell {
margin-left: -13px !important;
}
}
}
}
</style>
<style scoped>
:deep(.el-table--fit ) {
height: 311px !important;
}
</style>
<template>
<el-row>
<el-col :span="24">
<baseTitle :title="'项目附件'"></baseTitle>
</el-col>
<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>
<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 {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: {
type: String,
default: '400'
},
isLineBtn: {
type: Boolean,
default: false
},
})
const executeTableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: 85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: props.fileNameTableWidth,
showOverflowTooltip: false,
currentRender: ({row, index}) => (
<div style="color: #2a99ff;cursor: pointer;" onClick={() => clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center',
showOverflowTooltip: false,
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
return (
<div>
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
{
uploadState.value ?
<popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => deleteSingleFile(row)}/> : ''
}
</div>
)
}
}
]
})
// row.newFile ?: ''
const otherAttachmentList = ref([])
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
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,otherAttachmentList.value)
console.log("🚀 row.newFile ", row.newFile)
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);
otherAttachmentList.value.splice(otherAttachmentList.value.findIndex((item) => item.fileId === row.fileId), 1);
localStorage.setItem(`implementAllFileList-${route.query.projectId}`, JSON.stringify(finalList))
} else {
otherAttachmentList.value.splice(otherAttachmentList.value.findIndex((item) => item.fileId === row.fileId), 1);
allFiles.value.splice(allFiles.value.findIndex((item) => item.fileId === row.fileId), 1);
}
// getAttachmentList()
}
});
}
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(() => {
filePreviewShow.value = true
})
}
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"
}
showAttachmentTable.value = false
searchImplementationFileList(params).then(res => {
if (res.code === 1000) {
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({
title: '提示',
message: res.msg,
type: 'error'
})
loading.close()
}
})
}
const getTagsOption = (flag) => {
if (!route.query.projectId) return
getTagList(route.query.projectId).then(res => {
if (res.code === 1000) {
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: '提示',
message: res.msg,
type: 'error'
})
}
})
}
const handleUpload = () => {
router.push({
name: 'Implementation/upload',
query: {
id: route.query.id,
projectId: route.query.projectId,
state: route.query.state,
step: '30'
}
})
}
getAttachmentList()
onActivated(() => {
getAttachmentList()
})
</script>
<style lang="scss">
.execute-apply-table {
//.el-table__header {
// .el-table__cell:last-child {
// .cell {
// margin-left: -108px !important;
// }
// }
//}
//.el-table__body {
// .el-table__cell:last-child {
// .cell {
// margin-left: -108px !important;
// }
// }
//}
.is-leaf:first-child {
.cell {
margin-left: -25px !important;
}
}
.el-table__body {
.el-table__cell:first-child {
.cell {
margin-left: -13px !important;
}
}
}
}
</style>
<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

@@ -1,275 +1,275 @@
<template>
<div v-loading="loading" style="padding: 0 30px">
<baseTitle title="专项资金详情"></baseTitle>
<el-form :model="formData" ref="form" >
<el-row style="margin-left: 15px;margin-bottom: -18px">
<el-col :span="6">
<el-form-item label="专项名称">
<span>{{ formData.name }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="金额(元)">
<span>{{ toThousands(formData.fundAmount) }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="剩余金额(元)">
<span>{{ toThousands(formData.residualAmount) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="专项资金情况说明" >
<div style="white-space: pre-wrap">{{formData.introduce}}
</div>
</el-form-item>
</el-col>
</el-row>
<el-row style="margin-bottom: -18px" class="projects">
<baseTitle title="关联项目" v-if="!data.taskId"></baseTitle>
<el-col :span="24" v-if="!data.taskId" >
<el-form-item >
<fvTable style="width: 100%;max-height:160px" height="160" v-if="showTable" :tableConfig="projectTable"
:data="formData.projects" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-col>
<baseTitle title="附件文件"></baseTitle>
<el-col :span="24">
<el-form-item>
<fvTable style="width: 100%;max-height: 160px;" height="160" v-if="showTable" :tableConfig="fileTable"
:data="formData.files" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-top: -18px">
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="auditOpinion">
<el-input
v-model="formData.auditOpinion"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
</el-col>
</el-row>
<div class="approval-record">
<div class="approval-title">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
/>
</div>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="fundProcess"/>
</div>
</div>
</el-form>
<opinion v-if="data.taskId" :formData="data.formData" :taskId="data.taskId"
:taskUserOptionList="data.taskUserOptionList"
v-model:value="formData.auditOpinion"></opinion>
<file-preview ref="filePreviewRef" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</div>
</template>
<script setup lang="jsx">
import {toThousands} from '@/utils/changePrice.js'
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {downloadFile} from "@/api/project-demand";
const changeDiagram = ref(false)
const emit = defineEmits(['getInfo', "update:formData"])
const form = ref()
const router = useRouter()
const props = defineProps({
formData: {
type: Array,
default: []
},
data: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
}, showTable: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
}
})
const projectTable = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'projectName',
label: '项目名称',
align: 'center',
width: 400
},
{
prop: 'specialFundAmount',
label: '项目金额',
align: 'center',
currentRender:({row})=>{
return <span>{toThousands(row.specialFundAmount)}</span>
}
},
{
prop: 'startTime',
label: '项目时间',
align: 'center'
},
{
prop: 'oper',
label: '操作',
align: 'center',
currentRender: ({row, index}) => {
return (
<el-button type="primary" link onClick={() => handleView(row)}>查看</el-button>
)
}
}
]
})
const fileTable = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: 400,
showOverflowTooltip: false,
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
currentRender: ({row, index}) => {
return (
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
)
}
}
]
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const handleView=(row)=>{
router.push({
name: 'Implementation/detail',
query: {
id: row.requirementId,
projectId: row.projectId,
step: '10'
}
})
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
watch(() => props.showTable, (newVal) => {
props.showTable = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
.projects{
:deep(.el-table--fit ) {
height: 300px !important;
}
}
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: -20px !important;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: -10px !important;
}
}
}
</style>
<template>
<div v-loading="loading" style="padding: 0 30px">
<baseTitle title="专项资金详情"></baseTitle>
<el-form :model="formData" ref="form" >
<el-row style="margin-left: 15px;margin-bottom: -18px">
<el-col :span="6">
<el-form-item label="专项名称">
<span>{{ formData.name }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="金额(元)">
<span>{{ toThousands(formData.fundAmount) }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="剩余金额(元)">
<span>{{ toThousands(formData.residualAmount) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="专项资金情况说明" >
<div style="white-space: pre-wrap">{{formData.introduce}}
</div>
</el-form-item>
</el-col>
</el-row>
<el-row style="margin-bottom: -18px" class="projects">
<baseTitle title="关联项目" v-if="!data.taskId"></baseTitle>
<el-col :span="24" v-if="!data.taskId" >
<el-form-item >
<fvTable style="width: 100%;max-height:160px" height="160" v-if="showTable" :tableConfig="projectTable"
:data="formData.projects" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-col>
<baseTitle title="附件文件"></baseTitle>
<el-col :span="24">
<el-form-item>
<fvTable style="width: 100%;max-height: 160px;" height="160" v-if="showTable" :tableConfig="fileTable"
:data="formData.files" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-top: -18px">
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="auditOpinion">
<el-input
v-model="formData.auditOpinion"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
</el-col>
</el-row>
<div class="approval-record">
<div class="approval-title">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
/>
</div>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="fundProcess"/>
</div>
</div>
</el-form>
<opinion v-if="data.taskId" :formData="data.formData" :taskId="data.taskId"
:taskUserOptionList="data.taskUserOptionList"
v-model:value="formData.auditOpinion"></opinion>
<file-preview ref="filePreviewRef" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</div>
</template>
<script setup lang="jsx">
import {toThousands} from '@/utils/changePrice.js'
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {downloadFile} from "@/api/project-demand";
const changeDiagram = ref(false)
const emit = defineEmits(['getInfo', "update:formData"])
const form = ref()
const router = useRouter()
const props = defineProps({
formData: {
type: Array,
default: []
},
data: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
}, showTable: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
}
})
const projectTable = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'projectName',
label: '项目名称',
align: 'center',
width: 400
},
{
prop: 'specialFundAmount',
label: '项目金额',
align: 'center',
currentRender:({row})=>{
return <span>{toThousands(row.specialFundAmount)}</span>
}
},
{
prop: 'startTime',
label: '项目时间',
align: 'center'
},
{
prop: 'oper',
label: '操作',
align: 'center',
currentRender: ({row, index}) => {
return (
<el-button type="primary" link onClick={() => handleView(row)}>查看</el-button>
)
}
}
]
})
const fileTable = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: 400,
showOverflowTooltip: false,
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
currentRender: ({row, index}) => {
return (
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
)
}
}
]
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const handleView=(row)=>{
router.push({
name: 'Implementation/detail',
query: {
id: row.requirementId,
projectId: row.projectId,
step: '10'
}
})
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
watch(() => props.showTable, (newVal) => {
props.showTable = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
.projects{
:deep(.el-table--fit ) {
height: 300px !important;
}
}
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: -20px !important;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: -10px !important;
}
}
}
</style>

View File

@@ -1,342 +1,442 @@
<template>
<div class="detail-block" v-loading="loading">
<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="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">
<span>{{ localFormData.newPatent }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="软件著作权(项)" prop="softwareCopyright">
<span>{{ localFormData.softwareCopyright }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="著作权(项)" prop="copyright">
<span>{{ localFormData.copyright }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="其他(项)" prop="other">
<span>{{ localFormData.other }}</span>
</el-form-item>
</el-col>
</el-row>
<baseTitle title="项目描述"></baseTitle>
<el-row gutter="20" style="margin-left: 5px;margin-bottom: -18px;">
<el-col :span="24">
<el-form-item label="现有业务描述" prop="serviceDescription">
<span style="white-space: pre-wrap">{{ localFormData.serviceDescription }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="建设目标描述" prop="contentDescription">
<span style="white-space: pre-wrap">{{ localFormData.contentDescription }}</span>
</el-form-item>
</el-col>
</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: -18px;">
<el-col :span="24" class="file-table-style">
<file-component tag="需求上报"
v-model:value="localFormData.fileList" :processViewer="processViewer"
:file-list-show="fileListShow"/>
</el-col>
<el-col :span="24" style="margin-top: -15px">
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
v-model="_value"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
<div v-if="data.state==='5'" style="margin-bottom: 15px">
<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"
style="color: #2a99ff;cursor: pointer">{{ item.requestName }}<span
v-if="index != localFormData.preProcess.length -1"></span>
</a>
</div>
</div>
</div>
<div v-perm="['annual:plan:approve']" v-if="data.state==='4'">
<baseTitle title="前置流程"></baseTitle>
<select-pre-process :formData="localFormData"/>
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
v-model="_value"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
</el-col>
</el-row>
<div class="approval-record">
<div class="approval-title" style="margin-top: -12px">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
/>
</div>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:step="'report'"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="summaryProcess"/>
</div>
</div>
</el-form>
<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>
</div>
</div>
</template>
<script setup lang="jsx">
import {toThousands} from '@/utils/changePrice.js'
import {downloadFile, deleteFile} from "@/api/project-demand";
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {useTagsView} from '@/stores/tagsview.js'
import {getFundOption} from "@/api/special-fund";
import {useCacheStore} from '@/stores/cache.js'
import {getSubCompOpt} from "@/api/user/user";
import FileComponent from "./FileComponent.vue";
import {ElNotification} from "element-plus";
import {approvePlan} from "@/api/project-demand/summary";
import SelectPreProcess from "@/components/SelectPreProcess.vue";
const emit = defineEmits(['update:value'])
const tagsViewStore = useTagsView()
const cacheStore = useCacheStore()
const props = defineProps({
formData: {
type: Object,
default: {}
},
data: {
type: Object,
default: {
state: '1'
}
},
processViewer: {
type: Boolean,
default: false
},
fileListShow: {
type: String,
default: 'READ'
},
loading: {
type: Boolean,
default: false
},
value: {
type: String,
default: ''
}
})
const changeDiagram = ref(false)
const localFormData = ref({})
const route = useRoute()
const router = useRouter()
const fundOption = ref([])
const companyOption = ref([])
const dictName = ref({})
const rules = reactive({
auditOpinion: [{required: true, message: '请输入审核意见', trigger: 'blur'}],
})
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const handleRejectPlan = async () => {
// const values = form.value.getValues()
// console.log('route',route.query.projectId)
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
const params = {
auditOpinion: _value.value,
projectId: parseInt(route.query.projectId),
state: false
}
// console.log('params', params)
const res = await approvePlan(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
router.push({
name: 'Summary'
})
}
const handleAgreePlan = async () => {
const params = {
auditOpinion: _value.value,
projectId: parseInt(route.query.projectId),
preProcess: JSON.stringify(localFormData.value.preProcess),
state: true
}
const res = await approvePlan(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
router.push({
name: 'Summary'
})
}
const filterDict = (data, value) => {
if (data === undefined || value === undefined) return;
let label = ''
let result = []
if (value instanceof Array) {
value.forEach(item1 => {
data.find(item => {
if (item.value == item1) {
result.push(item.label)
}
})
})
label = result.map(item => item).join('')
} else {
if (data instanceof Array) {
data.find(item => {
if (item.value == value) {
label = item.label
}
})
}
}
return label
}
const getFundOptions = async () => {
const resFund = await getFundOption()
fundOption.value = resFund.data
const res = await getSubCompOpt()
companyOption.value = res.data
}
const changeName = (option, value) => {
let name = ''
option.forEach(item => {
if (item.value == value) {
name = item.label
}
})
return name
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
watchEffect(() => {
props.formData.singleFile = [props.formData.singleFile]
return Object.keys(props.formData).length && (localFormData.value = props.formData)
})
getFundOptions()
</script>
<style scoped lang="scss">
.detail-block {
overflow-x: hidden;
overflow-y: auto;
padding-bottom: 0 !important;
}
.file-table-style{
: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;
}
}
}
}
</style>
<template>
<div class="detail-block" v-loading="loading">
<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="intellectualProperty">
<span>{{
filterDict(cacheStore.getDict('intellectual_property'), localFormData.intellectualProperty)
}}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估专利(项)" prop="newPatent">
<span>{{ localFormData.newPatent }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估软件著作权(项)" prop="softwareCopyright">
<span>{{ localFormData.softwareCopyright }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估技术标准(项)" prop="technicalNorms">
<span>{{ localFormData.technicalNorms }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<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>
<baseTitle title="项目描述"></baseTitle>
<el-row gutter="20" style="margin-left: 5px;margin-bottom: -18px;">
<el-col :span="24">
<el-form-item label="现有业务描述" prop="serviceDescription">
<span style="white-space: pre-wrap">{{ localFormData.serviceDescription }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="建设目标描述" prop="contentDescription">
<span style="white-space: pre-wrap">{{ localFormData.contentDescription }}</span>
</el-form-item>
</el-col>
</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: -18px;">
<el-col :span="24" class="file-table-style">
<file-component tag="需求上报"
v-model:value="localFormData.fileList" :processViewer="processViewer"
:file-list-show="fileListShow"/>
</el-col>
<el-col :span="24" style="margin-top: -15px">
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
v-model="_value"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
<div v-if="data.state==='5'" style="margin-bottom: 15px">
<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"
style="color: #2a99ff;cursor: pointer">{{ item.requestName }}<span
v-if="index != localFormData.preProcess.length -1"></span>
</a>
</div>
</div>
</div>
<div v-perm="['annual:plan:approve']" v-if="data.state==='4'">
<!-- <baseTitle title="前置流程"></baseTitle>-->
<!-- <select-pre-process :formData="localFormData"/>-->
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
v-model="_value"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
</el-col>
</el-row>
<div class="approval-record">
<div class="approval-title" style="margin-top: -12px">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
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"
:operation-list="data.operationList"
:step="'report'"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="summaryProcess"/>
</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>
</div>
</div>
</template>
<script setup lang="jsx">
import {toThousands} from '@/utils/changePrice.js'
import {downloadFile, deleteFile} from "@/api/project-demand";
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {useTagsView} from '@/stores/tagsview.js'
import {getFundOption} from "@/api/special-fund";
import {useCacheStore} from '@/stores/cache.js'
import {getSubCompOpt} from "@/api/user/user";
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','ccSend'])
const tagsViewStore = useTagsView()
const cacheStore = useCacheStore()
const props = defineProps({
formData: {
type: Object,
default: {}
},
data: {
type: Object,
default: {
state: '1'
}
},
processViewer: {
type: Boolean,
default: false
},
fileListShow: {
type: String,
default: 'READ'
},
loading: {
type: Boolean,
default: false
},
value: {
type: String,
default: ''
}
})
const changeDiagram = ref(false)
const localFormData = ref({})
const route = useRoute()
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'}],
})
const _value = computed({
get() {
return props.value;
},
set(val) {
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)
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
const params = {
auditOpinion: _value.value,
projectId: parseInt(route.query.projectId),
state: false
}
// console.log('params', params)
const res = await approvePlan(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
router.push({
name: 'Summary'
})
}
const handleAgreePlan = async () => {
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
const params = {
auditOpinion: _value.value,
projectId: parseInt(route.query.projectId),
preProcess: JSON.stringify(localFormData.value.preProcess),
state: true
}
const res = await approvePlan(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
router.push({
name: 'Summary'
})
}
const filterDict = (data, value) => {
if (data === undefined || value === undefined) return;
let label = ''
let result = []
if (value instanceof Array) {
value.forEach(item1 => {
data.find(item => {
if (item.value == item1) {
result.push(item.label)
}
})
})
label = result.map(item => item).join('')
} else {
if (data instanceof Array) {
data.find(item => {
if (item.value == value) {
label = item.label
}
})
}
}
return label
}
const getFundOptions = async () => {
const resFund = await getFundOption()
fundOption.value = resFund.data
const res = await getSubCompOpt()
companyOption.value = res.data
}
const changeName = (option, value) => {
let name = ''
option.forEach(item => {
if (item.value == value) {
name = item.label
}
})
return name
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
watchEffect(() => {
props.formData.singleFile = [props.formData.singleFile]
return Object.keys(props.formData).length && (localFormData.value = props.formData)
})
getFundOptions()
</script>
<style scoped lang="scss">
.detail-block {
overflow-x: hidden;
overflow-y: auto;
padding-bottom: 0 !important;
}
.file-table-style {
: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;
}
}
}
}
</style>

View File

@@ -1,209 +1,209 @@
<template>
<el-form :label-position="labelAlign">
<el-form-item :label="title?'其他文件':''" :label-position="labelAlign" :label-width="title?95:''">
<fvTable style="width: 100%;max-height: 80px;" v-if="processViewer" height="80" :tableConfig="tableConfig"
:data="_value" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-form>
<file-preview ref="filePreviewRef" :fullscreen="fullscreen" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</template>
<script setup lang="jsx">
import {downloadFile, deleteFile} from "@/api/project-demand";
import {ElNotification} from "element-plus";
const props = defineProps({
title: {
type: String,
default: ''
},
tag: {
type: String,
default: ''
},
fileNameTableWidth: {
type: String,
default: '400'
},
value: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
},
labelAlign: {
type: String,
default: 'right'
},
//弹窗是否铺满全屏
fullscreen: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['update:value'])
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: 85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: props.fileNameTableWidth,
showOverflowTooltip: false,
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
width: 150,
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
// if (row.newFile) {
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
// }
return (
<div style={{width: '100%'}}>
{
btn.map(item => (
<el-button
type={item.type}
onClick={() => item.func()}
link>
{item.label}
</el-button>
))
}
{
row.newFile ? <popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => handleDelete(row)}/>
: ''
}
</div>
)
}
}
]
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const getOtherFile = (val) => {
props.processViewer = false
let fileObj = compositeParam(val)
_value.value.push(fileObj)
nextTick(() => {
props.processViewer = true
})
}
const compositeParam = (item, type) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: props.tag
}
}
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 handleDelete = (row) => {
deleteFile(row.fileId).then(res => {
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
_value.value.splice(_value.value.findIndex((item) => item.fileId === row.fileId), 1);
}
});
}
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
:deep(.el-table--fit ) {
height: 80px !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;
}
}
}
</style>
<template>
<el-form :label-position="labelAlign">
<el-form-item :label="title?'其他文件':''" :label-position="labelAlign" :label-width="title?95:''">
<fvTable style="width: 100%;max-height: 80px;" v-if="processViewer" height="80" :tableConfig="tableConfig"
:data="_value" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-form>
<file-preview ref="filePreviewRef" :fullscreen="fullscreen" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</template>
<script setup lang="jsx">
import {downloadFile, deleteFile} from "@/api/project-demand";
import {ElNotification} from "element-plus";
const props = defineProps({
title: {
type: String,
default: ''
},
tag: {
type: String,
default: ''
},
fileNameTableWidth: {
type: String,
default: '400'
},
value: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
},
labelAlign: {
type: String,
default: 'right'
},
//弹窗是否铺满全屏
fullscreen: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['update:value'])
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: 85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: props.fileNameTableWidth,
showOverflowTooltip: false,
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
width: 150,
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
// if (row.newFile) {
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
// }
return (
<div style={{width: '100%'}}>
{
btn.map(item => (
<el-button
type={item.type}
onClick={() => item.func()}
link>
{item.label}
</el-button>
))
}
{
row.newFile ? <popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => handleDelete(row)}/>
: ''
}
</div>
)
}
}
]
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const getOtherFile = (val) => {
props.processViewer = false
let fileObj = compositeParam(val)
_value.value.push(fileObj)
nextTick(() => {
props.processViewer = true
})
}
const compositeParam = (item, type) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: props.tag
}
}
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 handleDelete = (row) => {
deleteFile(row.fileId).then(res => {
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
_value.value.splice(_value.value.findIndex((item) => item.fileId === row.fileId), 1);
}
});
}
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
:deep(.el-table--fit ) {
height: 80px !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;
}
}
}
</style>

View File

@@ -1,117 +1,210 @@
<template>
<el-upload :file-list="_value"
:action="uploadFileUrl"
:headers="headers"
:limit="maxSize"
with-credentials
:multiple="multiple"
:data="uploadParams"
:show-file-list="showFileList"
:auto-upload="true"
:before-upload="beforeUpload"
:on-success="handleUploadSuccess"
:on-error="uploadError"
:before-remove="beforeRemove"
:on-remove="handleRemove"
>
<el-button color="#DED0B2" :loading="loading" :disabled="disabled">上传文件</el-button>
</el-upload>
</template>
<script setup>
import { ElMessageBox, ElNotification} from "element-plus";
import {getToken} from '@/utils/auth'
const baseURL = import.meta.env.VITE_BASE_URL
const uploadFileUrl = ref(baseURL + "/workflow/process/file/upload")
const headers = reactive({
authorization: getToken()
})
const loading = ref(false)
const showTable = ref(false)
const uploadParams = ref({})
const props = defineProps({
value: {
type: Array,
default: () => {
return []
}
},
maxSize: {
type: Number,
default: 30
},
showFileList: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: true
}
})
const emit = defineEmits(["input", "getFile", "delete"])
const fileList = ref([])
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("input", val);
}
})
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 handleUploadSuccess = (res) => {
ElNotification({
title: '提示',
message: res.code === 1000 ? '上传成功' : '上传失败',
type: res.code === 1000 ? 'success' : 'error'
})
loading.value = false
showTable.value = true
let data = res.data
fileList.value.push(data)
emit("getFile", res.data)
}
const uploadError = () => {
loading.value = false
ElNotification({
title: '提示',
message: "上传失败,请稍后再试!",
type: 'error'
})
}
defineExpose({
handleRemove
})
</script>
<style lang="scss" scoped>
a {
font-size: 14px;
color: #2a99ff;
}
:deep(.el-upload-list) {
width: 400px;
}
</style>
<template>
<el-upload :file-list="_value" ref="uploadRef"
action="#"
:headers="headers"
:limit="maxSize"
with-credentials
:multiple="multiple"
:data="uploadParams" :on-change="handleChange"
:http-request="customUpload"
:show-file-list="showFileList"
:auto-upload="false"
:before-upload="beforeUpload"
:on-error="uploadError"
:before-remove="beforeRemove"
:on-remove="handleRemove"
>
<!-- :on-success="handleUploadSuccess"-->
<el-button color="#DED0B2" :loading="loading" :disabled="disabled">上传文件</el-button>
</el-upload>
</template>
<script setup>
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: {
type: Array,
default: () => {
return []
}
},
maxSize: {
type: Number,
default: 999999
},
showFileList: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: true
}
})
const uploadRef = ref(null); // el-upload 的 ref
const uploadPromises = ref([]); // 跟踪每个文件的上传状态
const emit = defineEmits(["input", "beforeUpload", "getFile", "delete"])
const fileList = ref([])
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("input", val);
}
})
const beforeRemove = (file) => {
return ElMessageBox.confirm(`确认删除名称为${file.name}的文件吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => true)
}
const uploadLoading = ref(false)
const uploadFile = ref([])
const handleRemove = (file) => {
emit("delete", file.response.data.id)
}
// 文件选择变化时触发
const handleChange = (file, files) => {
const deleteFileRow = JSON.parse(localStorage.getItem('deleteFileRow'));
console.log("🚀 ~ file:deleteFileRow ", deleteFileRow, uploadFile.value)
let deleteIndex = null
if (deleteFileRow) {
deleteIndex = uploadFile.value.findIndex((item) => item.name === deleteFileRow.originalFileName && item.size === deleteFileRow.size)
console.log("🚀 ~ file:deleteIndex ", deleteIndex)
if (deleteIndex != -1) {
uploadFile.value.splice(deleteIndex, 1);
}
}
console.log(file, files, 'files')
uploadIndex.value++
uploadFile.value.push(file)
console.log("🚀 ~ file:uploadFile.value ", uploadFile.value)
localStorage.removeItem('deleteFileRow')
};
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(); // 清空上传组件
uploadFile.value = [] // 清空文件列表
nextTick(() => {
uploadLoading.value.close()
uploadLoading.value = null
})
})
};
const beforeUpload = () => {
loading.value = true
return true
}
const handleUploadSuccess = (res) => {
ElNotification({
title: '提示',
message: res.code === 1000 ? '上传成功' : '上传失败',
type: res.code === 1000 ? 'success' : 'error'
})
loading.value = false
showTable.value = true
let data = res.data
fileList.value.push(data)
// emit("getFile", res.data)
}
const uploadError = () => {
loading.value = false
ElNotification({
title: '提示',
message: "上传失败,请稍后再试!",
type: 'error'
})
}
defineExpose({
handleRemove
})
</script>
<style lang="scss" scoped>
a {
font-size: 14px;
color: #2a99ff;
}
:deep(.el-upload-list) {
width: 400px;
}
</style>

View File

@@ -1,43 +1,43 @@
<script setup>
defineProps({
msg: {
type: String,
required: true
}
})
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
Youve successfully created a project with
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>.
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>
<script setup>
defineProps({
msg: {
type: String,
required: true
}
})
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
Youve successfully created a project with
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>.
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>

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

@@ -1,116 +1,116 @@
<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-left: 10px; 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
},
projectId: {
type: Number,
default: 0
}
})
const baseURL = import.meta.env.VITE_BASE_URL
const uploadFileUrl = ref(baseURL + "/workflow/mosr/expense/ledger/import?projectId=" + props.projectId)
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) => {
// loading.value = false
ElNotification({
title: '提示',
message: "上传失败,请稍后再试!",
type: 'error'
})
}
defineExpose({
handleRemove
})
</script>
<style lang="scss" scoped>
a {
font-size: 14px;
color: #2a99ff;
}
</style>
<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-left: 10px; 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
},
projectId: {
type: Number,
default: 0
}
})
const baseURL = import.meta.env.VITE_BASE_URL
const uploadFileUrl = ref(baseURL + "/workflow/mosr/expense/ledger/import?projectId=" + props.projectId)
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) => {
// loading.value = false
ElNotification({
title: '提示',
message: "上传失败,请稍后再试!",
type: 'error'
})
}
defineExpose({
handleRemove
})
</script>
<style lang="scss" scoped>
a {
font-size: 14px;
color: #2a99ff;
}
</style>

View File

@@ -1,133 +1,133 @@
<template>
<div style="display: block">
<slot name="pre"></slot>
<div class="user-audit">
<div class="circle-user">
<Tooltip v-if="userName" :content="userName" placement="bottom-start" width="45px"/>
<Tooltip v-else :content="user.name" placement="bottom-start" width="45px"/>
<!-- :style="{-->
<!-- backgroundColor: '#fff'-->
<!-- }">-->
<div v-if="user.icon"
class="el-timeline-item__node">
<div v-if="user.isAgent&&!showIcon">
</div>
<el-icon v-else size="15" :color="user.color" :class="user.class">
<component :is="user.icon"/>
</el-icon>
</div>
</div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
row: {
type: Number,
default: 1
},
hoverTip: {
type: Boolean,
default: false
},
showIcon: {
type: Boolean,
default: false
},
user: {
type: Object,
default: {}
},
userName: {
type: String,
default: ''
},
mode: {
type: String,
default: 'design'
},
type: {
type: String,
default: ''
},
})
const init = () => {
// for (let user of props.userInfo) {
initUser(props.user)
// }
}
const initUser = (user) => {
let state = user.state
//创建节点
if (state === 'CREATE') {
user["icon"] = 'CircleCheckFilled'
user["color"] = "#0bbd87"
}
//审批通过
if (state === 'AGREE' || state === 'AUTO_PASS') {
user["icon"] = 'CircleCheckFilled'
user["color"] = "#0bbd87"
}
if (props.type === "CC") {
user["icon"] = "Promotion"
user["color"] = "#3395f8"
}
//审批处理中
if (state === 'RUNNING') {
user["icon"] = 'Loading'
user["color"] = "#f78f5f"
user["class"] = 'is-loading'
}
//拒绝后评论
if (state === 'REFUSE' || state === 'ROLLBACK') {
// user["icon"] = 'Close'
// user["color"] = "#f56c6c"
user["icon"] = 'CircleCloseFilled'
user["color"] = "#f56c6c"
}
if (state === 'PASS') {
user["icon"] = 'MoreFilled'
user["color"] = "#c0c4cc"
}
// if (state === 'ROLLBACK') {
// // user["icon"] = 'RefreshLeft'
// // user["color"] = "#f78f5f"
// user["icon"] = 'CircleCloseFilled'
// user["color"] = "#f56c6c"
// }
return user;
}
init()
</script>
<style scoped lang="scss">
.user-audit {
display: flex;
flex-direction: column;
align-items: center;
.circle-user {
width: 46px;
height: 46px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
border: 1px solid #ACACAC;
position: relative;
background-color: #8a7243;
color: #fff;
.el-timeline-item__node {
position: absolute;
bottom: 0;
right: 1px;
}
}
}
</style>
<template>
<div style="display: block">
<slot name="pre"></slot>
<div class="user-audit">
<div class="circle-user">
<Tooltip v-if="userName" :content="userName" placement="bottom-start" width="45px"/>
<Tooltip v-else :content="user.name" placement="bottom-start" width="45px"/>
<!-- :style="{-->
<!-- backgroundColor: '#fff'-->
<!-- }">-->
<div v-if="user.icon"
class="el-timeline-item__node">
<div v-if="user.isAgent&&!showIcon">
</div>
<el-icon v-else size="15" :color="user.color" :class="user.class">
<component :is="user.icon"/>
</el-icon>
</div>
</div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
row: {
type: Number,
default: 1
},
hoverTip: {
type: Boolean,
default: false
},
showIcon: {
type: Boolean,
default: false
},
user: {
type: Object,
default: {}
},
userName: {
type: String,
default: ''
},
mode: {
type: String,
default: 'design'
},
type: {
type: String,
default: ''
},
})
const init = () => {
// for (let user of props.userInfo) {
initUser(props.user)
// }
}
const initUser = (user) => {
let state = user.state
//创建节点
if (state === 'CREATE') {
user["icon"] = 'CircleCheckFilled'
user["color"] = "#0bbd87"
}
//审批通过
if (state === 'AGREE' || state === 'AUTO_PASS') {
user["icon"] = 'CircleCheckFilled'
user["color"] = "#0bbd87"
}
if (props.type === "CC") {
user["icon"] = "Promotion"
user["color"] = "#3395f8"
}
//审批处理中
if (state === 'RUNNING') {
user["icon"] = 'Loading'
user["color"] = "#f78f5f"
user["class"] = 'is-loading'
}
//拒绝后评论
if (state === 'REFUSE' || state === 'ROLLBACK') {
// user["icon"] = 'Close'
// user["color"] = "#f56c6c"
user["icon"] = 'CircleCloseFilled'
user["color"] = "#f56c6c"
}
if (state === 'PASS') {
user["icon"] = 'MoreFilled'
user["color"] = "#c0c4cc"
}
// if (state === 'ROLLBACK') {
// // user["icon"] = 'RefreshLeft'
// // user["color"] = "#f78f5f"
// user["icon"] = 'CircleCloseFilled'
// user["color"] = "#f56c6c"
// }
return user;
}
init()
</script>
<style scoped lang="scss">
.user-audit {
display: flex;
flex-direction: column;
align-items: center;
.circle-user {
width: 46px;
height: 46px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
border: 1px solid #ACACAC;
position: relative;
background-color: #8a7243;
color: #fff;
.el-timeline-item__node {
position: absolute;
bottom: 0;
right: 1px;
}
}
}
</style>

View File

@@ -1,3 +1,3 @@
<template>
<router-view></router-view>
<template>
<router-view></router-view>
</template>

View File

@@ -1,101 +1,101 @@
<template>
<div style="display: flex;justify-content: center">
<span class="stateIcon" :style="{backgroundColor: filterDictClass(cacheStore.getDict(dictType), value)}"></span>
<span>{{tagConfig.label}}</span>
<span> {{ filterDict(cacheStore.getDict(dictType), value) }}</span>
</div>
</template>
<script setup>
import {defineProps} from "vue";
import {useCacheStore} from "@/stores/cache.js";
const cacheStore = useCacheStore();
const props = defineProps({
dictType: {
type: String,
default: ""
},
value: {
type: Object,
default: null
}
});
const tagConfig = reactive({
listClass: "green",
isType: true,
label: ""
});
const filterDictClass = (data, value) => {
if (!data|| value == null) return 'gray'
if (data instanceof Array) {
tagConfig.value = data.find(item => item.value == value)
if (!tagConfig.value) {
return '#409EFF'
} else {
if (tagConfig.value?.isType) {
return changeParams(tagConfig.value.listClass)
} else {
return tagConfig.value.listClass
}
}
}
}
const filterDict = (data, value) => {
if (!data || value == null) return '未知'
if (data instanceof Array) {
if (value == true || value == false) {
tagConfig.value = data.find(item => item.value == value.toString())
} else if (typeof value === "object") {
if (value !== null) {
tagConfig.value = data.find(item => item.value == value[0])
} else {
tagConfig.value = {}
}
} else {
tagConfig.value = data.find(item => item.value == value)
}
}
return tagConfig.value?.label || '未知'
}
/**
* 根据接口返回的listClass切换成对应的颜色
* @param listClass 后端返回的listClass字段
* @returns {string}
*/
const changeParams = (listClass) => {
switch (listClass) {
case 'danger':
return 'red'
case 'success':
return '#67C23A'
case 'info':
return '#909399'
case 'primary':
return '#409EFF'
case 'warning':
return '#E6A23C'
default:
return listClass
}
}
// dictFormat()
</script>
<style scoped lang="scss">
//.dot{
// width:8px;
// height: 20px;
// margin-left: -5px;
// background-color: green;
// z-index: 99999;
//}
:deep(.el-tag){
position: relative;
margin-top: 9px;
margin-right: 7px;
height: 8px;
}
</style>
<template>
<div style="display: flex;justify-content: center">
<span class="stateIcon" :style="{backgroundColor: filterDictClass(cacheStore.getDict(dictType), value)}"></span>
<span>{{tagConfig.label}}</span>
<span> {{ filterDict(cacheStore.getDict(dictType), value) }}</span>
</div>
</template>
<script setup>
import {defineProps} from "vue";
import {useCacheStore} from "@/stores/cache.js";
const cacheStore = useCacheStore();
const props = defineProps({
dictType: {
type: String,
default: ""
},
value: {
type: Object,
default: null
}
});
const tagConfig = reactive({
listClass: "green",
isType: true,
label: ""
});
const filterDictClass = (data, value) => {
if (!data|| value == null) return 'gray'
if (data instanceof Array) {
tagConfig.value = data.find(item => item.value == value)
if (!tagConfig.value) {
return '#409EFF'
} else {
if (tagConfig.value?.isType) {
return changeParams(tagConfig.value.listClass)
} else {
return tagConfig.value.listClass
}
}
}
}
const filterDict = (data, value) => {
if (!data || value == null) return '未知'
if (data instanceof Array) {
if (value == true || value == false) {
tagConfig.value = data.find(item => item.value == value.toString())
} else if (typeof value === "object") {
if (value !== null) {
tagConfig.value = data.find(item => item.value == value[0])
} else {
tagConfig.value = {}
}
} else {
tagConfig.value = data.find(item => item.value == value)
}
}
return tagConfig.value?.label || '未知'
}
/**
* 根据接口返回的listClass切换成对应的颜色
* @param listClass 后端返回的listClass字段
* @returns {string}
*/
const changeParams = (listClass) => {
switch (listClass) {
case 'danger':
return 'red'
case 'success':
return '#67C23A'
case 'info':
return '#909399'
case 'primary':
return '#409EFF'
case 'warning':
return '#E6A23C'
default:
return listClass
}
}
// dictFormat()
</script>
<style scoped lang="scss">
//.dot{
// width:8px;
// height: 20px;
// margin-left: -5px;
// background-color: green;
// z-index: 99999;
//}
:deep(.el-tag){
position: relative;
margin-top: 9px;
margin-right: 7px;
height: 8px;
}
</style>

View File

@@ -1,81 +1,81 @@
<template>
<el-popconfirm
confirm-button-text="确认"
cancel-button-text="取消"
icon="WarningFilled"
icon-color="#E6A23C"
:title="title"
@confirm="handleDelete"
@cancel="handleCancel"
>
<template #reference>
<el-button :type="btnType" size="mini" :disabled="isDisabled" v-if="perm" v-perm="perm" :icon="btnIcon" :plain="isPlain" :link="link">
{{ btnText }}
</el-button>
<el-button :type="btnType" size="mini" :disabled="isDisabled" v-else :icon="btnIcon" :plain="isPlain" :link="link">
{{ btnText }}
</el-button>
</template>
</el-popconfirm>
</template>
<script setup>
const props = defineProps({
name: {
type: Object,
default: null
},
btnType: {
type: String,
default: 'danger'
},
type: {
type: String,
default: ''
},
link: {
type: Boolean,
default: true
},
btnIcon: {
type: String,
default: ''
},
btnText: {
type: String,
default: '删除'
},
perm: {
type: Array,
default: null
},
isDisabled: {
type: Boolean,
default: false
},
isPlain: {
type: Boolean,
default: false
},
})
const emit = defineEmits()
const title = ref(`确认${props.btnText}名称为"${props.name}"的${props.type}吗!`)
const visible = ref(false)
watch(() => props.name, (newVal) => {
title.value = "确认" + props.btnText + "名称为" + '"' + props.name + '"' + "的" + props.type + "吗!"
})
const handleCancel = () => {
visible.value = false
}
const handleDelete = () => {
emit("delete")
}
</script>
<style lang="scss">
.el-popconfirm__main {
display: flex;
word-break: break-all;
align-items: center;
}
</style>
<template>
<el-popconfirm
confirm-button-text="确认"
cancel-button-text="取消"
icon="WarningFilled"
icon-color="#E6A23C"
:title="title"
@confirm="handleDelete"
@cancel="handleCancel"
>
<template #reference>
<el-button :type="btnType" size="mini" :disabled="isDisabled" v-if="perm" v-perm="perm" :icon="btnIcon" :plain="isPlain" :link="link">
{{ btnText }}
</el-button>
<el-button :type="btnType" size="mini" :disabled="isDisabled" v-else :icon="btnIcon" :plain="isPlain" :link="link">
{{ btnText }}
</el-button>
</template>
</el-popconfirm>
</template>
<script setup>
const props = defineProps({
name: {
type: Object,
default: null
},
btnType: {
type: String,
default: 'danger'
},
type: {
type: String,
default: ''
},
link: {
type: Boolean,
default: true
},
btnIcon: {
type: String,
default: ''
},
btnText: {
type: String,
default: '删除'
},
perm: {
type: Array,
default: null
},
isDisabled: {
type: Boolean,
default: false
},
isPlain: {
type: Boolean,
default: false
},
})
const emit = defineEmits()
const title = ref(`确认${props.btnText}名称为"${props.name}"的${props.type}吗!`)
const visible = ref(false)
watch(() => props.name, (newVal) => {
title.value = "确认" + props.btnText + "名称为" + '"' + props.name + '"' + "的" + props.type + "吗!"
})
const handleCancel = () => {
visible.value = false
}
const handleDelete = () => {
emit("delete")
}
</script>
<style lang="scss">
.el-popconfirm__main {
display: flex;
word-break: break-all;
align-items: center;
}
</style>

View File

@@ -1,215 +1,275 @@
<template>
<div v-loading="_value">
<el-form :model="attachment" inline style="margin-left: 15px" @submit.prevent="handleSearch">
<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-option
v-for="item in cacheStore.getDict('archive_file_type')"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="标签" prop="tag" v-if="type==='30'">
<el-select v-model="attachment.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 @click="handleReset">重置</el-button>
<el-button v-if="uploadState&&!allFile" color="#DED0B2" @click="handleUpload">上传附件</el-button>
</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"
:data="fileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="99" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-card>
<file-preview ref="filePreviewRef" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</div>
</template>
<script setup lang="jsx">
import {downloadFile} from "@/api/project-demand";
import {ElNotification} from "element-plus";
import {getTags} from "@/api/project-manage";
import {computed, ref} from "vue";
import {useCacheStore} from '@/stores/cache.js'
const route = useRoute()
const router = useRouter()
const cacheStore = useCacheStore()
const attachment = reactive({})
const emit = defineEmits(['search','update:modelValue'])
const props = defineProps({
fileList: {
type: Array,
default: []
},
type: {
type: String,
default: '00'
},
uploadState: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: true
},
allFile: {
type: Boolean,
default: false
}
})
const tagsOption = ref([])
const tableConfig = 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: 'tag',
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 showTable = ref(true)
const _value = computed({
get() {
return props.loading || ""
},
set(value) {
emit('update:modelValue', value)
}
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const getTagsOption = () => {
if (!route.query.id) return
getTags(route.query.id).then(res => {
if (res.code === 1000) {
tagsOption.value = res.data
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
})
}
const handleSearch = () => {
emit('search', attachment)
}
const handleReset=()=>{
attachment.fileName=''
attachment.targetState=''
attachment.tag=null
emit('search', {})
}
const handleUpload = () => {
emit('upload')
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.type, (val) => {
props.type = val
})
watch(() => props.fileList, (val) => {
showTable.value = false
nextTick(() => {
showTable.value = true
})
props.fileList = val
})
if (props.type === '30') {
getTagsOption()
}
onActivated(()=>{
if (props.type === '30') {
getTagsOption()
}
handleSearch()
})
</script>
<style scoped>
:deep(.el-table--fit ) {
height: 318px !important;
}
</style>
<template>
<div v-loading="_value">
<el-form :model="attachment" inline style="margin-left: 15px" @submit.prevent="handleSearch">
<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-option
v-for="item in cacheStore.getDict('archive_file_type')"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="标签" prop="tag" v-if="type==='30'">
<el-select v-model="attachment.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 @click="handleReset">重置</el-button>
<el-button v-if="uploadState&&!allFile" color="#DED0B2" @click="handleUpload">上传附件</el-button>
</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="allFile?tableConfigAll:tableConfig"
:data="fileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="99" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-card>
<file-preview ref="filePreviewRef" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</div>
</template>
<script setup lang="jsx">
import {downloadFile} from "@/api/project-demand";
import {ElNotification} from "element-plus";
import {getTags} from "@/api/project-manage";
import {computed, ref} from "vue";
import {useCacheStore} from '@/stores/cache.js'
const route = useRoute()
const router = useRouter()
const cacheStore = useCacheStore()
const attachment = reactive({})
const emit = defineEmits(['search','update:modelValue'])
const props = defineProps({
fileList: {
type: Array,
default: []
},
type: {
type: String,
default: '00'
},
uploadState: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: true
},
allFile: {
type: Boolean,
default: false
}
})
const tagsOption = ref([])
const tableConfig = 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: 'tag',
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'
},
{
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 showTable = ref(true)
const _value = computed({
get() {
return props.loading || ""
},
set(value) {
emit('update:modelValue', value)
}
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const getTagsOption = () => {
if (!route.query.id) return
getTags(route.query.id).then(res => {
if (res.code === 1000) {
tagsOption.value = res.data
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
})
}
const handleSearch = () => {
emit('search', attachment)
}
const handleReset=()=>{
attachment.fileName=''
attachment.targetState=''
attachment.tag=null
emit('search', {})
}
const handleUpload = () => {
emit('upload')
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.type, (val) => {
props.type = val
})
watch(() => props.fileList, (val) => {
showTable.value = false
nextTick(() => {
showTable.value = true
})
props.fileList = val
})
if (props.type === '30') {
getTagsOption()
}
onActivated(()=>{
if (props.type === '30') {
getTagsOption()
}
handleSearch()
})
</script>
<style scoped>
:deep(.el-table--fit ) {
height: 318px !important;
}
</style>

View File

@@ -1,191 +1,226 @@
<template>
<div style="display: flex;align-items: center;flex-wrap: wrap;">
<el-button color="#DED0B2" @click="handleShowPreTable" style="margin-right: 10px">
{{
localFormData.preProcess && localFormData.preProcess.length > 0 ? '更改' : '请选择前置流程'
}}
</el-button>
<div v-for="(item,index) in 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>
</div>
<el-dialog v-if="showPreTable" title="前置流程" v-model="showPreTable" width="80%">
<el-form :model="preProcessForm" inline @submit.prevent="getPreProcessList">
<el-form-item label="请求名称">
<el-input v-model="preProcessForm.requestName" placeholder="请输入请求名称" clearable>
</el-input>
</el-form-item>
<el-form-item>
<el-button color="#DED0B2" @click="getPreProcessList">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
<el-form-item>
<el-tag type="danger" style="font-size: 16px;color: red;" >特别提示{{ getPreProcessTag(localFormData.projectImpact,basicData.projectImpact) }}</el-tag>
</el-form-item>
</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 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>
<el-table-column prop="lastOperateTime" label="最后操作时间"></el-table-column>
<el-table-column prop="currentNodeName" label="当前节点"></el-table-column>
<el-table-column prop="creatorName" label="创建人"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<a :href="scope.row.baseUrl" target="_blank" style="color: #2a99ff;margin-left: 10px">查看流程</a>
</template>
</el-table-column>
</el-table>
<paging :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[10, 20, 30, 40,50]"
:total="total" @changeSize="handleSizeChange" @goPage="handleCurrentChange"/>
<div class="oper">
<el-button color="#DED0B2" @click="choosePreProcess">确定</el-button>
<el-button @click="handleCancel">取消</el-button>
</div>
</el-dialog>
</template>
<script setup>
import {
getPreProcess
} from "@/api/project-manage";
import Paging from "@/components/pagination/index.vue";
const props = defineProps({
formData: {
type: Object,
default: {}
},
basicData: {
type: Object,
default: {}
},
})
const loading = ref(false)
//暂存数据
const currentList = ref([])
const showPreTable = ref(false)
const selectRows = ref([])
const preProcessList = ref([])
const total = ref(0)
const localFormData = ref({
projectPersonIds: [],
projectChargePerson: null,
preProcess: [
// {
// requestId: null,
// requestName: '',
// baseUrl: ''
// }
]
})
const preProcessForm = reactive({
requestName: ''
})
const pageInfo = reactive({
pageNum: 1,
pageSize: 10,
})
const getPreProcessTag = (impact,basicImpact) => {
let data=''
if(impact){
data= impact
}else if(basicImpact){
data= basicImpact
}
if (data == 1) {
//一般项目
return '一般项目20万以下要总经理审批'
} else if (data == 2) {
//重大项目
return '重大项目20万元到500万元之间要总办会审批'
} else if (data == 3) {
//特别重大项目
return '特别重大项目500万元以上要董事会审批'
}
}
const handleReset = () => {
preProcessForm.requestName = ''
getPreProcessList()
}
const handleSelect = async (selection) => {
selectRows.value = selection
}
const handleShowPreTable = () => {
showPreTable.value = true
getPreProcessList()
}
const handleCancel = () => {
showPreTable.value = false
}
const choosePreProcess = () => {
let preProcessObj = {}
let preProcessArray = []
selectRows.value.forEach((item) => {
preProcessObj = {
requestId: item.requestId,
requestName: item.requestName,
baseUrl: item.baseUrl
}
preProcessArray.push(preProcessObj)
})
localFormData.value.preProcess = preProcessArray
showPreTable.value = false
localStorage.setItem('preProcess', JSON.stringify(preProcessArray))
}
const getPreProcessList = () => {
loading.value = true
getPreProcess().then(res => {
loading.value = false
let searchArray = []
let regexPattern = ("%" + preProcessForm.requestName + "%").replace(/%/g, '.*').replace(/_/g, '.');
let regex = new RegExp('^' + regexPattern + '$');
res.data.filter((item) => {
if (regex.test(item.requestName)) {
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)
})
}
//切换每页显示条数
const handleSizeChange = (val) => {
pageInfo.pageSize = val;
preProcessList.value = currentList.value.slice((pageInfo.pageNum - 1) * val, pageInfo.pageNum * val)
};
//点击页码进行分页功能
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)
})
</script>
<style scoped>
.oper {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
</style>
<template>
<div style="display: flex;align-items: center;flex-wrap: wrap;">
<el-button color="#DED0B2" @click="handleShowPreTable" style="margin-right: 10px">
{{
localFormData.preProcess && localFormData.preProcess.length > 0 ? '更改' : '请选择前置流程'
}}
</el-button>
<div v-for="(item,index) in 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>
</div>
<el-dialog v-if="showPreTable" title="前置流程" v-model="showPreTable" width="80%">
<el-form :model="preProcessForm" inline @submit.prevent="getPreProcessList">
<el-form-item label="请求名称">
<el-input v-model="preProcessForm.requestName" placeholder="请输入请求名称" clearable>
</el-input>
</el-form-item>
<el-form-item>
<el-button color="#DED0B2" @click="getPreProcessList">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
<el-form-item>
<el-tag type="danger" style="font-size: 16px;color: red;" >特别提示{{ getPreProcessTag(localFormData.projectImpact,basicData.projectImpact) }}</el-tag>
</el-form-item>
</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"
: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>
<el-table-column prop="lastOperateTime" label="最后操作时间"></el-table-column>
<el-table-column prop="currentNodeName" label="当前节点"></el-table-column>
<el-table-column prop="creatorName" label="创建"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<a :href="scope.row.baseUrl" target="_blank" style="color: #2a99ff;margin-left: 10px">查看流程</a>
</template>
</el-table-column>
</el-table>
<paging :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[10, 20, 30, 40,50]"
:total="total" @changeSize="handleSizeChange" @goPage="handleCurrentChange"/>
<div class="oper">
<el-button color="#DED0B2" @click="choosePreProcess">确定</el-button>
<el-button @click="handleCancel">取消</el-button>
</div>
</el-dialog>
</template>
<script setup>
import {
getPreProcess
} from "@/api/project-manage";
import Paging from "@/components/pagination/index.vue";
const props = defineProps({
formData: {
type: Object,
default: {}
},
basicData: {
type: Object,
default: {}
},
})
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,
preProcess: [
// {
// requestId: null,
// requestName: '',
// baseUrl: ''
// }
]
})
const preProcessForm = reactive({
requestName: ''
})
const pageInfo = reactive({
pageNum: 1,
pageSize: 10,
})
const getPreProcessTag = (impact,basicImpact) => {
let data=''
if(impact){
data= impact
}else if(basicImpact){
data= basicImpact
}
if (data == 1) {
//一般项目
return '研发费用20万元以下科技创新项目报总经理审批'
} else if (data == 2) {
//重大项目
return '重大项目20万元到500万元之间要总办会审批'
} else if (data == 3) {
//特别重大项目
return '特别重大项目500万元以上要董事会审批'
}
}
const handleReset = () => {
preProcessForm.requestName = ''
getPreProcessList()
}
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 = () => {
showPreTable.value = false
}
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) => {
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)
}
})
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 = () => {
loading.value = true
getPreProcess().then(res => {
loading.value = false
let searchArray = []
let regexPattern = ("%" + preProcessForm.requestName + "%").replace(/%/g, '.*').replace(/_/g, '.');
let regex = new RegExp('^' + regexPattern + '$');
res.data.filter((item) => {
if (regex.test(item.requestName)) {
searchArray.push(item)
}
})
total.value = searchArray.length
currentList.value = searchArray
preProcessList.value = currentList.value.slice(0, 10)
})
}
//切换每页显示条数
const handleSizeChange = (val) => {
pageInfo.pageSize = val;
preProcessList.value = currentList.value.slice((pageInfo.pageNum - 1) * val, pageInfo.pageNum * val)
};
//点击页码进行分页功能
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)
})
</script>
<style scoped>
.oper {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
</style>

View File

@@ -1,63 +1,63 @@
<template>
<div class="tag-style">
<el-tag v-if="tagConfig?.isType" :type="tagConfig?.listClass" :effect="tagConfig?.theme || 'plain'">
{{ filterDict(cacheStore.getDict(dictType), value) }}
</el-tag>
<el-tag v-else :color="tagConfig?.listClass" :effect="tagConfig?.theme || 'plain'"
:class="{'null-tag':filterDict(cacheStore.getDict(dictType), value)===undefined}">
{{ filterDict(cacheStore.getDict(dictType), value) }}
</el-tag>
</div>
</template>
<script setup>
import {useCacheStore} from "@/stores/cache.js";
import {defineProps, nextTick} from "vue";
const cacheStore = useCacheStore();
const props = defineProps({
dictType: {
type: String,
default: "",
required: true
},
value: {
type: String || Number,
default: null
}
});
const tagConfig = ref({})
const filterDict = (data, value) => {
if (!data || value == null) return
if (data instanceof Array) {
if (value == true || value == false) {
tagConfig.value = data.find(item => item.value == value.toString())
} else if (typeof value === "object") {
if (value !== null) {
tagConfig.value = data.find(item => item.value == value[0])
} else {
tagConfig.value = {}
}
} else {
tagConfig.value = data.find(item => item.value == value)
}
}
return tagConfig.value?.label || '未知'
}
</script>
<style scoped lang="scss">
.tag-style {
:deep(.el-tag.el-tag--dark) {
border-color: transparent !important;
}
.null-tag {
border-color: transparent;
background-color: transparent;
}
}
</style>
<template>
<div class="tag-style">
<el-tag v-if="tagConfig?.isType" :type="tagConfig?.listClass" :effect="tagConfig?.theme || 'plain'">
{{ filterDict(cacheStore.getDict(dictType), value) }}
</el-tag>
<el-tag v-else :color="tagConfig?.listClass" :effect="tagConfig?.theme || 'plain'"
:class="{'null-tag':filterDict(cacheStore.getDict(dictType), value)===undefined}">
{{ filterDict(cacheStore.getDict(dictType), value) }}
</el-tag>
</div>
</template>
<script setup>
import {useCacheStore} from "@/stores/cache.js";
import {defineProps, nextTick} from "vue";
const cacheStore = useCacheStore();
const props = defineProps({
dictType: {
type: String,
default: "",
required: true
},
value: {
type: String || Number,
default: null
}
});
const tagConfig = ref({})
const filterDict = (data, value) => {
if (!data || value == null) return
if (data instanceof Array) {
if (value == true || value == false) {
tagConfig.value = data.find(item => item.value == value.toString())
} else if (typeof value === "object") {
if (value !== null) {
tagConfig.value = data.find(item => item.value == value[0])
} else {
tagConfig.value = {}
}
} else {
tagConfig.value = data.find(item => item.value == value)
}
}
return tagConfig.value?.label || '未知'
}
</script>
<style scoped lang="scss">
.tag-style {
:deep(.el-tag.el-tag--dark) {
border-color: transparent !important;
}
.null-tag {
border-color: transparent;
background-color: transparent;
}
}
</style>

View File

@@ -1,120 +1,120 @@
<template>
<baseTitle title="标签名称"></baseTitle>
<el-form :model="formData" ref="tagForm" label-width="auto" :rules="rules">
<el-form-item label="标签名称" prop="tagName">
<el-input v-model="formData.tagName" placeholder="请输入标签名称" style="width: 300px" v-if="showInput"/>
<el-select v-model="formData.tagName" placeholder="请选择标签" remote clearable filterable style="width: 300px" v-else>
<el-option
v-for="item in tagsOption"
:key="item.label"
:label="item.value"
:value="item.label"
/>
</el-select>
</el-form-item>
</el-form>
<baseTitle title="其他文件"></baseTitle>
<el-card style="width: 100%;margin: 15px 0">
<file-upload @getFile="getFiles"/>
<fvTable style="width: 100%;max-height: 160px;height: 160px" height="160" v-if="showTable" :tableConfig="tableConfig"
:data="fileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-card>
<div class="oper-page-btn">
<el-button color="#DED0B2" @click="handleSubmit(tagForm)">提交</el-button>
</div>
</template>
<script setup lang="jsx">
const props = defineProps({
tagsOption: {
type: Array,
default: []
}, formData: {
type: Array,
default: []
}, showInput: {
type: Boolean,
default: true
},
})
const rules = reactive({
tagName: [{required: true, message: '请输入标签名称', trigger: ['blur', 'change']}],
})
const tagForm = ref()
const showTable = ref(true)
const emits = defineEmits(['getFile'])
const fileList = ref([])
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'tag',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
currentRender: ({row, index}) => {
return (
<div>
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
</div>
)
}
}
]
})
const compositeParam = (item) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: formData.value.tagName,
}
}
const getFiles = (val) => {
showTable.value = false
let fileObj = compositeParam(val)
// emit("getFile", fileObj)
fileList.value.push(fileObj)
nextTick(() => {
showTable.value = true
})
}
watch(() => fileList.value, (val) => {
fileList.value = val
})
defineExpose({
fileList
})
</script>
<style scoped>
</style>
<template>
<baseTitle title="标签名称"></baseTitle>
<el-form :model="formData" ref="tagForm" label-width="auto" :rules="rules">
<el-form-item label="标签名称" prop="tagName">
<el-input v-model="formData.tagName" placeholder="请输入标签名称" style="width: 300px" v-if="showInput"/>
<el-select v-model="formData.tagName" placeholder="请选择标签" remote clearable filterable style="width: 300px" v-else>
<el-option
v-for="item in tagsOption"
:key="item.label"
:label="item.value"
:value="item.label"
/>
</el-select>
</el-form-item>
</el-form>
<baseTitle title="其他文件"></baseTitle>
<el-card style="width: 100%;margin: 15px 0">
<file-upload @getFile="getFiles"/>
<fvTable style="width: 100%;max-height: 160px;height: 160px" height="160" v-if="showTable" :tableConfig="tableConfig"
:data="fileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-card>
<div class="oper-page-btn">
<el-button color="#DED0B2" @click="handleSubmit(tagForm)">提交</el-button>
</div>
</template>
<script setup lang="jsx">
const props = defineProps({
tagsOption: {
type: Array,
default: []
}, formData: {
type: Array,
default: []
}, showInput: {
type: Boolean,
default: true
},
})
const rules = reactive({
tagName: [{required: true, message: '请输入标签名称', trigger: ['blur', 'change']}],
})
const tagForm = ref()
const showTable = ref(true)
const emits = defineEmits(['getFile'])
const fileList = ref([])
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'tag',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
currentRender: ({row, index}) => {
return (
<div>
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
</div>
)
}
}
]
})
const compositeParam = (item) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: formData.value.tagName,
}
}
const getFiles = (val) => {
showTable.value = false
let fileObj = compositeParam(val)
// emit("getFile", fileObj)
fileList.value.push(fileObj)
nextTick(() => {
showTable.value = true
})
}
watch(() => fileList.value, (val) => {
fileList.value = val
})
defineExpose({
fileList
})
</script>
<style scoped>
</style>

View File

@@ -1,86 +1,86 @@
<script setup>
import WelcomeItem from './WelcomeItem.vue'
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
import CommunityIcon from './icons/IconCommunity.vue'
import SupportIcon from './icons/IconSupport.vue'
</script>
<template>
<WelcomeItem>
<template #icon>
<DocumentationIcon />
</template>
<template #heading>Documentation</template>
Vues
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
provides you with all information you need to get started.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<ToolingIcon />
</template>
<template #heading>Tooling</template>
This project is served and bundled with
<a href="https://vitejs.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
recommended IDE setup is
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a> +
<a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
you need to test your components and web pages, check out
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a> and
<a href="https://on.cypress.io/component" target="_blank">Cypress Component Testing</a>.
<br />
More instructions are available in <code>README.md</code>.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<EcosystemIcon />
</template>
<template #heading>Ecosystem</template>
Get official tools and libraries for your project:
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
you need more resources, we suggest paying
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
a visit.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<CommunityIcon />
</template>
<template #heading>Community</template>
Got stuck? Ask your question on
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>, our official
Discord server, or
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
>StackOverflow</a
>. You should also subscribe to
<a href="https://news.vuejs.org" target="_blank" rel="noopener">our mailing list</a> and follow
the official
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
twitter account for latest news in the Vue world.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<SupportIcon />
</template>
<template #heading>Support Vue</template>
As an independent project, Vue relies on community backing for its sustainability. You can help
us by
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
</WelcomeItem>
</template>
<script setup>
import WelcomeItem from './WelcomeItem.vue'
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
import CommunityIcon from './icons/IconCommunity.vue'
import SupportIcon from './icons/IconSupport.vue'
</script>
<template>
<WelcomeItem>
<template #icon>
<DocumentationIcon />
</template>
<template #heading>Documentation</template>
Vues
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
provides you with all information you need to get started.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<ToolingIcon />
</template>
<template #heading>Tooling</template>
This project is served and bundled with
<a href="https://vitejs.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
recommended IDE setup is
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a> +
<a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
you need to test your components and web pages, check out
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a> and
<a href="https://on.cypress.io/component" target="_blank">Cypress Component Testing</a>.
<br />
More instructions are available in <code>README.md</code>.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<EcosystemIcon />
</template>
<template #heading>Ecosystem</template>
Get official tools and libraries for your project:
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
you need more resources, we suggest paying
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
a visit.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<CommunityIcon />
</template>
<template #heading>Community</template>
Got stuck? Ask your question on
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>, our official
Discord server, or
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
>StackOverflow</a
>. You should also subscribe to
<a href="https://news.vuejs.org" target="_blank" rel="noopener">our mailing list</a> and follow
the official
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
twitter account for latest news in the Vue world.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<SupportIcon />
</template>
<template #heading>Support Vue</template>
As an independent project, Vue relies on community backing for its sustainability. You can help
us by
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
</WelcomeItem>
</template>

View File

@@ -1,277 +1,286 @@
<template>
<div class="tinymce-boxz" style="width: 100%">
<Editor v-model="content" :init="init"/>
</div>
</template>
<script setup>
import tinymce from 'tinymce'
import Editor from "@tinymce/tinymce-vue";
import {defineProps} from "vue";
import {ElLoading, ElMessage, ElNotification} from "element-plus";
import {getToken} from '@/utils/auth'
import axios from "axios";
import 'tinymce/themes/silver'
import 'tinymce/icons/default/icons'
import 'tinymce/plugins/preview'
import 'tinymce/plugins/searchreplace'
import 'tinymce/plugins/autolink'
import 'tinymce/plugins/directionality'
import 'tinymce/plugins/visualblocks'
import 'tinymce/plugins/visualchars'
import 'tinymce/plugins/advlist'
import 'tinymce/plugins/fullscreen'
import 'tinymce/plugins/image'
import 'tinymce/plugins/link'
import 'tinymce/plugins/media'
import 'tinymce/plugins/template'
import 'tinymce/plugins/code'
import 'tinymce/plugins/codesample'
import 'tinymce/plugins/table'
import 'tinymce/plugins/pagebreak'
import 'tinymce/plugins/nonbreaking'
import 'tinymce/plugins/anchor'
import 'tinymce/plugins/insertdatetime'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/wordcount'
import 'tinymce/plugins/autosave'
import '@/assets/axupimgs/plugin.js'//多图上传插件
const emit = defineEmits(['update:value'])
const props = defineProps({
//默认值
value: {
type: String,
default: "",
},
imageUrl: {
type: String,
default: "",
},
fileUrl: {
type: String,
default: "",
},
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: {
type: [String, Array],
default: [
"fullscreen undo redo | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link anchor | alignleft aligncenter alignright alignjustify outdent indent | bullist numlist | blockquote subscript superscript removeformat ",
"styleselect formatselect fontselect fontsizeselect | table image axupimgs media pagebreak insertdatetime selectall visualblocks searchreplace | code preview | indent2em lineheight formatpainter",
],
},
fontFormats: {
type: [String, Array],
default: "微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;"
},
width: {
type: String,
default: 'auto'
},
height: {
type: Number,
default: 500
}
})
const content = ref(props.value);
const imgUrl = ref();
// const apiKey = reactive("v4zo4n22oanvco29ws5drh0pecuf3gh53clx53cccj3grjwg");
const init = reactive({
language_url: '/langs/zh_CN.js', //汉化路径是自定义的
skin_url: '/skins/ui/oxide', //皮肤
content_css: '/skins/content/default/content.css',
language: 'zh_CN',
placeholder: "在这里输入文字", //textarea中的提示信息
min_width: 300,
min_height: 200,
width: props.width,
height: props.height, //注引入autoresize插件时此属性失效
resize: "both", //编辑器宽高是否可变false-否,true-高可变,'both'-宽高均可,注意引号
promotion: false,
branding: false, //tiny技术支持信息是否显示
statusbar: false, //最下方的元素路径和字数统计那一栏是否显示
elementpath: false, //元素路径是否显示
font_formats: props.fontFormats, //字体样式
plugins: props.plugins, //插件配置 axupimgs indent2em
toolbar: props.toolbar, //工具栏配置设为false则隐藏
menubar: "file edit view format table tools", //菜单栏配置设为false则隐藏不配置则默认显示全部菜单也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”
images_upload_url: '/workflow/process/file/upload', //后端处理程序的url建议直接自定义上传函数image_upload_handler这个就可以不用了
// images_upload_base_path: '/demo', //相对基本路径--关于图片上传建议查看--http://tinymce.ax-z.cn/general/upload-images.php
paste_data_images: true, //图片是否可粘贴
file_picker_types: "file image", //file image media分别对应三个类型文件的上传link插件image和axupimgs插件media插件。想屏蔽某个插件的上传就去掉对应的参数
// 文件上传处理函数
setup: function (editor) {
editor.on('change', function (e) {
tinymce.activeEditor.save();//执行自动保存
});
},
//此处为图片上传处理函数
images_upload_handler: (blobInfo, success) => {
// new Promise((resolve, reject) => {
let formData = new FormData()
formData.append('file', blobInfo.blob())
//上传图片接口 上传成功后返回图片地址,用于显示在富文本中
uploadFile(formData, props.imageUrl, success, true)
// }),
},
images_upload_handler_not_loading: (blobInfo, success) => {
let formData = new FormData()
formData.append('file', blobInfo.blob())
//上传图片接口
uploadFile(formData, props.imageUrl, success, false)
},
file_picker_callback: (callback, value, meta) => {
// 使用案例http://tinymce.ax-z.cn/general/upload-images.php
// meta.filetype //根据这个判断点击的是什么file image media
let filetype; //限制文件的上传类型,需要什么就添加什么的后缀
if (meta.filetype == "image") {
filetype = ".jpg, .jpeg, .png, .gif, .ico, .svg";
} else if (meta.filetype == "media") {
filetype = ".mp3, .mp4, .avi, .mov";
} else {
filetype =
".pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4, .jpg, .jpeg, .png, .gif, .ico, .svg";
}
let inputElem = document.createElement("input"); //创建文件选择
inputElem.setAttribute("type", "file");
inputElem.setAttribute("accept", filetype);
inputElem.click();
inputElem.onchange = () => {
let file = inputElem.files[0]; //获取文件信息
let xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', import.meta.env.VITE_BASE_URL + props.imageUrl);
xhr.setRequestHeader(
'Authorization', getToken()
)
let loading = ElLoading.service({
lock: true,
text: '文件上传中...',
background: 'rgba(0, 0, 0, 0.7)',
})
xhr.onload = function () {
let res;
// if (xhr.status != 200) {
// failure('HTTP Error: ' + xhr.status);
// return;
// }
res = JSON.parse(xhr.responseText);
ElNotification({
title: '提示',
message: res.code === 1000 ? '上传成功' : '上传失败',
type: res.code === 1000 ? 'success' : 'error'
})
loading.close()
const fileUrl = res.data.url;
// '?fileId='+res.data.id+
callback(fileUrl + '?fileName=' + res.data.originalFilename, {text: file.name, title: file.name});
};
formData = new FormData();
formData.append('file', file, file.name);
xhr.send(formData);
//
// let reader = new FileReader();
// reader.readAsDataURL(file);
// reader.onload = function () {
// let formData;
// let id = "blobid" + new Date().getTime();
// let blobCache = tinymce.activeEditor.editorUpload.blobCache;
// let base64 = reader.result.split(",")[1];
// let blobInfo = blobCache.create(id, file, base64);
// blobCache.add(blobInfo);
// // callback(blobInfo.blobUri(), {alt: file.name});
// formData = new FormData();
// formData.append('file', file, file.name );
// uploadFile(formData, props.imageUrl,callback)
// };
};
},
});
//内容有变化,就更新内容,将值返回给父组件
watch(() => {
emit("update:value", content.value);
});
const uploadFile = (formData, url, success, isLoading) => {
let loading = null
if (isLoading) {
loading = ElLoading.service({
lock: true,
text: '图片上传中...',
background: 'rgba(0, 0, 0, 0.7)',
})
}
axios.post(
import.meta.env.VITE_BASE_URL + url,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
Authorization: getToken()
}
}
).then(res => {
// if (res.status !== 200) {
// ElMessage.error("上传失败!")
// }
let data = res.data
if (data.code !== 1000) {
ElMessage.error(data.msg)
if (loading) {
loading.close()
}
} else {
if (isLoading) {
success(data.data.url)
} else {
success(data.data.url, data.data.originalFilename)
}
if (loading) {
loading.close()
}
}
})
}
</script>
<style scoped lang="scss">
.tox-sidebar-wrap {
&::-webkit-scrollbar {
width: 6px;
}
// 滚动条轨道
&::-webkit-scrollbar-track {
background: rgb(239, 239, 239);
border-radius: 2px;
}
// 小滑块
&::-webkit-scrollbar-thumb {
background: rgba(80, 81, 82, 0.29);
border-radius: 10px;
}
}
.tinymce-boxz > textarea {
display: none;
}
</style>
<style lang="scss">
/* 隐藏apikey没有绑定当前域名的提示 */
.tox-notifications-container .tox-notification--warning {
display: none !important;
}
.tox.tox-tinymce {
max-width: 100%;
}
</style>
<template>
<div class="tinymce-boxz" style="width: 100%">
<Editor v-model="content" :init="init"/>
</div>
</template>
<script setup>
import tinymce from 'tinymce'
import Editor from "@tinymce/tinymce-vue";
import {defineProps} from "vue";
import {ElLoading, ElMessage, ElNotification} from "element-plus";
import {getToken} from '@/utils/auth'
import axios from "axios";
import 'tinymce/themes/silver'
import 'tinymce/icons/default/icons'
import 'tinymce/plugins/preview'
import 'tinymce/plugins/searchreplace'
import 'tinymce/plugins/autolink'
import 'tinymce/plugins/directionality'
import 'tinymce/plugins/visualblocks'
import 'tinymce/plugins/visualchars'
import 'tinymce/plugins/advlist'
import 'tinymce/plugins/fullscreen'
import 'tinymce/plugins/image'
import 'tinymce/plugins/link'
import 'tinymce/plugins/media'
import 'tinymce/plugins/template'
import 'tinymce/plugins/code'
import 'tinymce/plugins/codesample'
import 'tinymce/plugins/table'
import 'tinymce/plugins/pagebreak'
import 'tinymce/plugins/nonbreaking'
import 'tinymce/plugins/anchor'
import 'tinymce/plugins/insertdatetime'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/wordcount'
import 'tinymce/plugins/autosave'
import '@/assets/axupimgs/plugin.js'//多图上传插件
const emit = defineEmits(['update:value','getFiles'])
const props = defineProps({
//默认值
value: {
type: String,
default: "",
},
imageUrl: {
type: String,
default: "",
},
fileUrl: {
type: String,
default: "",
},
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: {
type: [String, Array],
default: [
"fullscreen undo redo | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link anchor | alignleft aligncenter alignright alignjustify outdent indent | bullist numlist | blockquote subscript superscript removeformat ",
"styleselect formatselect fontselect fontsizeselect | table image axupimgs media pagebreak insertdatetime selectall visualblocks searchreplace | code preview | indent2em lineheight formatpainter",
],
},
fontFormats: {
type: [String, Array],
default: "微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;"
},
width: {
type: String,
default: 'auto'
},
height: {
type: Number,
default: 500
}
})
const fileLists=ref([])
const content = ref(props.value);
const imgUrl = ref();
// const apiKey = reactive("v4zo4n22oanvco29ws5drh0pecuf3gh53clx53cccj3grjwg");
const init = reactive({
language_url: '/langs/zh_CN.js', //汉化路径是自定义的
skin_url: '/skins/ui/oxide', //皮肤
content_css: '/skins/content/default/content.css',
language: 'zh_CN',
placeholder: "在这里输入文字", //textarea中的提示信息
min_width: 300,
min_height: 200,
width: props.width,
height: props.height, //注引入autoresize插件时此属性失效
resize: "both", //编辑器宽高是否可变false-否,true-高可变,'both'-宽高均可,注意引号
promotion: false,
branding: false, //tiny技术支持信息是否显示
statusbar: false, //最下方的元素路径和字数统计那一栏是否显示
elementpath: false, //元素路径是否显示
font_formats: props.fontFormats, //字体样式
plugins: props.plugins, //插件配置 axupimgs indent2em
toolbar: props.toolbar, //工具栏配置设为false则隐藏
menubar: "file edit view format table tools", //菜单栏配置设为false则隐藏不配置则默认显示全部菜单也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”
images_upload_url: '/workflow/process/file/upload', //后端处理程序的url建议直接自定义上传函数image_upload_handler这个就可以不用了
// images_upload_base_path: '/demo', //相对基本路径--关于图片上传建议查看--http://tinymce.ax-z.cn/general/upload-images.php
paste_data_images: true, //图片是否可粘贴
file_picker_types: "file image", //file image media分别对应三个类型文件的上传link插件image和axupimgs插件media插件。想屏蔽某个插件的上传就去掉对应的参数
// 文件上传处理函数
setup: function (editor) {
editor.on('change', function (e) {
tinymce.activeEditor.save();//执行自动保存
});
},
//此处为图片上传处理函数
images_upload_handler: (blobInfo, success) => {
// new Promise((resolve, reject) => {
let formData = new FormData()
formData.append('file', blobInfo.blob())
//上传图片接口 上传成功后返回图片地址,用于显示在富文本中
uploadFile(formData, props.imageUrl, success, true)
// }),
},
images_upload_handler_not_loading: (blobInfo, success) => {
let formData = new FormData()
formData.append('file', blobInfo.blob())
//上传图片接口
uploadFile(formData, props.imageUrl, success, false)
},
file_picker_callback: (callback, value, meta) => {
// 使用案例http://tinymce.ax-z.cn/general/upload-images.php
// meta.filetype //根据这个判断点击的是什么file image media
let filetype; //限制文件的上传类型,需要什么就添加什么的后缀
if (meta.filetype == "image") {
filetype = ".jpg, .jpeg, .png, .gif, .ico, .svg";
} else if (meta.filetype == "media") {
filetype = ".mp3, .mp4, .avi, .mov";
} else {
filetype =
".pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4, .jpg, .jpeg, .png, .gif, .ico, .svg";
}
let inputElem = document.createElement("input"); //创建文件选择
inputElem.setAttribute("type", "file");
inputElem.setAttribute("accept", filetype);
inputElem.click();
inputElem.onchange = () => {
let file = inputElem.files[0]; //获取文件信息
let xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', import.meta.env.VITE_BASE_URL + props.imageUrl);
xhr.setRequestHeader(
'Authorization', getToken()
)
let loading = ElLoading.service({
lock: true,
text: '文件上传中...',
background: 'rgba(0, 0, 0, 0.7)',
})
xhr.onload = function () {
let res;
// if (xhr.status != 200) {
// failure('HTTP Error: ' + xhr.status);
// return;
// }
res = JSON.parse(xhr.responseText);
ElNotification({
title: '提示',
message: res.code === 1000 ? '上传成功' : '上传失败',
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});
};
formData = new FormData();
formData.append('file', file, file.name);
xhr.send(formData);
//
// let reader = new FileReader();
// reader.readAsDataURL(file);
// reader.onload = function () {
// let formData;
// let id = "blobid" + new Date().getTime();
// let blobCache = tinymce.activeEditor.editorUpload.blobCache;
// let base64 = reader.result.split(",")[1];
// let blobInfo = blobCache.create(id, file, base64);
// blobCache.add(blobInfo);
// // callback(blobInfo.blobUri(), {alt: file.name});
// formData = new FormData();
// formData.append('file', file, file.name );
// uploadFile(formData, props.imageUrl,callback)
// };
};
},
});
//内容有变化,就更新内容,将值返回给父组件
watch(() => {
emit("update:value", content.value);
});
const uploadFile = (formData, url, success, isLoading) => {
let loading = null
if (isLoading) {
loading = ElLoading.service({
lock: true,
text: '图片上传中...',
background: 'rgba(0, 0, 0, 0.7)',
})
}
axios.post(
import.meta.env.VITE_BASE_URL + url,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
Authorization: getToken()
}
}
).then(res => {
// if (res.status !== 200) {
// ElMessage.error("上传失败!")
// }
let data = res.data
if (data.code !== 1000) {
ElMessage.error(data.msg)
if (loading) {
loading.close()
}
} else {
if (isLoading) {
success(data.data.url)
} else {
success(data.data.url, data.data.originalFilename)
}
if (loading) {
loading.close()
}
}
})
}
</script>
<style scoped lang="scss">
.tox-sidebar-wrap {
&::-webkit-scrollbar {
width: 6px;
}
// 滚动条轨道
&::-webkit-scrollbar-track {
background: rgb(239, 239, 239);
border-radius: 2px;
}
// 小滑块
&::-webkit-scrollbar-thumb {
background: rgba(80, 81, 82, 0.29);
border-radius: 10px;
}
}
.tinymce-boxz > textarea {
display: none;
}
</style>
<style lang="scss">
/* 隐藏apikey没有绑定当前域名的提示 */
.tox-notifications-container .tox-notification--warning {
display: none !important;
}
.tox.tox-tinymce {
max-width: 100%;
}
</style>

View File

@@ -1,63 +1,63 @@
<template>
<el-tooltip
effect="dark"
:content="props.content"
placement="bottom-start"
:disabled="isShow"
>
<div :class="lines?'content-lines':textAlign=='left'?'left-content':'content'" :style="{width: props.width+'px'}" @mouseover="isShowTooltip">
<span ref="contentRef">
<slot name="content">{{ props.content }}</slot>
</span>
</div>
</el-tooltip>
</template>
<script setup>
const props = defineProps({
content: {
type: String,
default: ''
},
width: {
type: String,
default: '100%'
},
lines: {
type: Boolean,
default: false
},
textAlign: {
type: String,
default: ''
},
})
const contentRef = ref()
const isShow = ref(false)
const isShowTooltip = () => {
isShow.value = parseInt(props.width) > contentRef.value.offsetWidth;
}
</script>
<style scoped>
.left-content{
width: 45px;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.content {
width: 45px;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.content-lines{
word-break:break-all;
overflow:hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
}
</style>
<template>
<el-tooltip
effect="dark"
:content="props.content"
placement="bottom-start"
:disabled="isShow"
>
<div :class="lines?'content-lines':textAlign=='left'?'left-content':'content'" :style="{width: props.width+'px'}" @mouseover="isShowTooltip">
<span ref="contentRef">
<slot name="content">{{ props.content }}</slot>
</span>
</div>
</el-tooltip>
</template>
<script setup>
const props = defineProps({
content: {
type: String,
default: ''
},
width: {
type: String,
default: '100%'
},
lines: {
type: Boolean,
default: false
},
textAlign: {
type: String,
default: ''
},
})
const contentRef = ref()
const isShow = ref(false)
const isShowTooltip = () => {
isShow.value = parseInt(props.width) > contentRef.value.offsetWidth;
}
</script>
<style scoped>
.left-content{
width: 45px;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.content {
width: 45px;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.content-lines{
word-break:break-all;
overflow:hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
}
</style>

View File

@@ -1,85 +1,85 @@
<template>
<div class="item">
<i>
<slot name="icon"></slot>
</i>
<div class="details">
<h3>
<slot name="heading"></slot>
</h3>
<slot></slot>
</div>
</div>
</template>
<style scoped>
.item {
margin-top: 2rem;
display: flex;
}
.details {
flex: 1;
margin-left: 1rem;
}
i {
display: flex;
place-items: center;
place-content: center;
width: 32px;
height: 32px;
color: var(--color-text);
}
h3 {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 0.4rem;
color: var(--color-heading);
}
@media (min-width: 1024px) {
.item {
margin-top: 0;
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
}
i {
top: calc(50% - 25px);
left: -26px;
position: absolute;
border: 1px solid var(--color-border);
background: var(--color-background);
border-radius: 8px;
width: 50px;
height: 50px;
}
.item:before {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
bottom: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:after {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
top: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:first-of-type:before {
display: none;
}
.item:last-of-type:after {
display: none;
}
}
</style>
<template>
<div class="item">
<i>
<slot name="icon"></slot>
</i>
<div class="details">
<h3>
<slot name="heading"></slot>
</h3>
<slot></slot>
</div>
</div>
</template>
<style scoped>
.item {
margin-top: 2rem;
display: flex;
}
.details {
flex: 1;
margin-left: 1rem;
}
i {
display: flex;
place-items: center;
place-content: center;
width: 32px;
height: 32px;
color: var(--color-text);
}
h3 {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 0.4rem;
color: var(--color-heading);
}
@media (min-width: 1024px) {
.item {
margin-top: 0;
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
}
i {
top: calc(50% - 25px);
left: -26px;
position: absolute;
border: 1px solid var(--color-border);
background: var(--color-background);
border-radius: 8px;
width: 50px;
height: 50px;
}
.item:before {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
bottom: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:after {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
top: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:first-of-type:before {
display: none;
}
.item:last-of-type:after {
display: none;
}
}
</style>

View File

@@ -1,33 +1,33 @@
<template>
<div class="base-title">
<span></span>
<span>{{ title }}</span>
</div>
</template>
<script setup>
const props = defineProps({
title: {
type: String,
default: ''
}
})
</script>
<style lang="scss" scoped>
.base-title {
display: flex;
justify-content: flex-start;
align-items: center;
margin: 15px 0;
font-weight: bold;
>span:first-child {
display: inline-block;
width: 10px;
height: 20px;
background: #BEA266;
margin-right: 5px;
}
}
<template>
<div class="base-title">
<span></span>
<span>{{ title }}</span>
</div>
</template>
<script setup>
const props = defineProps({
title: {
type: String,
default: ''
}
})
</script>
<style lang="scss" scoped>
.base-title {
display: flex;
justify-content: flex-start;
align-items: center;
margin: 15px 0;
font-weight: bold;
>span:first-child {
display: inline-block;
width: 10px;
height: 20px;
background: #BEA266;
margin-right: 5px;
}
}
</style>

View File

@@ -1,69 +1,69 @@
<template>
<codemirror
v-model="javaCode"
:placeholder="editorPlaceholder"
:style="{ height: editorHeight+'px' }"
:autofocus="true"
:indent-with-tab="true"
:tabSize="tabSize"
:extensions="extensions"
:scrollbarStyle="null"
/>
</template>
<script setup>
import {Codemirror} from "vue-codemirror";
import {java, javaLanguage} from "@codemirror/lang-java";
const emit = defineEmits()
const props = defineProps({
value: {
type: String,
default: "",
},
editorPlaceholder: {
type: String,
default: "请输入代码",
},
editorHeight: {
type: String,
default: "300",
},
tabSize: {
type: Number,
default: 2,
}
})
const _value = computed({
get() {
return props.value || ""
},
set(value) {
emit('update:value', value)
}
})
const javaCode = ref();
const customJavaCodeTips = (context) => {
let word = context.matchBefore(/\w*/)
if (word.from == word.to && !context.explicit) return null;
return {
from: word.from?word.from:context.pos,
options: [
{label: "function", type: "keyword",apply:"function name(params) {\n\t\n}",detail: "definition"},
// {label: "hello", type: "variable", info: "(World)"},
{label: "fori", type: "keyword",apply:"for (let i = 0; i < list.length; i++) {\n\n}", detail: "loop"},
{label: "for", type: "keyword",apply:"for (let name of list) {\n\n}", detail: "of loop"},
{label: "psf", type: "keyword",apply:"public static final ", detail: "public static final"},
{label: "psv", type: "keyword",apply:"public static void name(){\n\n}", detail: "public static void"},
{label: "psfi", type: "keyword",apply:"public static final int ", detail: "public static final int"},
{label: "psfs", type: "keyword",apply:"public static final String ", detail: "public static final String"},
{label: "psvm", type: "keyword", apply: "public static void main(String[] args){\n\t\n}", detail: "main() 方法声明"}
]
}
}
const javaSnippets = javaLanguage.data.of({
autocomplete: customJavaCodeTips,
})
const extensions = ref([java(), javaSnippets]);
</script>
<template>
<codemirror
v-model="javaCode"
:placeholder="editorPlaceholder"
:style="{ height: editorHeight+'px' }"
:autofocus="true"
:indent-with-tab="true"
:tabSize="tabSize"
:extensions="extensions"
:scrollbarStyle="null"
/>
</template>
<script setup>
import {Codemirror} from "vue-codemirror";
import {java, javaLanguage} from "@codemirror/lang-java";
const emit = defineEmits()
const props = defineProps({
value: {
type: String,
default: "",
},
editorPlaceholder: {
type: String,
default: "请输入代码",
},
editorHeight: {
type: String,
default: "300",
},
tabSize: {
type: Number,
default: 2,
}
})
const _value = computed({
get() {
return props.value || ""
},
set(value) {
emit('update:value', value)
}
})
const javaCode = ref();
const customJavaCodeTips = (context) => {
let word = context.matchBefore(/\w*/)
if (word.from == word.to && !context.explicit) return null;
return {
from: word.from?word.from:context.pos,
options: [
{label: "function", type: "keyword",apply:"function name(params) {\n\t\n}",detail: "definition"},
// {label: "hello", type: "variable", info: "(World)"},
{label: "fori", type: "keyword",apply:"for (let i = 0; i < list.length; i++) {\n\n}", detail: "loop"},
{label: "for", type: "keyword",apply:"for (let name of list) {\n\n}", detail: "of loop"},
{label: "psf", type: "keyword",apply:"public static final ", detail: "public static final"},
{label: "psv", type: "keyword",apply:"public static void name(){\n\n}", detail: "public static void"},
{label: "psfi", type: "keyword",apply:"public static final int ", detail: "public static final int"},
{label: "psfs", type: "keyword",apply:"public static final String ", detail: "public static final String"},
{label: "psvm", type: "keyword", apply: "public static void main(String[] args){\n\t\n}", detail: "main() 方法声明"}
]
}
}
const javaSnippets = javaLanguage.data.of({
autocomplete: customJavaCodeTips,
})
const extensions = ref([java(), javaSnippets]);
</script>

Some files were not shown because too many files have changed in this diff Show More