Compare commits

..

350 Commits

Author SHA1 Message Date
zt
3b580788f1 Merge remote-tracking branch 'origin/updateMenu' into updateMenu 2025-12-12 18:16:20 +08:00
zt
7b6ff3bcc6 优化 2025-12-12 18:16:05 +08:00
zzz
8e5303838e 派单 2025-12-12 18:14:57 +08:00
28f92b6138 增值税发票excel导入 2025-12-12 18:10:42 +08:00
lcj
8ece9617d6 修改 bug 2025-12-12 17:46:35 +08:00
lcj
a5cf647f2b 修改bug 2025-12-12 17:12:04 +08:00
zzz
758e49973b 修改标后分析 2025-12-12 15:58:01 +08:00
zzz
876f8b700d 修改标后分析 2025-12-12 15:48:36 +08:00
zzz
53b777c7af 修改实用工具的模糊查询 2025-12-12 15:02:19 +08:00
5e749f6de6 新中大项目创建时添加建管项目修改 2025-12-12 14:54:35 +08:00
dcd0907cdd 12-12-修改收开票搜索条件 2025-12-12 11:58:04 +08:00
3f16621313 12-12-搭配角色流程列表修改 2025-12-12 11:28:02 +08:00
lcj
03b3c8141a 项目详情 2025-12-12 11:26:35 +08:00
zzz
509683386f 修改机械合同 2025-12-12 11:24:17 +08:00
e3b6c3d8d6 总体计划成本接口修改 2025-12-12 11:15:52 +08:00
29cdd7b3e7 总体计划成本接口修改 2025-12-12 10:40:47 +08:00
zzz
ee864c882a 修改税率 2025-12-12 10:08:30 +08:00
10e449c001 阶段成本分解接口修改 2025-12-12 09:41:22 +08:00
89d60dc528 阶段成本分解接口修改 2025-12-11 22:13:34 +08:00
zt
ce35086316 优化 2025-12-11 20:29:29 +08:00
e7376086f9 将供应商由建管转到新中大供应商,总体计划成本接口修改 2025-12-11 20:28:31 +08:00
zzz
4588f3f4c0 标后分析自动生成项目 2025-12-11 20:15:55 +08:00
lcj
97898aa395 修改权限 2025-12-11 18:56:57 +08:00
lcj
b4a7c6ba90 修改权限 2025-12-11 17:25:06 +08:00
4d6a225f96 12-11-权限修改,排除SuperAdmin 2025-12-11 16:38:31 +08:00
zzz
6d9b5a727d query权限去除 2025-12-11 11:42:25 +08:00
a79e08f6bc 12-11-大屏接口权限修改 2025-12-11 10:11:38 +08:00
lcj
e49ab63a0b 关联项目 2025-12-11 08:52:58 +08:00
lcj
2b3c86e763 Merge remote-tracking branch 'gitea/dev' into updateMenu 2025-12-10 19:02:01 +08:00
zt
1263b4812d 个人首页 2025-12-10 18:58:29 +08:00
lcj
755969b069 Merge branch 'dev' into updateMenu 2025-12-10 18:49:14 +08:00
lcj
dbe8556741 关联项目 2025-12-10 18:48:18 +08:00
lcj
b10e7b4ca1 修改配置 2025-12-10 17:18:03 +08:00
zt
844b3addf3 Merge remote-tracking branch 'origin/dev' into dev 2025-12-10 17:16:23 +08:00
zt
77532caf47 退出班组 2025-12-10 17:15:59 +08:00
lcj
ff9cc76ebc Merge remote-tracking branch 'gitea/updateMenu' into updateMenu 2025-12-10 15:59:50 +08:00
lcj
d125510267 Merge branch 'dev' into updateMenu 2025-12-10 15:56:18 +08:00
lcj
46ac312ddf 创建新项目 2025-12-10 15:53:31 +08:00
c45d98856e 12-10-修改事故 2025-12-10 15:52:05 +08:00
lcj
f2c0932e2e 修改bug 2025-12-10 10:58:25 +08:00
zt
b8334c7764 优化 2025-12-10 10:14:08 +08:00
c709e04c88 标前管理人员任命添加审核状态 2025-12-09 19:31:55 +08:00
509fc8cc28 标前管理-风险信息,人员任命修改 2025-12-09 18:59:18 +08:00
48338278f0 安全事故bug修改和意见箱bug修改 2025-12-09 18:50:20 +08:00
833ea7af7d 标前管理-风险信息,人员任命 2025-12-09 14:33:49 +08:00
f5cea23daa 安全事故接口优化 2025-12-09 09:06:35 +08:00
zt
a29c9c8d4d 优化 2025-12-08 19:57:28 +08:00
511bf33914 12-05-事故管理-事故上报、事故调查-修改-修改部门 2025-12-08 19:36:59 +08:00
4450f82717 12-05-事故管理-事故上报、事故调查-修改 2025-12-08 19:28:29 +08:00
lcj
f62c542684 项目对接 2025-12-08 19:10:04 +08:00
bb8c951651 安全事故接口优化 2025-12-08 18:51:31 +08:00
9f5b3918d0 12-05-事故管理-事故上报、事故调查 2025-12-08 18:48:53 +08:00
zrl
84d9291763 安全技术交底,监控修改 2025-12-08 15:52:24 +08:00
fcbc5a30c4 12-05-事故管理-事故上报、事故调查 2025-12-08 15:26:13 +08:00
zt
6f4eb21deb 危大 2025-12-08 10:43:09 +08:00
387a7488ab Merge branch 'dev' into updateMenu 2025-12-08 10:39:50 +08:00
lg
6819eb5f80 危大工程-技术交底,过程监控 2025-12-06 19:31:19 +08:00
lg
0f1ad34342 危大工程-技术交底,过程监控 2025-12-06 19:07:28 +08:00
zt
35d1cfc668 危大 2025-12-06 18:39:35 +08:00
zt
a6dc40760d 危大 2025-12-06 14:22:07 +08:00
2486bb4c6e 12-05-事故管理-事故上报 2025-12-05 20:47:10 +08:00
a59a452f89 Merge remote-tracking branch 'origin/dev' into dev 2025-12-05 20:10:20 +08:00
930bff6cba 安全事故初始化 2025-12-05 20:10:13 +08:00
lcj
70c9997c82 接入消息队列,处理延迟消息 2025-12-05 19:53:34 +08:00
lg
0db70d3d73 机械安全模块修改 2025-12-05 18:54:36 +08:00
zt
2884699ff2 bug 2025-12-05 18:53:33 +08:00
lcj
849eb802bc 隐患整改 2025-12-05 18:52:52 +08:00
4ce8ea6a3a 安全事故初始化 2025-12-05 16:59:41 +08:00
7e1db73fb0 意见箱修改 2025-12-05 16:45:22 +08:00
lcj
46299e5732 隐患整改 2025-12-05 14:24:17 +08:00
zt
6032869417 奖惩 2025-12-05 14:16:46 +08:00
lg
955d7e39e6 机械安全模块修改 2025-12-05 09:28:05 +08:00
lcj
ecc0595ec3 施工产值,隐患整改 2025-12-05 08:58:40 +08:00
6b22ed8b0a Merge remote-tracking branch 'origin/dev' into dev 2025-12-04 20:21:34 +08:00
9b7db3214e 12-04-人员定位-终版-优化版之修复版 2025-12-04 20:21:24 +08:00
zt
71b3c77028 奖惩 2025-12-04 20:08:53 +08:00
zt
c7bd709240 奖惩 2025-12-04 19:18:49 +08:00
lg
a80c38f87f 机械安全模块 2025-12-04 18:15:49 +08:00
7b91443532 Merge remote-tracking branch 'origin/dev' into dev 2025-12-04 16:27:29 +08:00
lcj
a9b9e12732 修改bug 2025-12-04 15:55:31 +08:00
99ecb29f3c 12-04-人员定位-终版-优化版 2025-12-04 15:39:06 +08:00
lg
4fe7a435c6 机械安全模块 2025-12-04 15:27:35 +08:00
zt
18be0f00a3 奖惩 2025-12-04 15:21:29 +08:00
67bbf94359 12-04-收票登记修改 2025-12-04 15:12:56 +08:00
lg
9dfea176b3 Merge remote-tracking branch 'origin/dev' into dev 2025-12-04 15:11:59 +08:00
lcj
09d3b06e7a 隐患整改 2025-12-04 15:11:27 +08:00
lg
8b60d13c0a 机械安全模块 2025-12-04 15:10:41 +08:00
188172692b 12-03-人员定位-终版 2025-12-04 14:31:48 +08:00
lcj
556f3b6535 隐患规则 2025-12-04 10:18:26 +08:00
0b81a8dc63 Merge remote-tracking branch 'origin/dev' into dev 2025-12-03 22:23:20 +08:00
982ec18490 12-03-人员定位-再版 2025-12-03 22:23:12 +08:00
0c38c42bfe 摄像头回放 2025-12-03 20:28:58 +08:00
zt
2f0b323680 顺序 2025-12-03 20:18:34 +08:00
zt
35d2a10c0e 顺序 2025-12-03 20:09:19 +08:00
zt
9c7f9ad980 隐患 2025-12-03 19:54:45 +08:00
79a2dbfcd3 12-03-人员定位-初版 2025-12-03 18:57:00 +08:00
lg
b5b7324f7c 模块添加 2025-12-03 17:14:31 +08:00
zt
b171ec6af0 隐患 2025-12-03 17:01:37 +08:00
lcj
85c7ded162 隐患规则 2025-12-03 17:00:43 +08:00
lcj
b39aa7be71 施工产值 2025-12-03 15:46:28 +08:00
8ae5614ce9 12-03-人员定位-柱状图数据 2025-12-03 09:34:45 +08:00
03cf7ebac7 12-01-人员定位 2025-12-02 21:57:46 +08:00
lg
3efa899a97 机械维护与故障 2025-12-02 19:07:26 +08:00
zt
bf1b9cf98f Merge branch 'refs/heads/dev' into updateMenu 2025-12-02 17:46:42 +08:00
zt
e800ff3ac9 Merge branch 'refs/heads/dev' into updateMenu 2025-12-02 17:44:27 +08:00
lcj
f0802432ed 修改execl导入校验 2025-12-02 17:43:59 +08:00
zt
c96808efc1 bug 2025-12-02 17:42:35 +08:00
zt
e972efb247 设计权限 2025-12-02 16:24:39 +08:00
zt
f782edd68b 设计权限 2025-12-02 16:24:02 +08:00
zt
45702ef838 设备 2025-12-02 16:22:42 +08:00
lcj
4e3faa7a23 进度识别 2025-12-02 16:12:07 +08:00
zt
40559d4d73 设备 2025-12-02 15:59:06 +08:00
zt
7816fec7aa 设备 2025-12-02 15:57:39 +08:00
lcj
37c95ab0bd 施工产值导出,大图 2025-12-02 15:51:44 +08:00
lg
3e38cf9abb 合同显示bug修改 2025-12-02 10:10:50 +08:00
lg
4aaf384ce8 机械 2025-12-01 20:00:39 +08:00
6a06d8596d 意见箱 2025-12-01 19:49:40 +08:00
be89a6fe9e 12-01-修改 2025-12-01 19:28:21 +08:00
40b51e5e9d 12-01-修改 2025-12-01 19:28:10 +08:00
zt
4b14ea5c7f 设备 2025-12-01 17:09:58 +08:00
a44777d7b2 Merge remote-tracking branch 'origin/updateMenu' into updateMenu 2025-11-28 19:55:38 +08:00
492fba5fd3 11-28-详情权限修改 2025-11-28 19:55:29 +08:00
zt
07b921d630 人员迁移 2025-11-28 19:51:41 +08:00
zt
13d33e9d53 token时间 2025-11-28 19:27:41 +08:00
zt
4f38db5fde bug 2025-11-28 18:56:59 +08:00
a868c7b5cb gps功能优化,添加人员轨迹,补充绑定车辆时历史记录返回车辆名称 2025-11-28 17:49:24 +08:00
d37b41c967 11-28-详情权限修改 2025-11-28 16:05:21 +08:00
b8fb9413de 标前立项bug修改 2025-11-28 15:22:39 +08:00
zt
fa9fcb1167 bug 2025-11-28 11:32:35 +08:00
zt
ebd88a999c bug 2025-11-27 19:17:15 +08:00
97079abdef 11-27-修改推荐审批文件操作 2025-11-27 18:56:33 +08:00
zt
94aaa90775 Merge branch 'refs/heads/dev' into updateMenu 2025-11-27 18:47:51 +08:00
lcj
1e01c53c52 大图 2025-11-27 17:41:36 +08:00
6c9e23e662 修改立项及成本权限 2025-11-27 17:37:25 +08:00
zt
8a27da9975 bug 2025-11-27 15:45:07 +08:00
e160cc5ff3 11-27-修改承包合同信息必填 2025-11-27 15:15:32 +08:00
zt
80b5f94cd4 bug 2025-11-27 11:44:03 +08:00
c9c81bb761 11-27-完善开票单位改为部门公司 2025-11-27 11:14:31 +08:00
zt
af90b0f879 产值及人员 2025-11-27 09:26:30 +08:00
lcj
b51a3ccf28 安全员轨迹信息 2025-11-26 19:57:00 +08:00
f07db8c368 车辆管理菜单修改和物资管理菜单修改 2025-11-26 19:18:52 +08:00
5e9d36400c 11-26-承包合同开票单位改为部门公司 2025-11-26 19:01:14 +08:00
zt
8f4a3e167a 产值及人员 2025-11-26 17:18:04 +08:00
lg
3ccd54a03b 权限字符修改 2025-11-26 16:15:03 +08:00
03177f58f2 11-26-更新供应商sql 2025-11-26 15:22:54 +08:00
zt
b0c875c9c4 班组 2025-11-26 10:25:44 +08:00
zt
bfe74bdb4c 去掉人脸 2025-11-25 19:47:16 +08:00
lg
cad5ba1101 权限字符修改 2025-11-25 19:40:59 +08:00
lcj
45d143ace3 进度计划菜单 2025-11-25 19:37:45 +08:00
zt
df08eb3dd6 Merge remote-tracking branch 'origin/dev' into dev 2025-11-25 19:26:22 +08:00
zt
8c292850c2 去掉人脸 2025-11-25 19:26:02 +08:00
12d3924e8a 11-25-更新收票登记 2025-11-25 19:19:52 +08:00
zt
d32947afe2 人员管理 2025-11-25 19:15:12 +08:00
lcj
9eecf67374 无人机大图 2025-11-25 17:30:31 +08:00
zt
d7fd7d6cc4 人员数据 2025-11-25 16:30:16 +08:00
lcj
77482c71b3 安全菜单修改 2025-11-25 16:16:16 +08:00
zt
66893410e9 菜单 2025-11-25 16:05:58 +08:00
fbbc4846de 车辆管理菜单修改和机械台账菜单修改 2025-11-25 14:53:20 +08:00
lcj
aac6efc568 无人机大图压缩包上传 2025-11-25 14:05:27 +08:00
lcj
209e624fc2 无人机大图压缩包上传 2025-11-25 12:31:25 +08:00
lcj
fe79bf282c 无人机大图压缩包上传 2025-11-25 12:29:57 +08:00
lcj
18cbc0655b 安全 2025-11-25 10:47:18 +08:00
6b59d264b4 Merge remote-tracking branch 'origin/dev' into dev 2025-11-25 10:41:17 +08:00
74785a768e 11-25-报销默认只能看见自己 2025-11-25 10:41:08 +08:00
lcj
32aafaa2db 修改bug 2025-11-25 10:05:00 +08:00
lcj
06617d94a7 修改bug 2025-11-25 09:52:25 +08:00
lcj
1b2f9aa755 安全 2025-11-25 09:42:28 +08:00
lg
04407d2f84 权限字符修改 2025-11-24 20:01:26 +08:00
lcj
c0fef2521f 无人机大图合并优化 2025-11-24 19:32:15 +08:00
04430d8853 综合服务合同vo修改 2025-11-24 16:04:26 +08:00
zt
875b436eea 考勤 2025-11-24 15:25:38 +08:00
2c1ca98e4e 菜单表修改 2025-11-24 14:55:49 +08:00
765490b51c 11-24-修复 2025-11-24 14:49:47 +08:00
lcj
b116db0bcd 更换菜单表 2025-11-24 14:28:36 +08:00
e2892b460b 设计合同付款、设计合同收款优化 2025-11-24 11:54:59 +08:00
30b1586a4a 设计合同付款、设计合同收款优化 2025-11-24 11:42:46 +08:00
lcj
15d86526ac 修改bug 2025-11-24 11:37:54 +08:00
cdf5f8bf5b 设计合同付款、设计合同收款优化 2025-11-24 11:37:07 +08:00
9bb41d903e 11-24-修复 2025-11-24 10:22:00 +08:00
d5f1c22bd4 设计合同进度结算、设计合同竣工结算、设计合同付款、设计合同收款的新增、修改、查询、删除 2025-11-21 20:31:45 +08:00
d2dcf656df Merge remote-tracking branch 'origin/dev' into dev 2025-11-21 20:29:30 +08:00
lcj
7191a60841 分包考勤机 2025-11-21 17:07:09 +08:00
3f21d39653 11-21-还原 2025-11-21 16:11:42 +08:00
b520ea6afe 11-21-添加对应方法2 2025-11-21 11:42:17 +08:00
e6283bee1c 11-21-添加对应方法 2025-11-21 11:15:40 +08:00
f6e1d0c73e 11-21-改善 2025-11-21 10:19:13 +08:00
c7e06ade6d Merge remote-tracking branch 'origin/dev' into dev 2025-11-20 20:00:23 +08:00
3d85b10475 11-20-改善 2025-11-20 20:00:03 +08:00
lg
e26dfc098a 竣工日期回填 2025-11-20 19:47:33 +08:00
lcj
c3ab46c8c8 降低springdoc版本 2025-11-20 19:27:17 +08:00
lcj
e37d118d0c 修改bug 2025-11-20 18:29:41 +08:00
lg
a6c92e8ba9 事务添加,删除sql问题 2025-11-20 16:17:19 +08:00
zt
02f324e1d4 sql 2025-11-20 11:15:52 +08:00
96392dbf57 供应商列表查询关联银行修改 2025-11-20 10:48:14 +08:00
lcj
e39e788ddc 优化 2025-11-20 09:21:41 +08:00
e17ab16821 新中大修改人员银行绑定逻辑,修改承包合同、供应商等涉及到银行的地方,添加设计合同的信息、变更、终止的crud 2025-11-19 22:23:06 +08:00
lg
8a928e852d 机械合同名称结算,收付款 2025-11-19 20:06:32 +08:00
zt
397f8ee768 日报 2025-11-19 19:47:14 +08:00
8e25b416ec 11-19-模板初版(完成版) 2025-11-19 19:39:37 +08:00
e6b0527e44 Merge remote-tracking branch 'origin/dev' into dev 2025-11-19 18:50:00 +08:00
lcj
403848cb4b 优化 2025-11-19 17:57:06 +08:00
a4b1820e1c Merge remote-tracking branch 'origin/dev' into dev 2025-11-19 17:31:37 +08:00
zt
c2afe05e81 文档 2025-11-19 17:30:31 +08:00
lcj
1902ba9d59 用户文件批量上传 2025-11-19 17:11:18 +08:00
1d1a0e45c6 11-19-模板初版 2025-11-19 16:46:30 +08:00
lcj
72c775b1e3 进度计划周报数据 2025-11-19 11:25:13 +08:00
zt
bec0848cd9 考勤 2025-11-19 10:48:22 +08:00
4e78886a82 11-19-模板 2025-11-19 09:56:36 +08:00
zt
292a56bccd AI工单 2025-11-18 19:47:31 +08:00
lcj
3f12c15cf8 大图合并图片压缩,考试、人员文件压缩包上传 2025-11-18 19:28:32 +08:00
zt
1ab47ccb57 AI工单 2025-11-18 19:17:08 +08:00
321fc67c4f 新中大添加人员与银行绑定,并且修改报销与银行的绑定逻辑,修改建管添加批次需求计划的招标计划查询接口 2025-11-18 17:20:26 +08:00
lg
b6e8031cef 机械合同名称注解 2025-11-18 17:13:25 +08:00
d7265b08a8 11-18-报销类型权限接口 2025-11-18 16:50:20 +08:00
2f0ad8a8cd Merge remote-tracking branch 'origin/dev' into dev 2025-11-18 16:11:52 +08:00
22c58031d2 11-18-报销类型解绑 2025-11-18 16:11:39 +08:00
lg
473f6943d5 机械合同单据日期搜索 2025-11-18 15:52:04 +08:00
08ef9ccfea 11-18-初版 2025-11-18 15:07:54 +08:00
94b5736241 11-18-初版 2025-11-18 14:25:37 +08:00
lcj
95b4bc85b3 大图合并进度 2025-11-18 09:05:54 +08:00
dfaadd4977 11-18-初版 2025-11-18 02:29:54 +08:00
f372f22934 Merge remote-tracking branch 'origin/dev' into dev 2025-11-18 02:29:43 +08:00
bc91c44596 11-18-初版 2025-11-18 02:24:19 +08:00
480d7be81d 11-18-初版 2025-11-18 02:07:26 +08:00
1c0be9b5ee 添加车辆实时轨迹接口 2025-11-17 20:13:00 +08:00
zt
9c7d8ffc96 日报 2025-11-17 20:10:22 +08:00
167cbf256b 11-17-修改 2025-11-17 19:28:27 +08:00
lcj
c3ce1c22d3 大图合并、进度计划日报 2025-11-17 19:22:17 +08:00
891c205233 Merge remote-tracking branch 'origin/dev' into dev 2025-11-17 19:18:07 +08:00
3b184abc96 11-17-修改 2025-11-17 19:17:59 +08:00
lg
9a20cf0e43 部门树接口 2025-11-17 19:06:52 +08:00
lg
faf434e4d2 组织修改接口 2025-11-17 18:53:13 +08:00
73988b8828 添加车辆实时轨迹接口 2025-11-17 18:45:06 +08:00
lg
0c3b14e010 客户信息 2025-11-17 18:39:45 +08:00
lg
d764fbe473 Merge remote-tracking branch 'origin/dev' into dev 2025-11-17 16:39:36 +08:00
lg
073f704c0e 详情权限 2025-11-17 16:39:15 +08:00
zt
5f64f3aef4 日报 2025-11-17 16:38:59 +08:00
baa492b799 11-17-更改接口及权限 2025-11-17 15:13:09 +08:00
a668381101 添加其他页面调用合同列表详情接口 2025-11-17 14:36:40 +08:00
4f2ac72edc 11-17-更改接口及权限 2025-11-17 10:22:33 +08:00
lcj
b501965d25 大图合并、进度计划导出 2025-11-17 09:08:58 +08:00
lg
57b662837d 分包质保金退还 2025-11-16 18:50:44 +08:00
lg
f11ed11629 分包质保金退还 2025-11-16 18:25:50 +08:00
cdcbfaa1a9 Merge remote-tracking branch 'origin/dev' into dev 2025-11-15 17:42:46 +08:00
ef775a3cfb 11-15-更改接口及权限 2025-11-15 17:42:38 +08:00
lg
818b67b5aa 权限字符修改 2025-11-15 17:34:40 +08:00
lg
a0554e47fd zuyin 2025-11-15 17:21:40 +08:00
lg
49c9ef8878 权限修改 2025-11-15 17:03:33 +08:00
3265a58813 11-15-调整 2025-11-15 09:58:20 +08:00
5a9044786c 11-14-报销银行调整 2025-11-14 20:42:59 +08:00
d8d0828f8e 11-14-承包合同列表权限调整 2025-11-14 20:42:29 +08:00
lg
8bade20502 客户银行添加 2025-11-14 19:55:26 +08:00
be944595e3 添加其他页面调用合同列表接口 2025-11-14 19:53:43 +08:00
1eaf29b282 11-14-更改银行相关 2025-11-14 19:24:17 +08:00
4bb24fe464 Merge remote-tracking branch 'origin/dev' into dev 2025-11-14 15:02:48 +08:00
e704522965 11-14-更改供应商条件 2025-11-14 15:02:41 +08:00
3440b885ee 综合服务合同修改 2025-11-14 12:04:40 +08:00
3e85e79bdd 11-14-修改银行 2025-11-14 11:13:33 +08:00
90b0eb82f4 11-13-修改 2025-11-13 20:49:58 +08:00
ef2c1ff455 Merge remote-tracking branch 'origin/dev' into dev 2025-11-13 20:03:10 +08:00
074fb5bf86 11-13-修改 2025-11-13 20:03:04 +08:00
lg
3f4b127cdf 机械增加单据日期查询 2025-11-13 19:55:52 +08:00
lcj
e93ea2fdfd 进度计划数据处理 2025-11-13 19:34:24 +08:00
cf368db9af 11-13-修改银行相关SQL 2025-11-13 19:27:18 +08:00
034d01d604 11-13-修改银行,增加中间表 2025-11-13 19:01:34 +08:00
zt
af247d917b 修改密码 2025-11-13 17:40:40 +08:00
lg
a51d836dc2 统计数据 2025-11-13 15:29:06 +08:00
1f233c142a 物资采购联系单新增优化和车辆管理增加GPS绑定、增加轨迹功能 2025-11-12 20:09:10 +08:00
lg
4b3a56eb5f 机械合同 2025-11-12 19:46:40 +08:00
2b25ec1483 11-12-修改 2025-11-12 19:43:47 +08:00
zt
0736552eb7 考勤范围和导出 2025-11-12 16:55:46 +08:00
zt
d99d59ffa0 Merge remote-tracking branch 'origin/dev' into dev 2025-11-12 09:57:01 +08:00
zt
5da05dcf24 分包考勤 2025-11-12 09:56:39 +08:00
lcj
fceb06eca8 分包公司数据校验 2025-11-11 19:58:09 +08:00
24219b6942 Merge remote-tracking branch 'origin/dev' into dev 2025-11-11 19:55:27 +08:00
8566231790 11-11-修改 2025-11-11 19:55:20 +08:00
lcj
b96cc95741 大图光伏板识别、填报 2025-11-11 19:40:03 +08:00
lg
8478cd2997 承包合同保函详情添加返回字段 2025-11-11 17:23:08 +08:00
1bbc1e52ae 修改成本预算模块接口 2025-11-11 17:12:00 +08:00
9221cb50a3 11-11-修改 2025-11-11 17:10:33 +08:00
lg
e8e15f4a98 bug修改 2025-11-11 17:08:30 +08:00
zt
0941197ca9 考勤 2025-11-11 16:41:55 +08:00
lg
23dc2f2759 bug修改销货清单excel导入 2025-11-11 16:15:57 +08:00
7321db3419 修改成本预算模块接口 2025-11-11 15:53:33 +08:00
be7576f8ea 修改菜单 2025-11-11 15:02:31 +08:00
cc72b1bd64 修改菜单 2025-11-11 11:52:18 +08:00
e1d713b23e 11-10-修改 2025-11-10 20:17:30 +08:00
lcj
5ebc46d2e1 修改包结构 2025-11-10 19:59:49 +08:00
lcj
0da63144e7 修改包结构 2025-11-10 19:59:04 +08:00
347bd92b69 综合服务合同信息和变更添加印章修改 2025-11-10 19:57:44 +08:00
lg
6d859c6a8c bug修改 2025-11-10 19:51:52 +08:00
zt
733b95632b 考勤 2025-11-10 18:57:07 +08:00
lg
b905320413 采购合同,分包合同,job修改 2025-11-10 17:37:20 +08:00
8d4059bbf4 综合服务合同信息和变更添加印章 2025-11-10 17:26:17 +08:00
lcj
b1b8ced0a8 AI 违章工单等级关联角色 2025-11-10 15:32:41 +08:00
9d3c212856 gps添加设备类型、车辆设备绑定 2025-11-10 14:26:51 +08:00
lcj
ceec388f5f 施工产值导出 2025-11-10 10:58:57 +08:00
44f604ff57 综合服务合同变更添加印章和成本预算-总体计划成本变更添加字段 2025-11-10 10:31:02 +08:00
fae9c61f07 为印章中间表添加类型 2025-11-10 09:58:34 +08:00
e48b27715f 11-10-修改 2025-11-10 09:29:59 +08:00
feb0e49da3 11-08-修改 2025-11-08 20:02:21 +08:00
lg
245cdb40f7 bug修改 2025-11-07 19:59:34 +08:00
zt
a2d2431bce 排序 2025-11-07 19:52:19 +08:00
lcj
048a175526 修改bug 2025-11-07 19:50:36 +08:00
d9d2688e24 11-07-修改,添加合同状态 2025-11-07 19:39:17 +08:00
lcj
15382b5aba 大屏接口,修改bug 2025-11-07 17:45:37 +08:00
zt
8500469918 角色强退 2025-11-07 16:29:56 +08:00
864eb1462f 11-7 2025-11-07 14:27:05 +08:00
zt
86b44282ea 数据推送 2025-11-07 10:34:03 +08:00
lcj
7ccf5e4469 Merge remote-tracking branch 'gitea/dev' into dev 2025-11-06 20:52:07 +08:00
lcj
137ab4e802 修改bug 2025-11-06 20:23:38 +08:00
a941db7870 11-06-修改 2025-11-06 20:01:51 +08:00
lcj
35c32d68c3 产值导出,bug修改 2025-11-06 19:26:42 +08:00
lg
359600004d 文档中心修改 2025-11-06 19:14:35 +08:00
lg
910801b057 采购合同分包合同修改 2025-11-06 16:46:47 +08:00
7aa9d519a0 11-06-角色流程对应模块 2025-11-06 15:22:40 +08:00
5d7b438745 11-06-修改 2025-11-06 14:29:52 +08:00
zt
204177afa0 数据推送 2025-11-06 11:15:43 +08:00
lcj
1d8d9c0236 1 2025-11-06 11:12:49 +08:00
zt
8ceade6227 数据推送 2025-11-06 11:11:25 +08:00
zt
5714079de3 数据推送 2025-11-06 11:06:08 +08:00
zt
f21a298b8f 数据推送 2025-11-06 10:46:13 +08:00
zt
09fbf237f0 数据推送 2025-11-06 10:43:46 +08:00
zt
a6fd3e0cef 数据推送 2025-11-06 10:36:41 +08:00
zt
e47cd3eba7 数据推送 2025-11-06 10:35:41 +08:00
zt
a6976aaac4 数据推送 2025-11-06 10:35:04 +08:00
lg
dd970d200c 采购合同变更数据 2025-11-06 10:27:41 +08:00
lcj
d1d6c443de ai 2025-11-06 09:18:34 +08:00
d26a99cdbb 11-5-修改 2025-11-05 19:18:30 +08:00
lg
90dbc34a93 采购合同变更数据 2025-11-05 17:12:03 +08:00
lg
0408afb67e 文档中心,实用工具 2025-11-05 16:54:28 +08:00
587cabc166 11-5-报销模块 2025-11-05 16:25:57 +08:00
30f916f8eb 11-5-修改 2025-11-05 16:18:32 +08:00
lcj
fae046885e ai 2025-11-05 11:46:48 +08:00
05569d0471 11-5-修改 2025-11-05 11:43:17 +08:00
lg
8efeff20d4 派单任务,备忘录查询接口 2025-11-05 09:45:27 +08:00
lg
bc21aa3f41 支付条款类型修改 2025-11-04 20:02:37 +08:00
lg
fedbb99b18 支付条款类型修改 2025-11-04 20:00:01 +08:00
4b2b68d9ef 11-4-修改 2025-11-04 19:16:01 +08:00
lcj
a663e30759 ai 对话记忆功能,识别 2025-11-04 18:00:52 +08:00
b6a2d41f57 11-4-新增父级字段 2025-11-04 16:13:37 +08:00
cd87783ad0 11-4-新增父级字段 2025-11-04 15:37:01 +08:00
lg
7876a82ca4 标前立项修改 2025-11-04 11:52:12 +08:00
0a18a0892a Merge remote-tracking branch 'origin/dev' into dev 2025-11-04 10:23:24 +08:00
b2e1cce667 11-4-标志字典改为字符串 2025-11-04 10:23:14 +08:00
64c1c84ed3 websocket优化以及传递初始值 2025-11-04 09:46:40 +08:00
f2301264ea 11-3-修复 2025-11-03 20:15:44 +08:00
lg
c83af6df6d 分包合同修改 2025-11-03 20:04:56 +08:00
zt
22d9dfe138 Merge remote-tracking branch 'origin/dev' into dev 2025-11-03 19:59:02 +08:00
zt
bcee164f48 车辆 2025-11-03 19:58:44 +08:00
1297 changed files with 85551 additions and 7599 deletions

View File

@ -53,3 +53,5 @@ logs/
docs
/file
.idea/
chat-memory/
queries/

View File

@ -18,7 +18,7 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>21</java.version>
<mybatis.version>3.5.16</mybatis.version>
<springdoc.version>2.8.4</springdoc.version>
<springdoc.version>2.3.0</springdoc.version>
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
<easyexcel.version>4.0.3</easyexcel.version>
<velocity.version>2.3</velocity.version>
@ -86,6 +86,15 @@
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>menu</id>
<properties>
<profiles.active>menu</profiles.active>
<logging.level>info</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>

View File

@ -5,6 +5,8 @@ import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -76,7 +78,7 @@ public class CaptchaController {
SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, map);
if (!smsResponse.isSuccess()) {
log.error("验证码短信发送异常 => {}", smsResponse);
return R.fail(smsResponse.getData().toString());
return R.fail(parseData(smsResponse));
}
return R.ok();
}
@ -140,4 +142,35 @@ public class CaptchaController {
return R.ok(captchaVo);
}
public static String parseData(SmsResponse smsResponse ) {
try {
JSONObject json = JSONUtil.parseObj(smsResponse.getData());
// 核心:用 JsonUtil 解析 data通过键路径 "Response.SendStatusSet[0].Code" 提取字段
// 键路径规则:层级用 "." 分隔,列表索引用 "[0]" 表示(第 1 个元素)
String code = json.getByPath("Response.SendStatusSet[0].Code", String.class);
System.out.println("错误码:" + code); // 输出FailedOperation.InsufficientBalanceInSmsPackage
return convert(code);
} catch (Exception e) {
return "短信发送未知错误";
}
}
public static String convert(String code) {
return switch (code) {
case "FailedOperation.InsufficientBalanceInSmsPackage" -> "套餐包余量不足,请购买套餐包";
case "InternalError.SendAndRecvFail" -> "短信收发超时,请检查您的网络是否有波动";
case "InvalidParameterValue.IncorrectPhoneNumber" -> "手机号格式错误";
case "LimitExceeded.AppCountryOrRegionDailyLimit" -> "业务短信国家/地区日下发条数超过设定的上限";
case "LimitExceeded.AppDailyLimit" -> "业务短信日下发条数超过设定的上限";
case "LimitExceeded.PhoneNumberDailyLimit" -> "单个手机号日下发短信条数超过设定的上限";
case "UnauthorizedOperation.ServiceSuspendDueToArrears" -> "欠费被停止服务";
case "UnsupportedOperation.UnsupportedRegion" -> "不支持该地区短信下发";
default -> "短信发送未知错误";
};
}
}

View File

@ -41,7 +41,7 @@ spring:
api-key: sk-8d8df92fcbac4bd2922edba30b0bb8fa
chat:
options:
model: qwen-plus
model: qwen3-max
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
@ -66,7 +66,7 @@ spring:
# username: xinnengyuan
# password: mEZPC5Sdf3r2HENi
# 从库数据源
# slave:
# slave:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
@ -368,3 +368,14 @@ drone:
chat:
server:
port: 19099
# rabbitmq 配置
rabbitmq:
exchange-name: dev-normal-exchange
queue-name: dev-normal-queue
routing-key: dev.normal.routing.key
delay-exchange-name: dev-delay-queue
delay-queue-name: dev-delay-exchange
delay-routing-key: dev.delay.routing.key
dead-letter-exchange: dev-dlx-exchange
dead-letter-queue: dev-dlx-queue
dead-letter-routing-key: dev.dlx.routing.key

View File

@ -41,10 +41,10 @@ snail-job:
spring:
ai:
dashscope:
api-key: xxx
api-key: sk-8d8df92fcbac4bd2922edba30b0bb8fa
chat:
options:
model: qwen-plus
model: qwen3-max
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
@ -343,3 +343,14 @@ drone:
chat:
server:
port: 18088
# rabbitmq 配置
rabbitmq:
exchange-name: local-normal-exchange
queue-name: local-normal-queue
routing-key: local.normal.routing.key
delay-exchange-name: local-delay-queue
delay-queue-name: local-delay-exchange
delay-routing-key: local.delay.routing.key
dead-letter-exchange: local-dlx-exchange
dead-letter-queue: local-dlx-queue
dead-letter-routing-key: local.dlx.routing.key

View File

@ -0,0 +1,356 @@
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 9528
--- # 临时文件存储位置 避免临时文件被系统清理报错
spring.servlet.multipart.location: /ruoyi/server/temp
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: false
url: http://localhost:9090/admin
instance:
service-host-type: IP
metadata:
username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@
password: @monitor.password@
--- # snail-job 配置
snail-job:
enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config`表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
host: 127.0.0.1
port: 17888
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
namespace: ${spring.profiles.active}
# 随主应用端口漂移
port: 2${server.port}
# 客户端ip指定
host:
# RPC类型: netty, grpc
rpc-type: grpc
--- # 数据源配置
spring:
ai:
dashscope:
api-key: sk-8d8df92fcbac4bd2922edba30b0bb8fa
chat:
options:
model: qwen3-max
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: false
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
# 严格模式 匹配不到数据源则报错
strict: true
datasource:
# 主库数据源
master:
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://192.168.110.2:13386/xinnengyuanmenu?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: xinnengyuanmenu
password: 2RkXFG8ZE6r5LL7B
# # 从库数据源
# slave:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username:
# password:
# oracle:
# type: ${spring.datasource.type}
# driverClassName: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@//localhost:1521/XE
# username: ROOT
# password: root
# postgres:
# type: ${spring.datasource.type}
# driverClassName: org.postgresql.Driver
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username: root
# password: root
# sqlserver:
# type: ${spring.datasource.type}
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
# username: SA
# password: root
hikari:
# 最大连接池数量
maxPoolSize: 20
# 最小空闲线程数量
minIdle: 10
# 配置获取连接等待超时的时间
connectionTimeout: 30000
# 校验超时时间
validationTimeout: 5000
# 空闲连接存活最大时间默认10分钟
idleTimeout: 600000
# 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟
maxLifetime: 1800000
# 多久检查一次连接的活性
keepaliveTime: 30000
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data:
redis:
# 地址
host: 192.168.110.2
# 端口默认为6379
port: 9287
# 数据库索引
database: 21
# redis 密码必须配置
password: syar23rdsaagdrsa
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson:
# redis key前缀
keyPrefix:
# 线程池数量
threads: 16
# Netty线程池数量
nettyThreads: 32
# 单节点配置
singleServerConfig:
# 客户端名称
clientName: ${ruoyi.name}
# 最小空闲连接数
connectionMinimumIdleSize: 32
# 连接池大小
connectionPoolSize: 64
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
--- # mail 邮件发送
mail:
enabled: false
host: smtp.163.com
port: 465
# 是否需要用户名密码验证
auth: true
# 发送方遵循RFC-822标准
from: xxx@163.com
# 用户名注意如果使用foxmail邮箱此处user为qq号
user: xxx@163.com
# 密码注意某些邮箱需要为SMTP服务单独设置密码详情查看相关帮助
pass: xxxxxxxxxx
# 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true
# 使用SSL安全连接
sslEnable: true
# SMTP超时时长单位毫秒缺省值不超时
timeout: 0
# Socket连接超时值单位毫秒缺省值不超时
connectionTimeout: 0
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截接口配置不受此限制
restricted: false
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
blends:
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
config1:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
# 有些称为accessKey有些称之为apiKey也有称为sdkKey或者appId。
access-key-id: 您的accessKey
# 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 登录
supplier: tencent
access-key-id: AKIDb3JK5dx4wa0DCxWqvxlKejvysZ3ITVJv
access-key-secret: c5LPFsJI8k7GDxTkoeFj4A1ukQr66rPi
signature: 重庆远界大数据研究院
sdk-app-id: 1401018866
template-id: 2491779
config3:
# 注册
supplier: tencent
access-key-id: AKIDb3JK5dx4wa0DCxWqvxlKejvysZ3ITVJv
access-key-secret: c5LPFsJI8k7GDxTkoeFj4A1ukQr66rPi
signature: 重庆远界大数据研究院
sdk-app-id: 1401018866
template-id: 2491776
config4:
# 质量工单逾期
supplier: tencent
access-key-id: AKIDb3JK5dx4wa0DCxWqvxlKejvysZ3ITVJv
access-key-secret: c5LPFsJI8k7GDxTkoeFj4A1ukQr66rPi
signature: 重庆远界大数据研究院
sdk-app-id: 1401018866
template-id: 2534747
config5:
# 设计图纸
supplier: tencent
access-key-id: AKIDb3JK5dx4wa0DCxWqvxlKejvysZ3ITVJv
access-key-secret: c5LPFsJI8k7GDxTkoeFj4A1ukQr66rPi
signature: 重庆远界大数据研究院
sdk-app-id: 1401018866
template-id: 2534750
config6:
# 安全工单
supplier: tencent
access-key-id: AKIDb3JK5dx4wa0DCxWqvxlKejvysZ3ITVJv
access-key-secret: c5LPFsJI8k7GDxTkoeFj4A1ukQr66rPi
signature: 重庆远界大数据研究院
sdk-app-id: 1401018866
template-id: 2534848
--- # 三方授权
justauth:
# 前端外网访问地址
address: http://localhost:80
type:
maxkey:
# maxkey 服务器地址
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
server-url: http://sso.maxkey.top
client-id: 876892492581044224
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
redirect-uri: ${justauth.address}/social-callback?source=maxkey
topiam:
# topiam 服务器地址
server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol
client-id: 449c4*********937************759
client-secret: ac7***********1e0************28d
redirect-uri: ${justauth.address}/social-callback?source=topiam
scopes: [ openid, email, phone, profile ]
qq:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false
weibo:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee:
client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
redirect-uri: ${justauth.address}/social-callback?source=gitee
dingtalk:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn
coding:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx
oschina:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay_wallet:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay-public-key: MIIB**************DAQAB
wechat_open:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
# 和风天气 https://dev.qweather.com/
weather:
key-id: T65EAABUXC
project-id: 2JTHPUQ5YY
private-key: MC4CAQAwBQYDK2VwBCIEIMAglX7IsxYiTeM+FXXnvCUsIggajeP4s8gAllewm6BN
api-host: n35rk53njv.re.qweatherapi.com
# dxf转 geojson 执行文件名
dxf2GeoJson:
file-name: main
ys7:
app-key: xxx
app-secret: xxx
job:
capture-enabled: false # 控制是否启用萤石抓拍任务
device-sync-enabled: false # 控制是否同步萤石设备
# 斯巴达算法
sparta:
url: http://119.3.204.120:8040
client-id: test
client-secret: 115fcb08fa6742a1b086d9bb80a6ad59
# 身份证加密密钥32 位)
id-card:
encrypt-key: 7ae260d150a14027d2238a1cf80a48ef
recognizer:
url: http://192.168.110.5:50071
qrCode:
url: http://xny.yj-3d.com:7788
# 无人机大图
drone:
url: http://192.168.110.2:9512
# 聊天服务
chat:
server:
port: 17077
# rabbitmq 配置
rabbitmq:
exchange-name: menu-normal-exchange
queue-name: menu-normal-queue
routing-key: menu.normal.routing.key
delay-exchange-name: menu-delay-queue
delay-queue-name: menu-delay-exchange
delay-routing-key: menu.delay.routing.key
dead-letter-exchange: menu-dlx-exchange
dead-letter-queue: menu-dlx-queue
dead-letter-routing-key: menu.dlx.routing.key

View File

@ -41,10 +41,10 @@ snail-job:
spring:
ai:
dashscope:
api-key: xxx
api-key: sk-8d8df92fcbac4bd2922edba30b0bb8fa
chat:
options:
model: qwen-plus
model: qwen3-max
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
@ -358,3 +358,14 @@ drone:
chat:
server:
port: 19099
# rabbitmq 配置
rabbitmq:
exchange-name: prod-normal-exchange
queue-name: prod-normal-queue
routing-key: prod.normal.routing.key
delay-exchange-name: prod-delay-queue
delay-queue-name: prod-delay-exchange
delay-routing-key: prod.delay.routing.key
dead-letter-exchange: prod-dlx-exchange
dead-letter-queue: prod-dlx-queue
dead-letter-routing-key: prod.dlx.routing.key

View File

@ -76,9 +76,9 @@ spring:
servlet:
multipart:
# 单个文件大小
max-file-size: 200MB
max-file-size: 1024MB
# 设置总上传的文件大小
max-request-size: 200MB
max-request-size: 1024MB
mvc:
# 设置静态资源路径 防止所有请求都去查静态资源
static-path-pattern: /static/**
@ -95,7 +95,13 @@ spring:
deserialization:
# 允许对象忽略json中不存在的属性
fail_on_unknown_properties: false
rabbitmq:
host: 192.168.110.2
port: 5672
username: admin
password: yuanjiexny
publisher-returns: true
publisher-confirm-type: correlated
# Sa-Token配置
sa-token:
# token名称 (同时也是cookie名称)
@ -109,7 +115,9 @@ sa-token:
# token有效期单位s 默认30天, -1代表永不过期
timeout: 2592000
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
active-timeout: 86400
active-timeout: 2592000
# 同一账号最大登录数量,-1代表不限
max-login-count: -1
# security配置
security:
@ -135,6 +143,7 @@ security:
- /facility/matrix/**
- /hat/device/data
- /websocket/ue
- /websocket/vehicle
# 多租户配置
tenant:
@ -173,7 +182,7 @@ mybatis-plus:
# 数据加密
mybatis-encryptor:
# 是否开启加密
enable: false
enable: true
# 默认加密算法
algorithm: BASE64
# 编码方式 BASE64/HEX。默认BASE64
@ -207,6 +216,10 @@ api-decrypt:
- /gps/equipment/dataAcceptance # GPS数据接收接口
springdoc:
default-flat-param-object: true
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
api-docs:
# 是否开启接口文档
enabled: true
@ -226,10 +239,14 @@ springdoc:
components:
# 鉴权方式配置
security-schemes:
apiKey:
type: APIKEY
Authorization:
type: HTTP
in: HEADER
name: ${sa-token.token-name}
Clientid:
type: HTTP
in: HEADER
name: Clientid
#这里定义了两个分组,可定义多个,也可以不定义
group-configs:
- group: 1.通用模块
@ -262,8 +279,6 @@ springdoc:
packages-to-scan: org.dromara.ctr
- group: 15.无人机模块
packages-to-scan: org.dromara.drone
- group: 20.代码生成模块
packages-to-scan: org.dromara.generator
- group: 16.app模块
packages-to-scan: org.dromara.app
- group: 17.材料设备模块
@ -272,18 +287,16 @@ springdoc:
packages-to-scan: org.dromara.out
- group: 19.消息模块
packages-to-scan: org.dromara.message
- group: 20.代码生成模块
packages-to-scan: org.dromara.generator
- group: 21.分标策划模块
packages-to-scan: org.dromara.tender
- group: 22.大屏模块
packages-to-scan: org.dromara.bigscreen
- group: 22.投标管理模块
packages-to-scan: org.dromara.bidding
- group: 23.GPS定位模块
packages-to-scan: org.dromara.gps
- group: 24.招标模块
packages-to-scan: org.dromara.tender
- group: 29.app版本模块
packages-to-scan: org.dromara.app
- group: 25.数据迁移模块
packages-to-scan: org.dromara.transferData
- group: 26.netty消息模块
@ -292,6 +305,18 @@ springdoc:
packages-to-scan: org.dromara.xzd
- group: 28.车辆模块
packages-to-scan: org.dromara.vehicle
- group: 29.app版本模块
packages-to-scan: org.dromara.app
- group: 30.AI 模块
packages-to-scan: org.dromara.ai
- group: 31.投标管理模块
packages-to-scan: org.dromara.bidding
- group: 32.设备模块
packages-to-scan: org.dromara.device
- group: 33.摄像头模块
packages-to-scan: org.dromara.other
- group: 34.机械模块
packages-to-scan: org.dromara.mechanical
# knife4j的增强配置不需要增强可以不配
knife4j:
enable: true
@ -316,6 +341,8 @@ xss:
- /xzd/fenbaohetongbiangg/**
- /xzd/fenbaohetongxinxi/**
- /xzd/contractManagement/**
- /xzd/jixiehetongxinxi/contractMachinery/**
- /xzd/jixiehetongbiang/machineryContractAlteration/**
# 全局线程池相关配置
# 如使用JDK21请直接使用虚拟线程 不要开启此配置

View File

@ -24,6 +24,7 @@ import org.dromara.facility.domain.FacMatrix;
import org.dromara.facility.service.IFacMatrixService;
import org.dromara.facility.service.IFacPhotovoltaicPanelPartsService;
import org.dromara.facility.service.IFacPhotovoltaicPanelService;
import org.dromara.manager.recognizermanager.enums.RecognizerTypeEnum;
import org.dromara.manager.recognizermanager.vo.RecognizeConvertCoordinateResult;
import org.dromara.manager.ys7manager.Ys7Constant;
import org.dromara.manager.ys7manager.Ys7Manager;
@ -135,7 +136,7 @@ public class DemoTest {
log.info("执行定时任务:同步 {}至{} 计划详情到施工产值", lastMonday, lastSunday);
Boolean synced = progressPlanDetailService.syncPlanDetail2ConstructionValue(lastMonday, lastSunday, null);*/
LocalDate start = LocalDate.of(2024, 1, 1); // 起始时间2024-01-01
LocalDate end = LocalDate.of(2025, 10, 20); // 截止时间2025-09-15
LocalDate end = LocalDate.of(2025, 10, 27); // 截止时间2025-09-15
// 如果起始不是周一,调整到当周的周一
if (start.getDayOfWeek() != DayOfWeek.MONDAY) {
@ -150,12 +151,18 @@ public class DemoTest {
System.out.println(monday + " ~ " + sunday);
log.info("执行定时任务:同步 {}至{} 计划详情到施工产值", monday, sunday);
// Boolean synced = progressPlanDetailService.syncPlanDetail2ConstructionValue(start, now, null);
List<BusProject> list = projectService.lambdaQuery()
.eq(BusProject::getPId, 1968506669544656898L)
.list();
List<Long> list1 = new ArrayList<>(list.stream().map(BusProject::getId).toList());
list1.add(1968506669544656898L);
// 获取范围时间内的计划详情
List<PgsProgressPlanDetail> planDetailList = progressPlanDetailService.lambdaQuery()
.in(PgsProgressPlanDetail::getProjectId, list1)
.ge(PgsProgressPlanDetail::getDate, monday)
.le(PgsProgressPlanDetail::getDate, sunday)
.ne(PgsProgressPlanDetail::getFinishedNumber, BigDecimal.ZERO)
// .eq(PgsProgressPlanDetail::getStatus, "1")
.eq(PgsProgressPlanDetail::getStatus, "1")
.list();
if (CollUtil.isEmpty(planDetailList)) {
// 下一周
@ -397,7 +404,8 @@ public class DemoTest {
@Test
void testImport() {
photovoltaicPanelService.updateFinishNumberByCoordinate(List.of(1968510961294921730L),
List.of(new RecognizeConvertCoordinateResult("107.124334530", "23.830557974")));
List.of(new RecognizeConvertCoordinateResult("107.124334530", "23.830557974")),
RecognizerTypeEnum.BRACKET.getValue());
}
@Test

View File

@ -1,14 +1,23 @@
package org.dromara.test;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.manager.recognizermanager.RecognizerManager;
import org.dromara.manager.recognizermanager.enums.RecognizerTypeEnum;
import org.dromara.manager.recognizermanager.vo.RecognizeVo;
import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo;
import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.dromara.progress.service.IPgsProgressPlanService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author lilemy
@ -21,9 +30,55 @@ public class RecognizerTest {
@Resource
private RecognizerManager recognizerManager;
@Resource
private IPgsProgressPlanDetailService progressPlanDetailService;
@Resource
private IPgsProgressPlanService progressPlanService;
@Test
void test() {
RecognizeVo recognize = recognizerManager.recognize("http://xny.yj-3d.com:7363/file/tif/20250625160218orthophoto.png", List.of(RecognizerTypeEnum.PANEL));
log.info("recognize: {}", recognize);
}
@Test
void testChange() {
recognizerManager.convertCoordinate("http://xny.yj-3d.com:9000/xinnengyuan-dev/2025/11/11/d48767a62bc04867a552e06ba6712004.tif", List.of());
}
@Test
void checkNumber() {
List<PgsProgressPlanDetail> detailList = progressPlanDetailService.list();
List<PgsProgressPlanDetail> planDetailList = detailList.stream()
.filter(detail -> StringUtils.isNotBlank(detail.getFinishedDetail()))
.toList();
Map<String, List<PgsProgressPlanDetail>> collect = planDetailList.stream()
.collect(Collectors.groupingBy(PgsProgressPlanDetail::getFinishedDetail));
// 遍历分组结果,输出重复项
for (Map.Entry<String, List<PgsProgressPlanDetail>> entry : collect.entrySet()) {
String fieldValue = entry.getKey();
List<PgsProgressPlanDetail> duplicates = entry.getValue();
if (duplicates.size() > 1) { // 筛选出有重复的字段值
PgsProgressPlanDetail first = duplicates.getFirst();
Long id = first.getId();
Long planId = first.getProgressPlanId();
progressPlanService.removeById(planId);
progressPlanDetailService.removeById(id);
System.out.println("重复对象的对象:" + duplicates.stream().map(PgsProgressPlanDetail::getId).toList());
}
}
for (PgsProgressPlanDetail detail : detailList) {
BigDecimal aiFill = detail.getFinishedNumber();
String finishedDetail = detail.getFinishedDetail();
if (StringUtils.isBlank(finishedDetail)) {
continue;
}
// log.info("id: {}, finishedDetail: {}", detail.getId(), finishedDetail);
List<PgsProgressPlanDetailFinishedVo> finishedVos = JSONUtil.toList(finishedDetail, PgsProgressPlanDetailFinishedVo.class);
if (aiFill.compareTo(BigDecimal.valueOf(finishedVos.size())) != 0) {
log.info("数量异常:{}{}", detail.getId(), detail.getProgressCategoryId());
}
}
}
}

View File

@ -5,11 +5,14 @@ import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.core.task.VirtualThreadTaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 异步配置
@ -26,12 +29,48 @@ public class AsyncConfig implements AsyncConfigurer {
*/
@Override
public Executor getAsyncExecutor() {
if(SpringUtils.isVirtual()) {
if (SpringUtils.isVirtual()) {
return new VirtualThreadTaskExecutor("async-");
}
return SpringUtils.getBean("scheduledExecutorService");
}
/**
* 新增:自定义线程池(可以在 @Async("capturePicExecutor") 使用)
*/
@Bean("capturePicExecutor")
public Executor customExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(5);
// 最大线程数
executor.setMaxPoolSize(10);
// 队列容量(超过核心线程数时,任务进入队列)
executor.setQueueCapacity(50);
// 空闲线程最大存活时间(秒)
executor.setKeepAliveSeconds(60);
// 线程名前缀,方便定位日志
executor.setThreadNamePrefix("capturePic-async-");
// 拒绝策略:当线程池满时
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// CallerRunsPolicy由调用线程执行任务相对安全
// 初始化
executor.initialize();
return executor;
}
// 解压线程池(大文件操作,不需要太多线程)
@Bean("unzipExecutor")
public Executor unzipExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(4);
executor.setQueueCapacity(10);
executor.setThreadNamePrefix("unzip-");
executor.initialize();
return executor;
}
/**
* 异步执行异常处理
*/

View File

@ -0,0 +1,5 @@
package org.dromara.common.core.service;
public interface XzdCbysZjhcbService {
String selectNmaeByIds(String ids);
}

View File

@ -0,0 +1,14 @@
package org.dromara.common.core.service;
/**
* 机械合同信息Service接口
*
* @author Lion Li
* @date 2025-11-12
*/
public interface XzdContractMachineryService {
String selectNmaeByIds(String ids);
}

View File

@ -0,0 +1,6 @@
package org.dromara.common.core.service;
public interface XzdProjectManagerApprovalService {
String selectNmaeByIds(String ids);
}

View File

@ -0,0 +1,6 @@
package org.dromara.common.core.service;
public interface XzdSjContractInfoService {
String selectNameByIds(String ids);
}

View File

@ -0,0 +1,146 @@
package org.dromara.common.core.utils;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
/**
* 时间戳转换工具类(包含时分秒提取)
*/
public class TimestampUtils {
// 默认时区(东八区)
private static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone("GMT+8");
// 完整日期格式
private static final String FULL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
// 时分秒格式
private static final String TIME_FORMAT = "HH:mm:ss";
// 日期格式
private static final String DATE_FORMAT = "yyyy-MM-dd";
/**
* 将日期字符串转为秒级时间戳(优化版)
* 支持格式:"2025-12-03 23:59:59"、"2025-12-03"等
* @param dateStr 日期字符串
* @return 秒级时间戳
*/
public static Long parseDateToTimestamp(String dateStr) {
if (StrUtil.isBlank(dateStr)) {
return null;
}
// 使用Hutool的DateUtil进行智能解析推荐
try {
Date date = DateUtil.parse(dateStr);
return date.getTime() / 1000L; // 转为秒级时间戳
} catch (Exception e) {
throw new IllegalArgumentException(
String.format("日期格式错误:%s支持格式yyyy-MM-dd HH:mm:ss、yyyy-MM-dd等", dateStr)
);
}
}
/**
* 将时间戳转换为完整日期格式yyyy-MM-dd HH:mm:ss
*/
public static String formatTimestamp(Object timestamp) {
if (timestamp == null) {
return null;
}
String timestampStr = timestamp.toString().trim();
if (StrUtil.isBlank(timestampStr)) {
return null;
}
Long time = parseToMilliseconds(timestampStr);
SimpleDateFormat sdf = new SimpleDateFormat(FULL_DATE_FORMAT);
sdf.setTimeZone(DEFAULT_TIME_ZONE);
return sdf.format(new Date(time));
}
/**
* 提取时间戳中的时分秒部分HH:mm:ss
*/
public static String extractTime(Object timestamp) {
if (timestamp == null) {
return null;
}
String timestampStr = timestamp.toString().trim();
if (StrUtil.isBlank(timestampStr)) {
return null;
}
Long time = parseToMilliseconds(timestampStr);
SimpleDateFormat sdf = new SimpleDateFormat(TIME_FORMAT);
sdf.setTimeZone(DEFAULT_TIME_ZONE);
return sdf.format(new Date(time));
}
/**
* 提取时间戳中的日期部分yyyy-MM-dd
*/
public static String extractDate(Object timestamp) {
if (timestamp == null) {
return null;
}
String timestampStr = timestamp.toString().trim();
if (StrUtil.isBlank(timestampStr)) {
return null;
}
Long time = parseToMilliseconds(timestampStr);
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
sdf.setTimeZone(DEFAULT_TIME_ZONE);
return sdf.format(new Date(time));
}
/**
* 解析时间戳字符串为毫秒级时间戳
*/
private static Long parseToMilliseconds(String timestampStr) {
try {
Long time = Long.parseLong(timestampStr);
// 10位秒级时间戳转为13位毫秒级
if (timestampStr.length() == 10) {
time = time * 1000;
}
return time;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("时间戳格式错误:" + timestampStr);
}
}
/**
* 获取时间戳对应的小时
*/
public static int getHour(Object timestamp) {
String timeStr = extractTime(timestamp);
return Integer.parseInt(timeStr.split(":")[0]);
}
/**
* 获取时间戳对应的分钟
*/
public static int getMinute(Object timestamp) {
String timeStr = extractTime(timestamp);
return Integer.parseInt(timeStr.split(":")[1]);
}
/**
* 获取时间戳对应的秒
*/
public static int getSecond(Object timestamp) {
String timeStr = extractTime(timestamp);
return Integer.parseInt(timeStr.split(":")[2]);
}
}

View File

@ -44,7 +44,17 @@
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.4.0</version>
<version>4.5.0</version>
<exclusions>
<exclusion>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

View File

@ -1,6 +1,8 @@
package org.dromara.common.doc.config;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
@ -9,6 +11,7 @@ import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.doc.config.properties.SpringDocProperties;
import org.dromara.common.doc.handler.OpenApiHandler;
import org.springdoc.core.configuration.SpringDocConfiguration;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
@ -23,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import java.util.ArrayList;
import java.util.List;
@ -61,7 +65,6 @@ public class SpringDocConfig {
keySet.forEach(securityRequirement::addList);
list.add(securityRequirement);
openApi.security(list);
return openApi;
}
@ -123,4 +126,26 @@ public class SpringDocConfig {
}
}
@Bean
public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() {
return openApi -> {
// 全局添加鉴权参数
if(openApi.getPaths()!=null){
openApi.getPaths().forEach((s, pathItem) -> {
// 为所有接口添加鉴权
List<Operation> operations = pathItem.readOperations();
operations.forEach(operation -> {
operation.addSecurityItem(new SecurityRequirement()
.addList(HttpHeaders.AUTHORIZATION)
.addList("Clientid")
);
});
});
}
};
}
}

View File

@ -73,8 +73,7 @@ public class ExcelReader {
// 从MultipartFile获取输入流
try (InputStream stream = file.getInputStream();
org.apache.poi.ss.usermodel.Workbook workbook = isXlsx ?
new XSSFWorkbook(stream) : new HSSFWorkbook(stream)) {
Workbook workbook = WorkbookFactory.create(stream)) {
for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
org.apache.poi.ss.usermodel.Sheet sheet = workbook.getSheetAt(sheetIndex);

View File

@ -0,0 +1,40 @@
package org.dromara.common.excel.handler;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Workbook;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
public class LockColumnHandler implements CellWriteHandler {
private final Set<Integer> lockColumns;
public LockColumnHandler(Collection<Integer> lockColumns) {
this.lockColumns = new HashSet<>(lockColumns);
}
@Override
public void afterCellDispose(CellWriteHandlerContext context) {
Cell cell = context.getCell();
if (cell == null) return;
Workbook workbook = cell.getSheet().getWorkbook();
// 必须为所有单元格创建一个新的 CellStyle
CellStyle style = workbook.createCellStyle();
// 锁定指定列
if (lockColumns.contains(cell.getColumnIndex())) {
style.setLocked(true);
} else {
style.setLocked(false); // 非锁定列必须明确设置为 false
}
cell.setCellStyle(style);
}
}

View File

@ -0,0 +1,26 @@
package org.dromara.common.excel.handler;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.Sheet;
/**
* @author lilemy
* @date 2025-11-14 15:05
*/
public class SheetProtectHandler implements SheetWriteHandler {
private final String password;
public SheetProtectHandler(String password) {
this.password = password;
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder,
WriteSheetHolder writeSheetHolder) {
Sheet sheet = writeSheetHolder.getSheet();
sheet.protectSheet(password); // 可为空字符串
}
}

View File

@ -4,7 +4,10 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
@ -14,27 +17,27 @@ import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.excel.convert.ExcelBigNumberConvert;
import org.dromara.common.excel.core.*;
import org.dromara.common.excel.handler.DataWriteHandler;
import org.springframework.http.HttpHeaders;
import org.dromara.common.excel.handler.LockColumnHandler;
import org.dromara.common.excel.handler.SheetProtectHandler;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* Excel相关处理
*
* @author Lion Li
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ExcelUtil {
@ -48,6 +51,41 @@ public class ExcelUtil {
return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync();
}
/**
* 同步读取 Excel支持读取多个 Sheet
*
* @param is 输入流(一次性读取)
* @param clazz Excel 映射实体类
* @return 所有 Sheet 的数据汇总
*/
public static <T> List<T> importExcelAllSheet(InputStream is, Class<T> clazz) {
// 用于存放所有 sheet 的数据
List<T> allData = new ArrayList<>();
// 1. 构建 ExcelReader
ExcelReaderBuilder readerBuilder = EasyExcel.read(is);
ExcelReader reader = readerBuilder.build();
// 2. 获取 Excel 中全部 Sheet 信息(包含 SheetNo、页名等
List<ReadSheet> readSheets = reader.excelExecutor().sheetList();
// 3. 遍历每一个 Sheet
for (ReadSheet sheet : readSheets) {
// 为每个 Sheet 创建独立监听器,用于接收读取结果
DefaultExcelListener<T> listener = new DefaultExcelListener<>(false);
// 4. 构建当前 Sheet 的读取器 使用 sheet.getSheetNo() 指定当前 sheet
ReadSheet readSheet = EasyExcel.readSheet(sheet.getSheetNo())
// 设置头映射实体类
.head(clazz)
// 注册读取监听器
.registerReadListener(listener)
.build();
// 5. 开始读取当前 Sheet
reader.read(readSheet);
// 6. 收集当前 Sheet 读取的数据
allData.addAll(listener.getExcelResult().getList());
}
// 7. 关闭读取器,释放资源
reader.finish();
return allData;
}
/**
* 使用校验监听器 异步导入 同步返回
@ -205,15 +243,48 @@ public class ExcelUtil {
builder.doWrite(list);
}
/**
* 导出excel
*
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @param clazz 实体类
* @param lockColumns 锁定列
* @param merge 是否合并单元格
* @param os 输出流
*/
public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, List<Integer> lockColumns,
boolean merge, OutputStream os, List<DropDownOptions> options) {
ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz)
.registerWriteHandler(new LockColumnHandler(lockColumns)) // 锁定第3列
.registerWriteHandler(new SheetProtectHandler("dawdawdwad")) // 保护整张 sheet
.autoCloseStream(false)
// 自动适配
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
// 大数值自动转换 防止失真
.registerConverter(new ExcelBigNumberConvert())
.registerWriteHandler(new DataWriteHandler(clazz))
.sheet(sheetName);
if (merge) {
// 合并处理器
builder.registerWriteHandler(new CellMergeStrategy(list, true));
}
// 添加下拉框操作
builder.registerWriteHandler(new ExcelDownHandler(options));
builder.doWrite(list);
}
/**
* 导出多sheet excel增强版解决XML安全问题
*
* @param sheetData 多个sheet的数据
* @param sheetNames 多个sheet的名称
* @param clazz 实体类
* @param optionsList 级联下拉选内容列表
* @param sheetData 多个sheet的数据
* @param sheetNames 多个sheet的名称
* @param clazz 实体类
* @param optionsList 级联下拉选内容列表
*/
public static <T> void exportMultiSheetExcelEnhanced(List<List<T>> sheetData, List<String> sheetNames, Class<T> clazz, List<List<DropDownOptions>> optionsList,HttpServletResponse response) throws IOException {
public static <T> void exportMultiSheetExcelEnhanced(List<List<T>> sheetData, List<String> sheetNames,
Class<T> clazz, List<List<DropDownOptions>> optionsList,
HttpServletResponse response) throws IOException {
resetResponse("file", response);
ExcelWriter excelWriter = null;
ServletOutputStream os = response.getOutputStream();
@ -224,6 +295,9 @@ public class ExcelUtil {
.head(clazz)
.autoCloseStream(false)
.registerConverter(new ExcelBigNumberConvert())
// 自动适配
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
.registerWriteHandler(new DataWriteHandler(clazz))
.build();
@ -252,12 +326,71 @@ public class ExcelUtil {
excelWriter.finish();
} catch (Exception e) {
// 记录日志但不中断主流程
e.printStackTrace();
log.error("Excel 导出错误", e);
}
}
}
}
/**
* 导出多sheet excel增强版解决XML安全问题
*
* @param sheetData 多个sheet的数据
* @param sheetNames 多个sheet的名称
* @param clazz 实体类
* @param optionsList 级联下拉选内容列表
*/
public static <T> void exportExcel(List<List<T>> sheetData, List<String> sheetNames, List<Integer> lockColumns,
Class<T> clazz, List<List<DropDownOptions>> optionsList,
HttpServletResponse response) throws IOException {
resetResponse("file", response);
ExcelWriter excelWriter = null;
ServletOutputStream os = response.getOutputStream();
try {
// 使用SXSSFWorkbook避免内存问题并减少XML处理复杂度
excelWriter = EasyExcel.write(os)
.head(clazz)
.registerWriteHandler(new LockColumnHandler(lockColumns)) // 锁定第3列
// .registerWriteHandler(new SheetProtectHandler("dawdawdwad")) // 保护整张 sheet
.autoCloseStream(false)
.registerConverter(new ExcelBigNumberConvert())
// 自动适配
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
.registerWriteHandler(new DataWriteHandler(clazz))
.build();
// 为每个sheet写入数据
for (int i = 0; i < sheetData.size(); i++) {
// 创建基本sheet配置
WriteSheet writeSheet = EasyExcel.writerSheet(i, sheetNames.get(i))
.head(clazz)
.build();
// 添加下拉选项(如果存在)
if (optionsList != null && optionsList.size() > i && optionsList.get(i) != null) {
ExcelDownHandler handler = new ExcelDownHandler(optionsList.get(i));
writeSheet.setCustomWriteHandlerList(
Collections.singletonList(handler));
}
// 写入数据
excelWriter.write(sheetData.get(i), writeSheet);
}
} finally {
// 确保资源正确释放
if (excelWriter != null) {
try {
excelWriter.finish();
} catch (Exception e) {
// 记录日志但不中断主流程
log.error("Excel 导出错误", e);
}
}
}
}
/**
* 单表多数据模板导出 模板格式为 {.属性}
@ -493,6 +626,4 @@ public class ExcelUtil {
}
}

View File

@ -91,7 +91,7 @@ public class PlusDataPermissionHandler {
DataPermissionHelper.setVariable("user", currentUser);
}
// 如果是超级管理员或租户管理员,则不过滤数据
if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
if (LoginHelper.isSuperAdmin()) {
return where;
}
// 构造数据过滤条件的 SQL 片段

View File

@ -4,6 +4,7 @@ import cn.hutool.core.map.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.sse.dto.SseMessageDto;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
@ -22,7 +23,14 @@ public class SseEmitterManager {
/**
* 订阅的频道
*/
private final static String SSE_TOPIC = "global:sse";
// private final static String SSE_TOPIC = "global:sse";
private static String SSE_TOPIC;
@Value("${spring.data.redis.database:0}")
public void setDatabase(int database) {
SSE_TOPIC = "global:sse:db" + database;
}
private final static Map<Long, Map<String, SseEmitter>> USER_TOKEN_EMITTERS = new ConcurrentHashMap<>();

View File

@ -44,10 +44,6 @@ public interface TransConstant {
String XZD_KHXX_ID_TO_NAME = "khxx_id_to_name";
// /**
// * 供应商id转名称
// */
// String XZD_KHXX_ID_TO_NAME = "gysxx_id_to_name";
/**
* 新中大项目id转名称
@ -57,6 +53,12 @@ public interface TransConstant {
* 采购合同id转名称
*/
String XZD_PURCHASE_CONTRACT_ID_TO_NAME = "xzd_purchase_contract_id_to_name";
/**
* 机械合同id转名称
*/
String XZD_PURCHASE_JXXIE_ID_TO_NAME = "xzd_purchase_contract_jixie_id_to_name";
/**
* 综合服务合同id转名称
*/
@ -69,4 +71,21 @@ public interface TransConstant {
* 新中大供应商信息-开户银行id转银行名称
*/
String XZD_SUPPLIER_OPEN_BANK_ID_TO_NAME = "xzd_supplier_open_bank_id_to_name";
/**
* 新中大-项目经理推荐及审批id转名称
*/
String XZD_PROJECT_MANAGER_APPROVAL_ID_TO_NAME = "xzd_project_manager_approval_id_to_name";
/**
* 新中大-立项及成本-成本预算-总体计划成本id转名称
*/
String XZD_CBYS_ZJHCB_ID_TO_NAME = "xzd_cbys_zjhcb_id_to_name";
/**
* 新中大-设计合同信息id转name
*/
String XZD_SJ_CONTRACT_INFO_ID_TO_NAME = "xzd_sj_contract_info_id_to_name";
}

View File

@ -1,23 +1,23 @@
package org.dromara.common.translation.core.impl;
import lombok.AllArgsConstructor;
import org.dromara.common.core.service.XzdSupplierInfoService;
import org.dromara.common.core.service.XzdCbysZjhcbService;
import org.dromara.common.core.service.XzdProjectManagerApprovalService;
import org.dromara.common.translation.annotation.TranslationType;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.common.translation.core.TranslationInterface;
@AllArgsConstructor
//@TranslationType(type = TransConstant.XZD_KHXX_ID_TO_NAME)
public class XzdSupplierInfoImpl implements TranslationInterface<String> {
private final XzdSupplierInfoService xzdSupplierInfoService;
@TranslationType(type = TransConstant.XZD_CBYS_ZJHCB_ID_TO_NAME)
public class XzdCbysZjhcbImpl implements TranslationInterface<String> {
private final XzdCbysZjhcbService xzdCbysZjhcbService;
@Override
public String translation(Object key, String other) {
if (key instanceof String ids) {
return xzdSupplierInfoService.selectNmaeByIds(ids);
return xzdCbysZjhcbService.selectNmaeByIds(ids);
} else if (key instanceof Long id) {
return xzdSupplierInfoService.selectNmaeByIds(id.toString());
return xzdCbysZjhcbService.selectNmaeByIds(id.toString());
}
return null;
}

View File

@ -0,0 +1,27 @@
package org.dromara.common.translation.core.impl;
import lombok.AllArgsConstructor;
import org.dromara.common.core.service.XzdContractMachineryService;
import org.dromara.common.core.service.XzdJsCgJungonService;
import org.dromara.common.translation.annotation.TranslationType;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.common.translation.core.TranslationInterface;
@AllArgsConstructor
@TranslationType(type = TransConstant.XZD_PURCHASE_JXXIE_ID_TO_NAME)
public class XzdJXHTTranslation implements TranslationInterface<String> {
private final XzdContractMachineryService xzdContractMachineryService;
@Override
public String translation(Object key, String other) {
if (key instanceof String ids) {
return xzdContractMachineryService.selectNmaeByIds(ids);
} else if (key instanceof Long id) {
return xzdContractMachineryService.selectNmaeByIds(id.toString());
}
return null;
}
}

View File

@ -0,0 +1,23 @@
package org.dromara.common.translation.core.impl;
import lombok.AllArgsConstructor;
import org.dromara.common.core.service.XzdProjectManagerApprovalService;
import org.dromara.common.translation.annotation.TranslationType;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.common.translation.core.TranslationInterface;
@AllArgsConstructor
@TranslationType(type = TransConstant.XZD_PROJECT_MANAGER_APPROVAL_ID_TO_NAME)
public class XzdProjectManagerApprovalImpl implements TranslationInterface<String> {
private final XzdProjectManagerApprovalService xzdProjectManagerApprovalService;
@Override
public String translation(Object key, String other) {
if (key instanceof String ids) {
return xzdProjectManagerApprovalService.selectNmaeByIds(ids);
} else if (key instanceof Long id) {
return xzdProjectManagerApprovalService.selectNmaeByIds(id.toString());
}
return null;
}
}

View File

@ -0,0 +1,24 @@
package org.dromara.common.translation.core.impl;
import lombok.AllArgsConstructor;
import org.dromara.common.core.service.XzdSjContractInfoService;
import org.dromara.common.core.service.XzdSupplierOpenBankService;
import org.dromara.common.translation.annotation.TranslationType;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.common.translation.core.TranslationInterface;
@AllArgsConstructor
@TranslationType(type = TransConstant.XZD_SJ_CONTRACT_INFO_ID_TO_NAME)
public class XzdSjContractInfoImpl implements TranslationInterface<String> {
private final XzdSjContractInfoService xzdSjContractInfoService;
@Override
public String translation(Object key, String other) {
if (key instanceof String ids) {
return xzdSjContractInfoService.selectNameByIds(ids);
} else if (key instanceof Long id) {
return xzdSjContractInfoService.selectNameByIds(id.toString());
}
return null;
}
}

View File

@ -8,7 +8,10 @@ org.dromara.common.translation.core.impl.ProjectNameTranslationImpl
org.dromara.common.translation.core.impl.XzdCustomerinformationImpl
org.dromara.common.translation.core.impl.XzdProjectImpl
org.dromara.common.translation.core.impl.XzdPurchaseContractInformationImpl
org.dromara.common.translation.core.impl.XzdSupplierInfoImpl
org.dromara.common.translation.core.impl.XzdJsCgJungonImpl
org.dromara.common.translation.core.impl.XzdCsContractInformationImpl
org.dromara.common.translation.core.impl.XzdSupplierOpenBankImpl
org.dromara.common.translation.core.impl.XzdProjectManagerApprovalImpl
org.dromara.common.translation.core.impl.XzdCbysZjhcbImpl
org.dromara.common.translation.core.impl.XzdJXHTTranslation
org.dromara.common.translation.core.impl.XzdSjContractInfoImpl

View File

@ -45,8 +45,7 @@ public class PlusWebSocketInterceptor implements HandshakeInterceptor {
String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY);
String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
String projectIdStr = ServletUtils.getRequest().getParameter("projectId");
Long projectId = Long.parseLong(projectIdStr);
String projectIdStr = ServletUtils.getRequest().getParameter(LoginHelper.PROJECT_KEY);
if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
// token 无效
throw NotLoginException.newInstance(StpUtil.getLoginType(),
@ -55,7 +54,10 @@ public class PlusWebSocketInterceptor implements HandshakeInterceptor {
}
attributes.put(LOGIN_USER_KEY, loginUser);
attributes.put(PROJECT_ID,projectId);
if (projectIdStr != null && !projectIdStr.isEmpty()) {
Long projectId = Long.parseLong(projectIdStr);
attributes.put(PROJECT_ID,projectId);
}
return true;
} catch (NotLoginException e) {
log.error("WebSocket 认证失败'{}',无法访问系统资源", e.getMessage());

View File

@ -29,10 +29,36 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- TwelveMonkeys ImageIO 扩展 -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-core</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-webp</artifactId>
<version>3.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.sejda.imageio/webp-imageio -->
<dependency>
<groupId>org.sejda.imageio</groupId>
<artifactId>webp-imageio</artifactId>
<version>0.1.6</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>5.6.2</version>
</dependency>
<!-- Java WebSocket 标准API -->
<!-- <dependency>-->
<!-- <groupId>javax.websocket</groupId>-->

View File

@ -0,0 +1,61 @@
package org.dromara.ai.advisor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClientMessageAggregator;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.CallAdvisor;
import org.springframework.ai.chat.client.advisor.api.CallAdvisorChain;
import org.springframework.ai.chat.client.advisor.api.StreamAdvisor;
import org.springframework.ai.chat.client.advisor.api.StreamAdvisorChain;
import reactor.core.publisher.Flux;
/**
* 自定义日志拦截器
*
* @author lilemy
* @date 2025-11-04 10:15
*/
@Slf4j
public class CustomLoggerAdvisor implements CallAdvisor, StreamAdvisor {
private void before(ChatClientRequest request) {
log.info("AI 请求参数:{}", request.prompt());
}
private void observeAfter(ChatClientResponse response) {
if (response.chatResponse() != null) {
log.info("AI 响应结果:{}", response.chatResponse().getResult().getOutput().getText());
}
}
@Override
public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
before(chatClientRequest);
ChatClientResponse chatClientResponse = callAdvisorChain.nextCall(chatClientRequest);
observeAfter(chatClientResponse);
return chatClientResponse;
}
@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest, StreamAdvisorChain streamAdvisorChain) {
before(chatClientRequest);
Flux<ChatClientResponse> chatClientResponseFlux = streamAdvisorChain.nextStream(chatClientRequest);
return (new ChatClientMessageAggregator()).aggregateChatClientResponse(chatClientResponseFlux, this::observeAfter);
}
/**
* Return the name of the advisor.
*
* @return the advisor name.
*/
@Override
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public int getOrder() {
return 0;
}
}

View File

@ -0,0 +1,116 @@
package org.dromara.ai.chat;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.ai.advisor.CustomLoggerAdvisor;
import org.dromara.ai.chatmemory.FileBasedChatMemory;
import org.dromara.ai.domain.AIChatMemory;
import org.dromara.ai.service.IAIChatMemoryService;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import java.util.concurrent.CompletableFuture;
/**
* @author lilemy
* @date 2025-11-04 09:34
*/
@Slf4j
@Component
public class DashScopeChat {
@Resource
private DashScopeSimpleChat dashScopeSimpleChat;
@Resource
private IAIChatMemoryService chatMemoryService;
private final ChatClient chatClient;
private static final String DEFAULT_PROMPT =
"你是一名智能助手,代号为“煤球”。回答时不要提及自身身份或角色设定,除非用户主动询问;请直接提供清晰、准确、专业的回答。";
private static final String DEFAULT_FILE_DIR = System.getProperty("user.dir") + "/chat-memory";
public DashScopeChat(ChatModel dashScopeChatModel) {
// 初始化基于文件的对话记忆
ChatMemory chatMemory = new FileBasedChatMemory(DEFAULT_FILE_DIR);
chatClient = ChatClient.builder(dashScopeChatModel)
.defaultSystem(DEFAULT_PROMPT)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build(),
// 自定义日志输出
new CustomLoggerAdvisor()
).build();
}
/**
* AI 对话,流式输出
*
* @param message 用户输入
* @param chatId 会话id
* @return 流式输出结果
*/
public Flux<String> doChatStream(String message, String chatId, Boolean isFirst) {
Long userId = LoginHelper.getUserId();
return chatClient
.prompt()
.user(message)
.advisors(spec -> spec.param(ChatMemory.CONVERSATION_ID, chatId))
.stream()
.content()// 收集所有 token生成完整回复
.collectList()
.flatMapMany(tokens -> {
String aiResponse = String.join("", tokens);
// 异步生成标题
generateChatTitleAsync(chatId, message, aiResponse, userId);
// 返回完整的流结果
return Flux.fromIterable(tokens);
});
}
/**
* 异步生成标题
*
* @param chatId 会话id
* @param userMessage 用户输入
* @param aiResponse AI回复
* @param userId 用户id
*/
private void generateChatTitleAsync(String chatId, String userMessage, String aiResponse, Long userId) {
CompletableFuture.runAsync(() -> {
try {
// 先判断一下当前聊天是否存在
Long count = chatMemoryService.lambdaQuery()
.eq(AIChatMemory::getUserId, userId)
.eq(AIChatMemory::getFileName, chatId)
.count();
if (count > 0) {
return;
}
// 构建生成标题的提示词
String prompt = String.format("""
请以陈述句的形式总结下面这段用户与AI的对话生成一个简短的标题不超过10个字
用户:%s
AI%s
""", userMessage, aiResponse);
String title = dashScopeSimpleChat.doChat(prompt);
log.info("用户:{} 生成标题成功:{} -> {}", userId, chatId, title);
// 保存对话数据
AIChatMemory memory = new AIChatMemory();
memory.setUserId(userId);
memory.setFileName(chatId);
memory.setFirstQuestion(title);
chatMemoryService.save(memory);
} catch (Exception e) {
log.error("生成标题失败", e);
}
});
}
}

View File

@ -0,0 +1,36 @@
package org.dromara.ai.chat;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Component;
/**
* @author lilemy
* @date 2025-11-04 15:26
*/
@Component
public class DashScopeSimpleChat {
private final ChatClient dashScopeChatClient;
public DashScopeSimpleChat(ChatClient.Builder chatClientBuilder) {
this.dashScopeChatClient = chatClientBuilder
// 设置 ChatClient 中 ChatModel 的 Options 参数
.defaultOptions(
DashScopeChatOptions.builder()
.withTopP(0.7)
.build()
)
.build();
}
/**
* AI 对话
*
* @param message 用户输入
* @return 响应结果
*/
public String doChat(String message) {
return dashScopeChatClient.prompt(message).call().content();
}
}

View File

@ -0,0 +1,89 @@
package org.dromara.ai.chatmemory;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import lombok.extern.slf4j.Slf4j;
import org.objenesis.strategy.StdInstantiatorStrategy;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 基于文件持久化的对话记忆
*/
@Slf4j
public class FileBasedChatMemory implements ChatMemory {
private final String BASE_DIR;
private static final Kryo kryo = new Kryo();
static {
kryo.setRegistrationRequired(false);
// 设置实例化策略
kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
}
// 构造对象时,指定文件保存目录
public FileBasedChatMemory(String dir) {
this.BASE_DIR = dir;
File baseDir = new File(dir);
if (!baseDir.exists()) {
baseDir.mkdirs();
}
}
@Override
public void add(String conversationId, List<Message> messages) {
List<Message> conversationMessages = getOrCreateConversation(conversationId);
conversationMessages.addAll(messages);
saveConversation(conversationId, conversationMessages);
}
@Override
public List<Message> get(String conversationId) {
List<Message> messages = getOrCreateConversation(conversationId);
log.info("获取对话:{}", messages);
return messages;
}
@Override
public void clear(String conversationId) {
File file = getConversationFile(conversationId);
if (file.exists()) {
file.delete();
}
}
private List<Message> getOrCreateConversation(String conversationId) {
File file = getConversationFile(conversationId);
List<Message> messages = new ArrayList<>();
if (file.exists()) {
try (Input input = new Input(new FileInputStream(file))) {
messages = kryo.readObject(input, ArrayList.class);
} catch (IOException e) {
log.error("读取对话失败", e);
}
}
return messages;
}
private void saveConversation(String conversationId, List<Message> messages) {
File file = getConversationFile(conversationId);
try (Output output = new Output(new FileOutputStream(file))) {
kryo.writeObject(output, messages);
} catch (IOException e) {
log.error("保存对话失败", e);
}
}
private File getConversationFile(String conversationId) {
return new File(BASE_DIR, conversationId + ".kryo");
}
}

View File

@ -0,0 +1,49 @@
package org.dromara.ai.controller;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.dromara.ai.chat.DashScopeChat;
import org.dromara.ai.chatmemory.FileBasedChatMemory;
import org.dromara.ai.domain.dto.AIChatReq;
import org.dromara.common.core.domain.R;
import org.springframework.ai.chat.messages.Message;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.util.List;
/**
* @author lilemy
* @date 2025-10-23 11:32
*/
@Slf4j
@Validated
@RestController
@RequestMapping("/ai/chat")
public class AIChatController {
@Resource
private DashScopeChat dashScopeChat;
/**
* ChatClient 流式调用
*/
@GetMapping("/stream")
public Flux<String> streamChat(@Validated AIChatReq req, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
return dashScopeChat.doChatStream(req.getQuery(), req.getChatId(), req.getIsFirst());
}
/**
* 对话记录
*/
@GetMapping("/history")
public R<List<Message>> getChatHistory(String chatId) {
FileBasedChatMemory memory = new FileBasedChatMemory(System.getProperty("user.dir") + "/chat-memory");
return R.ok(memory.get(chatId));
}
}

View File

@ -0,0 +1,94 @@
package org.dromara.ai.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.ai.domain.dto.AIChatMemoryQueryReq;
import org.dromara.ai.domain.dto.AIChatMemoryUpdateReq;
import org.dromara.ai.domain.vo.AIChatMemoryVo;
import org.dromara.ai.service.IAIChatMemoryService;
import org.dromara.common.core.domain.R;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* AI 对话记录信息
*
* @author lilemy
* @date 2025-11-04
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/ai/chatMemory")
public class AIChatMemoryController extends BaseController {
private final IAIChatMemoryService aiChatMemoryService;
/**
* 查询AI 对话记录信息列表
*/
@SaCheckPermission("ai:chatMemory:list")
@GetMapping("/list")
public TableDataInfo<AIChatMemoryVo> list(AIChatMemoryQueryReq req, PageQuery pageQuery) {
return aiChatMemoryService.queryPageList(req, pageQuery);
}
/**
* 导出AI 对话记录信息列表
*/
@SaCheckPermission("ai:chatMemory:export")
@Log(title = "AI 对话记录信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(AIChatMemoryQueryReq req, HttpServletResponse response) {
List<AIChatMemoryVo> list = aiChatMemoryService.queryList(req);
ExcelUtil.exportExcel(list, "AI 对话记录信息", AIChatMemoryVo.class, response);
}
/**
* 获取AI 对话记录信息详细信息
*
* @param id 主键
*/
@SaCheckPermission("ai:chatMemory:query")
@GetMapping("/{id}")
public R<AIChatMemoryVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(aiChatMemoryService.queryById(id));
}
/**
* 修改 AI 对话记录信息
*/
@SaCheckPermission("ai:chatMemory:edit")
@Log(title = "AI 对话记录信息", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> updateAIChatMemory(@Validated AIChatMemoryUpdateReq req) {
return toAjax(aiChatMemoryService.updateByReq(req));
}
/**
* 删除AI 对话记录信息
*
* @param ids 主键串
*/
@SaCheckPermission("ai:chatMemory:remove")
@Log(title = "AI 对话记录信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(aiChatMemoryService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -1,51 +0,0 @@
package org.dromara.ai.controller;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
/**
* @author lilemy
* @date 2025-10-23 11:32
*/
@Validated
@RestController
@RequestMapping("/ai")
public class AIController {
private static final String DEFAULT_PROMPT = "你是一个博学的智能聊天助手,请根据用户提问回答!";
private final ChatClient dashScopeChatClient;
public AIController(ChatClient.Builder chatClientBuilder) {
this.dashScopeChatClient = chatClientBuilder
.defaultSystem(DEFAULT_PROMPT)
// 实现 Logger 的 Advisor
.defaultAdvisors(
new SimpleLoggerAdvisor()
)
// 设置 ChatClient 中 ChatModel 的 Options 参数
.defaultOptions(
DashScopeChatOptions.builder()
.withTopP(0.7)
.build()
)
.build();
}
/**
* ChatClient 流式调用
*/
@GetMapping("/stream/chat")
public Flux<String> streamChat(@RequestParam(value = "query", defaultValue = "你好,很高兴认识你,能简单介绍一下自己吗?") String query, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
return dashScopeChatClient.prompt(query).stream().content();
}
}

View File

@ -0,0 +1,52 @@
package org.dromara.ai.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
* AI 对话记录信息对象 ai_chat_memory
*
* @author lilemy
* @date 2025-11-04
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("ai_chat_memory")
public class AIChatMemory extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 用户id
*/
private Long userId;
/**
* 文件名
*/
private String fileName;
/**
* 第一条问题
*/
private String firstQuestion;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,32 @@
package org.dromara.ai.domain.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lilemy
* @date 2025-11-04 15:19
*/
@Data
public class AIChatMemoryQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = -4090176451164739134L;
/**
* 用户id
*/
private Long userId;
/**
* 文件名
*/
private String fileName;
/**
* 第一条问题
*/
private String firstQuestion;
}

View File

@ -0,0 +1,34 @@
package org.dromara.ai.domain.dto;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lilemy
* @date 2025-11-05 11:28
*/
@Data
public class AIChatMemoryUpdateReq implements Serializable {
@Serial
private static final long serialVersionUID = 6541297164616819137L;
/**
* 主键
*/
@NotNull(message = "主键不能为空")
private Long id;
/**
* 第一条问题
*/
private String firstQuestion;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,37 @@
package org.dromara.ai.domain.dto;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lilemy
* @date 2025-11-05 09:31
*/
@Data
public class AIChatReq implements Serializable {
@Serial
private static final long serialVersionUID = -4669223630531267889L;
/**
* 聊天内容
*/
@NotBlank(message = "请输入内容")
private String query;
/**
* 会话id
*/
@NotBlank(message = "请输入会话id")
private String chatId;
/**
* 是否首次对话
*/
@NotNull(message = "请选择是否首次对话")
private Boolean isFirst;
}

View File

@ -0,0 +1,58 @@
package org.dromara.ai.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.ai.domain.AIChatMemory;
import java.io.Serial;
import java.io.Serializable;
/**
* AI 对话记录信息视图对象 ai_chat_memory
*
* @author lilemy
* @date 2025-11-04
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = AIChatMemory.class)
public class AIChatMemoryVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ExcelProperty(value = "主键")
private Long id;
/**
* 用户id
*/
@ExcelProperty(value = "用户id")
private Long userId;
/**
* 文件名
*/
@ExcelProperty(value = "文件名")
private String fileName;
/**
* 第一条问题
*/
@ExcelProperty(value = "第一条问题")
private String firstQuestion;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@ -0,0 +1,15 @@
package org.dromara.ai.mapper;
import org.dromara.ai.domain.AIChatMemory;
import org.dromara.ai.domain.vo.AIChatMemoryVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* AI 对话记录信息Mapper接口
*
* @author lilemy
* @date 2025-11-04
*/
public interface AIChatMemoryMapper extends BaseMapperPlus<AIChatMemory, AIChatMemoryVo> {
}

View File

@ -0,0 +1,63 @@
package org.dromara.ai.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.ai.domain.AIChatMemory;
import org.dromara.ai.domain.dto.AIChatMemoryQueryReq;
import org.dromara.ai.domain.dto.AIChatMemoryUpdateReq;
import org.dromara.ai.domain.vo.AIChatMemoryVo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import java.util.Collection;
import java.util.List;
/**
* AI 对话记录信息Service接口
*
* @author lilemy
* @date 2025-11-04
*/
public interface IAIChatMemoryService extends IService<AIChatMemory> {
/**
* 查询AI 对话记录信息
*
* @param id 主键
* @return AI 对话记录信息
*/
AIChatMemoryVo queryById(Long id);
/**
* 分页查询AI 对话记录信息列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return AI 对话记录信息分页列表
*/
TableDataInfo<AIChatMemoryVo> queryPageList(AIChatMemoryQueryReq bo, PageQuery pageQuery);
/**
* 查询符合条件的AI 对话记录信息列表
*
* @param bo 查询条件
* @return AI 对话记录信息列表
*/
List<AIChatMemoryVo> queryList(AIChatMemoryQueryReq bo);
/**
* 修改 AI 对话记录信息
*
* @param req 修改参数
* @return 是否修改成功
*/
Boolean updateByReq(AIChatMemoryUpdateReq req);
/**
* 校验并批量删除AI 对话记录信息信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -0,0 +1,150 @@
package org.dromara.ai.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dromara.ai.domain.AIChatMemory;
import org.dromara.ai.domain.dto.AIChatMemoryQueryReq;
import org.dromara.ai.domain.dto.AIChatMemoryUpdateReq;
import org.dromara.ai.domain.vo.AIChatMemoryVo;
import org.dromara.ai.mapper.AIChatMemoryMapper;
import org.dromara.ai.service.IAIChatMemoryService;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* AI 对话记录信息Service业务层处理
*
* @author lilemy
* @date 2025-11-04
*/
@Slf4j
@Service
public class AIChatMemoryServiceImpl extends ServiceImpl<AIChatMemoryMapper, AIChatMemory>
implements IAIChatMemoryService {
/**
* 查询AI 对话记录信息
*
* @param id 主键
* @return AI 对话记录信息
*/
@Override
public AIChatMemoryVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 分页查询AI 对话记录信息列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return AI 对话记录信息分页列表
*/
@Override
public TableDataInfo<AIChatMemoryVo> queryPageList(AIChatMemoryQueryReq req, PageQuery pageQuery) {
LambdaQueryWrapper<AIChatMemory> lqw = buildQueryWrapper(req);
Page<AIChatMemoryVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的AI 对话记录信息列表
*
* @param req 查询条件
* @return AI 对话记录信息列表
*/
@Override
public List<AIChatMemoryVo> queryList(AIChatMemoryQueryReq req) {
LambdaQueryWrapper<AIChatMemory> lqw = buildQueryWrapper(req);
return baseMapper.selectVoList(lqw);
}
/**
* 修改 AI 对话记录信息
*
* @param req 修改参数
* @return 是否修改成功
*/
@Override
public Boolean updateByReq(AIChatMemoryUpdateReq req) {
AIChatMemory oldChatMemory = this.getById(req.getId());
if (oldChatMemory == null) {
throw new ServiceException("数据不存在", HttpStatus.NOT_FOUND);
}
AIChatMemory update = new AIChatMemory();
BeanUtils.copyProperties(req, update);
return this.updateById(update);
}
private LambdaQueryWrapper<AIChatMemory> buildQueryWrapper(AIChatMemoryQueryReq req) {
LambdaQueryWrapper<AIChatMemory> lqw = Wrappers.lambdaQuery();
lqw.orderByDesc(AIChatMemory::getId);
lqw.eq(req.getUserId() != null, AIChatMemory::getUserId, req.getUserId());
lqw.like(StringUtils.isNotBlank(req.getFileName()), AIChatMemory::getFileName, req.getFileName());
lqw.eq(StringUtils.isNotBlank(req.getFirstQuestion()), AIChatMemory::getFirstQuestion, req.getFirstQuestion());
return lqw;
}
/**
* 校验并批量删除AI 对话记录信息信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
List<AIChatMemory> aiChatMemories = this.listByIds(ids);
if (aiChatMemories.size() != ids.size()) {
throw new ServiceException("数据不存在");
}
// 暂存文件路径
List<File> filesToDelete = new ArrayList<>();
for (AIChatMemory mem : aiChatMemories) {
if (StringUtils.isNotBlank(mem.getFileName())) {
File file = new File(System.getProperty("user.dir")
+ "/chat-memory/", mem.getFileName());
try {
// 防止目录穿越
if (file.getCanonicalPath().startsWith(
new File(System.getProperty("user.dir") + "/chat-memory").getCanonicalPath())) {
filesToDelete.add(file);
} else {
log.warn("危险的 filename 路径被拒绝删除: {}", mem.getFileName());
}
} catch (IOException e) {
log.warn("filename 获取失败: {}", mem.getFileName());
throw new ServiceException("文件获取失败: " + mem.getFileName());
}
}
}
// 删除数据库
boolean b = baseMapper.deleteByIds(ids) > 0;
if (!b) {
throw new ServiceException("数据库删除失败");
}
// 删除文件(非事务,不影响数据库逻辑)
for (File f : filesToDelete) {
if (f.exists() && !FileUtils.del(f)) {
log.warn("文件删除失败: {}", f.getAbsolutePath());
}
}
return true;
}
}

View File

@ -2,6 +2,7 @@ package org.dromara.bidding.controller;
import java.util.List;
import cn.dev33.satoken.annotation.SaMode;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
@ -50,7 +51,7 @@ public class BusBiddingUserController extends BaseController {
/**
* 查询招投标人员列表
*/
@SaCheckPermission("bidding:biddingUser:getUser")
@SaCheckPermission(value = {"bidding:biddingUser:list","bidding:biddingUser:query","bidding:biddingUser:add"},mode = SaMode.OR)
@GetMapping("/getUser")
public R<List<SysUser>> getUser() {
return R.ok(busBiddingUserService.getUser());

View File

@ -8,6 +8,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;

View File

@ -0,0 +1,106 @@
package org.dromara.bigscreen.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.bigscreen.domain.dto.BusBwlBo;
import org.dromara.bigscreen.domain.vo.BusBwlVo;
import org.dromara.bigscreen.service.IBusBwlService;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 备忘录
*
* @author Lion Li
* @date 2025-11-04
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/bwl/bwl")
public class BusBwlController extends BaseController {
private final IBusBwlService busBwlService;
/**
* 查询备忘录列表
*/
// @SaCheckPermission("bwl:bwl:list")
@GetMapping("/list")
public TableDataInfo<BusBwlVo> list(BusBwlBo bo, PageQuery pageQuery) {
return busBwlService.queryPageList(bo, pageQuery);
}
/**
* 导出备忘录列表
*/
@SaCheckPermission("bwl:bwl:export")
@Log(title = "备忘录", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(BusBwlBo bo, HttpServletResponse response) {
List<BusBwlVo> list = busBwlService.queryList(bo);
ExcelUtil.exportExcel(list, "备忘录", BusBwlVo.class, response);
}
/**
* 获取备忘录详细信息
*
* @param id 主键
*/
@SaCheckPermission("bwl:bwl:query")
@GetMapping("/{id}")
public R<BusBwlVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(busBwlService.queryById(id));
}
/**
* 新增备忘录
*/
@SaCheckPermission("bwl:bwl:add")
@Log(title = "备忘录", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody BusBwlBo bo) {
return toAjax(busBwlService.insertByBo(bo));
}
/**
* 修改备忘录
*/
@SaCheckPermission("bwl:bwl:edit")
@Log(title = "备忘录", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody BusBwlBo bo) {
return toAjax(busBwlService.updateByBo(bo));
}
/**
* 删除备忘录
*
* @param ids 主键串
*/
@SaCheckPermission("bwl:bwl:remove")
@Log(title = "备忘录", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(busBwlService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,106 @@
package org.dromara.bigscreen.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.bigscreen.domain.dto.BusSygjBo;
import org.dromara.bigscreen.domain.vo.BusSygjVo;
import org.dromara.bigscreen.service.IBusSygjService;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 实用工具
*
* @author Lion Li
* @date 2025-11-05
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/bigscreen/sygj")
public class BusSygjController extends BaseController {
private final IBusSygjService busSygjService;
/**
* 查询实用工具列表
*/
// @SaCheckPermission("bigscreen:sygj:list")
@GetMapping("/list")
public TableDataInfo<BusSygjVo> list(BusSygjBo bo, PageQuery pageQuery) {
return busSygjService.queryPageList(bo, pageQuery);
}
/**
* 导出实用工具列表
*/
@SaCheckPermission("bigscreen:sygj:export")
@Log(title = "实用工具", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(BusSygjBo bo, HttpServletResponse response) {
List<BusSygjVo> list = busSygjService.queryList(bo);
ExcelUtil.exportExcel(list, "实用工具", BusSygjVo.class, response);
}
/**
* 获取实用工具详细信息
*
* @param id 主键
*/
@SaCheckPermission("bigscreen:sygj:query")
@GetMapping("/{id}")
public R<BusSygjVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(busSygjService.queryById(id));
}
/**
* 新增实用工具
*/
@SaCheckPermission("bigscreen:sygj:add")
@Log(title = "实用工具", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody BusSygjBo bo) {
return toAjax(busSygjService.insertByBo(bo));
}
/**
* 修改实用工具
*/
@SaCheckPermission("bigscreen:sygj:edit")
@Log(title = "实用工具", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody BusSygjBo bo) {
return toAjax(busSygjService.updateByBo(bo));
}
/**
* 删除实用工具
*
* @param ids 主键串
*/
@SaCheckPermission("bigscreen:sygj:remove")
@Log(title = "实用工具", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(busSygjService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,106 @@
package org.dromara.bigscreen.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.bigscreen.domain.dto.BusWjzxBo;
import org.dromara.bigscreen.domain.vo.BusWjzxVo;
import org.dromara.bigscreen.service.IBusWjzxService;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 文件中心
*
* @author Lion Li
* @date 2025-11-05
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/bigscreen/wjzx")
public class BusWjzxController extends BaseController {
private final IBusWjzxService busWjzxService;
/**
* 查询文件中心列表
*/
// @SaCheckPermission("bigscreen:wjzx:list")
@GetMapping("/list")
public TableDataInfo<BusWjzxVo> list(BusWjzxBo bo, PageQuery pageQuery) {
return busWjzxService.queryPageList(bo, pageQuery);
}
/**
* 导出文件中心列表
*/
@SaCheckPermission("bigscreen:wjzx:export")
@Log(title = "文件中心", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(BusWjzxBo bo, HttpServletResponse response) {
List<BusWjzxVo> list = busWjzxService.queryList(bo);
ExcelUtil.exportExcel(list, "文件中心", BusWjzxVo.class, response);
}
/**
* 获取文件中心详细信息
*
* @param id 主键
*/
@SaCheckPermission("bigscreen:wjzx:query")
@GetMapping("/{id}")
public R<BusWjzxVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(busWjzxService.queryById(id));
}
/**
* 新增文件中心
*/
@SaCheckPermission("bigscreen:wjzx:add")
@Log(title = "文件中心", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody BusWjzxBo bo) {
return toAjax(busWjzxService.insertByBo(bo));
}
/**
* 修改文件中心
*/
@SaCheckPermission("bigscreen:wjzx:edit")
@Log(title = "文件中心", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody BusWjzxBo bo) {
return toAjax(busWjzxService.updateByBo(bo));
}
/**
* 删除文件中心
*
* @param ids 主键串
*/
@SaCheckPermission("bigscreen:wjzx:remove")
@Log(title = "文件中心", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(busWjzxService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -4,12 +4,44 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.ai.chat.DashScopeChat;
import org.dromara.ai.chatmemory.FileBasedChatMemory;
import org.dromara.ai.domain.dto.AIChatMemoryQueryReq;
import org.dromara.ai.domain.dto.AIChatMemoryUpdateReq;
import org.dromara.ai.domain.dto.AIChatReq;
import org.dromara.ai.domain.vo.AIChatMemoryVo;
import org.dromara.ai.service.IAIChatMemoryService;
import org.dromara.bigscreen.domain.dto.BusBwlBo;
import org.dromara.bigscreen.domain.dto.BusSygjBo;
import org.dromara.bigscreen.domain.dto.BusWjzxBo;
import org.dromara.bigscreen.domain.dto.TaskInfoDto;
import org.dromara.bigscreen.domain.vo.*;
import org.dromara.bigscreen.service.IBusBwlService;
import org.dromara.bigscreen.service.IBusSygjService;
import org.dromara.bigscreen.service.IBusWjzxService;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.dto.UserDTO;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.patch.domain.bo.PdMasterBo;
import org.dromara.patch.domain.vo.PdMasterBymiAndQt;
import org.dromara.patch.service.IPdMasterService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.system.domain.SysMenu;
import org.dromara.system.domain.vo.RouterVo;
import org.dromara.system.service.impl.SysMenuServiceImpl;
import org.dromara.system.service.impl.SysUserServiceImpl;
import org.dromara.warm.flow.core.FlowEngine;
import org.dromara.warm.flow.core.entity.User;
@ -19,19 +51,24 @@ import org.dromara.warm.flow.orm.mapper.FlowDefinitionMapper;
import org.dromara.workflow.domain.bo.FlowTaskBo;
import org.dromara.workflow.domain.vo.FlowTaskVo;
import org.dromara.workflow.mapper.FlwTaskMapper;
import org.springframework.ai.chat.messages.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
/**
* 个人首页接口
*/
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/personalHome")
public class PersonalHomeController extends BaseController {
@ -42,14 +79,120 @@ public class PersonalHomeController extends BaseController {
@Autowired
private SysUserServiceImpl userService;
private final IBusWjzxService busWjzxService;
private final IBusSygjService busSygjService;
@Autowired
private IPdMasterService pdMasterService;
private final IBusBwlService busBwlService;
@Resource
private DashScopeChat dashScopeChat;
@Resource
private IAIChatMemoryService aiChatMemoryService;
@Resource
private IBusProjectService projectService;
private final SysMenuServiceImpl sysMenuService;
// region AI 模块
/**
* 获取新 AI 对话聊天id
*/
@GetMapping("/ai/chat/new")
public R<String> getNewAIChat() {
return R.ok(UUID.randomUUID().toString());
}
/**
* AI 对话流式调用
*/
@GetMapping("/ai/chat/stream")
public Flux<String> streamChat(@Validated AIChatReq req, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
return dashScopeChat.doChatStream(req.getQuery(), req.getChatId(), req.getIsFirst());
}
/**
* 获取 AI 对话记录
*/
@GetMapping("/ai/chat/history")
public R<List<Message>> getChatHistory(String chatId) {
FileBasedChatMemory memory = new FileBasedChatMemory(System.getProperty("user.dir") + "/chat-memory");
return R.ok(memory.get(chatId));
}
/**
* 查询 AI 对话记录信息列表
*/
@GetMapping("/ai/chatMemory/list")
public TableDataInfo<AIChatMemoryVo> listAIChatMemory(AIChatMemoryQueryReq req, PageQuery pageQuery) {
return aiChatMemoryService.queryPageList(req, pageQuery);
}
/**
* 获取 AI 对话记录信息详细信息
*
* @param id 主键
*/
@GetMapping("/ai/chatMemory/{id}")
public R<AIChatMemoryVo> getAIChatMemoryInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(aiChatMemoryService.queryById(id));
}
/**
* 修改 AI 对话记录信息
*/
@Log(title = "AI 对话记录信息", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/ai/chatMemory")
public R<Void> updateAIChatMemory(@Validated AIChatMemoryUpdateReq req) {
return toAjax(aiChatMemoryService.updateByReq(req));
}
/**
* 删除 AI 对话记录信息
*
* @param ids 主键串
*/
@Log(title = "AI 对话记录信息", businessType = BusinessType.DELETE)
@DeleteMapping("/ai/chatMemory/{ids}")
public R<Void> removeAIChatMemory(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(aiChatMemoryService.deleteWithValidByIds(List.of(ids), true));
}
// endregion
/**
* 获取我的项目信息
*/
@GetMapping("/getMyProjectInfo")
public R<List<MyProjectInfoVo>> getMyProjectInfoList() {
return R.ok(projectService.getMyProjectInfo());
}
/**
* 首页待办事项
*
* @param projectId
* @return
*/
@GetMapping("/getTaskList")
public R<List<FlowTaskVo>> getTaskList(FlowTaskBo flowTaskBo) {
public R<TaskInfoDto> getTaskList(String projectId) {
TaskInfoDto taskInfoDto = new TaskInfoDto();
QueryWrapper<FlowTaskBo> queryWrapper = new QueryWrapper<>();
List<Long> definitionIds = new ArrayList<>();
if (!"0".equals(flowTaskBo.getProjectId())){
if (!"0".equals(projectId)) {
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>()
.select(FlowDefinition::getId)
.like(FlowDefinition::getFlowCode, flowTaskBo.getProjectId()));
.like(FlowDefinition::getFlowCode, projectId));
if (flowDefinitions != null && !flowDefinitions.isEmpty()) {
flowDefinitions.forEach(flowDefinition -> {
definitionIds.add(flowDefinition.getId());
@ -63,7 +206,36 @@ public class PersonalHomeController extends BaseController {
queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr());
queryWrapper.in("t.flow_status", BusinessStatusEnum.WAITING.getStatus());
List<FlowTaskVo> page = this.getFlowTaskDefinitionIdsVoPage(definitionIds, queryWrapper);
return R.ok(page);
//根据createTime过滤出本周数据
// 获取本周一和本周日
LocalDate today = LocalDate.now();
LocalDate monday = today.with(DayOfWeek.MONDAY);
LocalDate sunday = today.with(DayOfWeek.SUNDAY);
// 筛选本周数据
List<FlowTaskVo> weeklyTasks = page.stream()
.filter(task -> {
Date createTime = task.getCreateTime(); // 假设字段名为createTime
if (createTime != null) {
LocalDate createLocalDate = createTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
return !createLocalDate.isBefore(monday) && !createLocalDate.isAfter(sunday);
}
return false;
})
.toList();
taskInfoDto.setList(page);
taskInfoDto.setTotal((long) page.size());
taskInfoDto.setWeekCount((long) weeklyTasks.size());
BusPdSjVo busPdSjVo = pdMasterService.queryPageListByDate();
BusWjzxSjDateVo busWjzxSjDateVo = busWjzxService.queryWjzx();
taskInfoDto.setBusWjzxSjDateVo(busWjzxSjDateVo);
taskInfoDto.setBusPdSjVo(busPdSjVo);
return R.ok(taskInfoDto);
}
private List<FlowTaskVo> getFlowTaskDefinitionIdsVoPage(List<Long> definitionIds, QueryWrapper<FlowTaskBo> queryWrapper) {
@ -97,4 +269,56 @@ public class PersonalHomeController extends BaseController {
return map;
}
/**
* 查询实用工具列表
*/
// @SaCheckPermission("bigscreen:sygj:list")
@GetMapping("/listsygj")
public TableDataInfo<BusSygjVo> listsygj(BusSygjBo bo, PageQuery pageQuery) {
return busSygjService.queryPageList(bo, pageQuery);
}
/**
* 查询文件中心列表
*/
// @SaCheckPermission("bigscreen:wjzx:list")
@GetMapping("/listBywjzx")
public TableDataInfo<BusWjzxVo> listBywjzx(BusWjzxBo bo, PageQuery pageQuery) {
return busWjzxService.queryPageList(bo, pageQuery);
}
/**
* 查询派单列表
*/
// @SaCheckPermission("patch:master:list")
@GetMapping("/listPd")
public PdMasterBymiAndQt listPd(PdMasterBo bo, PageQuery pageQuery) {
return pdMasterService.queryPageListBy(bo, pageQuery);
}
/**
* 查询备忘录列表
*/
// @SaCheckPermission("bwl:bwl:list")
@GetMapping("/listbwl")
public TableDataInfo<BusBwlVo> listbwl(BusBwlBo bo, PageQuery pageQuery) {
return busBwlService.queryPageList(bo, pageQuery);
}
/**
* 获取部门树
*/
@GetMapping("/deptTree")
public R<List<RouterVo>> deptTree() {
// SysRole role = roleMapper.selectById(1);
List<SysMenu> menus = sysMenuService.selectMenuTreeByUserId(LoginHelper.getUserId(), null);
// menus = menus.stream().filter(menu -> "2".equals(menu.getMenuSource())).collect(Collectors.toList());
menus = menus.stream().filter(menu -> "1".equals(menu.getMenuSource())).collect(Collectors.toList());
return R.ok(sysMenuService.buildMenus(menus));
}
}

View File

@ -53,6 +53,7 @@ import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
@ -211,6 +212,22 @@ public class ProjectBigScreenController extends BaseController {
return R.ok(projectBigScreenService.getProjectPeople(projectId));
}
/**
* 查询项目人员情况
*/
// @SaCheckPermission("project:big:screen")
@GetMapping("/ue/people/{projectId}")
public R<ProjectPeopleVo> getProjectPeopleUe(@NotNull(message = "主键不能为空")
@PathVariable Long projectId) {
final Long tdyq = 1897160897167638529L;
final Long tdeq = 1968506669544656898L;
if (Objects.equals(projectId, tdeq) || Objects.equals(projectId, tdyq)) {
return R.ok(projectBigScreenService.getProjectPeopleTianDong());
} else {
return R.ok(projectBigScreenService.getProjectPeople(projectId));
}
}
/**
* 查询项目形象进度
*/

View File

@ -0,0 +1,150 @@
package org.dromara.bigscreen.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.bigscreen.domain.SysRoleWork;
import org.dromara.bigscreen.domain.bo.SysRoleWorkBo;
import org.dromara.bigscreen.domain.vo.SysRoleWorkVo;
import org.dromara.bigscreen.service.impl.SysRoleWorkServiceImpl;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.project.domain.vo.project.BusProjectVo;
import org.dromara.system.domain.vo.SysRoleVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 角色流程对应
*
* @author Lion Li
* @date 2025-11-06
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/bigscreen/roleWork")
public class SysRoleWorkController extends BaseController {
private final SysRoleWorkServiceImpl sysRoleWorkService;
/**
* 查询角色流程对应列表
*/
@GetMapping("/list")
public TableDataInfo<SysRoleWorkVo> list(SysRoleWorkBo bo, PageQuery pageQuery) {
return sysRoleWorkService.queryPageList(bo, pageQuery);
}
/**
* 导出角色流程对应列表
*/
@SaCheckPermission("bigscreen:roleWork:export")
@Log(title = "角色流程对应", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(SysRoleWorkBo bo, HttpServletResponse response) {
List<SysRoleWorkVo> list = sysRoleWorkService.queryList(bo);
ExcelUtil.exportExcel(list, "角色流程对应", SysRoleWorkVo.class, response);
}
/**
* 获取角色流程对应详细信息
*
* @param id 主键
*/
@SaCheckPermission("bigscreen:roleWork:query")
@GetMapping("/{id}")
public R<SysRoleWorkVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(sysRoleWorkService.queryById(id));
}
/**
* 新增角色流程对应
*/
@SaCheckPermission("bigscreen:roleWork:add")
@Log(title = "角色流程对应", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody SysRoleWorkBo bo) {
return toAjax(sysRoleWorkService.insertByBo(bo));
}
/**
* 修改角色流程对应
*/
@SaCheckPermission("bigscreen:roleWork:edit")
@Log(title = "角色流程对应", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysRoleWorkBo bo) {
return toAjax(sysRoleWorkService.updateByBo(bo));
}
/**
* 删除角色流程对应
*
* @param ids 主键串
*/
@SaCheckPermission("bigscreen:roleWork:remove")
@Log(title = "角色流程对应", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(sysRoleWorkService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 获取当前用户在制定项目下有流程的角色列表
*/
@GetMapping("/getRoleList/{projectId}")
public R<List<SysRoleVo>> getRoleList(@PathVariable("projectId") Long projectId) {
return R.ok(sysRoleWorkService.getRoleList(projectId));
}
/**
* 判断当前用户在所有项目下所有角色是否有角色流程
*/
@GetMapping("/isHaveValue")
public R<Boolean> isHaveValue() {
return R.ok(sysRoleWorkService.isHaveValue(LoginHelper.getUserId()));
}
/**
* 根据用户和项目判断是否有角色流程
*/
@GetMapping("/getRoleWork/{projectId}")
public R<Boolean> getRoleWorkByProject(@PathVariable("projectId") Long projectId) {
return R.ok(sysRoleWorkService.isHaveValueByProject(projectId));
}
/**
* 获取角色对应流程 弃用
*/
@GetMapping("/getRoleToWork/{projectId}")
public R<SysRoleWork> getRoleWork(@PathVariable("projectId") Long projectId) {
return R.ok(sysRoleWorkService.getRoleWork(projectId));
}
/**
* 获取有对应流程并且包含角色列表的项目列表
*/
@GetMapping("/getProjectRoles")
public R<List<BusProjectVo>> getProjectRoles() {
return R.ok(sysRoleWorkService.getProjectRoles());
}
}

View File

@ -0,0 +1,39 @@
package org.dromara.bigscreen.controller;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.bigscreen.domain.vo.ProjectPeopleVo;
import org.dromara.bigscreen.service.ProjectBigScreenService;
import org.dromara.common.core.domain.R;
import org.dromara.project.domain.vo.project.BusProjectVo;
import org.dromara.project.service.IBusProjectService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* UE大屏
*
* @author Lion Li
* @date 2025-11-04
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/UE/screen")
public class UEController {
@Resource
private IBusProjectService projectService;
@GetMapping("/projectInfo/{projectId}")
public R<BusProjectVo> getProjectPeople(@NotNull(message = "主键不能为空")
@PathVariable Long projectId) {
return R.ok(projectService.selectById(projectId));
}
}

View File

@ -1,58 +0,0 @@
package org.dromara.bigscreen.domain;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class BusAttendanceByGo {
private Long id; // 主键ID
private String userName; // 人员姓名
private String pacePhoto; // 人脸照
private Long projectId; // 项目id
private String createBy; // 创建者
private String updateBy; // 更新者
private LocalDateTime createdAt; // 创建时间
private LocalDateTime updatedAt; // 更新时间
private LocalDateTime deletedAt; // 删除时间
private String clockOn; // 上午打卡
private String clockOff; // 下午打卡
private String printingDate; // 年月日打卡时间
private String isPinch; // 1正常,2迟到,3早退,4缺勤,5补卡
private String openid; // 微信id
private String pinchOpenId; // 代打id
private String clockRecord; // 多次打卡时间记录
private String pinchUserName; // 代打人姓名
private String commuter; // 上下班1上班 2下班
private String punchRange; // 打卡范围
private BigDecimal dailyWage; // 日薪
private String lng; // 经度
private String lat; // 纬度
private String location; // 逆编码地址信息
private LocalDateTime missing; // 缺卡统一处理时间
}

View File

@ -0,0 +1,58 @@
package org.dromara.bigscreen.domain;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* 备忘录对象 bus_bwl
*
* @author Lion Li
* @date 2025-11-04
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("bus_bwl")
public class BusBwl extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 备忘录ID
*/
@TableId(value = "id")
private Long id;
/**
* 标题
*/
private String title;
/**
* 内容
*/
private String content;
/**
* 状态0:未完成 1已完成
*/
private Long status;
/**
* 计划开始时间
*/
private Date jhkssj;
/**
* 计划结束时间
*/
private Date jhjssj;
}

View File

@ -1,91 +0,0 @@
package org.dromara.bigscreen.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("bus_construction_user")
public class BusConstructionUser {
@TableId(type = IdType.AUTO)
private Long id; // 主键ID
private String openid; // 微信id
private String nickName; // 微信名称
private Long teamId; // 班组id
private String headIcon; // 登陆照片
private String pacePhoto; // 人脸照
private String userName; // 人员姓名
private Long projectId; // 项目id
private String status; // 状态0在职 1离职-字典position_status
private String isPinch; // 是否代打
private String ifManagement; // 是否班组管理
private String createBy; // 创建者
private String updateBy; // 更新者
private LocalDateTime createdAt; // 创建时间
private LocalDateTime updatedAt; // 更新时间
private LocalDateTime deletedAt; // 删除时间
private String phone; // 电话
private String sex; // 1:男,2女,3保密
private String sfzNation; // 身份证民族
private String sfzNumber; // 身份证号码
private String sfzStart; // 身份证有效开始期
private String sfzEnd; // 身份证有效结束期
private String sfzSite; // 身份证地址
private String sfzBirth; // 身份证出生日期
private String nativePlace; // 籍贯
private String yhkNumber; // 银行卡号
private String yhkOpeningBank; // 开户行
private String yhkCardholder; // 持卡人
private String typeOfWork; // 工种(字典)
private String clock; // 打卡(1启用打卡 2禁止打卡)
private Long labourserviceId; // 劳务公司id
private String entryDate; // 入场时间
private String leaveDate; // 离场时间
private BigDecimal salary; // 薪水为0表示无效
private String projectRecord; // 是否开启项目备案1开启 2不开启
private String wxOrPc; // 哪添加的1表示pc 2表示小程序
private String subscription; // 消息订阅状态1订阅 2无订阅
private String devNum; // 安全帽设备标识
}

View File

@ -1,52 +0,0 @@
package org.dromara.bigscreen.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 企业大事记
*/
@Data
@TableName("bus_corporate_events")
public class BusCorporateEvents {
@TableId(type = IdType.AUTO)
private Long id;
/**
* 标题
*/
private String headline;
/**
* 内容
*/
private String content;
/**
* 创建人
*/
private Long createdBy;
/**
* 更新人
*/
private Long updatedBy;
/**
* 创建时间
*/
private LocalDateTime createdAt;
/**
* 更新时间
*/
private LocalDateTime updatedAt;
/**
* 删除时间(软删除标记)
*/
private LocalDateTime deletedAt;
}

View File

@ -1,31 +0,0 @@
package org.dromara.bigscreen.domain;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class BusProjectTeamByGo {
private Long id; // 主键id
private Long projectId; // 项目id
private String name; // 班组名称
private String isClockIn; // 范围内打卡0范围内打卡 1任何地点打卡
private String punchRange; // 打卡范围(id串)
private String remark; // 备注
private String createBy; // 创建者
private String updateBy; // 更新者
private Long createDept; // 创建部门
private LocalDateTime createTime; // 创建时间
private LocalDateTime updateTime; // 更新时间
}

View File

@ -1,25 +0,0 @@
package org.dromara.bigscreen.domain;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class BusProjectTeamMemberByGo {
private Long id; // 主键id
private Long teamId; // 班组id
private Long projectId; // 项目id
private Long memberId; // 施工人员id
private String postId; // 岗位0普通员工1组长
private String remark; // 备注
private LocalDateTime createTime; // 创建时间
private LocalDateTime updateTime; // 更新时间
}

View File

@ -0,0 +1,67 @@
package org.dromara.bigscreen.domain;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* 实用工具对象 bus_sygj
*
* @author Lion Li
* @date 2025-11-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("bus_sygj")
public class BusSygj extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId(value = "id")
private Long id;
/**
* 工具名
*/
private String gjm;
/**
* 工具路径
*/
private String gjUrl;
/**
* 图片id
*
* */
private Long imgId;
/**
* 图片路径
* */
private String imgUrl;
/**
* 审核标志
*/
private String auditStatus;
/**
* 工具类型 1内部 2外部
*/
private String type;
/**
* 功能描述
*/
private String gnms;
}

View File

@ -1,35 +0,0 @@
package org.dromara.bigscreen.domain;
import lombok.Data;
import java.util.Date;
@Data
public class BusTour {
private Long id; // 主键ID
private Long projectId; // 项目id
private String tourCategory; // 类别字典(如:无人机识别、监控拍摄)
private String tourType; // 类型字典(如:安全帽、安全带)
private String picture; // 图片路径
private Integer num; // 违规数量
private String describe; // 故障描述
private Date createdAt; // 创建时间
private Date updatedAt; // 更新时间
private Date deletedAt; // 删除时间
private String tableName; // 表名
private Long tableId; // 表id
private String sxtName; // 摄像头名称
}

View File

@ -0,0 +1,57 @@
package org.dromara.bigscreen.domain;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* 文件中心对象 bus_wjzx
*
* @author Lion Li
* @date 2025-11-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("bus_wjzx")
public class BusWjzx extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId(value = "id")
private Long id;
/**
* 文件名
*/
private String wjm;
/**
* 文件上传路径
*/
private String wjId;
/**
* 文件类型
*/
private String wjlx;
/**
* 文件描述
*/
private String gnms;
/**
* 审核标志
*/
private String auditStatus;
}

View File

@ -1,34 +0,0 @@
package org.dromara.bigscreen.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("sys_project_introduce")
public class SysProjectIntroduce {
@TableId(type = IdType.AUTO)
private Long id; // 主键id
private Long projectId; // 项目id
private String headline; // 标题
private String richText; // 富文本
private String createdBy; // 创建人
private String updatedBy; // 更新人
private LocalDateTime createdAt; // 创建时间
private LocalDateTime updatedAt; // 更新时间
private LocalDateTime deletedAt; // 删除时间
private String files; // 附件
}

View File

@ -0,0 +1,57 @@
package org.dromara.bigscreen.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
* 角色流程对应对象 sys_role_work
*
* @author Lion Li
* @date 2025-11-06
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_role_work")
public class SysRoleWork extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(value = "id")
private Long id;
/**
* 绑定角色ID
*/
private Long roleId;
/**
* 绑定项目id
*/
private Long projectId;
/**
* 流程名称
*/
private String lcmc;
/**
* 流程描述
*/
private String lcms;
/**
* 流程详情
*/
private String lcxq;
}

View File

@ -0,0 +1,51 @@
package org.dromara.bigscreen.domain.bo;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.bigscreen.domain.SysRoleWork;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* 角色流程对应业务对象 sys_role_work
*
* @author Lion Li
* @date 2025-11-06
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = SysRoleWork.class, reverseConvertGenerate = false)
public class SysRoleWorkBo extends BaseEntity {
/**
* id
*/
private Long id;
/**
* 绑定角色ID
*/
private Long roleId;
/**
* 绑定项目id
*/
private Long projectId;
/**
* 流程名称
*/
private String lcmc;
/**
* 流程描述
*/
private String lcms;
/**
* 流程详情
*/
private String lcxq;
}

View File

@ -0,0 +1,57 @@
package org.dromara.bigscreen.domain.dto;
import org.dromara.bigscreen.domain.BusBwl;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 备忘录业务对象 bus_bwl
*
* @author Lion Li
* @date 2025-11-04
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = BusBwl.class, reverseConvertGenerate = false)
public class BusBwlBo extends BaseEntity {
/**
* 备忘录ID
*/
@NotNull(message = "备忘录ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 标题
*/
private String title;
/**
* 内容
*/
private String content;
/**
* 状态0:未完成 1已完成
*/
private Long status;
/**
* 计划开始时间
*/
private Date jhkssj;
/**
* 计划结束时间
*/
private Date jhjssj;
}

View File

@ -0,0 +1,62 @@
package org.dromara.bigscreen.domain.dto;
import org.dromara.bigscreen.domain.BusSygj;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 实用工具业务对象 bus_sygj
*
* @author Lion Li
* @date 2025-11-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = BusSygj.class, reverseConvertGenerate = false)
public class BusSygjBo extends BaseEntity {
/**
*
*/
@NotNull(message = "不能为空", groups = { EditGroup.class })
private Long id;
/**
* 工具名
*/
private String gjm;
/**
* 工具路径
*/
private String gjUrl;
private Long imgId;
/**
* 图片路径
* */
private String imgUrl;
/**
* 审核标志
*/
private String auditStatus;
/**
* 工具类型 1内部 2外部
*/
private String type;
/**
* 功能描述
*/
private String gnms;
}

View File

@ -0,0 +1,55 @@
package org.dromara.bigscreen.domain.dto;
import org.dromara.bigscreen.domain.BusWjzx;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 文件中心业务对象 bus_wjzx
*
* @author Lion Li
* @date 2025-11-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = BusWjzx.class, reverseConvertGenerate = false)
public class BusWjzxBo extends BaseEntity {
/**
*
*/
@NotNull(message = "不能为空", groups = { EditGroup.class })
private Long id;
/**
* 文件名
*/
private String wjm;
/**
* 文件上传路径
*/
private String wjId;
/**
* 文件描述
*/
private String gnms;
/**
* 文件类型
*/
private String wjlx;
/**
* 审核标志
*/
private String auditStatus;
}

View File

@ -0,0 +1,39 @@
package org.dromara.bigscreen.domain.dto;
import lombok.Data;
import org.dromara.bigscreen.domain.vo.BusPdSjVo;
import org.dromara.bigscreen.domain.vo.BusWjzxSjDateVo;
import org.dromara.workflow.domain.vo.FlowTaskVo;
import java.io.Serializable;
import java.util.List;
@Data
public class TaskInfoDto implements Serializable {
/**
* 列表对象
*/
private List<FlowTaskVo> list;
/**
* 总数
*/
private Long total;
/**
* 本周数
*/
private Long weekCount;
/**
*知识库上传数据
*/
private BusWjzxSjDateVo busWjzxSjDateVo;
/**
* 派单数据
*/
private BusPdSjVo busPdSjVo;
}

View File

@ -0,0 +1,71 @@
package org.dromara.bigscreen.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.bigscreen.domain.BusBwl;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 备忘录视图对象 bus_bwl
*
* @author Lion Li
* @date 2025-11-04
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = BusBwl.class)
public class BusBwlVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 备忘录ID
*/
@ExcelProperty(value = "备忘录ID")
private Long id;
/**
* 标题
*/
@ExcelProperty(value = "标题")
private String title;
/**
* 内容
*/
@ExcelProperty(value = "内容")
private String content;
/**
* 状态0:未完成 1已完成
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=:未完成,1=:已完成")
private Long status;
/**
* 计划开始时间
*/
@ExcelProperty(value = "计划开始时间")
private Date jhkssj;
/**
* 计划结束时间
*/
@ExcelProperty(value = "计划结束时间")
private Date jhjssj;
}

View File

@ -0,0 +1,19 @@
package org.dromara.bigscreen.domain.vo;
import lombok.Data;
@Data
public class BusPdSjVo {
/**
* 我的派单
*/
private Long wdpdrw;
/**
* 其他派单
*/
private Long qtbmpd;
}

View File

@ -0,0 +1,75 @@
package org.dromara.bigscreen.domain.vo;
import org.dromara.bigscreen.domain.BusSygj;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 实用工具视图对象 bus_sygj
*
* @author Lion Li
* @date 2025-11-05
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = BusSygj.class)
public class BusSygjVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@ExcelProperty(value = "")
private Long id;
/**
* 工具名
*/
@ExcelProperty(value = "工具名")
private String gjm;
/**
* 工具路径
*/
@ExcelProperty(value = "工具路径")
private String gjUrl;
/**
* 审核标志
*/
@ExcelProperty(value = "审核标志")
private String auditStatus;
private Long imgId;
/**
* 图片路径
* */
private String imgUrl;
/**
* 工具类型 1内部 2外部
*/
@ExcelProperty(value = "工具类型 1内部 2外部")
private String type;
/**
* 功能描述
*/
@ExcelProperty(value = "功能描述")
private String gnms;
}

View File

@ -0,0 +1,16 @@
package org.dromara.bigscreen.domain.vo;
import lombok.Data;
@Data
public class BusWjzxSjDateVo {
/**
* 最近上传
*/
private Long zjsc;
/**
* 总数
*/
private Long zs;
}

View File

@ -0,0 +1,67 @@
package org.dromara.bigscreen.domain.vo;
import org.dromara.bigscreen.domain.BusWjzx;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 文件中心视图对象 bus_wjzx
*
* @author Lion Li
* @date 2025-11-05
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = BusWjzx.class)
public class BusWjzxVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@ExcelProperty(value = "")
private Long id;
/**
* 文件名
*/
@ExcelProperty(value = "文件名")
private String wjm;
/**
* 文件上传路径
*/
@ExcelProperty(value = "文件上传路径")
private String wjId;
/**
* 文件描述
*/
private String gnms;
/**
* 文件类型
*/
private String wjlx;
/**
* 审核标志
*/
@ExcelProperty(value = "审核标志")
private String auditStatus;
}

View File

@ -0,0 +1,72 @@
package org.dromara.bigscreen.domain.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
/**
* @author lilemy
* @date 2025-11-06 14:28
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MilestoneVo {
/**
* 主键ID
*/
private Long id;
/**
* 节点名称
*/
private String nodeName;
/**
* 对应项目结构
*/
private Long projectStructure;
/**
* 对应项目结构名称
*/
private String projectStructureName;
/**
* 预计开始时间
*/
private LocalDate planStartDate;
/**
* 预计结束时间
*/
private LocalDate planEndDate;
/**
* 实际开始时间
*/
private LocalDate practicalStartDate;
/**
* 实际结束时间
*/
private LocalDate practicalEndDate;
/**
* 状态
*/
private String status;
/**
* 是否为当前节点(0不是 1是)
*/
private Integer active = 0;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,60 @@
package org.dromara.bigscreen.domain.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
/**
* @author lilemy
* @date 2025-11-06 10:01
*/
@Data
public class MyProjectInfoVo implements Serializable {
@Serial
private static final long serialVersionUID = 2737004515142334438L;
/**
* 项目id
*/
private Long projectId;
/**
* 负责人
*/
private String principal;
/**
* 项目名称
*/
private String projectName;
/**
* 项目概括
*/
private String projectGeneralize;
/**
* 开始时间
*/
private LocalDate StartTime;
/**
* 结束时间
*/
private LocalDate endTime;
/**
* 里程碑
*/
private List<MilestoneVo> milestones;
/**
* 进度
*/
private BigDecimal progress;
}

View File

@ -16,6 +16,11 @@ public class ProjectImageProgressDetailVo implements Serializable {
@Serial
private static final long serialVersionUID = -8317739851423164942L;
/**
* 主键
*/
private Long id;
/**
* 进度名称
*/
@ -36,4 +41,9 @@ public class ProjectImageProgressDetailVo implements Serializable {
*/
private BigDecimal totalProgress;
/**
* 单位
*/
private String unit;
}

View File

@ -0,0 +1,69 @@
package org.dromara.bigscreen.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.bigscreen.domain.SysRoleWork;
import java.io.Serial;
import java.io.Serializable;
/**
* 角色流程对应视图对象 sys_role_work
*
* @author Lion Li
* @date 2025-11-06
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = SysRoleWork.class)
public class SysRoleWorkVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
@ExcelProperty(value = "id")
private Long id;
/**
* 绑定角色ID
*/
@ExcelProperty(value = "绑定角色ID")
private Long roleId;
/**
* 绑定项目id
*/
@ExcelProperty(value = "绑定项目ID")
private Long projectId;
/**
* 角色名称
*/
private String roleName;
/**
* 流程名称
*/
@ExcelProperty(value = "流程名称")
private String lcmc;
/**
* 流程描述
*/
@ExcelProperty(value = "流程描述")
private String lcms;
/**
* 流程详情
*/
@ExcelProperty(value = "流程详情")
private String lcxq;
}

View File

@ -41,7 +41,7 @@ public class RedisMessageListener implements MessageListener {
public void onMessage(Message message, byte[] pattern) {
try {
// 1. 快速日志记录(证明监听到消息)
log.info("【Redis消息监听】收到消息长度{}字节,提交异步处理", message.getBody().length);
// log.info("【Redis消息监听】收到消息长度{}字节,提交异步处理", message.getBody().length);
// 2. 提交给异步服务处理(核心:线程分离,监听线程立即返回)
asyncMessageHandlerService.handleRedisMessageAsync(message);

View File

@ -1,23 +1,20 @@
package org.dromara.bigscreen.manager;
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.websocket.websocket.service.InitOnStartWebSocketServer;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.drone.domain.DroProjectDrone;
import org.dromara.drone.service.IDroProjectDroneService;
import org.dromara.websocket.websocket.service.InitOnStartWebSocketServer;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -44,13 +41,20 @@ public class RedisSubscribeManager {
private IDroProjectDroneService droProjectDroneService;
// 3. 维护已订阅的主题关系key=完整主题如wrj:8UUXN4P00A06NKvalue=对应的PatternTopic
private final Map<String, PatternTopic> subscribedTopics = new ConcurrentHashMap<>();
private final Map<String, ChannelTopic> subscribedTopics = new ConcurrentHashMap<>();
// 定义锁对象
private final Object lock = new Object();
// 注入 RedisConnectionFactory
@Resource
private RedisConnectionFactory redisConnectionFactory;
/**
* 项目启动后立即执行一次订阅(避免等待定时任务首次执行)
*/
@PostConstruct
// @PostConstruct
public void initSubscribe() {
log.info("项目启动初始化Redis订阅...");
// 步骤1从数据库获取最新的主题列表原逻辑getTopicsByKeyPrefix
@ -133,56 +137,58 @@ public class RedisSubscribeManager {
}
@Scheduled(cron = "0/10 * * * * ?")
@Scheduled(cron = "0/10 * * * * ?")
// @JobExecutor(name = "ueWsConnect")
public void ueWsConnect() {
try {
int onlineCount = InitOnStartWebSocketServer.getOnlineCount();
Object object = RedisUtils.getCacheObject("xmjdap:ws");
log.info("开始执行Redis订阅更新定时任务...");
if (onlineCount == 0 && object == null) {
cancelAllSubscribes();
return;
}
if (object != null) {
long oldTime = Long.parseLong(String.valueOf(object));
long now = System.currentTimeMillis();
if (now-oldTime > 300000) {
RedisUtils.deleteObject("xmjdap:ws");
synchronized (lock) { // 确保同一时间只有一个线程修改
try {
int onlineCount = InitOnStartWebSocketServer.getOnlineCount();
Object object = RedisUtils.getCacheObject("xmjdap:ws");
log.info("开始执行Redis订阅更新定时任务...");
if (onlineCount == 0 && object == null) {
cancelAllSubscribes();
return;
}
log.info("Redis时间缓存更新定时任务");
}
// 步骤1从数据库获取最新的主题列表原逻辑getTopicsByKeyPrefix
List<DroProjectDrone> latestKeys = droProjectDroneService.getBaseMapper().selectList(new LambdaQueryWrapper<DroProjectDrone>().groupBy(DroProjectDrone::getDroneSn));
if (latestKeys == null || latestKeys.isEmpty()) {
log.warn("定时任务未获取到任何主题,将取消所有现有订阅");
cancelAllSubscribes();
return;
}
// 步骤2构建最新的完整主题格式wrj:key
Set<String> latestFullTopics = new HashSet<>();
for (DroProjectDrone key : latestKeys) {
latestFullTopics.add("wrj:osd1:" + key.getDroneSn());
latestFullTopics.add("wrj:osd2:" + key.getDroneSn());
latestFullTopics.add("wrj:osd3:" + key.getDroneSn());
if (key.getAirplaneSn() != null && !key.getAirplaneSn().isEmpty()) {
latestFullTopics.add("wrj:osd4:" + key.getAirplaneSn());
if (object != null) {
long oldTime = Long.parseLong(String.valueOf(object));
long now = System.currentTimeMillis();
if (now - oldTime > 300000) {
RedisUtils.deleteObject("xmjdap:ws");
cancelAllSubscribes();
return;
}
log.info("Redis时间缓存更新定时任务");
}
// 步骤1从数据库获取最新的主题列表原逻辑getTopicsByKeyPrefix
List<DroProjectDrone> latestKeys = droProjectDroneService.getBaseMapper().selectList(new LambdaQueryWrapper<DroProjectDrone>().groupBy(DroProjectDrone::getDroneSn));
if (latestKeys == null || latestKeys.isEmpty()) {
log.warn("定时任务未获取到任何主题,将取消所有现有订阅");
cancelAllSubscribes();
return;
}
// 步骤2构建最新的完整主题格式wrj:key
Set<String> latestFullTopics = new HashSet<>();
for (DroProjectDrone key : latestKeys) {
latestFullTopics.add("wrj:osd1:" + key.getDroneSn());
latestFullTopics.add("wrj:osd2:" + key.getDroneSn());
latestFullTopics.add("wrj:osd3:" + key.getDroneSn());
if (key.getAirplaneSn() != null && !key.getAirplaneSn().isEmpty()) {
latestFullTopics.add("wrj:osd4:" + key.getAirplaneSn());
}
}
// 步骤3对比现有订阅删除过期主题
cancelExpiredSubscribes(latestFullTopics);
// 步骤4对比现有订阅新增未订阅的主题
addNewSubscribes(latestFullTopics);
log.info("Redis订阅更新完成当前已订阅主题数{}", subscribedTopics.size());
} catch (Exception e) {
log.error("Redis订阅更新定时任务执行失败", e);
// 异常时不修改现有订阅,避免误删
}
// 步骤3对比现有订阅删除过期主题
cancelExpiredSubscribes(latestFullTopics);
// 步骤4对比现有订阅新增未订阅的主题
addNewSubscribes(latestFullTopics);
log.info("Redis订阅更新完成当前已订阅主题数{}", subscribedTopics.size());
} catch (Exception e) {
log.error("Redis订阅更新定时任务执行失败", e);
// 异常时不修改现有订阅,避免误删
}
}
@ -190,24 +196,30 @@ public class RedisSubscribeManager {
* 取消过期的订阅(现有订阅不在最新列表中的主题)
*/
public void cancelExpiredSubscribes(Set<String> latestFullTopics) {
// 遍历现有订阅,找出需要删除的主题
Set<String> expiredTopics = subscribedTopics.keySet().stream()
synchronized (lock) { // 确保同一时间只有一个线程修改
if (!redisMessageListenerContainer.isRunning()) {
log.error("RedisMessageListenerContainer 未运行,无法取消订阅");
return;
}
// 遍历现有订阅,找出需要删除的主题
Set<String> expiredTopics = subscribedTopics.keySet().stream()
.filter(topic -> !latestFullTopics.contains(topic))
.collect(Collectors.toSet());
if (expiredTopics.isEmpty()) {
log.info("无过期订阅主题,无需删除");
return;
}
if (expiredTopics.isEmpty()) {
log.info("无过期订阅主题,无需删除");
return;
}
// 取消每个过期主题的订阅
for (String expiredTopic : expiredTopics) {
PatternTopic topic = subscribedTopics.get(expiredTopic);
if (topic != null) {
// 从容器中移除监听器(取消订阅)
redisMessageListenerContainer.removeMessageListener(redisMessageListenerAdapter, topic);
subscribedTopics.remove(expiredTopic);
log.info("已取消过期订阅:{}", expiredTopic);
// 取消每个过期主题的订阅
for (String expiredTopic : expiredTopics) {
ChannelTopic topic = subscribedTopics.get(expiredTopic);
if (topic != null) {
// 从容器中移除监听器(取消订阅)
redisMessageListenerContainer.removeMessageListener(redisMessageListenerAdapter, topic);
subscribedTopics.remove(expiredTopic);
log.info("已取消过期订阅:{}", expiredTopic);
}
}
}
}
@ -216,23 +228,41 @@ public class RedisSubscribeManager {
* 新增未订阅的主题(最新列表中有但现有订阅没有的主题)
*/
public void addNewSubscribes(Set<String> latestFullTopics) {
// 遍历最新主题,找出需要新增的主题
Set<String> newTopics = latestFullTopics.stream()
synchronized (lock) { // 确保同一时间只有一个线程修改
if (!redisMessageListenerContainer.isRunning()) {
log.error("RedisMessageListenerContainer 未运行,无法添加订阅");
return;
}
// // 测试 Redis 连接
// try (RedisConnection conn = redisConnectionFactory.getConnection()) {
// conn.ping(); // 发送 ping 命令,验证连接
// log.info("Redis 连接正常,可执行命令");
// } catch (Exception e) {
// log.error("Redis 连接失败,无法订阅主题", e);
// return; // 连接失败,终止订阅
// }
// 遍历最新主题,找出需要新增的主题
Set<String> newTopics = latestFullTopics.stream()
.filter(topic -> !subscribedTopics.containsKey(topic))
.collect(Collectors.toSet());
if (newTopics.isEmpty()) {
log.info("无新增订阅主题,无需添加");
return;
}
if (newTopics.isEmpty()) {
log.info("无新增订阅主题,无需添加");
return;
}
// Object delegate = redisMessageListenerAdapter.getDelegate();
// log.info("适配器绑定的监听器实例:{}",
// delegate.getClass().getName());
// 为每个新主题添加订阅
for (String newTopic : newTopics) {
PatternTopic topic = new PatternTopic(newTopic);
// 向容器中添加监听器(新增订阅)
redisMessageListenerContainer.addMessageListener(redisMessageListenerAdapter, topic);
subscribedTopics.put(newTopic, topic);
log.info("已新增订阅:{}", newTopic);
// 为每个新主题添加订阅
for (String newTopic : newTopics) {
ChannelTopic topic = new ChannelTopic(newTopic);
// 向容器中添加监听器(新增订阅)
// log.info("添加订阅前,容器状态:{}", redisMessageListenerContainer.isRunning() ? "运行中" : "已停止");
redisMessageListenerContainer.addMessageListener(redisMessageListenerAdapter, topic);
subscribedTopics.put(newTopic, topic);
log.info("已新增订阅:{}", newTopic);
}
}
}
@ -244,7 +274,7 @@ public class RedisSubscribeManager {
return;
}
// 遍历所有已订阅主题,取消订阅
for (Map.Entry<String, PatternTopic> entry : subscribedTopics.entrySet()) {
for (Map.Entry<String, ChannelTopic> entry : subscribedTopics.entrySet()) {
redisMessageListenerContainer.removeMessageListener(redisMessageListenerAdapter, entry.getValue());
log.info("已取消订阅:{}", entry.getKey());
}

View File

@ -0,0 +1,28 @@
package org.dromara.bigscreen.manager;
import jakarta.annotation.Resource;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* 项目启动完成后执行 Redis 订阅初始化
*/
@Component
public class RedisSubscribeStartupRunner implements ApplicationRunner {
// 注入 Redis 订阅管理器
@Resource
private RedisSubscribeManager redisSubscribeManager;
/**
* 项目完全启动后执行(替代 @PostConstruct
*/
@Override
public void run(ApplicationArguments args) throws Exception {
// 此时 Spring 容器已完全启动,所有组件就绪
redisSubscribeManager.initSubscribe();
}
}

View File

@ -0,0 +1,16 @@
package org.dromara.bigscreen.mapper;
import org.dromara.bigscreen.domain.BusBwl;
import org.dromara.bigscreen.domain.vo.BusBwlVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 备忘录Mapper接口
*
* @author Lion Li
* @date 2025-11-04
*/
public interface BusBwlMapper extends BaseMapperPlus<BusBwl, BusBwlVo> {
}

View File

@ -0,0 +1,15 @@
package org.dromara.bigscreen.mapper;
import org.dromara.bigscreen.domain.BusSygj;
import org.dromara.bigscreen.domain.vo.BusSygjVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 实用工具Mapper接口
*
* @author Lion Li
* @date 2025-11-05
*/
public interface BusSygjMapper extends BaseMapperPlus<BusSygj, BusSygjVo> {
}

View File

@ -0,0 +1,15 @@
package org.dromara.bigscreen.mapper;
import org.dromara.bigscreen.domain.BusWjzx;
import org.dromara.bigscreen.domain.vo.BusWjzxVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 文件中心Mapper接口
*
* @author Lion Li
* @date 2025-11-05
*/
public interface BusWjzxMapper extends BaseMapperPlus<BusWjzx, BusWjzxVo> {
}

View File

@ -0,0 +1,31 @@
package org.dromara.bigscreen.mapper;
import org.apache.ibatis.annotations.Select;
import org.dromara.bigscreen.domain.SysRoleWork;
import org.dromara.bigscreen.domain.vo.SysRoleWorkVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.system.domain.SysUserRole;
import java.util.List;
/**
* 角色流程对应Mapper接口
*
* @author Lion Li
* @date 2025-11-06
*/
public interface SysRoleWorkMapper extends BaseMapperPlus<SysRoleWork, SysRoleWorkVo> {
/**
* 根据登录人id和项目ID获取对应角色
*/
@Select("select * from sys_user_role where user_id = #{userId} and project_id = #{projectId}")
List<SysUserRole> getRoleList(Long userId,Long projectId);
/**
* 根据登录人id获取所有项目下所有角色
*/
@Select("select * from sys_user_role where user_id = #{userId}")
List<SysUserRole> getAllRoleList(Long userId);
}

View File

@ -0,0 +1,73 @@
package org.dromara.bigscreen.service;
import org.dromara.bigscreen.domain.BusBwl;
import org.dromara.bigscreen.domain.dto.BusBwlBo;
import org.dromara.bigscreen.domain.vo.BusBwlVo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Collection;
import java.util.List;
/**
* 备忘录Service接口
*
* @author Lion Li
* @date 2025-11-04
*/
public interface IBusBwlService extends IService<BusBwl>{
/**
* 查询备忘录
*
* @param id 主键
* @return 备忘录
*/
BusBwlVo queryById(Long id);
/**
* 分页查询备忘录列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 备忘录分页列表
*/
TableDataInfo<BusBwlVo> queryPageList(BusBwlBo bo, PageQuery pageQuery);
/**
* 查询符合条件的备忘录列表
*
* @param bo 查询条件
* @return 备忘录列表
*/
List<BusBwlVo> queryList(BusBwlBo bo);
/**
* 新增备忘录
*
* @param bo 备忘录
* @return 是否新增成功
*/
Boolean insertByBo(BusBwlBo bo);
/**
* 修改备忘录
*
* @param bo 备忘录
* @return 是否修改成功
*/
Boolean updateByBo(BusBwlBo bo);
/**
* 校验并批量删除备忘录信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
TableDataInfo<BusBwlVo> queryPageListbwl(BusBwlBo bo, PageQuery pageQuery);
}

View File

@ -0,0 +1,70 @@
package org.dromara.bigscreen.service;
import org.dromara.bigscreen.domain.dto.BusSygjBo;
import org.dromara.bigscreen.domain.vo.BusSygjVo;
import org.dromara.bigscreen.domain.BusSygj;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Collection;
import java.util.List;
/**
* 实用工具Service接口
*
* @author Lion Li
* @date 2025-11-05
*/
public interface IBusSygjService extends IService<BusSygj>{
/**
* 查询实用工具
*
* @param id 主键
* @return 实用工具
*/
BusSygjVo queryById(Long id);
/**
* 分页查询实用工具列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 实用工具分页列表
*/
TableDataInfo<BusSygjVo> queryPageList(BusSygjBo bo, PageQuery pageQuery);
/**
* 查询符合条件的实用工具列表
*
* @param bo 查询条件
* @return 实用工具列表
*/
List<BusSygjVo> queryList(BusSygjBo bo);
/**
* 新增实用工具
*
* @param bo 实用工具
* @return 是否新增成功
*/
Boolean insertByBo(BusSygjBo bo);
/**
* 修改实用工具
*
* @param bo 实用工具
* @return 是否修改成功
*/
Boolean updateByBo(BusSygjBo bo);
/**
* 校验并批量删除实用工具信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -0,0 +1,76 @@
package org.dromara.bigscreen.service;
import org.dromara.bigscreen.domain.dto.BusWjzxBo;
import org.dromara.bigscreen.domain.vo.BusWjzxSjDateVo;
import org.dromara.bigscreen.domain.vo.BusWjzxVo;
import org.dromara.bigscreen.domain.BusWjzx;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Collection;
import java.util.List;
/**
* 文件中心Service接口
*
* @author Lion Li
* @date 2025-11-05
*/
public interface IBusWjzxService extends IService<BusWjzx>{
/**
* 查询文件中心
*
* @param id 主键
* @return 文件中心
*/
BusWjzxVo queryById(Long id);
/**
* 分页查询文件中心列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 文件中心分页列表
*/
TableDataInfo<BusWjzxVo> queryPageList(BusWjzxBo bo, PageQuery pageQuery); /**
* 分页查询文件中心列表
*
* @return 文件中心分页列表
*/
BusWjzxSjDateVo queryWjzx();
/**
* 查询符合条件的文件中心列表
*
* @param bo 查询条件
* @return 文件中心列表
*/
List<BusWjzxVo> queryList(BusWjzxBo bo);
/**
* 新增文件中心
*
* @param bo 文件中心
* @return 是否新增成功
*/
Boolean insertByBo(BusWjzxBo bo);
/**
* 修改文件中心
*
* @param bo 文件中心
* @return 是否修改成功
*/
Boolean updateByBo(BusWjzxBo bo);
/**
* 校验并批量删除文件中心信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -0,0 +1,70 @@
package org.dromara.bigscreen.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.bigscreen.domain.SysRoleWork;
import org.dromara.bigscreen.domain.bo.SysRoleWorkBo;
import org.dromara.bigscreen.domain.vo.SysRoleWorkVo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import java.util.Collection;
import java.util.List;
/**
* 角色流程对应Service接口
*
* @author Lion Li
* @date 2025-11-06
*/
public interface ISysRoleWorkService extends IService<SysRoleWork>{
/**
* 查询角色流程对应
*
* @param id 主键
* @return 角色流程对应
*/
SysRoleWorkVo queryById(Long id);
/**
* 分页查询角色流程对应列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 角色流程对应分页列表
*/
TableDataInfo<SysRoleWorkVo> queryPageList(SysRoleWorkBo bo, PageQuery pageQuery);
/**
* 查询符合条件的角色流程对应列表
*
* @param bo 查询条件
* @return 角色流程对应列表
*/
List<SysRoleWorkVo> queryList(SysRoleWorkBo bo);
/**
* 新增角色流程对应
*
* @param bo 角色流程对应
* @return 是否新增成功
*/
Boolean insertByBo(SysRoleWorkBo bo);
/**
* 修改角色流程对应
*
* @param bo 角色流程对应
* @return 是否修改成功
*/
Boolean updateByBo(SysRoleWorkBo bo);
/**
* 校验并批量删除角色流程对应信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -60,6 +60,13 @@ public interface ProjectBigScreenService {
*/
ProjectPeopleVo getProjectPeople(Long projectId);
/**
* 获取项目人员(田东一二期)
*
* @return 项目人员
*/
ProjectPeopleVo getProjectPeopleTianDong();
/**
* 获取项目形象进度
*
@ -90,6 +97,8 @@ public interface ProjectBigScreenService {
List<Map<String, Object>> getClientList(Long projectId);
List<String> getUeClientList();
/**
* 更新无人机缓存
*/

View File

@ -43,7 +43,7 @@ public class AsyncMessageHandlerServiceImpl implements IAsyncMessageHandlerServi
try {
// 1. 解析消息体(只解析一次,避免重复操作)
byte[] messageBody = message.getBody();
if (messageBody == null || messageBody.length == 0) {
if (messageBody.length == 0) {
log.warn("【异步消息处理】消息体为空,忽略处理");
return;
}
@ -76,8 +76,8 @@ public class AsyncMessageHandlerServiceImpl implements IAsyncMessageHandlerServi
return;
}
String key = "";
DroProjectDrone droProjectDrone = null;
String key;
DroProjectDrone droProjectDrone;
boolean isOsd4 = false;
// 5. 根据data字段内容判断key类型并查询无人机信息
@ -92,7 +92,7 @@ public class AsyncMessageHandlerServiceImpl implements IAsyncMessageHandlerServi
new LambdaQueryWrapper<DroProjectDrone>()
.eq(DroProjectDrone::getDroneSn, gateway)
);
log.info("【异步消息处理】osd3类型消息gateway{}", gateway);
// log.info("【异步消息处理】osd3类型消息gateway{}", gateway);
// 调用setWs方法非osd4类型
setWs(messageContent, gateway, droProjectDrone, false);
} else {
@ -101,7 +101,7 @@ public class AsyncMessageHandlerServiceImpl implements IAsyncMessageHandlerServi
new LambdaQueryWrapper<DroProjectDrone>()
.eq(DroProjectDrone::getAirplaneSn, gateway)
);
log.info("【异步消息处理】osd4类型消息gateway{}", gateway);
// log.info("【异步消息处理】osd4类型消息gateway{}", gateway);
isOsd4 = true;
// 调用setWs方法osd4类型
setWs(messageContent, gateway, droProjectDrone, true);
@ -109,7 +109,7 @@ public class AsyncMessageHandlerServiceImpl implements IAsyncMessageHandlerServi
// 6. 存储消息到Redis使用Objects.requireNonNull避免空指针
stringRedisTemplate.opsForValue().set(key, Objects.requireNonNull(messageContent));
log.info("【异步消息处理】Redis存储成功key{}", key);
// log.info("【异步消息处理】Redis存储成功key{}", key);
} catch (Exception e) {
// 捕获所有异常,避免线程终止
@ -130,7 +130,7 @@ public class AsyncMessageHandlerServiceImpl implements IAsyncMessageHandlerServi
System.out.println("大屏已推送消息");
}
int onlineCount = InitOnStartWebSocketServer.getOnlineCount();
if (onlineCount > 0){
if (onlineCount > 0) {
String modleId = b ? droProjectDrone.getAirplaneModleId() : droProjectDrone.getDroneModleId();
if (modleId != null) {
String ued = ueStructureJsonMessage(message, modleId);
@ -143,14 +143,14 @@ public class AsyncMessageHandlerServiceImpl implements IAsyncMessageHandlerServi
private String buildPushMessage(String key, String message, Long projectId) {
JSONObject messageObj = new JSONObject();
messageObj.put("type", "wrj_DATA_UPDATE");
messageObj.put("projectId",projectId.toString());
messageObj.put("clientId",key);
messageObj.set("type", "wrj_DATA_UPDATE");
messageObj.set("projectId", projectId.toString());
messageObj.set("clientId", key);
// 位置信息
JSONObject locationObj = new JSONObject();
locationObj.put("latitude", JSONUtil.parseObj(message).getJSONObject("data").get("latitude").toString()); // 纬度
locationObj.put("longitude", JSONUtil.parseObj(message).getJSONObject("data").get("longitude").toString()); // 经度
messageObj.put("location", locationObj);
locationObj.set("latitude", JSONUtil.parseObj(message).getJSONObject("data").get("latitude").toString()); // 纬度
locationObj.set("longitude", JSONUtil.parseObj(message).getJSONObject("data").get("longitude").toString()); // 经度
messageObj.set("location", locationObj);
return messageObj.toString();
}
@ -161,19 +161,19 @@ public class AsyncMessageHandlerServiceImpl implements IAsyncMessageHandlerServi
private String ueStructureJsonMessage(String message, String modelId) {
// 构造消息对象(包含关键信息)
JSONObject messageObj = new JSONObject();
messageObj.put("type", "location"); // 消息类型
messageObj.set("type", "location"); // 消息类型
JSONObject data = new JSONObject();
data.put("id", modelId);
data.set("id", modelId);
// 位置信息
JSONObject position = new JSONObject();
position.put("lat", JSONUtil.parseObj(message).getJSONObject("data").get("latitude").toString()); // 纬度
position.put("lng", JSONUtil.parseObj(message).getJSONObject("data").get("longitude").toString()); // 经度
position.put("alt", JSONUtil.parseObj(message).getJSONObject("data").get("height").toString()); // 海拔
position.set("lat", JSONUtil.parseObj(message).getJSONObject("data").get("latitude")); // 纬度
position.set("lng", JSONUtil.parseObj(message).getJSONObject("data").get("longitude")); // 经度
position.set("alt", JSONUtil.parseObj(message).getJSONObject("data").get("height")); // 海拔
data.put("position", position);
messageObj.put("data", data); // 设备唯一标识
data.set("position", position);
messageObj.set("data", data); // 设备唯一标识
// 转换为String类型返回
return messageObj.toString();

View File

@ -0,0 +1,148 @@
package org.dromara.bigscreen.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.dromara.bigscreen.domain.BusBwl;
import org.dromara.bigscreen.domain.dto.BusBwlBo;
import org.dromara.bigscreen.domain.vo.BusBwlVo;
import org.dromara.bigscreen.mapper.BusBwlMapper;
import org.dromara.bigscreen.service.IBusBwlService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 备忘录Service业务层处理
*
* @author Lion Li
* @date 2025-11-04
*/
@RequiredArgsConstructor
@Service
public class BusBwlServiceImpl extends ServiceImpl<BusBwlMapper, BusBwl> implements IBusBwlService {
private final BusBwlMapper baseMapper;
/**
* 查询备忘录
*
* @param id 主键
* @return 备忘录
*/
@Override
public BusBwlVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 分页查询备忘录列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 备忘录分页列表
*/
@Override
public TableDataInfo<BusBwlVo> queryPageList(BusBwlBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<BusBwl> lqw = buildQueryWrapper(bo);
Page<BusBwlVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
@Override
public TableDataInfo<BusBwlVo> queryPageListbwl(BusBwlBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<BusBwl> lqw = buildQueryWrapper(bo);
lqw.eq(BusBwl::getCreateBy, LoginHelper.getUserId());
Page<BusBwlVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的备忘录列表
*
* @param bo 查询条件
* @return 备忘录列表
*/
@Override
public List<BusBwlVo> queryList(BusBwlBo bo) {
LambdaQueryWrapper<BusBwl> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<BusBwl> buildQueryWrapper(BusBwlBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<BusBwl> lqw = Wrappers.lambdaQuery();
lqw.orderByDesc(BusBwl::getId);
lqw.eq(StringUtils.isNotBlank(bo.getTitle()), BusBwl::getTitle, bo.getTitle());
lqw.eq(StringUtils.isNotBlank(bo.getContent()), BusBwl::getContent, bo.getContent());
lqw.eq(bo.getStatus() != null, BusBwl::getStatus, bo.getStatus());
lqw.eq(bo.getCreateBy() != null, BusBwl::getCreateBy, bo.getCreateBy());
lqw.eq(bo.getJhkssj() != null, BusBwl::getJhkssj, bo.getJhkssj());
lqw.eq(bo.getJhjssj() != null, BusBwl::getJhjssj, bo.getJhjssj());
return lqw;
}
/**
* 新增备忘录
*
* @param bo 备忘录
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(BusBwlBo bo) {
BusBwl add = MapstructUtils.convert(bo, BusBwl.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改备忘录
*
* @param bo 备忘录
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(BusBwlBo bo) {
BusBwl update = MapstructUtils.convert(bo, BusBwl.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(BusBwl entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除备忘录信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

View File

@ -0,0 +1,207 @@
package org.dromara.bigscreen.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dromara.bigscreen.domain.BusWjzx;
import org.dromara.bigscreen.domain.dto.BusSygjBo;
import org.dromara.bigscreen.domain.vo.BusWjzxVo;
import org.dromara.common.core.domain.event.ProcessDeleteEvent;
import org.dromara.common.core.domain.event.ProcessEvent;
import org.dromara.common.core.domain.event.ProcessTaskEvent;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.system.service.impl.SysOssServiceImpl;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.dromara.bigscreen.domain.vo.BusSygjVo;
import org.dromara.bigscreen.domain.BusSygj;
import org.dromara.bigscreen.mapper.BusSygjMapper;
import org.dromara.bigscreen.service.IBusSygjService;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 实用工具Service业务层处理
*
* @author Lion Li
* @date 2025-11-05
*/
@RequiredArgsConstructor
@Service
@Slf4j
public class BusSygjServiceImpl extends ServiceImpl<BusSygjMapper, BusSygj> implements IBusSygjService {
private final BusSygjMapper baseMapper;
private final SysOssServiceImpl sysOssService;
/**
* 查询实用工具
*
* @param id 主键
* @return 实用工具
*/
@Override
public BusSygjVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 分页查询实用工具列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 实用工具分页列表
*/
@Override
public TableDataInfo<BusSygjVo> queryPageList(BusSygjBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<BusSygj> lqw = buildQueryWrapper(bo);
Page<BusSygjVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的实用工具列表
*
* @param bo 查询条件
* @return 实用工具列表
*/
@Override
public List<BusSygjVo> queryList(BusSygjBo bo) {
LambdaQueryWrapper<BusSygj> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<BusSygj> buildQueryWrapper(BusSygjBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<BusSygj> lqw = Wrappers.lambdaQuery();
lqw.orderByDesc(BusSygj::getId);
lqw.like(StringUtils.isNotBlank(bo.getGjm()), BusSygj::getGjm, bo.getGjm());
lqw.eq(StringUtils.isNotBlank(bo.getGjUrl()), BusSygj::getGjUrl, bo.getGjUrl());
lqw.eq(StringUtils.isNotBlank(bo.getAuditStatus()), BusSygj::getAuditStatus, bo.getAuditStatus());
lqw.eq(StringUtils.isNotBlank(bo.getType()), BusSygj::getType, bo.getType());
lqw.eq(StringUtils.isNotBlank(bo.getGnms()), BusSygj::getGnms, bo.getGnms());
lqw.eq(bo.getCreateBy() != null, BusSygj::getCreateBy, bo.getCreateBy());
return lqw;
}
/**
* 新增实用工具
*
* @param bo 实用工具
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(BusSygjBo bo) {
BusSygj add = MapstructUtils.convert(bo, BusSygj.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改实用工具
*
* @param bo 实用工具
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(BusSygjBo bo) {
BusSygj update = MapstructUtils.convert(bo, BusSygj.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(BusSygj entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除实用工具信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
ArrayList<Long> temp = new ArrayList<>();
for (Long id : ids) {
BusSygjVo busSygjVo = baseMapper.selectVoById(id);
temp.add(busSygjVo.getImgId());
}
sysOssService.deleteWithValidByIds(temp, false);
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
* 正常使用只需#processEvent.flowCode=='leave1'
* 示例为了方便则使用startsWith匹配了全部示例key
*
* @param processEvent 参数
*/
@EventListener(condition = "#processEvent.flowCode.endsWith('grsygj')")
public void processPlansHandlErequipmentList(ProcessEvent processEvent) {
log.info("文件中心审核任务执行了{}", processEvent.toString());
String id = processEvent.getBusinessId();
BusSygj vo = baseMapper.selectById(Long.valueOf(id));
if (vo == null) {
return;
}
vo.setAuditStatus(processEvent.getStatus());
this.updateById(vo);
}
/**
* 执行任务创建监听
* 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断
* 在方法中判断流程节点key
* if ("xxx".equals(processTaskEvent.getNodeCode())) {
* //执行业务逻辑
* }
*
* @param processTaskEvent 参数
*/
@EventListener(condition = "#processTaskEvent.flowCode.endsWith('grsygj')")
public void processTaskPlansHandlerEquipmentList(ProcessTaskEvent processTaskEvent) {
log.info("文件中心审核任务创建了{}", processTaskEvent.toString());
}
/**
* 监听删除流程事件
* 正常使用只需#processDeleteEvent.flowCode=='leave1'
* 示例为了方便则使用startsWith匹配了全部示例key
*
* @param processDeleteEvent 参数
*/
@EventListener(condition = "#processDeleteEvent.flowCode.endsWith('grsygj')")
public void processDeletePlansHandlerEquipmentList(ProcessDeleteEvent processDeleteEvent) {
log.info("文件中心删除流程事件,文件中心审核任务执行了{}", processDeleteEvent.toString());
}
}

View File

@ -0,0 +1,214 @@
package org.dromara.bigscreen.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.bigscreen.domain.BusWjzx;
import org.dromara.bigscreen.domain.dto.BusWjzxBo;
import org.dromara.bigscreen.domain.vo.BusWjzxSjDateVo;
import org.dromara.bigscreen.domain.vo.BusWjzxVo;
import org.dromara.bigscreen.mapper.BusWjzxMapper;
import org.dromara.bigscreen.service.IBusWjzxService;
import org.dromara.common.core.domain.event.ProcessDeleteEvent;
import org.dromara.common.core.domain.event.ProcessEvent;
import org.dromara.common.core.domain.event.ProcessTaskEvent;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.system.service.impl.SysOssServiceImpl;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 文件中心Service业务层处理
*
* @author Lion Li
* @date 2025-11-05
*/
@RequiredArgsConstructor
@Service
@Slf4j
public class BusWjzxServiceImpl extends ServiceImpl<BusWjzxMapper, BusWjzx> implements IBusWjzxService {
private final BusWjzxMapper baseMapper;
private final SysOssServiceImpl sysOssService;
/**
* 查询文件中心
*
* @param id 主键
* @return 文件中心
*/
@Override
public BusWjzxVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 分页查询文件中心列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 文件中心分页列表
*/
@Override
public TableDataInfo<BusWjzxVo> queryPageList(BusWjzxBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<BusWjzx> lqw = buildQueryWrapper(bo);
Page<BusWjzxVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
@Override
public BusWjzxSjDateVo queryWjzx() {
BusWjzxSjDateVo busWjzxSjDateVo = new BusWjzxSjDateVo();
Long zjsc = baseMapper.selectCount(new LambdaQueryWrapper<BusWjzx>().ge(BusWjzx::getCreateTime, LocalDate.now()));
Long zs = this.count();
busWjzxSjDateVo.setZs(zs);
busWjzxSjDateVo.setZjsc(zjsc);
return busWjzxSjDateVo;
}
/**
* 查询符合条件的文件中心列表
*
* @param bo 查询条件
* @return 文件中心列表
*/
@Override
public List<BusWjzxVo> queryList(BusWjzxBo bo) {
LambdaQueryWrapper<BusWjzx> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<BusWjzx> buildQueryWrapper(BusWjzxBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<BusWjzx> lqw = Wrappers.lambdaQuery();
lqw.orderByDesc(BusWjzx::getId);
lqw.like(StringUtils.isNotBlank(bo.getWjm()), BusWjzx::getWjm, bo.getWjm());
lqw.eq(StringUtils.isNotBlank(bo.getAuditStatus()), BusWjzx::getAuditStatus, bo.getAuditStatus());
lqw.eq(bo.getCreateBy() != null, BusWjzx::getCreateBy, bo.getCreateBy());
return lqw;
}
/**
* 新增文件中心
*
* @param bo 文件中心
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(BusWjzxBo bo) {
BusWjzx add = MapstructUtils.convert(bo, BusWjzx.class);
validEntityBeforeSave(add);
if (add != null && StringUtils.isNotBlank(add.getWjm())) {
String[] split = add.getWjm().split("\\.");
add.setWjlx(split[split.length - 1]);
}
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改文件中心
*
* @param bo 文件中心
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(BusWjzxBo bo) {
BusWjzx update = MapstructUtils.convert(bo, BusWjzx.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(BusWjzx entity) {
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除文件中心信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
ArrayList<Long> temp = new ArrayList<>();
for (Long id : ids) {
BusWjzxVo busWjzxVo = baseMapper.selectVoById(id);
temp.add(Long.valueOf(busWjzxVo.getWjId()));
}
sysOssService.deleteWithValidByIds(temp, false);
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
* 正常使用只需#processEvent.flowCode=='leave1'
* 示例为了方便则使用startsWith匹配了全部示例key
*
* @param processEvent 参数
*/
@EventListener(condition = "#processEvent.flowCode.endsWith('grwjzx')")
public void processPlansHandlErequipmentList(ProcessEvent processEvent) {
log.info("文件中心审核任务执行了{}", processEvent.toString());
String id = processEvent.getBusinessId();
BusWjzx vo = baseMapper.selectById(Long.valueOf(id));
if (vo == null) {
return;
}
vo.setAuditStatus(processEvent.getStatus());
this.updateById(vo);
}
/**
* 执行任务创建监听
* 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断
* 在方法中判断流程节点key
* if ("xxx".equals(processTaskEvent.getNodeCode())) {
* //执行业务逻辑
* }
*
* @param processTaskEvent 参数
*/
@EventListener(condition = "#processTaskEvent.flowCode.endsWith('grwjzx')")
public void processTaskPlansHandlerEquipmentList(ProcessTaskEvent processTaskEvent) {
log.info("文件中心审核任务创建了{}", processTaskEvent.toString());
}
/**
* 监听删除流程事件
* 正常使用只需#processDeleteEvent.flowCode=='leave1'
* 示例为了方便则使用startsWith匹配了全部示例key
*
* @param processDeleteEvent 参数
*/
@EventListener(condition = "#processDeleteEvent.flowCode.endsWith('grwjzx')")
public void processDeletePlansHandlerEquipmentList(ProcessDeleteEvent processDeleteEvent) {
log.info("文件中心删除流程事件,文件中心审核任务执行了{}", processDeleteEvent.toString());
}
}

View File

@ -16,6 +16,7 @@ import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.utils.BigDecimalUtil;
import org.dromara.contractor.domain.SubConstructionUser;
import org.dromara.contractor.service.ISubConstructionUserService;
import org.dromara.drone.domain.vo.DroProjectDroneVo;
import org.dromara.drone.service.IDroProjectDroneService;
import org.dromara.gps.domain.bo.GpsEquipmentBo;
import org.dromara.gps.domain.vo.GpsEquipmentSonVo;
@ -233,6 +234,91 @@ public class ProjectBigScreenServiceImpl implements ProjectBigScreenService {
return vo;
}
/**
* 获取项目人员
*
* @return 项目人员
*/
@Override
public ProjectPeopleVo getProjectPeopleTianDong() {
final Long tdyq = 1897160897167638529L;
final Long tdeq = 1968506669544656898L;
List<Long> ids = List.of(tdeq, tdyq);
BusProject project = projectService.getById(tdyq);
// 获取大屏数据
ProjectPeopleVo vo = new ProjectPeopleVo();
// 获取施工人员总数
List<SubConstructionUser> list = constructionUserService.lambdaQuery()
.in(SubConstructionUser::getProjectId, ids)
.eq(SubConstructionUser::getUserRole, "0")
.isNotNull(SubConstructionUser::getTeamId).list();
List<Long> sysUserIdList = list.stream().map(SubConstructionUser::getSysUserId).toList();
int count = list.size();
BigDecimal countDec = BigDecimal.valueOf(count);
vo.setPeopleCount(countDec);
// 获取考勤数据
List<Long> attendancePeopleList1 = attendanceService.listAttendancePeopleByProjectId(tdyq);
List<Long> attendancePeopleList2 = attendanceService.listAttendancePeopleByProjectId(tdeq);
List<Long> attendancePeopleList = new ArrayList<>();
attendancePeopleList.addAll(attendancePeopleList1);
attendancePeopleList.addAll(attendancePeopleList2);
BigDecimal attendanceSize = BigDecimal.valueOf(attendancePeopleList.size());
vo.setAttendanceCount(attendanceSize);
// 计算考勤率
vo.setAttendanceRate(BigDecimalUtil.toPercentage(attendanceSize, countDec));
if (count != 0) {
// 统计班组人数
List<BusProjectTeamMember> memberList = projectTeamMemberService.lambdaQuery()
.select(BusProjectTeamMember::getId, BusProjectTeamMember::getTeamId)
.in(BusProjectTeamMember::getProjectId, ids)
.in(BusProjectTeamMember::getMemberId, sysUserIdList)
.list();
Map<Long, List<BusProjectTeamMember>> memberMap = memberList.stream()
.collect(Collectors.groupingBy(BusProjectTeamMember::getTeamId));
// 统计班组考勤数据
Map<Long, List<SubConstructionUser>> userTeamMap = new HashMap<>();
if (CollUtil.isNotEmpty(attendancePeopleList)) {
List<SubConstructionUser> users = constructionUserService.lambdaQuery()
.in(SubConstructionUser::getSysUserId, attendancePeopleList)
.isNotNull(SubConstructionUser::getTeamId)
.list();
userTeamMap = users.stream()
.collect(Collectors.groupingBy(SubConstructionUser::getTeamId));
}
List<BusProjectTeam> teamList = projectTeamService.lambdaQuery()
.in(BusProjectTeam::getProjectId, ids)
.list();
String punchRange = project.getPunchRange();
String punchTime = "";
if (punchRange != null) {
String start = punchRange.split(",")[0];
punchTime = LocalDate.now() + " ";
}
List<ProjectTeamAttendanceVo> listVo = new ArrayList<>();
for (BusProjectTeam projectTeam : teamList) {
ProjectTeamAttendanceVo teamAttendanceVo = new ProjectTeamAttendanceVo();
Long id = projectTeam.getId();
teamAttendanceVo.setId(id);
teamAttendanceVo.setTeamName(projectTeam.getTeamName());
teamAttendanceVo.setAttendanceTime(punchTime);
BigDecimal allNumber = BigDecimal.ZERO;
if (memberMap.containsKey(id)) {
allNumber = BigDecimal.valueOf(memberMap.get(id).size());
}
BigDecimal attendanceNumber = BigDecimal.ZERO;
if (CollUtil.isNotEmpty(userTeamMap) && userTeamMap.containsKey(id)) {
attendanceNumber = BigDecimal.valueOf(userTeamMap.get(id).size());
}
teamAttendanceVo.setAttendanceNumber(attendanceNumber);
teamAttendanceVo.setAllNumber(allNumber);
teamAttendanceVo.setAttendanceRate(BigDecimalUtil.toPercentage(attendanceNumber, allNumber));
listVo.add(teamAttendanceVo);
}
vo.setTeamAttendanceList(listVo);
}
return vo;
}
/**
* 获取项目形象进度
*
@ -437,9 +523,15 @@ public class ProjectBigScreenServiceImpl implements ProjectBigScreenService {
Long projectId = req.getProjectId();
String progressName = req.getProgressName();
checkProject(projectId);
// 获取当前项目的所有子级
List<BusProject> subProjects = projectService.lambdaQuery()
.eq(BusProject::getPId, projectId)
.list();
Set<Long> projectIds = subProjects.stream().map(BusProject::getId).collect(Collectors.toSet());
projectIds.add(projectId);
// 获取对应进度
PgsProgressCategory progressCategory = progressCategoryService.lambdaQuery()
.eq(PgsProgressCategory::getProjectId, projectId)
.in(PgsProgressCategory::getProjectId, projectIds)
.eq(PgsProgressCategory::getName, progressName)
.last("limit 1")
.one();
@ -447,18 +539,38 @@ public class ProjectBigScreenServiceImpl implements ProjectBigScreenService {
return List.of();
}
Long topId = progressCategory.getId();
final List<String> gfcqName = List.of("场地平整", "桩基成孔", "桩基浇筑", "支架安装", "组件安装");
// 查出所有属于该顶级节点的子孙节点
List<PgsProgressCategory> allChildren = progressCategoryService.list(
Wrappers.<PgsProgressCategory>lambdaQuery()
.and(wrapper -> {
.in(progressName.equals("光伏场区"), PgsProgressCategory::getName, gfcqName)
.and(wrapper ->
wrapper.like(PgsProgressCategory::getAncestors, "," + topId + ",")
.or()
.like(PgsProgressCategory::getAncestors, "," + topId);
})
.like(PgsProgressCategory::getAncestors, "," + topId))
);
if (allChildren.isEmpty()) {
return Collections.emptyList();
}
if (progressName.equals("集电线路")) {
Set<Long> parentIds = allChildren.stream()
.map(PgsProgressCategory::getParentId)
.collect(Collectors.toSet());
List<PgsProgressCategory> dierList = allChildren.stream()
.filter(item -> !parentIds.contains(item.getId()))
.toList();
return dierList.stream().map(c -> {
ProjectImageProgressDetailVo vo = new ProjectImageProgressDetailVo();
vo.setId(c.getId());
vo.setUnit(c.getUnit());
vo.setProgressName(c.getName());
vo.setPlanProgress(c.getPlanTotal());
vo.setActualProgress(c.getCompleted());
vo.setTotalProgress(c.getTotal());
return vo;
}).toList();
}
// 判断层级
Set<Long> parentIds = allChildren.stream()
.map(PgsProgressCategory::getParentId)
@ -470,6 +582,8 @@ public class ProjectBigScreenServiceImpl implements ProjectBigScreenService {
if (CollUtil.isEmpty(dierList)) {
return allChildren.stream().map(c -> {
ProjectImageProgressDetailVo vo = new ProjectImageProgressDetailVo();
vo.setId(c.getId());
vo.setUnit(c.getUnit());
vo.setProgressName(c.getName());
vo.setPlanProgress(c.getPlanTotal());
vo.setActualProgress(c.getCompleted());
@ -490,6 +604,8 @@ public class ProjectBigScreenServiceImpl implements ProjectBigScreenService {
BigDecimal total = children.stream().map(PgsProgressCategory::getTotal)
.reduce(BigDecimal.ZERO, BigDecimal::add);
ProjectImageProgressDetailVo vo = new ProjectImageProgressDetailVo();
vo.setId(c.getId());
vo.setUnit(c.getUnit());
vo.setProgressName(c.getName());
vo.setPlanProgress(plan);
vo.setActualProgress(actual);
@ -702,6 +818,111 @@ public class ProjectBigScreenServiceImpl implements ProjectBigScreenService {
return maps;
}
@Override
public List<String> getUeClientList() {
// 获取当天的开始时间00:00:00
LocalDateTime startOfDay = LocalDateTime.now().with(LocalTime.MIN);
// 获取当前时间
LocalDateTime now = LocalDateTime.now();
List<GpsEquipmentSonVo> voList = gpsEquipmentService.getUeClientList(startOfDay, now);
List<GpsEquipmentSonVo> appList = gpsEquipmentService.getUeUserListByProjectId(startOfDay, now);
// List<LocationVo> anqmList = deviceService.getUeUserListByProjectId( startOfDay, now);
// List<OthYs7Device> othYs7DeviceList = othYs7DeviceService.lambdaQuery()
// .list();
List<DroProjectDroneVo> wrjKeys = droProjectDroneService.getUeTopicsByProjectId();
List<String> maps = new ArrayList<>();
if (voList != null && !voList.isEmpty()) {
for (GpsEquipmentSonVo item : voList) {
JSONObject messageObj = new JSONObject();
messageObj.set("type", "location"); // 消息类型
JSONObject data = new JSONObject();
data.set("id", item.getModelId());
// 位置信息
JSONObject position = new JSONObject();
position.set("lat", item.getLocLatitude()); // 纬度
position.set("lng", item.getLocLongitude()); // 经度
position.set("alt", item.getLocAltitude()); // 海拔
data.set("position", position);
messageObj.set("data", data); // 设备唯一标识
maps.add(messageObj.toString());
}
}
if (appList != null && !appList.isEmpty()) {
for (GpsEquipmentSonVo item : appList) {
JSONObject messageObj = new JSONObject();
messageObj.set("type", "location"); // 消息类型
JSONObject data = new JSONObject();
data.set("id", item.getModelId());
// 位置信息
JSONObject position = new JSONObject();
position.set("lat", item.getLocLatitude()); // 纬度
position.set("lng", item.getLocLongitude()); // 经度
position.set("alt", item.getLocAltitude()); // 海拔
data.set("position", position);
messageObj.set("data", data); // 设备唯一标识
maps.add(messageObj.toString());
}
}
if (wrjKeys != null && !wrjKeys.isEmpty()) {
for (DroProjectDroneVo key : wrjKeys) {
Object object = stringRedisTemplate.opsForValue().get("wrj:osd4:" + key.getAirplaneSn());
Object object6 = stringRedisTemplate.opsForValue().get("wrj:osd2:" + key.getDroneSn());
String status = "";
if (object6 != null) {
JSONObject object1 = JSONUtil.parseObj(object6);
status = object1.getJSONObject("data").get("flighttask_step_code").toString();
}
if (object != null) {
JSONObject object1 = JSONUtil.parseObj(object);
JSONObject messageObj = new JSONObject();
messageObj.set("type", "location"); // 消息类型
JSONObject data = new JSONObject();
data.set("id", key.getAirplaneModleId());
// 位置信息
JSONObject position = new JSONObject();
position.set("lat", object1.getJSONObject("data").get("latitude")); // 纬度
position.set("lng", object1.getJSONObject("data").get("longitude")); // 经度
position.set("alt", object1.getJSONObject("data").get("height")); // 海拔
data.set("position", position);
messageObj.set("data", data); // 设备唯一标识
maps.add(messageObj.toString());
} else {
Object object2 = stringRedisTemplate.opsForValue().get("wrj:osd3:" + key);
if (object2 != null) {
JSONObject object3 = JSONUtil.parseObj(object2);
JSONObject messageObj = new JSONObject();
messageObj.set("type", "location"); // 消息类型
JSONObject data = new JSONObject();
data.set("id", key.getDroneModleId());
// 位置信息
JSONObject position = new JSONObject();
position.set("lat", object3.getJSONObject("data").get("latitude")); // 纬度
position.set("lng", object3.getJSONObject("data").get("longitude")); // 经度
position.set("alt", object3.getJSONObject("data").get("height")); // 海拔
data.set("position", position);
messageObj.set("data", data); // 设备唯一标识
maps.add(messageObj.toString());
}
}
}
}
return maps;
}
@Override
public void setWrjHc() {
RedisUtils.setCacheObject("xmjdap:ws", System.currentTimeMillis());

View File

@ -0,0 +1,317 @@
package org.dromara.bigscreen.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.dromara.bigscreen.domain.SysRoleWork;
import org.dromara.bigscreen.domain.bo.SysRoleWorkBo;
import org.dromara.bigscreen.domain.vo.SysRoleWorkVo;
import org.dromara.bigscreen.mapper.SysRoleWorkMapper;
import org.dromara.bigscreen.service.ISysRoleWorkService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.project.domain.dto.project.BusProjectQueryReq;
import org.dromara.project.domain.vo.project.BusProjectVo;
import org.dromara.project.service.impl.BusProjectServiceImpl;
import org.dromara.system.domain.SysUserRole;
import org.dromara.system.domain.vo.SysRoleVo;
import org.dromara.system.service.impl.SysRoleServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 角色流程对应Service业务层处理
*
* @author Lion Li
* @date 2025-11-06
*/
@RequiredArgsConstructor
@Service
public class SysRoleWorkServiceImpl extends ServiceImpl<SysRoleWorkMapper, SysRoleWork> implements ISysRoleWorkService {
private final SysRoleWorkMapper baseMapper;
@Autowired
private SysRoleServiceImpl roleService;
@Autowired
private BusProjectServiceImpl projectService;
/**
* 查询角色流程对应
*
* @param id 主键
* @return 角色流程对应
*/
@Override
public SysRoleWorkVo queryById(Long id){
SysRoleWorkVo sysRoleWorkVo = baseMapper.selectVoById(id);
List<SysRoleWorkVo> sysRoleWorkVo1 = new ArrayList<>();
if (sysRoleWorkVo != null) {
sysRoleWorkVo1 = List.of(sysRoleWorkVo);
setValue(sysRoleWorkVo1);
}
return sysRoleWorkVo1.getFirst();
}
/**
* 分页查询角色流程对应列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 角色流程对应分页列表
*/
@Override
public TableDataInfo<SysRoleWorkVo> queryPageList(SysRoleWorkBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<SysRoleWork> lqw = buildQueryWrapper(bo);
Page<SysRoleWorkVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
setValue(result.getRecords());
return TableDataInfo.build(result);
}
/**
* 查询符合条件的角色流程对应列表
*
* @param bo 查询条件
* @return 角色流程对应列表
*/
@Override
public List<SysRoleWorkVo> queryList(SysRoleWorkBo bo) {
LambdaQueryWrapper<SysRoleWork> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<SysRoleWork> buildQueryWrapper(SysRoleWorkBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<SysRoleWork> lqw = Wrappers.lambdaQuery();
lqw.orderByDesc(SysRoleWork::getCreateTime);
lqw.eq(bo.getRoleId() != null, SysRoleWork::getRoleId, bo.getRoleId());
lqw.eq(StringUtils.isNotBlank(bo.getLcmc()), SysRoleWork::getLcmc, bo.getLcmc());
lqw.eq(StringUtils.isNotBlank(bo.getLcms()), SysRoleWork::getLcms, bo.getLcms());
lqw.eq(StringUtils.isNotBlank(bo.getLcxq()), SysRoleWork::getLcxq, bo.getLcxq());
return lqw;
}
/**
* 新增角色流程对应
*
* @param bo 角色流程对应
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(SysRoleWorkBo bo) {
LambdaQueryWrapper<SysRoleWork> lqw = new LambdaQueryWrapper<>();
lqw.eq(SysRoleWork::getRoleId, bo.getRoleId());
lqw.eq(SysRoleWork::getProjectId, bo.getProjectId());
List<SysRoleWork> workVos = list(lqw);
if (!workVos.isEmpty()) {
throw new RuntimeException("此角色已绑定流程");
}
SysRoleWork add = MapstructUtils.convert(bo, SysRoleWork.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改角色流程对应
*
* @param bo 角色流程对应
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(SysRoleWorkBo bo) {
SysRoleWork update = MapstructUtils.convert(bo, SysRoleWork.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(SysRoleWork entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除角色流程对应信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
public void setValue(List<SysRoleWorkVo> vos){
for (SysRoleWorkVo vo : vos) {
if (vo.getRoleId() != null){
SysRoleVo sysRoleVo = roleService.selectRoleById(vo.getRoleId());
if (sysRoleVo != null){
vo.setRoleName(sysRoleVo.getRoleName());
}
}
}
}
public List<SysRoleVo> getRoleList(Long projectId){
Long userId = LoginHelper.getUserId();
List<SysUserRole> list = baseMapper.getRoleList(userId,projectId);
List<SysRoleVo> roleList = new ArrayList<>();
for (SysUserRole sysUserRole : list) {
LambdaQueryWrapper<SysRoleWork> lqw = new LambdaQueryWrapper<>();
lqw.eq(SysRoleWork::getRoleId, sysUserRole.getRoleId());
lqw.eq(SysRoleWork::getProjectId,projectId);
SysRoleWork one = getOne(lqw);
if (one != null){
SysRoleVo sysRoleVo = roleService.selectRoleById(sysUserRole.getRoleId());
if (sysRoleVo != null){
roleList.add(sysRoleVo);
}
}
}
return roleList;
}
/**
* 判断此角色在所有项目下所有角色是否有流程
*/
public Boolean isHaveValue(Long userId){
List<SysUserRole> allRoleList = baseMapper.getAllRoleList(userId);
for (SysUserRole sysUserRole : allRoleList) {
LambdaQueryWrapper<SysRoleWork> lqw = new LambdaQueryWrapper<>();
lqw.eq(SysRoleWork::getRoleId, sysUserRole.getRoleId());
lqw.eq(SysRoleWork::getProjectId,sysUserRole.getProjectId());
List<SysRoleWork> list = list(lqw);
if (list != null && !list.isEmpty()){
return true;
}
}
return false;
}
/**
* 根据当前登录人获取角色流程对应
*/
public SysRoleWork getRoleWork(Long projectId){
Long userId = LoginHelper.getUserId();
List<SysUserRole> roleList = baseMapper.getRoleList(userId,projectId);
if (roleList == null || roleList.isEmpty()){
return null;
}
for (SysUserRole userRole : roleList) {
LambdaQueryWrapper<SysRoleWork> lqw = new LambdaQueryWrapper<>();
lqw.eq(SysRoleWork::getRoleId, userRole.getRoleId());
lqw.eq(SysRoleWork::getProjectId,projectId);
SysRoleWork one = getOne(lqw);
if (one != null){
return one;
}
}
return null;
}
/**
* 获取当前登录人在所有项目下有流程的角色列表
* @return
*/
public List<BusProjectVo> getProjectRoles(){
Long userId = LoginHelper.getUserId();
// 获取当前登录用户的所有项目及对应所有角色
List<SysUserRole> allRoleList = baseMapper.getAllRoleList(userId);
// 获取项目
List<BusProjectVo> busProjectVoList = new ArrayList<>();
//维护一个该用户的 项目ID:角色ID map
Map<Long,Long> map = new HashMap<>();
//获取到该用户所有有流程的项目 说明在该项目下该用户有角色有所属流程
for (SysUserRole sysUserRole : allRoleList) {
BusProjectQueryReq req = new BusProjectQueryReq();
req.setId(sysUserRole.getProjectId());
List<BusProjectVo> vos = projectService.queryList(req);
if (vos != null && !vos.isEmpty()){
if(!busProjectVoList.contains(vos.getFirst())){
busProjectVoList.add(vos.getFirst());
map.put(sysUserRole.getProjectId(),sysUserRole.getRoleId());
}
}
}
List<SysRoleWork> roleWorks = this.list();
List<SysRoleVo> roleVos;
for (BusProjectVo projectVo : busProjectVoList) {
roleVos = new ArrayList<>();
for (SysRoleWork roleWork : roleWorks) {
if (map.containsKey(projectVo.getId()) && roleWork.getRoleId().equals(map.get(projectVo.getId()))){
SysRoleVo sysRoleVo = roleService.selectRoleById(roleWork.getRoleId());
if (sysRoleVo != null){
roleVos.add(sysRoleVo);
}
}
}
projectVo.setRoleVos(roleVos);
}
//遍历
// for (BusProjectVo projectVo : busProjectVoList) {
// roleVos = new ArrayList<>();
// //通过项目查找所有角色
// LambdaQueryWrapper<SysRoleWork> lqw1 = new LambdaQueryWrapper<>();
// lqw1.eq(SysRoleWork::getProjectId,projectVo.getId());
// List<SysRoleWork> roleWorkList = list(lqw1);
// //遍历
// for (SysRoleWork sysRoleWork : roleWorkList) {
// SysRoleVo sysRoleVo = roleService.selectRoleById(sysRoleWork.getRoleId());
// if (sysRoleVo != null){
// roleVos.add(sysRoleVo);
// }
// }
// projectVo.setRoleVos(roleVos);
// }
return busProjectVoList;
}
/**
* 根据用户和项目判断是否有角色流程
*/
public Boolean isHaveValueByProject(Long projectId){
Long userId = LoginHelper.getUserId();
List<SysUserRole> roleList = baseMapper.getRoleList(userId, projectId);
if (roleList != null && !roleList.isEmpty()){
for (SysUserRole userRole : roleList) {
LambdaQueryWrapper<SysRoleWork> lqw = new LambdaQueryWrapper<>();
lqw.eq(SysRoleWork::getRoleId, userRole.getRoleId());
lqw.eq(SysRoleWork::getProjectId,projectId);
List<SysRoleWork> list = list(lqw);
if (list != null && !list.isEmpty()){
return true;
}
}
}
return false;
}
}

View File

@ -7,16 +7,21 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import cn.dev33.satoken.annotation.SaMode;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.cailiaoshebei.domain.bo.BusMaterialbatchdemandplanBo;
import org.dromara.cailiaoshebei.domain.bo.BusMrpBaseReq;
import org.dromara.cailiaoshebei.domain.bo.RemainingReq;
import org.dromara.cailiaoshebei.domain.dto.BusMrpDto;
import org.dromara.cailiaoshebei.domain.dto.BusMrpExportDto;
import org.dromara.cailiaoshebei.domain.vo.BusMaterialbatchdemandplanVo;
import org.dromara.cailiaoshebei.domain.vo.BusMrpVo;
import org.dromara.cailiaoshebei.service.IBusMaterialbatchdemandplanService;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.design.domain.BusBillofquantities;
@ -66,6 +71,18 @@ public class BusMrpBaseController extends BaseController {
private final IBusBillofquantitiesService busBillofquantitiesService;
private final IBusBiddingPlanService busBiddingPlanService;
private final IBusMaterialbatchdemandplanService busMaterialbatchdemandplanService;
/**
* 查询物资-批次需求计划列表
*/
@SaCheckPermission("cailiaoshebei:mrpBase:list")
@GetMapping("/getPlanList")
public TableDataInfo<BusMaterialbatchdemandplanVo> list(BusMaterialbatchdemandplanBo bo, PageQuery pageQuery) {
return busMaterialbatchdemandplanService.queryPageList(bo, pageQuery);
}
/**
* 查询物资-批次需求计划基础信息列表
*/
@ -75,6 +92,15 @@ public class BusMrpBaseController extends BaseController {
return busMrpBaseService.queryPageList(bo, pageQuery);
}
/**
* 查询物资-批次需求计划基础信息列表
*/
// @SaCheckPermission("cailiaoshebei:mrpBase:getListByName")
@GetMapping("/getListByName")
public R<List<BusMrpBaseVo>> getListByName(BusMrpBaseReq req) {
return R.ok(busMrpBaseService.getListByName(req));
}
/**
* 导出物资-批次需求计划基础信息列表
*/
@ -91,7 +117,7 @@ public class BusMrpBaseController extends BaseController {
*
* @param id 主键
*/
@SaCheckPermission("cailiaoshebei:mrpBase:query")
// @SaCheckPermission("cailiaoshebei:mrpBase:query")
@GetMapping("/{id}")
public R<BusMrpVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
@ -136,7 +162,7 @@ public class BusMrpBaseController extends BaseController {
/**
* 批量新增或修改
*/
@SaCheckPermission("cailiaoshebei:mrpBase:addbatch")
@SaCheckPermission("cailiaoshebei:mrpBase:add")
@RepeatSubmit()
@PostMapping("/batch")
public R<Void> batchAddOrUpdate(@RequestBody BusMrpDto dto) {
@ -146,6 +172,7 @@ public class BusMrpBaseController extends BaseController {
/**
* 获取剩余量
*/
@SaCheckPermission(value = {"cailiaoshebei:mrpBase:add","cailiaoshebei:mrpBase:edit"},mode = SaMode.OR)
@GetMapping("/remaining")
public R<List<Map<String,Object>>> remaining( RemainingReq req) {
String[] split = req.getLimitListId().split(",");
@ -161,7 +188,7 @@ public class BusMrpBaseController extends BaseController {
/**
* 导入物资需求批次计划
*/
@SaCheckPermission("cailiaoshebei:mrpBase:import")
@SaCheckPermission("cailiaoshebei:mrpBase:add")
@Log(title = "物资-批次需求计划基础信息", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/import")
@ -190,7 +217,7 @@ public class BusMrpBaseController extends BaseController {
/**
* 获取工程量清单列表
*/
@SaCheckPermission("cailiaoshebei:mrpBase:getZhaoBiaoList")
@SaCheckPermission(value = {"cailiaoshebei:mrpBase:add","cailiaoshebei:mrpBase:edit"},mode = SaMode.OR)
@GetMapping("/getZhaoBiaoList")
public R<List<BusBiddingPlanVo>> getZhaoBiaoList(CoryObtainTheListReq req) {
BusBiddingPlanBo bo = new BusBiddingPlanBo();
@ -206,7 +233,7 @@ public class BusMrpBaseController extends BaseController {
* @param bo
* @return
*/
@SaCheckPermission("cailiaoshebei:mrpBase:getMore")
@SaCheckPermission("cailiaoshebei:mrpBase:list")
@GetMapping("/getMore")
public R<List<BusBillofquantitiesLimitListVo>> getMore(BusBiddingPlanBo bo) {
if (bo.getId() == null) {

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