Compare commits

..

947 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
f6d8cb3ba7 11-3-获取待办事项不分页版 2025-11-03 19:56:28 +08:00
lcj
659146a2cf 进度计划大屏数据 2025-11-03 19:25:48 +08:00
lg
c17c084095 个人首页conreoller 2025-11-03 17:34:01 +08:00
5962f694e2 10-30-修改分包合同付款 2025-11-03 15:15:54 +08:00
373528b432 websocket优化 2025-11-03 11:45:08 +08:00
lcj
e9f5e0fa03 车辆管理 2025-11-03 10:22:19 +08:00
b88a92b7e1 对ue开发接口 2025-10-31 20:08:44 +08:00
lg
fb72063369 分包合同修改 2025-10-31 19:13:16 +08:00
zt
9809213a12 bug 2025-10-31 15:43:31 +08:00
lcj
87e1cb7473 摄像头拍摄逻辑,车辆管理 2025-10-30 20:03:43 +08:00
lcj
c456ae215f 同步材料数据 2025-10-30 18:45:21 +08:00
lcj
091d7bfc0e 同步材料数据 2025-10-30 18:02:08 +08:00
lg
c9f80fe498 bug修改 2025-10-30 16:39:33 +08:00
7a3deba52a 10-30-修改 2025-10-30 16:13:00 +08:00
eb015fcecc 10-30-修改 2025-10-30 15:28:07 +08:00
d9fab2a4a2 10-30-新增销方名称搜索条件 2025-10-30 10:50:56 +08:00
lcj
7f125b4548 车辆管理 2025-10-30 09:59:19 +08:00
88dcecc88c Merge remote-tracking branch 'origin/dev' into dev 2025-10-30 09:38:23 +08:00
5458329252 10-30-修改 2025-10-30 09:38:13 +08:00
lg
c4e275f5a8 征税项目修改 2025-10-30 09:34:15 +08:00
zt
f8f89fd96e 人脸 2025-10-29 19:45:35 +08:00
lg
b8ffa41a30 项目风险评估签审意见修改 2025-10-29 19:44:05 +08:00
lg
f99cd08d57 项目风险评估签审意见修改 2025-10-29 19:42:24 +08:00
lcj
45cae080a0 车辆管理,修改物资出入库逻辑 2025-10-29 19:35:33 +08:00
84a8f49e95 10-29-LocalDate修改 2025-10-29 19:32:36 +08:00
e725991ece Merge remote-tracking branch 'origin/dev' into dev 2025-10-29 19:17:30 +08:00
c2a06a729c 10-29-LocalDate修改 2025-10-29 19:17:09 +08:00
lg
4a5e50a7a2 投标保证金收回修改 2025-10-29 19:15:15 +08:00
9b30a7bcec 10-29-LocalDate修改 2025-10-29 18:51:06 +08:00
ec383e44db 10-29-LocalDate修改 2025-10-29 18:42:14 +08:00
d3909f131f 10-29-LocalDate修改 2025-10-29 18:41:00 +08:00
zt
a444d4c953 Merge remote-tracking branch 'origin/dev' into dev 2025-10-29 16:31:21 +08:00
zt
3c01ec861b 人脸报错 2025-10-29 16:31:04 +08:00
365cf00644 10-29-bug修复 2025-10-29 16:12:16 +08:00
4faff3b0bc Merge remote-tracking branch 'origin/dev' into dev 2025-10-29 15:57:06 +08:00
866f2336c3 10-29-bug修复 2025-10-29 15:56:56 +08:00
e4132ea540 处理长顺的老数据 2025-10-29 11:33:13 +08:00
zt
53208c36cf 考勤机 2025-10-29 11:21:47 +08:00
8f2a3e6e50 10-29-bug修复,安装包新增描述 2025-10-29 09:53:45 +08:00
lcj
b67a7d5370 考勤接口 2025-10-28 20:39:14 +08:00
zt
07509c8e15 考勤机 2025-10-28 20:23:23 +08:00
e6c58a64ac 10-28-bug修复 2025-10-28 20:02:57 +08:00
lg
abb6b8c13a 分包合同竣工结算添加合同文本字段 2025-10-28 19:05:36 +08:00
lg
de492728bc cbs权限 2025-10-28 18:42:24 +08:00
82fa732db6 10-28-bug修复 2025-10-28 15:52:07 +08:00
lcj
275d640263 车辆管理 2025-10-28 14:17:45 +08:00
7e47b8a74f 施工产值增加第N周 2025-10-28 11:57:14 +08:00
d4301da0ec 添加详情权限 2025-10-28 11:02:53 +08:00
lg
fe5b5473dd 审核数据添加 2025-10-28 09:44:33 +08:00
0126d44761 ws注解放开 2025-10-27 20:42:03 +08:00
dbefd88e41 添加客户详情权限 2025-10-27 20:09:39 +08:00
9a3b7ebe54 添加审核 2025-10-27 20:00:56 +08:00
81be4a862c 10-27-添加审核完善 2025-10-27 19:57:35 +08:00
lg
43f2db9f7e 审核数据添加 2025-10-27 19:51:55 +08:00
abefa90408 10-27-添加审核完善 2025-10-27 19:14:24 +08:00
08f48b7817 10-27-添加审核 2025-10-27 18:45:49 +08:00
lcj
6b8ace60d4 车辆管理,修改材料 2025-10-27 17:10:41 +08:00
lg
b997dd5f00 详情权限取消 2025-10-27 15:35:49 +08:00
6174743858 Merge remote-tracking branch 'origin/dev' into dev 2025-10-27 15:25:19 +08:00
82d55d7188 10-27-修改bug 2025-10-27 15:25:06 +08:00
lg
aec5eacd0b 采购详情权限取消 2025-10-27 15:25:04 +08:00
zt
a320b85965 考勤机 2025-10-27 15:14:29 +08:00
lg
b61a7c153d 投标文件-项目类型中文返回 2025-10-27 14:44:50 +08:00
fb9b01cf34 修改物资跟踪管理台账查询列表修改 2025-10-27 14:27:11 +08:00
lg
32f134873a 采购合同金额字段 2025-10-27 11:37:41 +08:00
f4220be9d6 10-27-修改bug 2025-10-27 10:29:27 +08:00
lg
8252fd7216 标后分析返回对象增加字段 2025-10-27 09:44:11 +08:00
lg
57855f4307 bug修改 2025-10-25 22:18:10 +08:00
6784eafe6e 供应商-客户中间表引用表的新增修改删除修改 2025-10-25 22:17:26 +08:00
0b42c1d6a6 Merge remote-tracking branch 'origin/dev' into dev 2025-10-25 22:16:07 +08:00
4b37a7327f 10-25-修改 2025-10-25 22:16:00 +08:00
lg
0287f1e4ce bug修改 2025-10-25 21:58:47 +08:00
5d8af1cab8 10-25-供应商删除修改 2025-10-25 21:57:13 +08:00
123896f08b Merge remote-tracking branch 'origin/dev' into dev 2025-10-25 21:25:40 +08:00
a8a198b51f 10-25-增加校验 2025-10-25 21:25:33 +08:00
lg
f00b98714a Merge remote-tracking branch 'origin/dev' into dev 2025-10-25 21:24:39 +08:00
lg
4ff87f3996 bug修改 2025-10-25 21:23:58 +08:00
5f3ae0f9f1 10-25-供应商地域绑定及搜索 2025-10-25 21:22:36 +08:00
786c864a27 供应商-客户中间表引用表的新增修改删除修改 2025-10-25 21:21:48 +08:00
lg
c61e802b85 bug修改 2025-10-25 21:09:26 +08:00
lg
9a568799f4 bug修改 2025-10-25 21:05:26 +08:00
8aa38063bf 供应商-客户中间表引用表的新增修改删除 2025-10-25 20:58:07 +08:00
c4a11ec245 10-25-解除继承 2025-10-25 20:28:40 +08:00
lg
169b76589c bug修改 2025-10-25 20:23:02 +08:00
lg
199f51ea21 bug修改 2025-10-25 20:19:21 +08:00
lg
23572dfc07 bug修改 2025-10-25 20:14:03 +08:00
570b0ce316 10-25-供应商新增、删除添加校验 2025-10-25 20:11:14 +08:00
lg
f953a96c36 bug修改 2025-10-25 20:05:43 +08:00
zt
25c4eee464 bug 2025-10-25 20:01:28 +08:00
lg
b209ef1fab 中间表数据添加 2025-10-25 19:20:32 +08:00
lg
77e9f4d9a2 中间表数据添加 2025-10-25 19:18:09 +08:00
lg
e73c808bc3 xzd前缀添加 2025-10-25 17:21:16 +08:00
zt
edf0d1a5db 设计导出 2025-10-25 17:10:43 +08:00
lcj
cc23a308c1 修改配置,车辆管理 2025-10-25 17:01:15 +08:00
bc891327c9 10-25-字段调整 2025-10-25 16:51:17 +08:00
39bedfeb92 10-25-字段调整 2025-10-25 16:44:33 +08:00
56fc4ff83e 10-24-修复 2025-10-24 22:16:26 +08:00
524ed30728 Merge remote-tracking branch 'origin/dev' into dev 2025-10-24 22:16:13 +08:00
584304e744 供应商-客户中间表初始化 2025-10-24 22:07:16 +08:00
zt
56418600c5 1 2025-10-24 20:17:03 +08:00
40e57b18cb 10-24-修复 2025-10-24 20:05:45 +08:00
lg
ced6cb219c deptid添加 2025-10-24 20:01:03 +08:00
218ec5ea95 gps接口修改 2025-10-24 19:40:54 +08:00
zt
1c601bd68e 设计导出 2025-10-24 19:32:20 +08:00
lg
7d6eba719b 投标保证金收回 2025-10-24 17:50:15 +08:00
8cfc34dbcb Merge remote-tracking branch 'origin/dev' into dev 2025-10-24 17:46:29 +08:00
23a749973d 10-24-修复 2025-10-24 17:45:59 +08:00
4b96702dc9 成本预算添加部门id 2025-10-24 17:41:37 +08:00
a1af8711ef 添加id转name注解方法 2025-10-24 17:05:11 +08:00
9e8cff931b 10-24-修复 2025-10-24 17:00:15 +08:00
lg
5bccd71bdc 投标保证金缴纳 2025-10-24 16:59:24 +08:00
lg
544f35a601 投标管理修改 2025-10-24 16:04:38 +08:00
f920d4976e 10-24-修复 2025-10-24 15:22:31 +08:00
cdcd665d43 添加id转name注解方法 2025-10-24 11:55:19 +08:00
lg
08de61e455 trans添加客户供应商 2025-10-24 10:48:06 +08:00
lcj
025c3115b7 接入ai,识别 2025-10-24 09:23:40 +08:00
9e366554b7 10-23-修复 2025-10-23 22:35:04 +08:00
zt
d934abf0fe bug修改 2025-10-23 19:36:49 +08:00
lg
e16e9133e2 采购合同修改 2025-10-23 17:42:42 +08:00
d7854a35d7 10-23-修复 2025-10-23 17:36:00 +08:00
97e0dd467f Merge remote-tracking branch 'origin/dev' into dev 2025-10-23 17:24:08 +08:00
e58a99e696 10-23-修复 2025-10-23 17:24:00 +08:00
lg
0d5a9eb505 采购合同修改 2025-10-23 17:18:36 +08:00
lg
45ac1817e1 成本预算修改 2025-10-23 16:08:17 +08:00
lg
f2d4ff4237 客户信息变更 2025-10-23 15:04:42 +08:00
a4cc5c14f3 Merge remote-tracking branch 'origin/dev' into dev 2025-10-23 14:27:41 +08:00
5be571cc30 10-23-修复 2025-10-23 14:27:32 +08:00
ff656dd046 富文本配置修改 2025-10-23 11:28:29 +08:00
lg
20574d0037 bug修改 2025-10-23 11:25:12 +08:00
42cf396e93 10-23-xss规则 2025-10-23 11:22:34 +08:00
2a30b05dd7 新中大综合服务合同优化 2025-10-23 11:21:46 +08:00
4ecee185bf 10-22-bug修复 2025-10-23 11:14:21 +08:00
lg
48ab59c67d bug修改 2025-10-23 09:22:27 +08:00
lcj
806e8f3391 修改配置文件 2025-10-22 20:19:40 +08:00
61244321a7 10-22-bug修复 2025-10-22 20:10:10 +08:00
zt
ff1e613316 设计导出 2025-10-22 18:58:30 +08:00
03161751fc 10-22-bug修复 2025-10-22 18:51:50 +08:00
9ebf4a3e5f 10-22-新增供应商空值校验 2025-10-22 18:38:48 +08:00
lcj
3ba13e3ef8 新部署一个项目 2025-10-22 16:07:10 +08:00
lg
8d3853fe6b bug修改 2025-10-22 15:08:30 +08:00
lg
dbc09a62ea 后端修改 2025-10-22 09:29:20 +08:00
zt
f3fa78475c bug 2025-10-21 20:05:55 +08:00
c565771283 10-21-修复 2025-10-21 20:04:59 +08:00
bac8488244 新中大综合服务合同修改,建管大屏接口优化、gps接口优化 2025-10-21 18:35:07 +08:00
lcj
a5f661b558 承包合同,安全质量大屏 2025-10-21 18:29:06 +08:00
zt
ceecec97c7 打印天气 2025-10-21 18:25:52 +08:00
c6ae8a4c00 10-21-收票与开票-收票登记 2025-10-21 17:31:00 +08:00
zt
37d0c776c0 设计计划 2025-10-21 15:53:56 +08:00
f8eea0f63f 修改查询语句 2025-10-21 10:36:52 +08:00
lg
59c749ab2a 表名修改 2025-10-21 10:09:59 +08:00
eeeba2bf4b 10-21-修复 2025-10-21 10:07:55 +08:00
lg
a9ce42101f 补充 2025-10-20 20:16:44 +08:00
lcj
13de88265f 识别逻辑 2025-10-20 20:09:51 +08:00
a464a1236d 综合服务进度、采购进度、竣工、竣工调整添加底部计量结算内容 2025-10-20 20:07:40 +08:00
fce5d0e7fc 10-20-修复字段 2025-10-20 19:57:27 +08:00
66ba43d030 Merge remote-tracking branch 'origin/dev' into dev 2025-10-20 19:26:18 +08:00
1aa77e5eda 10-20-决算清 2025-10-20 19:26:08 +08:00
zt
037016fc13 人脸对接 2025-10-20 19:24:36 +08:00
99f0026552 大屏接口添加计划容量 2025-10-20 17:12:06 +08:00
lg
535262d721 枚举 2025-10-20 16:32:32 +08:00
fbcb9ca3f2 10-20-决算清单(调整)初始化 2025-10-20 16:19:00 +08:00
2a7a20b966 Merge remote-tracking branch 'origin/dev' into dev 2025-10-20 16:10:14 +08:00
98fdab0dba 10-20-承包合同进度结算补齐 2025-10-20 16:10:03 +08:00
lg
bd71335ae6 分包合同枚举 2025-10-20 15:53:15 +08:00
zt
7f746fc250 考勤机 2025-10-20 15:41:43 +08:00
lg
901c8785fe 合同类型字段补充 2025-10-20 15:30:34 +08:00
e4e9718acb 10-20-初始化 2025-10-20 15:08:29 +08:00
738101f374 10-20-初始化 2025-10-20 15:05:58 +08:00
lg
a7befd7278 字段修改补充 2025-10-20 14:56:38 +08:00
lg
52e968c313 字段修改 2025-10-20 14:47:03 +08:00
lg
de9d7d34d6 部门修改和变更增加清单,合同内清单 2025-10-20 14:29:59 +08:00
zt
9f0105d88a 角色优化 2025-10-20 14:21:18 +08:00
lcj
80ec8ff86d 结算 2025-10-20 14:19:43 +08:00
f3473fe5d5 阶段成本分解校验修改 2025-10-18 21:05:20 +08:00
lcj
856f3f334b 修改日期 2025-10-18 20:35:50 +08:00
lcj
0b216a4101 修改配置 2025-10-18 20:19:35 +08:00
c7338b45ad 大屏项目 2025-10-18 20:09:38 +08:00
c93b1b752e Merge remote-tracking branch 'origin/dev' into dev 2025-10-18 20:08:43 +08:00
e38074bb25 大屏项目 2025-10-18 20:08:17 +08:00
zt
be0f425e14 Merge remote-tracking branch 'origin/dev' into dev 2025-10-18 20:03:14 +08:00
zt
f24e33b1c7 注销 2025-10-18 20:02:54 +08:00
48ea20581c 项目 2025-10-18 19:54:27 +08:00
lcj
e7fa22e573 承包分包合同进度结算 2025-10-18 19:44:37 +08:00
83b7b32035 解决冲突 2025-10-18 18:56:03 +08:00
6a0be071b8 合同管理-承包、分包、采购、综合服务的信息、变更添加合同变更清单 2025-10-18 18:47:21 +08:00
lg
7bdf8f53b9 采购合同修改 2025-10-18 18:45:25 +08:00
lg
03b249afe7 单据编号统一接口 2025-10-18 17:15:16 +08:00
lg
2e5e42fd84 成本单 2025-10-18 14:21:49 +08:00
f9d9785536 10-17-收票与开票-开票申请 2025-10-18 14:14:27 +08:00
a06511e0bf Merge remote-tracking branch 'origin/dev' into dev 2025-10-18 14:13:49 +08:00
zt
31aa56d34b 设备打卡 2025-10-17 21:15:44 +08:00
2b4517760f 立项及成本-成本预算-阶段成本分解接口 2025-10-17 20:10:36 +08:00
c318d0b10b 合同管理-合同变更清单初始化 2025-10-17 17:42:40 +08:00
lcj
ec54b4ff52 大屏、产值 2025-10-17 15:42:05 +08:00
zt
965a0cc90e 材料 2025-10-17 15:39:59 +08:00
zt
ebddc5c51f 分包 2025-10-17 15:37:24 +08:00
a323844440 立项与成本-成本预算-总体计划成本接口 2025-10-17 14:15:35 +08:00
lg
6bcddf50da 资金计划 2025-10-17 11:54:00 +08:00
lcj
c72275859f 大屏、产值 2025-10-17 11:51:09 +08:00
9561ee9323 10-17-收票与开票-开票申请 2025-10-17 11:24:46 +08:00
b7a52de2d2 立项与成本-成本预算-完工成本填报新增 2025-10-17 10:53:00 +08:00
bfc3ea60fd 立项与成本-成本预算-完工成本填报初始化 2025-10-17 10:34:03 +08:00
zt
1acc676b0f 短信优化 2025-10-17 10:15:11 +08:00
d6a378f711 Merge remote-tracking branch 'origin/dev' into dev 2025-10-16 21:59:24 +08:00
b4f56b6c79 10-16-承包合同收款-分包合同付款 2025-10-16 21:58:55 +08:00
zt
b5d2b3df06 优化 2025-10-16 20:33:34 +08:00
lcj
4042b4a441 修改bug 2025-10-16 20:31:56 +08:00
1fd3da3e2a 收款与付款-采购、综合服务付款接口 2025-10-16 20:07:05 +08:00
zt
0d84c49ca4 优化 2025-10-16 18:43:05 +08:00
lcj
cecfb60e71 项目部门关联 2025-10-16 17:55:48 +08:00
lcj
aec8667edc 进度计划产值 2025-10-16 15:18:39 +08:00
e930cd3b7c 10-16-承包合同竣工结算调整 2025-10-16 14:42:14 +08:00
373906bde7 Merge remote-tracking branch 'origin/dev' into dev 2025-10-16 14:40:51 +08:00
bca9745e60 收款与付款-采购、综合服务付款初始化 2025-10-16 14:40:31 +08:00
lcj
6808057111 考勤机 2025-10-15 23:57:32 +08:00
lg
9f1da9e6c0 结算信息 2025-10-15 22:50:38 +08:00
d8838f8e01 采购合同结算接口 2025-10-15 22:01:22 +08:00
d92d37c646 大屏接口修改与ws接口修改 2025-10-15 21:59:27 +08:00
zt
6398a28974 优化 2025-10-15 20:36:12 +08:00
cce9ef98d8 10-15-承包合同竣工结算 2025-10-15 19:52:55 +08:00
467a972a6d Merge remote-tracking branch 'origin/dev' into dev 2025-10-15 19:17:20 +08:00
00e5f5ede6 10-15-变更子表更新方式 2025-10-15 19:08:43 +08:00
1b590bbcbd 10-15-修复 2025-10-15 17:30:17 +08:00
40d53dffba 10-15-方案选择帮助,印章帮助,预算分类 2025-10-15 13:51:35 +08:00
zt
db3af72d5f 优化 2025-10-15 10:49:45 +08:00
9604cab4d6 综合服务对应接口和结算采购合同对应接口 2025-10-15 10:30:54 +08:00
536b25d773 Merge remote-tracking branch 'origin/dev' into dev 2025-10-14 23:21:52 +08:00
e87cbce77a 解决ws不兼容 2025-10-14 23:21:23 +08:00
f34afd962d Merge remote-tracking branch 'origin/dev' into dev 2025-10-14 21:10:20 +08:00
lcj
98f23e2c02 修改bug 2025-10-14 20:24:17 +08:00
zt
b9507e1fd7 优化 2025-10-14 18:42:02 +08:00
1ceef7f1d1 1 2025-10-14 17:38:15 +08:00
lcj
0fb3fd70a6 进度计划甘特图 2025-10-14 17:21:37 +08:00
aab0a5e0b8 10-13-承包合同结算周期 2025-10-14 16:26:40 +08:00
f9d1a7a489 10-13-承包合同,变更,终止,方案选择 2025-10-14 16:22:38 +08:00
87e58ca4af 增加移动考勤机 2025-10-14 16:02:32 +08:00
lcj
d6263c6430 大屏质量、物资、识别记录 2025-10-14 15:12:32 +08:00
lg
253ef81066 分包合同信息 2025-10-14 15:01:31 +08:00
2f4bec42a3 大屏接口修改 2025-10-14 14:57:54 +08:00
zt
3879ce28b6 bug 2025-10-14 14:25:59 +08:00
lg
691b5341c7 采购合同 2025-10-14 11:03:46 +08:00
4a50dc6ff0 10-13-承包合同,变更,终止 2025-10-13 22:46:49 +08:00
d7e4c65afb Merge remote-tracking branch 'origin/dev' into dev 2025-10-13 22:45:07 +08:00
61b39d89de 大屏接口修改 2025-10-13 21:49:27 +08:00
2497527c77 供应商接口修改 2025-10-13 21:47:46 +08:00
zt
79f74434f7 bug 2025-10-13 21:20:44 +08:00
zt
bd0fe7228b 设计优化 2025-10-13 19:59:52 +08:00
66b45df3fb Merge remote-tracking branch 'origin/dev' into dev 2025-10-13 18:44:18 +08:00
38d6832f2c 表名枚举 2025-10-13 18:34:06 +08:00
8e51d67071 表名枚举 2025-10-13 18:32:53 +08:00
942ca4202a 10-13-承包合同信息完善,合作协议完善 2025-10-13 15:09:43 +08:00
zt
255a202c02 Merge remote-tracking branch 'origin/dev' into dev 2025-10-13 11:44:29 +08:00
zt
1033ee01fb 审批 2025-10-13 11:44:13 +08:00
201f7bd3a7 安全帽表名修改 2025-10-13 11:42:14 +08:00
8a7726e216 安全帽接口修改 2025-10-13 09:55:16 +08:00
lcj
bc85fe64a4 进度计划,施工产值 2025-10-13 09:39:21 +08:00
549fbe92de 10-12-承包合同信息 2025-10-12 21:32:13 +08:00
270071a5f3 Merge remote-tracking branch 'origin/dev' into dev 2025-10-12 21:31:41 +08:00
09cbb6a8c5 大屏接口修改 2025-10-12 20:56:08 +08:00
zt
f825b9f968 优化 2025-10-12 20:51:38 +08:00
f7b9d2f431 10-12-支付条款新增 2025-10-12 19:32:10 +08:00
742df7279b 10-12-承包合同 2025-10-12 18:52:18 +08:00
684209aa36 安全帽和大屏接口 2025-10-12 18:18:30 +08:00
d033b505e2 10-12-合作协议 2025-10-12 17:20:45 +08:00
59623f53a0 Merge remote-tracking branch 'origin/dev' into dev 2025-10-12 16:08:01 +08:00
b9cf8ea3de 10-12-新增银行卡,合作协议 2025-10-12 16:07:54 +08:00
45761415fa 批次需求计划优化 2025-10-12 15:23:35 +08:00
lcj
4dca396d11 进度计划,施工产值 2025-10-12 14:16:05 +08:00
0efaf12849 Merge remote-tracking branch 'origin/dev' into dev 2025-10-12 00:25:45 +08:00
lg
51686c212e 标前立项 2025-10-12 00:25:23 +08:00
lg
866c53c6cc Merge remote-tracking branch 'origin/dev' into dev 2025-10-12 00:24:44 +08:00
809494ffca Merge remote-tracking branch 'origin/dev' into dev 2025-10-11 23:38:07 +08:00
zt
7824803bf6 管理员和分包补卡 2025-10-11 20:59:45 +08:00
zt
5df3bb7baf 管理员和分包补卡 2025-10-11 19:23:53 +08:00
c7dcddb58e 10-11-项目信息 2025-10-11 19:14:51 +08:00
zt
cc64f16231 优化 2025-10-11 15:27:33 +08:00
26129e7433 10-11-安装包上传,事务分离 2025-10-11 14:49:08 +08:00
lg
e7aec88abf Merge remote-tracking branch 'origin/dev' into dev 2025-10-11 10:56:21 +08:00
lg
f820edebb5 标前立项 2025-10-11 10:56:07 +08:00
9d586f7b77 Merge remote-tracking branch 'origin/dev' into dev 2025-10-11 10:55:31 +08:00
lcj
00e9fa1ea3 根据配置文件抓拍图片 2025-10-11 10:50:14 +08:00
9a698857ce 10-11-项目信息,工程建设 2025-10-11 10:16:11 +08:00
b47cdb5732 大屏接口优化 2025-10-10 22:46:42 +08:00
zt
3bf7a1201f bug修改 2025-10-10 22:44:03 +08:00
lcj
bb38b6a6e1 添加抓拍,修改项目大屏 2025-10-10 21:57:57 +08:00
zt
11b5908d8c bug修改 2025-10-10 21:45:08 +08:00
zt
6c96c6f534 bug修改 2025-10-10 21:03:10 +08:00
lg
22a7500048 误删除 2025-10-10 20:59:39 +08:00
lg
412db4d348 误删除 2025-10-10 20:36:44 +08:00
lg
6a200b391e 1111 2025-10-10 20:12:13 +08:00
lg
6e0e867e57 Merge branch 'dev' of http://192.168.110.2:3000/lcj/xinnengyuan into dev 2025-10-10 20:11:33 +08:00
66d2f24256 10-10-1 2025-10-10 20:10:20 +08:00
lg
69e8e4169b 1111 2025-10-10 20:07:47 +08:00
33d051164e 10-10-项目信息初始化 2025-10-10 18:25:22 +08:00
2d18345087 10-10-修复2 2025-10-10 16:34:21 +08:00
ef10a4f0a4 10-10-修复 2025-10-10 16:33:12 +08:00
9784aa7ee3 Merge remote-tracking branch 'origin/dev' into dev 2025-10-10 16:14:55 +08:00
af069f3fa5 10-10-xzd项目经理推荐审批模块 2025-10-10 16:14:49 +08:00
zt
d8f5cc34ea bug修改 2025-10-10 15:22:17 +08:00
0870003967 Merge remote-tracking branch 'origin/dev' into dev 2025-10-10 14:42:48 +08:00
fb4ce63f59 10-10-xzd供应商信息模块 2025-10-10 14:42:34 +08:00
lcj
502cc55143 修改bug,建表 2025-10-10 10:08:23 +08:00
zt
372c825844 考勤优化 2025-10-09 18:32:50 +08:00
lg
ca256a28a1 xzd-客户信息 2025-10-08 19:35:40 +08:00
lcj
666e402d5d 修改进度计划判定逻辑 2025-10-01 15:07:12 +08:00
lcj
3630c13f59 修改bug 2025-09-30 23:16:30 +08:00
zt
334ff20129 考勤 2025-09-30 17:45:56 +08:00
lcj
3371ef9c1c 修改bug 2025-09-30 16:59:59 +08:00
lg
ed6b4c608f xzd-客户信息 2025-09-30 11:24:14 +08:00
lcj
cdd9266452 修改权限 2025-09-30 09:37:25 +08:00
lcj
a1450c4796 进度计划 2025-09-29 20:08:07 +08:00
lcj
a1ba33c06d 进度计划同步、大屏摄像头 2025-09-29 17:06:44 +08:00
zt
b0493e7de9 考勤 2025-09-29 17:03:55 +08:00
zt
7b00d67cf7 施工产值报错 2025-09-29 15:53:07 +08:00
3eae13e67a Merge remote-tracking branch 'origin/dev' into dev 2025-09-29 15:19:59 +08:00
9fe3cd494f 09-29-上传时间改为120秒,上传时删除原文件使用日志记录 2025-09-29 15:19:51 +08:00
zt
2c554321bb 数据转移 2025-09-29 09:54:34 +08:00
lcj
39038889b6 萤石云 2025-09-28 20:14:39 +08:00
zt
cbf4b3b22e 专业 2025-09-28 20:03:36 +08:00
lcj
3d3df16817 进度计划 2025-09-28 17:04:29 +08:00
c66d5f0789 设计出图优化 2025-09-28 16:57:24 +08:00
zt
d644df94dc 专业 2025-09-28 16:25:42 +08:00
zt
eb6a7f2373 考勤 2025-09-28 12:31:24 +08:00
lcj
fa625aff6d 修改bug 2025-09-28 12:30:21 +08:00
e64897246a 合规性手续bug修改 2025-09-28 10:54:02 +08:00
lcj
6c138d1f4d 修改bug 2025-09-28 09:46:50 +08:00
fdd1b8dfa0 批次需求计划修改实体类字段类型 2025-09-28 09:45:54 +08:00
zt
9f7b6d77d3 分包 2025-09-26 20:45:19 +08:00
zt
45999b0c03 分包 2025-09-26 18:55:07 +08:00
944d36e5e7 09-26-修复联系人列表 2025-09-26 11:37:24 +08:00
f87c67349d 批次需求计划修改 2025-09-26 10:23:01 +08:00
zt
259ddd46cf 优化 2025-09-25 20:37:50 +08:00
lcj
570e7dd019 进度计划、施工产值逻辑修改;合同 2025-09-25 20:30:34 +08:00
zt
4a27c7d179 Merge remote-tracking branch 'origin/dev' into dev 2025-09-25 18:39:10 +08:00
zt
f2912f0661 优化 2025-09-25 18:38:50 +08:00
cd4e1db7bd Merge remote-tracking branch 'origin/dev' into dev 2025-09-25 17:35:06 +08:00
23eab88db1 09-25-完善功能 2025-09-25 17:34:47 +08:00
a7004ac125 招标计划新增添加事务 2025-09-25 17:01:28 +08:00
f02cd59135 一览表查询版本修改 2025-09-25 16:43:01 +08:00
zt
d0e40bdd33 优化 2025-09-25 15:50:58 +08:00
zt
a34c07c64e 优化 2025-09-25 15:17:53 +08:00
af83c40d98 09-25-供应商入库更新修复 2025-09-25 11:26:33 +08:00
1bb59cc2f1 一览表查询版本修改 2025-09-25 10:29:17 +08:00
zt
e1b9b0e8c5 Merge remote-tracking branch 'origin/dev' into dev 2025-09-25 10:24:59 +08:00
zt
1de11bb110 安全 2025-09-25 10:24:39 +08:00
84c9946337 供应商入库修改 2025-09-24 19:36:40 +08:00
bc41175162 供应商重复导入修改 2025-09-24 14:59:06 +08:00
1e76e4ffe1 供应商导入修改 2025-09-24 14:48:35 +08:00
2952d978d2 Merge remote-tracking branch 'origin/dev' into dev 2025-09-24 14:45:29 +08:00
256e3f9c0d 09-24-通讯录uer过滤条件新增管理员过滤 2025-09-24 14:45:19 +08:00
faff11ad6f 修改物资设备清单相关修改 2025-09-24 14:36:04 +08:00
zt
a177ab3067 bug 2025-09-24 13:16:18 +08:00
zt
7f1971248a 设计人员 2025-09-24 12:35:19 +08:00
zt
4d6c7fe2c0 bug 2025-09-23 20:25:40 +08:00
278004788b 修改物资设备清单导入修改 2025-09-23 19:52:09 +08:00
a8744cc4cc 修改物资设备清单导入修改 2025-09-23 16:49:06 +08:00
20dc9b3e85 修改物资设备清单导入和批次需求计划新增 2025-09-23 14:23:23 +08:00
zt
d0c1a1337e 优化 2025-09-23 14:11:58 +08:00
zt
70553dff79 优化 2025-09-23 11:38:29 +08:00
8af5fb52ec 项目级大屏出勤统计修改查询范围 2025-09-23 09:21:05 +08:00
zt
b754e3ffc0 优化 2025-09-22 22:57:43 +08:00
lcj
d72f763545 进度计划 2025-09-22 22:10:04 +08:00
zt
683f58cdc8 身份证 2025-09-22 21:37:32 +08:00
zt
61dfb371f8 身份证 2025-09-22 21:36:35 +08:00
zt
9772f1a024 BUG和工资 2025-09-22 21:09:36 +08:00
5b6d3bf758 09-22-优化安装包文件上传 2025-09-22 20:56:02 +08:00
a2167e8227 Merge remote-tracking branch 'origin/dev' into dev 2025-09-22 17:23:46 +08:00
lcj
49c5689b4a bug修改 2025-09-22 17:11:49 +08:00
53413e2ddf Merge remote-tracking branch 'origin/dev' into dev 2025-09-22 17:11:23 +08:00
6c0deb23c6 项目列表删除goid 2025-09-22 16:51:17 +08:00
5cd202ceda 变更安全工单、增加题库操作 2025-09-22 15:32:47 +08:00
71078cd36f 项目列表增加项目概况 2025-09-22 15:09:09 +08:00
81c8938076 人员任命导入导出接口修改 2025-09-22 11:49:50 +08:00
lcj
ce99cdd623 AI识别同步进度计划 2025-09-21 23:59:16 +08:00
9ad44e727e 项目级大屏接口、人员任命导入导出接口 2025-09-20 20:13:38 +08:00
zt
275ed8946c Merge remote-tracking branch 'origin/dev' into dev 2025-09-20 20:08:02 +08:00
zt
325547f201 BUG 2025-09-20 20:07:50 +08:00
7fdd75da1f 变更 2025-09-20 19:59:35 +08:00
zt
5f8d494154 BUG,分包薪水转换 2025-09-20 19:16:56 +08:00
lcj
f1dffb54eb 无人机、红线、进度 2025-09-20 18:46:07 +08:00
zt
8e4200323a 人脸转换 2025-09-20 15:24:29 +08:00
zt
40a8f0770a 人脸转换 2025-09-20 15:08:44 +08:00
zt
7fcf5ef303 appbug 2025-09-20 10:16:32 +08:00
lcj
fc9b64fc36 修改bug 2025-09-19 20:28:48 +08:00
c7400d25fe 设计出图bug修改 2025-09-19 18:26:27 +08:00
zt
48a08ac729 数据 2025-09-19 15:38:55 +08:00
zt
31dcd00bbc 数据 2025-09-19 14:34:42 +08:00
zt
4e3d62af4a 物资 2025-09-19 11:40:19 +08:00
zt
1e7ffe891a 工作流和角色 2025-09-18 21:31:53 +08:00
zt
f706e73c30 施工人员文件处理 2025-09-18 18:27:29 +08:00
zt
a64ff2ff32 土地 2025-09-18 18:12:02 +08:00
zt
15b3176893 设计人员 2025-09-18 17:15:17 +08:00
lcj
ee7981a462 修改bug 2025-09-18 16:37:12 +08:00
5c86398b75 09-18-优化安装包文件上传,优化netty系统首次发送消息 2025-09-18 15:05:01 +08:00
5f3b24868f 考勤列表详情bug修改 2025-09-18 11:15:37 +08:00
zt
b8f223aea1 bug 2025-09-18 10:56:17 +08:00
lcj
bf6ea00b26 畅写 2025-09-18 08:57:37 +08:00
zt
0c4a697fea bug 2025-09-18 02:26:12 +08:00
zt
6d7aa8ca17 bug 2025-09-18 02:18:26 +08:00
zt
caa134dfc4 bug 2025-09-18 00:47:42 +08:00
zt
23f0f2fd16 bug 2025-09-17 22:55:35 +08:00
lcj
25690503e5 接入无人机大图,AI进度填报 2025-09-17 22:46:34 +08:00
928ba9783b gps大屏 2025-09-17 21:30:23 +08:00
6224b42479 09-17-优化 2025-09-17 20:02:35 +08:00
1d2ec60e68 09-17-修改通讯录获权限判断 2025-09-17 19:12:55 +08:00
b35ff07ba4 09-17-netty完善 2025-09-17 18:32:52 +08:00
zt
4ffb639d33 bug 2025-09-17 17:44:28 +08:00
6110374e67 bug修改 2025-09-17 16:40:15 +08:00
19f8e10714 获取工程量清单接口回退版本、项目级大屏人员定位接口 2025-09-17 16:14:04 +08:00
42c5f46f75 09-17-netty完善 2025-09-17 14:58:04 +08:00
646b503d47 09-17-netty连接后初始化只创建系统消息 2025-09-17 14:54:03 +08:00
f6ed7d3d7b app人员轨迹接口 2025-09-17 10:21:02 +08:00
lcj
223f1aee98 进度,人员bug 2025-09-16 22:01:07 +08:00
8b4e56e6e8 Merge remote-tracking branch 'origin/dev' into dev 2025-09-16 21:31:52 +08:00
b2ec975f22 09-16-01 2025-09-16 21:31:12 +08:00
zt
267d62e5a5 app 2025-09-16 21:23:56 +08:00
579fd04687 09-16-netty优化 2025-09-16 20:45:30 +08:00
4354d0a687 导入读取excel数据工具类优化 2025-09-16 18:39:02 +08:00
zt
0f9beafd9c 安全,质量 2025-09-16 16:53:21 +08:00
c07e9f76a6 bug修改 2025-09-16 16:23:49 +08:00
e42e81ab06 数据转换1.0 2025-09-16 16:15:17 +08:00
5d6d9020e7 09-15-netty优化,修复完善app版本模块 2025-09-16 16:10:06 +08:00
zt
7ee081c39c 考勤 2025-09-16 15:52:30 +08:00
lcj
d66d44460b 安全、质量、进度、施工人员;对象存储添加文件大小 2025-09-16 15:24:05 +08:00
zt
9d0c66b2d3 考勤 2025-09-16 09:34:03 +08:00
300579d32c Merge remote-tracking branch 'origin/dev' into dev 2025-09-15 20:14:41 +08:00
e8838a91d0 09-15-netty优化兼容其余类型,app版本模块 2025-09-15 20:14:30 +08:00
2f57979a41 合规性手续修改状态接口修改 2025-09-15 19:47:20 +08:00
zt
e075f8f6e5 考勤 2025-09-15 19:14:40 +08:00
6032c6fcba 合规性手续删除接口 2025-09-15 17:12:28 +08:00
da20820627 09-15-netty优化,系统消息发送方法添加roomId 2025-09-15 16:28:54 +08:00
e7c50c770e 09-15-netty优化,土地流转修复 2025-09-15 16:08:49 +08:00
ef68e7b7a8 Merge remote-tracking branch 'origin/dev' into dev 2025-09-15 15:35:46 +08:00
d9b879667b 09-15-netty优化,恢复用户列表权限,暂留部门列表权限 2025-09-15 15:35:28 +08:00
3e1b698ea8 09-14-netty优化,恢复用户列表权限,暂留部门列表权限 2025-09-15 15:24:52 +08:00
af81b1b740 物资工程量清单暂时复原 2025-09-15 11:18:19 +08:00
lcj
2d7f9ea42d 安全、质量 2025-09-15 09:27:47 +08:00
5b94ae37cd bug优化、app获取天气接口 2025-09-14 18:35:00 +08:00
26cf862d6e 09-14-netty优化 2025-09-14 17:40:52 +08:00
zt
f7cd344a0b bug 2025-09-14 16:58:23 +08:00
89c89cbfcd 数据转换 2025-09-14 16:52:43 +08:00
868616ea26 09-14-netty新增其他类型系统房间 2025-09-14 15:35:30 +08:00
b5cf663a2b 09-14-netty发送注册初始化消息 2025-09-14 10:59:26 +08:00
lcj
4c536ca269 安全、质量 2025-09-13 22:10:24 +08:00
zt
f0f30ce841 bug 2025-09-13 18:08:21 +08:00
4d2a2186c9 bug修改和批次需求计划优化 2025-09-13 18:03:14 +08:00
c277e5f80d 09-12-netty发送房间确认信息逻辑优化 2025-09-13 15:13:20 +08:00
21aae1f8c0 09-12-netty房间创建后发送确认消息 2025-09-13 12:34:25 +08:00
lcj
7e90c101e8 项目大屏 2025-09-12 23:08:40 +08:00
lcj
c3899ae6a2 企业大屏 2025-09-12 22:16:33 +08:00
lcj
c662e1aa4d 接go数据 2025-09-12 21:16:00 +08:00
91f01dc012 09-12-netty优化 2025-09-12 20:18:13 +08:00
ce972d030f 机械台账管理接口 2025-09-12 20:10:26 +08:00
lcj
dd025df653 企业大屏 2025-09-12 19:49:28 +08:00
d77e12ee4e 09-12-netty优化 2025-09-12 19:15:00 +08:00
zt
9afda7305c 考勤数据 2025-09-12 17:18:47 +08:00
974b11f8d3 09-12-netty优化 2025-09-12 15:43:51 +08:00
a1d1aaff49 字体文件 2025-09-12 11:57:16 +08:00
zt
9402c3c9f3 app 2025-09-12 09:54:19 +08:00
8e9307bf00 09-10-netty新增隐藏聊天接口 2025-09-11 20:27:24 +08:00
c68d6cb53c gps新增数据来源 2025-09-11 20:17:47 +08:00
8e84195e98 09-10-netty修复消除未读消息,修改列表赋值 2025-09-11 19:36:36 +08:00
542c4e91ac 09-10-netty优化系统房间的创建 2025-09-11 17:24:55 +08:00
47b0a4b087 09-10-netty优化,将系统消息存储为JSON 2025-09-11 17:18:51 +08:00
6ace8b0dc2 09-10-netty优化,序号修复,新增移除审核 2025-09-11 16:04:01 +08:00
1e33027d4f 修改金额精度问题 2025-09-11 15:26:07 +08:00
9fbc9dbc45 09-10-netty优化已读返回 2025-09-11 15:21:19 +08:00
8bf12d04cd 09-10-netty优化已读返回 2025-09-11 15:18:53 +08:00
00dcc00b05 09-10-netty优化 2025-09-11 11:17:55 +08:00
0b29401112 09-10-netty发送时添加name字段 2025-09-11 11:14:22 +08:00
lcj
e8c78865cb 接go数据 2025-09-11 09:23:39 +08:00
zt
a8cb16ab3f 通知 2025-09-10 20:21:01 +08:00
2c45762c66 09-10-netty优化 2025-09-10 19:41:11 +08:00
056b28af31 我的任务优化、工程量清单优化、gps消息websocket连接、物资管理:物资验收入库添加附件 2025-09-10 19:38:10 +08:00
lcj
7dd6d97a3e 进度管理app 2025-09-10 19:18:30 +08:00
zt
697beb67c4 通知 2025-09-10 17:34:49 +08:00
lcj
4d627af3a1 进度管理app、注解翻译项目名称 2025-09-10 16:43:49 +08:00
ab332c462f 09-10-netty设置系统消息type为2 2025-09-10 16:11:30 +08:00
0f3d1e38be 09-10-netty优化 2025-09-10 16:00:43 +08:00
lcj
4392a287cc 修改bug 2025-09-10 10:03:53 +08:00
lcj
f38538be33 修改进度管理 2025-09-10 00:15:55 +08:00
lcj
ede1e501b4 企业级大屏 2025-09-09 23:42:24 +08:00
4a2b62cf92 我的任务bug修改 2025-09-09 21:52:49 +08:00
zt
325f392e8f 大屏,消息 2025-09-09 20:39:00 +08:00
lcj
5b991396c2 企业级大屏 2025-09-09 19:49:14 +08:00
c75563b46a 09-09-修改 2025-09-09 18:53:28 +08:00
724ebf8dbd 09-09-netty完善修改 2025-09-09 18:47:48 +08:00
a52b9078a0 gps定位接口 2025-09-09 17:47:49 +08:00
9d682a3290 09-09-netty发送系统消息 2025-09-09 17:08:39 +08:00
lcj
abad289c2b 进度管理,企业级大屏,修改bug 2025-09-09 15:42:00 +08:00
820188863e 修改一览表单价精度 2025-09-09 15:24:17 +08:00
113b5debc9 供应商bug修改 2025-09-09 10:40:17 +08:00
6b4cd4ae0d Merge remote-tracking branch 'origin/dev' into dev 2025-09-09 09:12:54 +08:00
261dd0b643 09-09-netty消息搭建 2025-09-09 09:12:19 +08:00
zt
71f3810e51 Merge remote-tracking branch 'origin/dev' into dev 2025-09-08 20:03:11 +08:00
zt
fa835684d4 消息 2025-09-08 20:02:51 +08:00
e19ef3003a bug修改 2025-09-08 20:00:29 +08:00
zt
8a18223d06 二维码 2025-09-08 16:38:01 +08:00
c90828f98e 09-08-土地流转新增type区分完成和未完成 2025-09-08 16:02:26 +08:00
2ecb0063bf 限价、投标、招采、物资一览bug修改 2025-09-08 15:33:03 +08:00
zt
998547e63f bug 2025-09-08 11:47:14 +08:00
zt
78829ef5e7 bug 2025-09-08 11:42:36 +08:00
zt
da0dd8f78f bug 2025-09-06 19:20:40 +08:00
lcj
96d0406931 物资、里程碑进度execl导出 2025-09-06 19:07:10 +08:00
d7616960c6 gpsbug修改 2025-09-06 18:48:39 +08:00
66e8495859 bug修改 2025-09-06 18:35:51 +08:00
95c2858a64 bug修改 2025-09-06 18:33:06 +08:00
5cbb0c630b bug修改 2025-09-06 18:24:27 +08:00
lcj
e0cc521291 进度、物资管理模块 2025-09-06 15:30:57 +08:00
ff9f49b1d9 09-06-修复bug,完善功能 2025-09-06 15:16:41 +08:00
zt
b738bb821d app 2025-09-06 13:06:33 +08:00
2cea57646d 设计管理设计出图导入导出 2025-09-06 12:52:12 +08:00
lcj
ab5cd491d6 修改ai工单 2025-09-04 22:25:10 +08:00
lcj
3f3e20a64b 项目大屏进度数据统计,修改ai工单逻辑 2025-09-04 21:30:18 +08:00
zt
f5d9cb7fc1 Merge remote-tracking branch 'origin/dev' into dev 2025-09-04 21:27:26 +08:00
zt
5b05d2eb40 版本号 2025-09-04 21:27:11 +08:00
fbffc18a9f 考试卷app 2025-09-04 21:26:19 +08:00
zt
490820d080 版本号 2025-09-04 20:26:56 +08:00
zt
8e9b7c9b14 优化 2025-09-04 20:17:25 +08:00
ae3738c098 增加iText 7 核心模块 2025-09-04 19:57:50 +08:00
zt
127059e934 Merge remote-tracking branch 'origin/dev' into dev 2025-09-04 17:45:42 +08:00
zt
742e67af23 考勤 2025-09-04 17:45:21 +08:00
lcj
4e61a4afe9 人员工资、退场,巡检工单 2025-09-04 17:05:00 +08:00
43d249d68a 配置文件修改 2025-09-04 15:18:14 +08:00
dc8a89f05e gps接口 2025-09-04 11:23:50 +08:00
17d4041ef3 变更jar,增加考试卷 2025-09-04 10:56:54 +08:00
zt
d19cda78b3 考勤 2025-09-04 09:27:21 +08:00
2f0b548f20 BUG修改 2025-09-03 20:36:55 +08:00
lcj
f1aed20560 安全日志、ai工单接口 2025-09-03 15:44:13 +08:00
zt
8c412d033b 考勤 2025-09-03 15:39:13 +08:00
a929225ed5 09-03-修复供应商入库修改 2025-09-03 15:11:01 +08:00
zt
3b6b1d53a9 app,角色,菜单 2025-09-03 10:26:28 +08:00
lcj
81162852a2 修改人员实名认证 2025-09-03 10:24:09 +08:00
lcj
f584e6233c 修改bug 2025-09-02 20:30:01 +08:00
e8da350f0b 收资清单模板导出接口优化 2025-09-02 19:08:16 +08:00
e916829032 收资清单模板导出接口优化 2025-09-02 18:58:56 +08:00
8c131cb9a5 新增收资清单模板导出接口 2025-09-02 18:57:32 +08:00
lcj
9aef0d4b86 物资领料逻辑修改 app人员管理接口 2025-09-02 17:32:42 +08:00
de5c569f88 09-02-更新apifox模块 2025-09-02 16:54:01 +08:00
lcj
79edeb6ccd 安全模块、人员模块app接口 2025-09-02 15:14:06 +08:00
a3ef525ab6 修改设计出图bug 2025-09-02 09:54:26 +08:00
659e4e3d5f 09-02-完善税率字段对应sql 2025-09-02 09:11:33 +08:00
lcj
96e6c75949 修改材料设备出入库逻辑 2025-09-01 17:33:19 +08:00
711c473749 09-01-供应商入库新增导入,修改字段;物资设备清单新增按设备名称查询,新增税率字段. 2025-09-01 17:08:21 +08:00
4636aa3c05 修改投标成本清单列表查询接口 2025-08-30 06:49:46 +08:00
lcj
788f13fa7b 修改采购联系单 2025-08-30 06:29:25 +08:00
a588b94310 修改分标策划、招标计划新增接口 2025-08-30 04:59:51 +08:00
lcj
b44de3ff49 修改站班会日期查询 2025-08-30 03:58:37 +08:00
lcj
5d643fbc6a 修改班组 2025-08-30 03:47:18 +08:00
lcj
19fd73f4c8 修改施工人员身份证转换 2025-08-30 03:32:36 +08:00
lcj
a07792c8e3 修改进度、产值 2025-08-30 03:25:03 +08:00
zt
8a29ffdd2e 优化 2025-08-30 02:05:48 +08:00
d46f672b9a 修改联系单排序 2025-08-30 00:53:31 +08:00
lcj
d6528845e4 修改项目结构,施工产值 2025-08-30 00:33:17 +08:00
lcj
0ff805683f 修改物质供货总计划逻辑 2025-08-29 23:18:22 +08:00
3f79a955b3 代码合并 2025-08-29 22:37:56 +08:00
zt
971c8c277d 优化 2025-08-29 20:52:14 +08:00
lcj
12f02638a2 修改物质供货总计划逻辑 2025-08-29 20:15:53 +08:00
b1c21b1f88 Merge remote-tracking branch 'origin/dev' into dev 2025-08-29 20:02:16 +08:00
642d5c73ca feat:增加批量新增或修改物资的权限 2025-08-29 19:59:43 +08:00
zt
d7054d6f02 优化 2025-08-29 18:17:04 +08:00
e85bbca73b 设计方案权限标识符 2025-08-29 17:11:21 +08:00
lcj
3f5396e347 修改施工产值查询 2025-08-29 14:55:23 +08:00
zt
c9041df9b8 优化 2025-08-29 04:24:59 +08:00
lcj
87e510aafc 修改权限字符 2025-08-29 03:54:05 +08:00
4e4497a07f 设计权限 2025-08-29 01:40:18 +08:00
lcj
7c4f6b8add 权限字符 2025-08-29 01:38:38 +08:00
7daf2ada66 设计权限 2025-08-29 01:30:46 +08:00
zt
073f614a21 优化 2025-08-28 23:32:19 +08:00
zt
1878a7dab3 优化 2025-08-28 22:37:32 +08:00
lcj
aa31eb97b9 修改部门和项目、分包关联 2025-08-28 21:28:25 +08:00
lcj
4f8776930e 添加分包和供应商关联 2025-08-28 19:56:44 +08:00
f171238029 分标策划、招标计划bug修改 2025-08-28 18:19:42 +08:00
zt
377892f691 优化 2025-08-28 14:41:12 +08:00
zt
7e0cd7c946 优化 2025-08-28 14:37:30 +08:00
936145138e 限价修改bug修改 2025-08-28 14:33:37 +08:00
lcj
e6f37662b0 修改权限逻辑 2025-08-28 04:20:40 +08:00
3ea6050dc3 合约规划、合规性手续bug修改 2025-08-27 18:41:22 +08:00
f7940e23fa 08-27-分项工程单价导入修改 2025-08-27 17:32:36 +08:00
zt
3d57edf374 优化 2025-08-27 16:43:36 +08:00
797e913b69 变更 2025-08-26 21:30:08 +08:00
lcj
2e40c3ac6d 修改进度计划、施工产值 2025-08-26 21:15:59 +08:00
61dc34c79e 变更 2025-08-26 21:12:56 +08:00
zt
5772b5fc83 优化 2025-08-26 21:05:13 +08:00
zt
971101d5e8 消息优化 2025-08-26 14:58:08 +08:00
lcj
508d81bedf 修bug 2025-08-25 20:20:43 +08:00
zt
57a39ad727 bug、优化 2025-08-25 20:13:30 +08:00
126fdeb6ba bug修改 2025-08-25 19:55:25 +08:00
zt
8e07ecc69b bug、优化 2025-08-25 18:32:19 +08:00
c26f23cfb0 1 2025-08-25 16:01:36 +08:00
lcj
b008a472fc 修bug 2025-08-23 15:16:49 +08:00
c2ce524ef3 变更产值 2025-08-23 10:32:14 +08:00
zt
a2b33f3b53 优化 2025-08-23 10:24:41 +08:00
551dd084b8 11 2025-08-23 10:17:28 +08:00
35323fa352 设计完工产值 2025-08-23 09:02:25 +08:00
3f6af11dff Merge remote-tracking branch 'origin/dev' into lcj 2025-08-23 09:01:23 +08:00
2fda6c8930 设计完工产值 2025-08-23 06:40:25 +08:00
2854 changed files with 266522 additions and 9126 deletions

Binary file not shown.

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>
@ -307,7 +316,6 @@
<artifactId>snail-job-client-job-core</artifactId>
<version>${snailjob.version}</version>
</dependency>
<!-- 加密包引入 -->
<dependency>
<groupId>org.bouncycastle</groupId>

View File

@ -6,6 +6,7 @@ import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -28,6 +29,8 @@ import org.dromara.common.social.utils.SocialUtils;
import org.dromara.common.sse.dto.SseMessageDto;
import org.dromara.common.sse.utils.SseMessageUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.dromara.system.domain.bo.SysTenantBo;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysTenantVo;
@ -41,16 +44,20 @@ import org.dromara.web.domain.vo.TenantListVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.dromara.web.service.SysRegisterService;
import org.dromara.websocket.domain.ChatGroup;
import org.dromara.websocket.service.Impl.ChatGroupServiceImpl;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 认证
@ -72,6 +79,7 @@ public class AuthController {
private final ISysSocialService socialUserService;
private final ISysClientService clientService;
private final ScheduledExecutorService scheduledExecutorService;
private final ChatGroupServiceImpl chatGroupService;
/**
@ -103,10 +111,7 @@ public class AuthController {
// Long userId = LoginHelper.getUserId();
// scheduledExecutorService.schedule(() -> {
// SseMessageDto dto = new SseMessageDto();
// dto.setMessage("欢迎登录新能源项目管理系统");
// dto.setUserIds(List.of(userId));
// SseMessageUtils.publishMessage(dto);
// chatGroupService.createSystem(userId,client.getClientKey());
// }, 5, TimeUnit.SECONDS);
return R.ok(loginVo);
}
@ -193,6 +198,17 @@ public class AuthController {
return R.ok();
}
@PostMapping("/app/register")
public R<Void> appRegister(@Validated @RequestBody RegisterBody user) {
if("sms".equals(user.getGrantType())){
registerService.appSmsRegister(user);
}else {
registerService.appRegister(user);
}
return R.ok();
}
/**
* 登录页面租户下拉框
*

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;
@ -57,19 +59,26 @@ public class CaptchaController {
*/
@RateLimiter(key = "#phonenumber", time = 60, count = 1)
@GetMapping("/resource/sms/code")
public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber,String type) {
String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber;
String code = RandomUtil.randomNumbers(4);
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
// 验证码模板id 自行处理 (查数据库或写死均可)
String templateId = "";
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put("code", code);
SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
map.put("1", code);
map.put("2", Constants.CAPTCHA_EXPIRATION.toString());
String configName;
if("login".equals(type)){
configName = "config2";
}else{
configName = "config3";
}
SmsBlend smsBlend = SmsFactory.getSmsBlend(configName);
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();
}
@ -133,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

@ -55,7 +55,8 @@ public class UserActionListener implements SaTokenListener {
String username = (String) loginModel.getExtra(LoginHelper.USER_NAME_KEY);
String tenantId = (String) loginModel.getExtra(LoginHelper.TENANT_KEY);
dto.setUserName(username);
dto.setClientKey((String) loginModel.getExtra(LoginHelper.CLIENT_KEY));
String clientId = (String) loginModel.getExtra(LoginHelper.CLIENT_KEY);
dto.setClientKey(clientId);
dto.setDeviceType(loginModel.getDevice());
dto.setDeptName((String) loginModel.getExtra(LoginHelper.DEPT_NAME_KEY));
TenantHelper.dynamic(tenantId, () -> {
@ -75,7 +76,7 @@ public class UserActionListener implements SaTokenListener {
SpringUtils.context().publishEvent(logininforEvent);
// 更新登录信息
loginService.recordLoginInfo((Long) loginModel.getExtra(LoginHelper.USER_KEY), ip);
log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
log.info("user doLogin, userId:{}, token:{}, clientid{}", loginId, tokenValue, clientId);
}
/**

View File

@ -154,6 +154,12 @@ public class SysLoginService {
loginUser.setTenantId(user.getTenantId());
loginUser.setUserId(userId);
loginUser.setDeptId(user.getDeptId());
List<Long> projectIds = user.getProjectIds();
Long projectId = null;
if (CollUtil.isNotEmpty(projectIds)) {
projectId = projectIds.getFirst();
}
loginUser.setProjectId(projectId);
loginUser.setUsername(user.getUserName());
loginUser.setNickname(user.getNickName());
loginUser.setUserType(user.getUserType());
@ -188,7 +194,7 @@ public class SysLoginService {
/**
* 登录校验
*/
public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) {
public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) {
String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username;
String loginFail = Constants.LOGIN_FAIL;

View File

@ -77,6 +77,90 @@ public class SysRegisterService {
recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success"));
}
/**
* 注册
*/
public void appRegister(RegisterBody registerBody) {
String tenantId = registerBody.getTenantId();
String username = registerBody.getPhonenumber();
String password = registerBody.getPassword();
// 校验用户类型是否存在
String userType = UserType.getUserType(registerBody.getUserType()).getUserType();
// 校验密码是否符合要求
// String pattern = "^(?!.*\\s)(?!^[a-zA-Z]+$)(?!^[0-9]+$)(?!^[^a-zA-Z0-9]+$)(?!^[a-zA-Z0-9]+$).{8,18}$";
// boolean isValid = password.matches(pattern);
// if (!isValid) {
// throw new UserException("注册失败密码需满足818位包含大小写字母、数字、特殊字符中的至少三种组合");
// }
SysUserBo sysUser = new SysUserBo();
sysUser.setUserName(username);
sysUser.setNickName(username);
sysUser.setPhonenumber(username);
sysUser.setPassword(BCrypt.hashpw(password));
sysUser.setUserType(userType);
sysUser.setEmail(registerBody.getEmail());
SysUser sysUserByPhonenumber = userMapper.selectDefFlagUser(username);
if(sysUserByPhonenumber != null){
sysUser.setUserId(sysUserByPhonenumber.getUserId());
userMapper.updateDefFlag(sysUser);
userMapper.updateConstructionUser(sysUserByPhonenumber.getUserId());
}else {
boolean exist = TenantHelper.dynamic(tenantId, () -> {
return userMapper.exists(new LambdaQueryWrapper<SysUser>()
.eq(SysUser::getPhonenumber, sysUser.getPhonenumber()));
});
if (exist) {
throw new UserException("user.register.save.error", username);
}
boolean regFlag = userService.registerUser(sysUser, tenantId);
if (!regFlag) {
throw new UserException("user.register.error");
}
}
recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success"));
}
/**
* 短信注册
*/
public void appSmsRegister(RegisterBody registerBody) {
String tenantId = registerBody.getTenantId();
String username = registerBody.getPhonenumber();
String smsCode = registerBody.getSmsCode();
validateSmsCode(tenantId, username, smsCode);
// 校验用户类型是否存在
String userType = UserType.getUserType(registerBody.getUserType()).getUserType();
// 验证码开关
SysUserBo sysUser = new SysUserBo();
sysUser.setUserName(username);
sysUser.setNickName(username);
sysUser.setPhonenumber(username);
sysUser.setUserType(userType);
boolean exist = TenantHelper.dynamic(tenantId, () -> {
return userMapper.exists(new LambdaQueryWrapper<SysUser>()
.eq(SysUser::getPhonenumber, sysUser.getPhonenumber()));
});
if (exist) {
throw new UserException("user.register.save.error", username);
}
boolean regFlag = userService.registerUser(sysUser, tenantId);
if (!regFlag) {
throw new UserException("user.register.error");
}
recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success"));
}
/**
* 校验验证码
*
@ -98,6 +182,18 @@ public class SysRegisterService {
}
}
/**
* 校验短信验证码
*/
private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) {
String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
if (StringUtils.isBlank(code)) {
recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
throw new CaptchaExpireException();
}
return code.equals(smsCode);
}
/**
* 记录登录信息
*

View File

@ -3,6 +3,7 @@ package org.dromara.web.service.impl;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
@ -24,6 +25,8 @@ import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.project.domain.BusUserProjectRelevancy;
import org.dromara.project.service.IBusUserProjectRelevancyService;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo;
@ -33,6 +36,8 @@ import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 密码认证策略
*
@ -46,6 +51,7 @@ public class PasswordAuthStrategy implements IAuthStrategy {
private final CaptchaProperties captchaProperties;
private final SysLoginService loginService;
private final SysUserMapper userMapper;
private final IBusUserProjectRelevancyService userProjectRelevancyService;
@Override
public LoginVo login(String body, SysClientVo client) {
@ -117,6 +123,14 @@ public class PasswordAuthStrategy implements IAuthStrategy {
log.info("登录用户:{} 已被停用.", username);
throw new UserException("user.blocked", username);
}
if (!SystemConstants.SUPER_ADMIN_ID.equals(user.getUserId())) {
List<BusUserProjectRelevancy> list = userProjectRelevancyService.lambdaQuery()
.eq(BusUserProjectRelevancy::getUserId, user.getUserId())
.list();
if (CollUtil.isNotEmpty(list)) {
user.setProjectIds(list.stream().map(BusUserProjectRelevancy::getProjectId).toList());
}
}
return user;
}

View File

@ -1,3 +1,7 @@
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 8899
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
@ -19,19 +23,25 @@ snail-job:
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
host: 192.168.110.119
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:
host: 127.0.0.1
# 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
@ -52,14 +62,38 @@ spring:
url: jdbc:mysql://192.168.110.2:13386/xinnengyuandev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: xinnengyuandev
password: StRWCZdZirysNSs2
# url: jdbc:mysql://192.168.110.2:13386/xinnengyuan?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# username: xinnengyuan
# password: mEZPC5Sdf3r2HENi
# 从库数据源
# slave:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://192.168.110.2:13386/zmkgdev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: zmkgdev
# password: JhYxREf25AXdy3h8
# slave:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://192.168.110.2:13386/zmkgc?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: zmkgc
# password: nWKDKRNRT48tFBdh
# slave1:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://192.168.110.2:13386/zmkgprod?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: zmkgprod
# password: MaY8nehwWkJriWPm
# slave2:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://192.168.110.2:13386/zmkgc?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: zmkgc
# password: nWKDKRNRT48tFBdh
# slave:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://192.168.110.2:13386/zmkgprod?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: zmkgprod
# password: MaY8nehwWkJriWPm
# oracle:
# type: ${spring.datasource.type}
# driverClassName: oracle.jdbc.OracleDriver
@ -102,7 +136,7 @@ spring.data:
# 端口默认为6379
port: 9287
# 数据库索引
database: 10
database: 16
# redis 密码必须配置
password: syar23rdsaagdrsa
# 连接超时时间
@ -161,7 +195,7 @@ sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截接口配置不受此限制
restricted: true
restricted: false
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
@ -180,12 +214,45 @@ sms:
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
# 登录
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
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
--- # 三方授权
@ -274,7 +341,10 @@ dxf2GeoJson:
file-name: main.exe
ys7:
app-key: 3acf9f1a43dc4209841e0893003db0a2
app-secret: 4bbf3e9394f55d3af6e3af27b2d3db36
app-secret: 09e29c70ae1161fbc3ce2030fc09ba2e
job:
capture-enabled: false # 控制是否启用萤石抓拍任务
device-sync-enabled: false # 控制是否同步萤石设备
#ys7:
# app-key: 081b0d6d5f7f4de8bc5c7fa350fb26ec
# app-secret: caa37b9f60ef02deb57e563bc190e6db
@ -287,7 +357,25 @@ sparta:
id-card:
encrypt-key: 7ae260d150a14027d2238a1cf80a48ef
recognizer:
url: http://192.168.110.5:50070
url: http://192.168.110.5:50071
qrCode:
url: http://192.168.110.151:7788
# 无人机大图
drone:
url: http://192.168.110.2:9512
# 聊天服务
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

@ -1,3 +1,7 @@
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 9918
--- # 临时文件存储位置 避免临时文件被系统清理报错
spring.servlet.multipart.location: /ruoyi/server/temp
@ -35,6 +39,12 @@ snail-job:
--- # 数据源配置
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
@ -105,7 +115,7 @@ spring.data:
# 端口默认为6379
port: 9287
# 数据库索引
database: 6
database: 17
# redis 密码必须配置
password: syar23rdsaagdrsa
# 连接超时时间
@ -164,7 +174,7 @@ sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截接口配置不受此限制
restricted: true
restricted: false
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
@ -183,12 +193,45 @@ sms:
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
# 登录
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
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:
@ -275,8 +318,11 @@ weather:
dxf2GeoJson:
file-name: main
ys7:
app-key: 3acf9f1a43dc4209841e0893003db0a2
app-secret: 4bbf3e9394f55d3af6e3af27b2d3db36
app-key: xxx
app-secret: xxx
job:
capture-enabled: false # 控制是否启用萤石抓拍任务
device-sync-enabled: false # 控制是否同步萤石设备
# 斯巴达算法
sparta:
url: http://119.3.204.120:8040
@ -286,7 +332,25 @@ sparta:
id-card:
encrypt-key: 7ae260d150a14027d2238a1cf80a48ef
recognizer:
url: http://192.168.110.5:50070
url: http://192.168.110.5:50071
qrCode:
url: http://xny.yj-3d.com:7171
url: http://xny.yj-3d.com:7788
# 无人机大图
drone:
url: http://192.168.110.2:9512
# 聊天服务
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

@ -1,3 +1,7 @@
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 8899
--- # 临时文件存储位置 避免临时文件被系统清理报错
spring.servlet.multipart.location: /ruoyi/server/temp
@ -16,7 +20,7 @@ spring.boot.admin.client:
--- # snail-job 配置
snail-job:
enabled: false
enabled: true
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config`表
@ -29,12 +33,18 @@ snail-job:
# 随主应用端口漂移
port: 2${server.port}
# 客户端ip指定
host:
host: 127.0.0.1
# 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
@ -60,6 +70,21 @@ spring:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://192.168.110.2:13386/zmkgc?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: zmkgc
# password: nWKDKRNRT48tFBdh
# slave1:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://192.168.110.2:13386/zmkgprod?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: zmkgprod
# password: MaY8nehwWkJriWPm
# # 从库数据源
# 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:
@ -164,7 +189,7 @@ sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截接口配置不受此限制
restricted: true
restricted: false
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
@ -183,12 +208,45 @@ sms:
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
# 登录
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
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:
@ -276,7 +334,10 @@ dxf2GeoJson:
file-name: main
ys7:
app-key: 3acf9f1a43dc4209841e0893003db0a2
app-secret: 4bbf3e9394f55d3af6e3af27b2d3db36
app-secret: 09e29c70ae1161fbc3ce2030fc09ba2e
job:
capture-enabled: true # 控制是否启用萤石抓拍任务
device-sync-enabled: true # 控制是否同步萤石设备
# 斯巴达算法
sparta:
url: http://119.3.204.120:8040
@ -286,7 +347,25 @@ sparta:
id-card:
encrypt-key: 7ae260d150a14027d2238a1cf80a48ef
recognizer:
url: http://192.168.110.5:50070
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: 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

@ -22,7 +22,7 @@ captcha:
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 8899
# port: 8899
servlet:
# 应用的访问路径
context-path: /
@ -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名称)
@ -106,6 +112,12 @@ sa-token:
is-share: false
# jwt秘钥
jwt-secret-key: abcdefghijklmnopqrstuvwxyz
# token有效期单位s 默认30天, -1代表永不过期
timeout: 2592000
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
active-timeout: 2592000
# 同一账号最大登录数量,-1代表不限
max-login-count: -1
# security配置
security:
@ -122,9 +134,16 @@ security:
- /warm-flow-ui/**
- /warm-flow/**
- /other/ys7Device/webhook
- /**/changxie/callback/**
- /progress/progressPlanDetail/insert/numberAI
- /project/project/list/sub/matrix/**
- /gps/equipment/dataAcceptance
- /resource/oss/upload
# todo 仅测试
- /facility/matrix/**
- /**/changxie/callback/**
- /hat/device/data
- /websocket/ue
- /websocket/vehicle
# 多租户配置
tenant:
@ -163,7 +182,7 @@ mybatis-plus:
# 数据加密
mybatis-encryptor:
# 是否开启加密
enable: false
enable: true
# 默认加密算法
algorithm: BASE64
# 编码方式 BASE64/HEX。默认BASE64
@ -194,8 +213,13 @@ api-decrypt:
- /actuator/** # 放行监控接口
- /other/ys7Device/webhook # 放行萤石云设备回调接口
- /auth/register # 放行注册接口
- /gps/equipment/dataAcceptance # GPS数据接收接口
springdoc:
default-flat-param-object: true
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
api-docs:
# 是否开启接口文档
enabled: true
@ -215,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.通用模块
@ -247,12 +275,10 @@ springdoc:
packages-to-scan: org.dromara.design
- group: 13.工作流模块
packages-to-scan: org.dromara.workflow
- group: 14.罗成模块
packages-to-scan: org.dromara.cory
- group: 14.合同模块
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.材料设备模块
@ -261,21 +287,36 @@ springdoc:
packages-to-scan: org.dromara.out
- group: 19.消息模块
packages-to-scan: org.dromara.message
# - group: 20.手续模块
# packages-to-scan: org.dromara.formalities
- 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.投标管理模块
- group: 23.GPS定位模块
packages-to-scan: org.dromara.gps
- group: 24.招标模块
packages-to-scan: org.dromara.tender
- group: 25.数据迁移模块
packages-to-scan: org.dromara.transferData
- group: 26.netty消息模块
packages-to-scan: org.dromara.websocket
- group: 27.新中大模块
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: 20.合同模块
# packages-to-scan: org.dromara.ctr
# - group: 21.招标模块
# packages-to-scan: org.dromara.tender
- 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
@ -290,6 +331,18 @@ xss:
excludeUrls:
- /system/notice
- /warm-flow/save-xml
- /project/project
- /xzd/contractDetails/**
- /xzd/contractChange/**
- /xzd/comprehensive/csContractChange/**
- /xzd/comprehensive/csContractInformation/**
- /xzd/hetongbiangeng/**
- /xzd/fenbaohetongjungong/**
- /xzd/fenbaohetongbiangg/**
- /xzd/fenbaohetongxinxi/**
- /xzd/contractManagement/**
- /xzd/jixiehetongxinxi/contractMachinery/**
- /xzd/jixiehetongbiang/machineryContractAlteration/**
# 全局线程池相关配置
# 如使用JDK21请直接使用虚拟线程 不要开启此配置
@ -324,11 +377,17 @@ management:
sse:
enabled: true
path: /resource/sse
wait: /task/taskWaiting
copy: /task/taskCopyList
project: /personnel-management/project
violationRecord: /safety-management/ai/violationRecord
drawing: /design-management/volumeCatalog
--- # websocket
websocket:
# 如果关闭 需要和前端开关一起关闭
enabled: false
enabled: true
# 路径
path: /resource/websocket
# 设置访问源地址

View File

@ -1,20 +1,66 @@
package org.dromara.test;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.utils.IdCardEncryptorUtil;
import org.dromara.contractor.domain.SubConstructionUser;
import org.dromara.contractor.service.ISubConstructionUserService;
import org.dromara.contractor.service.ISubUserSalaryDetailService;
import org.dromara.design.service.IDesTechnicalStandardService;
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;
import org.dromara.manager.ys7manager.vo.Ys7ResponseVo;
import org.dromara.other.domain.OthYs7Device;
import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCreateByCapture;
import org.dromara.other.service.IOthYs7DeviceImgService;
import org.dromara.other.service.IOthYs7DeviceService;
import org.dromara.out.domain.OutConstructionValue;
import org.dromara.out.domain.OutConstructionValueRange;
import org.dromara.out.service.IOutConstructionValueRangeService;
import org.dromara.out.service.IOutConstructionValueService;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryCreateReq;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.progress.service.IPgsProgressCategoryTemplateService;
import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService;
import org.dromara.system.service.ISysDeptService;
import org.dromara.tender.service.impl.TenderSupplierInputServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Date;
import java.util.List;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* @author lilemy
@ -30,6 +76,12 @@ public class DemoTest {
@Resource
private IPgsProgressCategoryService progressCategoryService;
@Resource
private IPgsProgressCategoryTemplateService progressCategoryTemplateService;
@Resource
private IPgsProgressPlanDetailService progressPlanDetailService;
@Resource
private IFacMatrixService matrixService;
@ -41,6 +93,236 @@ public class DemoTest {
@Resource
private ISysDeptService deptService;
@Autowired
private TenderSupplierInputServiceImpl tenderSupplierInputService;
@Resource
private ISubConstructionUserService constructionUserService;
@Resource
private ISubUserSalaryDetailService userSalaryDetailService;
@Resource
private IdCardEncryptorUtil idCardEncryptorUtil;
@Resource
private IFacPhotovoltaicPanelService photovoltaicPanelService;
@Resource
private IOutConstructionValueRangeService constructionValueRangeService;
@Resource
private IOutConstructionValueService constructionValueService;
@Resource
private IOthYs7DeviceService ys7DeviceService;
@Resource
private IOthYs7DeviceImgService ys7DeviceImgService;
@Resource
private Ys7Manager ys7Manager;
@Test
void testConstructionValue() {
/* LocalDate today = LocalDate.now();
// 找到本周一
LocalDate thisMonday = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
// 上周一 = 本周一 - 1 周
LocalDate lastMonday = thisMonday.minusWeeks(1);
// 上周日 = 上周一 + 6 天
LocalDate lastSunday = lastMonday.plusDays(6);
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, 27); // 截止时间2025-09-15
// 如果起始不是周一,调整到当周的周一
if (start.getDayOfWeek() != DayOfWeek.MONDAY) {
start = start.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
}
while (!start.isAfter(end)) {
LocalDate monday = start;
LocalDate sunday = start.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
// 输出本周的周一和周日
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")
.list();
if (CollUtil.isEmpty(planDetailList)) {
// 下一周
start = start.plusWeeks(1);
continue;
}
// 获取进度类别
List<Long> categoryIds = planDetailList.stream()
.map(PgsProgressPlanDetail::getProgressCategoryId)
.distinct()
.toList();
List<PgsProgressCategory> categoryList = progressCategoryService.lambdaQuery()
.in(CollUtil.isNotEmpty(categoryIds), PgsProgressCategory::getId, categoryIds)
.list();
Map<Long, PgsProgressCategory> categoryMap = categoryList.stream()
.collect(
Collectors.toMap(PgsProgressCategory::getId,
Function.identity(),
(v1, v2) -> v1)
);
// 为每一个项目创建一个施工产值范围
Set<Long> projectIds = planDetailList.stream()
.map(PgsProgressPlanDetail::getProjectId).collect(Collectors.toSet());
// 获取所有父级项目
List<BusProject> projectList = projectService.listByIds(projectIds);
List<Long> allProjectIds = projectList
.stream().map(project -> {
if (project.getPId() != 0L) {
return project.getPId();
} else {
return project.getId();
}
}).distinct().toList();
// 根据项目区分
Map<Long, List<PgsProgressPlanDetail>> detailMap = planDetailList.stream()
.collect(Collectors.groupingBy(PgsProgressPlanDetail::getProjectId));
List<OutConstructionValue> saveList = new ArrayList<>();
List<PgsProgressPlanDetail> allUpdateList = new ArrayList<>();
List<OutConstructionValueRange> ranges = allProjectIds.stream().map(id -> {
OutConstructionValueRange range = new OutConstructionValueRange();
long rangeId = IdWorker.getId(range);
range.setId(rangeId);
range.setProjectId(id);
range.setStartDate(monday);
range.setEndDate(sunday);
// 获取所有子项目
List<Long> subProject = new ArrayList<>(projectList.stream()
.filter(project -> Objects.equals(project.getPId(), id))
.map(BusProject::getId)
.distinct()
.toList());
subProject.add(id);
List<PgsProgressPlanDetail> detailList = new ArrayList<>();
for (Long p : subProject) {
List<PgsProgressPlanDetail> details = detailMap.getOrDefault(p, List.of());
detailList.addAll(details);
}
if (CollUtil.isEmpty(detailList)) {
return null;
}
BigDecimal allConstructionValue = BigDecimal.ZERO;
BigDecimal allOwnerValue = BigDecimal.ZERO;
List<PgsProgressPlanDetail> updateList = new ArrayList<>();
for (PgsProgressPlanDetail planDetail : detailList) {
OutConstructionValue value = new OutConstructionValue();
Long progressCategoryId = planDetail.getProgressCategoryId();
PgsProgressCategory category = categoryMap.get(progressCategoryId);
if (category == null) {
continue;
}
value.setProjectId(id);
value.setRangeId(rangeId);
value.setMatrixId(category.getMatrixId());
value.setProgressCategoryId(progressCategoryId);
value.setDetailId(planDetail.getId());
BigDecimal finishedNumber = planDetail.getFinishedNumber();
BigDecimal aiFill = planDetail.getAiFill();
// 如果完成数量为0, 则不保存
if (finishedNumber.compareTo(BigDecimal.ZERO) == 0) {
continue;
}
value.setArtificialNum(finishedNumber.subtract(aiFill).intValue());
value.setUavNum(aiFill.intValue());
value.setPlanNum(planDetail.getPlanNumber().intValue());
value.setReportDate(planDetail.getDate());
value.setPlanDate(planDetail.getDate());
// 计算产值
BigDecimal constructionPrice = category.getConstructionPrice();
BigDecimal ownerPrice = category.getOwnerPrice();
BigDecimal constructionValue = constructionPrice.multiply(finishedNumber).setScale(4, RoundingMode.HALF_UP);
BigDecimal ownerValue = ownerPrice.multiply(finishedNumber).setScale(4, RoundingMode.HALF_UP);
value.setOutValue(constructionValue);
value.setOwnerValue(ownerValue);
// 统计总产值
allConstructionValue = allConstructionValue.add(constructionValue);
allOwnerValue = allOwnerValue.add(ownerValue);
// 添加需要修改状态的计划详情
PgsProgressPlanDetail update = new PgsProgressPlanDetail();
update.setId(planDetail.getId());
update.setStatus("2");
updateList.add(update);
saveList.add(value);
}
range.setOutValue(allConstructionValue.setScale(4, RoundingMode.HALF_UP));
range.setOwnerValue(allOwnerValue.setScale(4, RoundingMode.HALF_UP));
// 如果产值都为0则不保存
if (allConstructionValue.compareTo(BigDecimal.ZERO) == 0 && allOwnerValue.compareTo(BigDecimal.ZERO) == 0) {
return null;
}
allUpdateList.addAll(updateList);
return range;
}).filter(Objects::nonNull).toList();
// 保存数据
if (CollUtil.isNotEmpty(ranges)) {
boolean saveBatch = constructionValueRangeService.saveBatch(ranges);
if (!saveBatch) {
throw new ServiceException("同步计划详情到施工产值失败,数据库异常", HttpStatus.ERROR);
}
}
if (CollUtil.isNotEmpty(saveList)) {
boolean saved = constructionValueService.saveBatch(saveList);
if (!saved) {
throw new ServiceException("同步计划详情到施工产值失败,数据库异常", HttpStatus.ERROR);
}
}
if (CollUtil.isNotEmpty(allUpdateList)) {
boolean updateBatch = progressPlanDetailService.updateBatchById(allUpdateList);
if (!updateBatch) {
throw new ServiceException("同步计划详情到施工产值失败,数据库异常", HttpStatus.ERROR);
}
}
// 下一周
start = start.plusWeeks(1);
}
/* LocalDate today = LocalDate.of(2025, 9, 16);
LocalDate localDate = today.minusDays(1);*/
/* // 找到本周一
LocalDate thisMonday = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
// 上周一 = 本周一 - 1 周
LocalDate lastMonday = thisMonday.minusWeeks(1);
// 上周日 = 上周一 + 6 天
LocalDate lastSunday = lastMonday.plusDays(6);*/
}
@Test
void setIdCardEncryptorUtil() {
List<SubConstructionUser> list = constructionUserService.list();
List<SubConstructionUser> update = list.stream().filter(user -> StringUtils.isNotBlank(user.getSfzNumber()))
.filter(user -> IdcardUtil.isValidCard18(user.getSfzNumber()))
.toList().stream()
.map(user -> {
SubConstructionUser updateUser = new SubConstructionUser();
updateUser.setId(user.getId());
updateUser.setSfzNumber(idCardEncryptorUtil.encrypt(user.getSfzNumber()));
return updateUser;
}).toList();
constructionUserService.updateBatchById(update);
}
@Test
void test() {
@ -85,8 +367,233 @@ public class DemoTest {
}
@Test
void testProject() {
// 初始化施工类型模版
Boolean init = progressCategoryTemplateService.initTemplateByProject(1958935730389606402L);
}
/* @Test
void testDeptProject() {
deptService.selectProjectIdById(100L);
deptService.selectProjectIdById(1937478258803171329L);
}*/
@Test
void tenderExport() {
// 同步修改用户表的team_id字段并添加入场时间
LambdaUpdateWrapper<SubConstructionUser> constructionUserLuw = Wrappers.lambdaUpdate(SubConstructionUser.class)
.in(SubConstructionUser::getId, 1961446214960435201L, 1963077776210710529L, 1963080543771832321L, 1963151975159324673L)
.set(SubConstructionUser::getEntryDate, new Date());
constructionUserService.update(constructionUserLuw);
}
@Test
void testSalary() {
List<SubConstructionUser> list = constructionUserService.lambdaQuery()
.eq(SubConstructionUser::getProjectId, 1897160897167638529L)
.list();
if (CollUtil.isNotEmpty(list)) {
for (SubConstructionUser user : list) {
for (int i = 1; i < 7; i++) {
userSalaryDetailService.insertByAttendance(user.getSysUserId(), LocalDate.now().minusDays(i));
}
}
}
}
@Test
void testImport() {
photovoltaicPanelService.updateFinishNumberByCoordinate(List.of(1968510961294921730L),
List.of(new RecognizeConvertCoordinateResult("107.124334530", "23.830557974")),
RecognizerTypeEnum.BRACKET.getValue());
}
@Test
void testRemove() {
List<Long> projectIds = List.of(
1968510961294921730L,
1968511074637598722L,
1968511192354934785L,
1968514103508094977L,
1968514270462365697L,
1968515178185248770L,
1968515232044306434L,
1968515275153362945L,
1968515323392053250L,
1968515384058466306L,
1968515428077686785L,
1968515467575447554L,
1968515518674653186L
);
for (Long projectId : projectIds) {
PgsProgressCategory p = progressCategoryService.lambdaQuery()
.eq(PgsProgressCategory::getProjectId, projectId)
.eq(PgsProgressCategory::getMatrixId, "0")
.eq(PgsProgressCategory::getName, "地埋电缆")
.one();
progressCategoryService.remove(new LambdaQueryWrapper<>(PgsProgressCategory.class)
.eq(PgsProgressCategory::getParentId, p.getId()));
progressCategoryService.removeById(p);
}
}
@Test
void testProject1() {
List<BusProject> projects = projectService.lambdaQuery()
.eq(BusProject::getPId, 1897160897167638529L)
.list();
List<Long> projectIds = projects.stream().map(BusProject::getId).toList();
List<PgsProgressCategory> t10101 = progressCategoryService.lambdaQuery()
.in(PgsProgressCategory::getProjectId, projectIds)
.ne(PgsProgressCategory::getMatrixId, "0")
.eq(PgsProgressCategory::getMatrixName, "T10101")
.list();
log.info("t10101: {}", t10101);
Map<String, PgsProgressCategory> name = t10101.stream()
.collect(Collectors.toMap(PgsProgressCategory::getName, Function.identity()));
List<PgsProgressCategory> other = progressCategoryService.lambdaQuery()
.in(PgsProgressCategory::getProjectId, projectIds)
.ne(PgsProgressCategory::getMatrixId, "0")
.ne(PgsProgressCategory::getMatrixName, "T10101")
.ne(PgsProgressCategory::getParentId, 0)
.list();
log.info("other: {}", other);
other.forEach(o -> {
o.setId(o.getId());
PgsProgressCategory category = name.get(o.getName());
if (StringUtils.isBlank(o.getWorkType())) {
o.setTotal(category.getTotal());
}
o.setUnit(category.getUnit());
o.setUnitType(category.getUnitType());
BigDecimal ownerPrice = category.getOwnerPrice();
o.setOwnerPrice(ownerPrice);
BigDecimal constructionPrice = category.getConstructionPrice();
o.setConstructionPrice(constructionPrice);
// 计算产值
try {
BigDecimal multiply = o.getOwnerPrice().multiply(o.getTotal());
o.setOwnerOutputValue(multiply.setScale(4, RoundingMode.HALF_UP));
BigDecimal multiply1 = o.getConstructionPrice().multiply(o.getTotal());
o.setConstructionOutputValue(multiply1.setScale(4, RoundingMode.HALF_UP));
} catch (Exception e) {
}
});
progressCategoryService.updateBatchById(other);
}
@Test
void testProject2() {
PgsProgressCategory p1 = progressCategoryService.lambdaQuery()
.eq(PgsProgressCategory::getProjectId, 1968510858786131970L)
.eq(PgsProgressCategory::getMatrixId, "0")
.eq(PgsProgressCategory::getName, "其他工程")
.one();
List<PgsProgressCategory> progressCategoryList = progressCategoryService.lambdaQuery()
.eq(PgsProgressCategory::getProjectId, 1968510858786131970L)
.eq(PgsProgressCategory::getMatrixId, "0")
.eq(PgsProgressCategory::getParentId, p1.getId())
.list();
List<Long> projectIds = List.of(
1968510961294921730L,
1968511074637598722L,
1968511192354934785L,
1968514103508094977L,
1968514270462365697L,
1968515178185248770L,
1968515232044306434L,
1968515275153362945L,
1968515323392053250L,
1968515384058466306L,
1968515428077686785L,
1968515467575447554L,
1968515518674653186L
);
for (Long projectId : projectIds) {
PgsProgressCategory p = progressCategoryService.lambdaQuery()
.eq(PgsProgressCategory::getProjectId, projectId)
.eq(PgsProgressCategory::getMatrixId, "0")
.eq(PgsProgressCategory::getName, "其他工程")
.one();
progressCategoryService.remove(new LambdaQueryWrapper<>(PgsProgressCategory.class)
.eq(PgsProgressCategory::getParentId, p.getId()));
for (PgsProgressCategory category : progressCategoryList) {
PgsProgressCategoryCreateReq req = new PgsProgressCategoryCreateReq();
req.setParentId(p.getId());
req.setProjectId(p.getProjectId());
req.setMatrixId(p.getMatrixId());
req.setName(category.getName());
req.setUnitType(category.getUnitType());
req.setUnit(category.getUnit());
req.setOwnerPrice(category.getOwnerPrice());
req.setConstructionPrice(category.getConstructionPrice());
req.setTotal(category.getTotal());
progressCategoryService.insertByReq(req);
}
}
}
@Test
void openSxtLx() {
String token = ys7Manager.getToken();
List<OthYs7Device> list = ys7DeviceService.list();
for (OthYs7Device othYs7Device : list) {
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("accessToken", token);
paramMap.put("deviceSerial", othYs7Device.getDeviceSerial());
paramMap.put("enable", 1);
String errorMsg = "Ys7 Token 请求失败";
try (HttpResponse response = HttpRequest.post(Ys7Constant.setDeviceVideoUrlByPost)
.form(paramMap)
.execute()) {
if (!response.isOk()) {
log.error("{}{}", errorMsg, response.getStatus());
// throw new ServiceException(errorMsg + response.getStatus());
}
String body = response.body();
Ys7ResponseVo responseVo = JSONUtil.toBean(body, Ys7ResponseVo.class);
if (!responseVo.getCode().equals("200")) {
log.error("{},状态码:{}{}", errorMsg, responseVo.getCode(), responseVo.getMsg());
// throw new ServiceException(errorMsg + responseVo.getMsg());
}
log.info("Ys7 Token 请求成功:{}", body);
}
}
}
@Test
void capturePic() {
List<String> urlList = List.of(
"http://xny.yj-3d.com:9000/xinnengyuan-dev/2025/10/23/db8a379b456142459852b654f20d5f97.png",
"http://xny.yj-3d.com:9000/xinnengyuan-dev/2025/10/23/913dbcf0f7244c8b878e84b5525bec4b.png",
"http://xny.yj-3d.com:9000/xinnengyuan-dev/2025/10/23/2b904765f03f40b2ad0ddbf6ddeadb45.png"
);
for (String url : urlList) {
Pattern pattern = Pattern.compile(".*/device/img/([^/]+)/.*");
Matcher matcher = pattern.matcher(url);
OthYs7Device ys7Device = ys7DeviceService.lambdaQuery()
.eq(OthYs7Device::getDeviceSerial, "GA1730672")
.last("limit 1")
.one();
if (ys7Device == null) {
throw new ServiceException("设备不存在", HttpStatus.ERROR);
}
String deviceSerial = ys7Device.getDeviceSerial();
// 如果没有预置位,则直接对默认通道抓图
OthYs7DeviceImgCreateByCapture img = new OthYs7DeviceImgCreateByCapture();
img.setProjectId(ys7Device.getProjectId());
img.setDeviceSerial(deviceSerial);
img.setDeviceName(ys7Device.getDeviceName());
// String url = "http://xny.yj-3d.com:9000/xinnengyuan/ys7/device/img/GA1044315/2025-10-13_859fdfb7dde540608356f29cb9e3d63e.jpg";
// String url = "http://xny.yj-3d.com:9000/xinnengyuan/ys7/device/img/GA1044315/2025-10-12_2801707255b84004acb5fee2a75299b2.jpg";
img.setCreateTime(new Date());
img.setUrl(url);
log.info("图片:{},识别中", url);
ys7DeviceImgService.saveCapturePic(List.of(img));
}
}
}

View File

@ -0,0 +1,132 @@
package org.dromara.test;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.materials.domain.MatMaterialIssue;
import org.dromara.materials.domain.MatMaterialReceive;
import org.dromara.materials.domain.MatMaterials;
import org.dromara.materials.domain.MatMaterialsInventory;
import org.dromara.materials.domain.enums.MatMaterialsInventoryOutPutEnum;
import org.dromara.materials.service.IMatMaterialIssueService;
import org.dromara.materials.service.IMatMaterialReceiveService;
import org.dromara.materials.service.IMatMaterialsInventoryService;
import org.dromara.materials.service.IMatMaterialsService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author lilemy
* @date 2025-10-30 15:58
*/
@Slf4j
@SpringBootTest
public class MaterialsTest {
/**
* 长顺项目id
*/
private static final Long PROJECT_ID = 1897161054676336641L;
@Resource
private IMatMaterialsService materialsService;
@Resource
private IMatMaterialsInventoryService materialsInventoryService;
@Resource
private IMatMaterialReceiveService materialReceiveService;
@Resource
private IMatMaterialIssueService materialIssueService;
@Test
void test() {
// 获取所有材料
List<MatMaterials> materials = materialsService.lambdaQuery()
.eq(MatMaterials::getProjectId, PROJECT_ID)
.list();
Set<Long> materialIds = materials.stream().map(MatMaterials::getId).collect(Collectors.toSet());
// 获取所有材料的出库数据
List<MatMaterialsInventory> inventoryList = materialsInventoryService.lambdaQuery()
.in(MatMaterialsInventory::getMaterialsId, materialIds)
.eq(MatMaterialsInventory::getOutPut, MatMaterialsInventoryOutPutEnum.OUT.getValue())
.list();
// 按表单编号分组
Map<String, List<MatMaterials>> map = materials.stream()
.collect(Collectors.groupingBy(MatMaterials::getFormCode));
for (Map.Entry<String, List<MatMaterials>> entry : map.entrySet()) {
String formCode = entry.getKey();
List<MatMaterials> materialsList = entry.getValue();
// 获取入库数据
MatMaterialReceive receive = materialReceiveService.lambdaQuery()
.eq(MatMaterialReceive::getFormCode, formCode)
.one();
// 创建领料出库数据
MatMaterialIssue issue = new MatMaterialIssue();
issue.setProjectId(PROJECT_ID);
issue.setMaterialSource("2");
issue.setFormCode(formCode);
issue.setProjectName(receive.getProjectName());
issue.setMaterialName(receive.getMaterialName());
issue.setOrderingUnit(receive.getOrderingUnit());
issue.setSupplierUnit(receive.getSupplierUnit());
// issue.setIssueUnit(inventory.getRecipient());
// issue.setIssueUnitId(inventory.getRecipientId());
// issue.setShipper(inventory.getShipper());
// issue.setStorageUnit();
issue.setCertCount(0);
issue.setReportCount(0);
issue.setTechDocCount(0);
issue.setLicenseCount(0);
log.info("领料出库数据:{}", issue);
log.info("=============================");
}
for (MatMaterials material : materials) {
String formCode = material.getFormCode();
// 查看入库数据
MatMaterialReceive receive = materialReceiveService.lambdaQuery()
.eq(MatMaterialReceive::getFormCode, formCode)
.one();
// 查看出库数据
/* List<MatMaterialsInventory> inventoryList = materialsInventoryService.lambdaQuery()
.eq(MatMaterialsInventory::getMaterialsId, material.getId())
.eq(MatMaterialsInventory::getOutPut, MatMaterialsInventoryOutPutEnum.OUT.getValue())
.list();
if (CollUtil.isEmpty(inventoryList)) {
continue;
}*/
// 创建领料出库数据
List<MatMaterialIssue> issueList = inventoryList.stream().map(inventory -> {
MatMaterialIssue issue = new MatMaterialIssue();
issue.setProjectId(PROJECT_ID);
issue.setMaterialSource("2");
issue.setFormCode(receive.getFormCode());
issue.setProjectName(receive.getProjectName());
issue.setMaterialName(receive.getMaterialName());
issue.setOrderingUnit(receive.getOrderingUnit());
issue.setSupplierUnit(receive.getSupplierUnit());
issue.setIssueUnit(inventory.getRecipient());
issue.setIssueUnitId(inventory.getRecipientId());
issue.setShipper(inventory.getShipper());
// issue.setStorageUnit();
issue.setCertCount(0);
issue.setReportCount(0);
issue.setTechDocCount(0);
issue.setLicenseCount(0);
log.info("领料出库数据:{}", issue);
log.info("=============================");
return issue;
}).toList();
}
}
}

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.PHO));
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

@ -1,9 +1,17 @@
package org.dromara.test;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordCreateDto;
import org.dromara.safety.service.IHseViolationRecordService;
import org.dromara.system.domain.SysMenu;
import org.dromara.system.domain.vo.SysMenuVo;
import org.dromara.system.mapper.SysMenuMapper;
import org.dromara.system.service.ISysMenuService;
import org.hamcrest.core.Is;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
@ -20,6 +28,9 @@ public class ViolationRecordTest {
@Resource
private IHseViolationRecordService violationRecordService;
@Autowired
private SysMenuMapper sysMenuMapper;
@Test
void test() {
List<HseViolationRecordCreateDto> list = new ArrayList<>();
@ -55,4 +66,26 @@ public class ViolationRecordTest {
list.add(dto5);
violationRecordService.insertByMonitor(list);
}
@Test
void contextLoads() {
SysMenuVo sysMenuVo = sysMenusByList(1972500768346673154L);
System.out.println(sysMenuVo.toString());
}
SysMenuVo sysMenusByList(Long id) {
SysMenuVo sysMenus = new SysMenuVo();
List<SysMenu> res = sysMenuMapper.selectList(new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getParentId, id));
if (res != null && res.size() > 0 ) {
sysMenus.setChildren(MapstructUtils.convert(res, SysMenuVo.class));
res.forEach(sysMenu -> {
sysMenusByList(sysMenu.getMenuId());
});
}
return sysMenus;
}
}

View File

@ -1,109 +0,0 @@
package org.dromara.test;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.formalities.domain.bo.AddBusFormalitiesAreConsolidatedBo;
import org.dromara.formalities.domain.bo.BusFormalitiesAreConsolidatedBo;
import org.dromara.formalities.domain.bo.BusListOfFormalitiesBo;
import org.dromara.formalities.domain.vo.BusListOfFormalitiesVo;
import org.dromara.formalities.service.IBusFormalitiesAreConsolidatedService;
import org.dromara.formalities.service.IBusListOfFormalitiesService;
import org.dromara.manager.ys7manager.Ys7Manager;
import org.dromara.manager.ys7manager.Ys7RequestUtils;
import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author lilemy
* @date 2025/6/12 17:06
*/
@Slf4j
@SpringBootTest
public class Ys7Test {
@Resource
private Ys7Manager ys7Manager;
@Test
void test() {
String token = ys7Manager.getToken();
List<Ys7QueryDeviceResponseVo> ys7QueryDeviceResponseVos = Ys7RequestUtils.queryDeviceVoList(token, 1, 20);
System.out.println(ys7QueryDeviceResponseVos);
}
@Test
void testCaptureDevicePic() {
String pic = ys7Manager.getCaptureDevicePic("AE9470016", 1, 1);
System.out.println(pic);
}
@Resource
private IBusListOfFormalitiesService busListOfFormalitiesService;
@Test
public void test111(){
BusListOfFormalitiesBo busListOfFormalitiesBo = new BusListOfFormalitiesBo();
// busListOfFormalitiesBo.setName("test1");
// busListOfFormalitiesBo.setPid(1955976169241026561L);
// busListOfFormalitiesService.insertByBo(busListOfFormalitiesBo);
// List<BusListOfFormalitiesVo> tree = busListOfFormalitiesService.getTree(busListOfFormalitiesBo);
// System.out.println(tree);
Boolean b = busListOfFormalitiesService.deleteWithValidByIds(1955976169241026561L, true);
System.out.println(b);
}
@Resource
private IBusFormalitiesAreConsolidatedService formalitiesAreConsolidatedService;
@Test
public void test222(){
BusFormalitiesAreConsolidatedBo busFormalitiesAreConsolidatedBo = new BusFormalitiesAreConsolidatedBo();
// List<AddBusFormalitiesAreConsolidatedBo> addBusFormalitiesAreConsolidatedBos = new ArrayList<>();
// AddBusFormalitiesAreConsolidatedBo bo1 = new AddBusFormalitiesAreConsolidatedBo();
// bo1.setFormalitiesId(1955977461032103939L);
// AddBusFormalitiesAreConsolidatedBo bo2 = new AddBusFormalitiesAreConsolidatedBo();
// bo2.setFormalitiesId(1955977461032103940L);
// bo2.setFormalitiesPid(1955977461032103939L);
// AddBusFormalitiesAreConsolidatedBo bo3 = new AddBusFormalitiesAreConsolidatedBo();
// bo3.setFormalitiesId(1955977461032103941L);
// bo3.setFormalitiesPid(1955977461032103939L);
// AddBusFormalitiesAreConsolidatedBo bo4 = new AddBusFormalitiesAreConsolidatedBo();
// bo4.setFormalitiesId(1955977461032103942L);
// bo4.setFormalitiesPid(1955977461032103939L);
// addBusFormalitiesAreConsolidatedBos.add(bo1);
// addBusFormalitiesAreConsolidatedBos.add(bo2);
// addBusFormalitiesAreConsolidatedBos.add(bo3);
// addBusFormalitiesAreConsolidatedBos.add(bo4);
// busFormalitiesAreConsolidatedBo.setAddBusFormalitiesAreConsolidatedBos(addBusFormalitiesAreConsolidatedBos);
// busFormalitiesAreConsolidatedBo.setProjectId(1555L);
// Boolean b = formalitiesAreConsolidatedService.insertByBo(busFormalitiesAreConsolidatedBo);
// System.out.println(b);
// busFormalitiesAreConsolidatedBo.setId(1956013379818409985L);
// busFormalitiesAreConsolidatedBo.setHead("舟山");
// busFormalitiesAreConsolidatedBo.setPlanTheStartTime(new Date());
// busFormalitiesAreConsolidatedBo.setRemark("asdasd");
// busFormalitiesAreConsolidatedBo.setStatus(0);
// MultipartFile[] files = {};
// Boolean b = formalitiesAreConsolidatedService.updateByBo(busFormalitiesAreConsolidatedBo, files);
// System.out.println(b);
}
@Resource
private IBusSegmentedIndicatorPlanningService busSegmentedIndicatorPlanningService;
@Test
public void test666(){
BusSegmentedIndicatorPlanningBo bo = new BusSegmentedIndicatorPlanningBo();
bo.setId(1958169755747459073L);
List<BusBillofquantitiesLimitListVo> more = busSegmentedIndicatorPlanningService.getMore(bo);
System.out.println(more);
}
}

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

@ -80,4 +80,9 @@ public interface CacheNames {
*/
String ONLINE_TOKEN = "online_tokens";
/**
* 项目名称
*/
String PROJECT_NAME = "project_name#30d";
}

View File

@ -65,7 +65,7 @@ public interface Constants {
/**
* 验证码有效期(分钟)
*/
Integer CAPTCHA_EXPIRATION = 2;
Integer CAPTCHA_EXPIRATION = 5;
/**
* 顶级父级id

View File

@ -70,4 +70,9 @@ public class UserDTO implements Serializable {
*/
private Date createTime;
/**
* 头像
*/
private String avatarUrl;
}

View File

@ -4,11 +4,12 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.common.core.domain.dto.PostDTO;
import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.vo.SysProjectRoleMenuVo;
import org.dromara.common.core.domain.vo.SysProjectRolePermissionVo;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
/**
* 登录用户身份权限
@ -37,6 +38,11 @@ public class LoginUser implements Serializable {
*/
private Long deptId;
/**
* 项目ID
*/
private Long projectId;
/**
* 部门类别编码
*/
@ -90,12 +96,12 @@ public class LoginUser implements Serializable {
/**
* 菜单权限
*/
private Set<String> menuPermission;
private List<SysProjectRoleMenuVo> menuPermission;
/**
* 角色权限
*/
private Set<String> rolePermission;
private List<SysProjectRolePermissionVo> rolePermission;
/**
* 用户名

View File

@ -30,4 +30,13 @@ public class RegisterBody extends LoginBody {
private String userType;
private Long projectId;
private String email;
private String phonenumber;
private Long deptId;
private String smsCode;
}

View File

@ -0,0 +1,28 @@
package org.dromara.common.core.domain.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Set;
/**
* @author lilemy
* @date 2025-08-27 18:14
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SysProjectRoleMenuVo {
/**
* 项目id
*/
private Long projectId;
/**
* 项目菜单权限
*/
private Set<String> projectPermissions;
}

View File

@ -0,0 +1,28 @@
package org.dromara.common.core.domain.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Set;
/**
* @author lilemy
* @date 2025-08-27 17:53
*/
@Data
public class SysProjectRolePermissionVo implements Serializable {
@Serial
private static final long serialVersionUID = -6552769878716622338L;
/**
* 项目id
*/
private Long projectId;
/**
* 项目菜单权限
*/
private Set<String> projectRoles;
}

View File

@ -0,0 +1,32 @@
package org.dromara.common.core.domain.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@Data
public class XzdCustomerSupplierVos implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
private Long id;
/**
* 类型1、供应商2、客户
*/
private String type;
/**
* 供应商-客户id
*/
private Long cSId;
}

View File

@ -0,0 +1,17 @@
package org.dromara.common.core.service;
/**
* @author lilemy
* @date 2025-09-10 16:15
*/
public interface ProjectService {
/**
* 通过项目ID查询项目名称
*
* @param projectId 项目ID
* @return 项目名称
*/
String selectProjectNameById(Long projectId);
}

View File

@ -74,7 +74,7 @@ public interface UserService {
* @param roleIds 角色ids
* @return 用户
*/
List<UserDTO> selectUsersByRoleIds(List<Long> roleIds);
List<UserDTO> selectUsersByRoleIds(List<Long> roleIds,Long projectId);
/**
* 通过部门ID查询用户
@ -124,4 +124,20 @@ public interface UserService {
*/
Map<Long, String> selectPostNamesByIds(List<Long> postIds);
/**
* 通过用户id查询头像
*/
String selectAvatarById(Long userId);
/**
* 通过用户id查询用户信息
*/
UserDTO selectUser(Long userId);
/**
* 查询对应专业的用户Id
*/
List<String> selectUserByProfession(String code,String businessId,String type,Long projectId);
}

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 XzdCsContractInformationService {
String selectNameByIds(String ids);
}

View File

@ -0,0 +1,14 @@
package org.dromara.common.core.service;
import org.dromara.common.core.domain.vo.XzdCustomerSupplierVos;
public interface XzdCustomerSupplierService {
/**
* 查询供应商-客户中间
*
* @param id 主键
* @return 供应商-客户中间
*/
XzdCustomerSupplierVos queryByIdone(Long id);
}

View File

@ -0,0 +1,8 @@
package org.dromara.common.core.service;
public interface XzdCustomerinformationService {
String selectNmaeByIds(String id);
String selectNmaeById(Long id);
}

View File

@ -0,0 +1,6 @@
package org.dromara.common.core.service;
public interface XzdJsCgJungonService {
String selectNameByIds(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 XzdProjectService {
String selectNmaeByIds(String ids);
}

View File

@ -0,0 +1,5 @@
package org.dromara.common.core.service;
public interface XzdPurchaseContractInformationService {
String selectNameByIds(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,9 @@
package org.dromara.common.core.service;
public interface XzdSupplierInfoService {
String selectNmaeByIds(String ids);
String selectNmaeById(Long id);
}

View File

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

View File

@ -376,4 +376,19 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
}
}
/**
* 校验日期范围
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return true 表示日期范围有效false 表示日期范围无效
*/
public static boolean isValidDateRange(LocalDate startDate, LocalDate endDate) {
try {
return !startDate.isAfter(endDate); // start <= end
} catch (DateTimeParseException e) {
return false; // 格式非法
}
}
}

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

@ -1,10 +1,7 @@
package org.dromara.common.excel.coryUtils;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;
@ -76,15 +73,14 @@ 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);
SheetData sheetData = new SheetData();
sheetData.setSheetName(sheet.getSheetName());
processSheetData(sheet, sheetData);
processSheetData(workbook,sheet, sheetData);
sheetDataList.add(sheetData);
}
}
@ -114,7 +110,7 @@ public class ExcelReader {
sheetData.setSheetName(sheet.getSheetName());
// 处理单个sheet的数据
processSheetData(sheet, sheetData);
processSheetData(workbook, sheet, sheetData);
sheetDataList.add(sheetData);
}
@ -129,7 +125,7 @@ public class ExcelReader {
/**
* 处理单个工作表的数据
*/
private static void processSheetData(org.apache.poi.ss.usermodel.Sheet sheet, SheetData sheetData) {
private static void processSheetData(Workbook workbook, Sheet sheet, SheetData sheetData) {
boolean foundChineseStart = false;
List<List<String>> data = new ArrayList<>();
boolean isFirstRow = true;
@ -140,29 +136,44 @@ public class ExcelReader {
isFirstRow = false;
continue;
}
if(hasValidData(workbook,row)){
List<String> rowData = new ArrayList<>();
// 读取A到E列索引0到4
for (int cellIndex = 0; cellIndex < 6; cellIndex++) {
Cell cell = row.getCell(cellIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
rowData.add(getCellValue(workbook,cell));
}
List<String> rowData = new ArrayList<>();
// 读取A到E列索引0到4
for (int cellIndex = 0; cellIndex < 6; cellIndex++) {
Cell cell = row.getCell(cellIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
rowData.add(getCellValue(cell));
// 检查是否找到中文数字开头的行
String aColumnValue = rowData.get(0).trim();
if (aColumnValue.matches(CHINESE_NUMBERS_REGEX)) {
foundChineseStart = true;
}
// 只有找到中文数字开头的行之后,才开始收集数据
if (foundChineseStart) {
data.add(rowData);
}
}
// 检查是否找到中文数字开头的行
String aColumnValue = rowData.get(0).trim();
if (aColumnValue.matches(CHINESE_NUMBERS_REGEX)) {
foundChineseStart = true;
}
// 只有找到中文数字开头的行之后,才开始收集数据
if (foundChineseStart) {
data.add(rowData);
}
}
sheetData.setData(data);
}
private static boolean hasValidData(Workbook workbook,Row row) {
// 遍历行中的所有单元格
for (int cellIndex = 0; cellIndex < row.getLastCellNum(); cellIndex++) {
Cell cell = row.getCell(cellIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
String cellValue = getCellValue(workbook, cell).trim();
// 只要有一个单元格有非空值,就认为是有效行
if (!cellValue.isEmpty()) {
return true;
}
}
return false;
}
/**
* 根据数据构建树形结构
*/
@ -263,7 +274,7 @@ public class ExcelReader {
/**
* 获取单元格的值,处理不同数据类型
*/
private static String getCellValue(Cell cell) {
private static String getCellValue(Workbook workbook, Cell cell) {
if (cell == null) {
return "";
}
@ -278,6 +289,21 @@ public class ExcelReader {
return numericValue.substring(0, numericValue.length() - 2);
}
return numericValue;
case FORMULA:
//这样对于字符串cell.getStringCellValue()方法即可取得其值如果公式生成的是数值使用cell.getStringCellValue()方法会抛出IllegalStateException异常在异常处理中使用cell.getNumericCellValue();
// 1. 获取公式文本(如 "A1+B1"
String formula = cell.getCellFormula();
System.out.println("公式文本:" + formula);
// 2. 创建公式计算器(关键步骤:用于计算公式结果)
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
// 3. 计算公式返回包含结果类型和值的CellValue对象
CellValue cellValue = evaluator.evaluate(cell);
// 4. 根据结果类型提取值
return getValue( cellValue.getCellType(), cellValue);
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
default:
@ -285,6 +311,19 @@ public class ExcelReader {
}
}
private static String getValue( CellType resultType, CellValue cellValue) {
return switch (resultType) {
case NUMERIC -> String.valueOf(cellValue.getNumberValue());
case STRING -> String.valueOf(cellValue.getStringValue());
case BOOLEAN -> String.valueOf(cellValue.getBooleanValue());
case ERROR -> String.valueOf(cellValue.getErrorValue());
case BLANK -> String.valueOf(CellType.BLANK);
default ->
// 保留原公式(不处理的类型)
cellValue.getStringValue();
};
}
/**
* 根据A列的值确定父节点的键
*/

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

@ -71,7 +71,7 @@ public class MybatisPlusConfig {
public PaginationInnerInterceptor paginationInnerInterceptor() {
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
// 分页合理化
paginationInnerInterceptor.setOverflow(true);
paginationInnerInterceptor.setOverflow(false);
return paginationInnerInterceptor;
}

View File

@ -8,6 +8,7 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

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

@ -183,7 +183,7 @@ public class OssClient {
// 创建异步请求体length如果为空会报错
BlockingInputStreamAsyncRequestBody body = BlockingInputStreamAsyncRequestBody.builder()
.contentLength(length)
.subscribeTimeout(Duration.ofSeconds(30))
.subscribeTimeout(Duration.ofSeconds(120)) // 增加超时时间到120秒
.build();
// 使用 transferManager 进行上传

View File

@ -77,7 +77,7 @@ public class RedisUtils {
public static <T> void publish(String channelKey, T msg, Consumer<T> consumer) {
RTopic topic = CLIENT.getTopic(channelKey);
topic.publish(msg);
System.out.println("发布通道消息---------"+msg.toString());
// System.out.println("发布通道消息---------"+msg.toString());
consumer.accept(msg);
}

View File

@ -1,13 +1,18 @@
package org.dromara.common.satoken.core.service;
import cn.dev33.satoken.stp.StpInterface;
import cn.hutool.core.collection.CollUtil;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.vo.SysProjectRoleMenuVo;
import org.dromara.common.core.domain.vo.SysProjectRolePermissionVo;
import org.dromara.common.core.enums.UserType;
import org.dromara.common.satoken.utils.LoginHelper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* sa-token 权限管理实现类
@ -23,11 +28,33 @@ public class SaPermissionImpl implements StpInterface {
public List<String> getPermissionList(Object loginId, String loginType) {
LoginUser loginUser = LoginHelper.getLoginUser();
UserType userType = UserType.getUserType(loginUser.getUserType());
if (userType == UserType.SYS_USER) {
return new ArrayList<>(loginUser.getMenuPermission());
} else if (userType == UserType.APP_USER) {
// 其他端 自行根据业务编写
if (userType == UserType.SYS_USER || userType == UserType.APP_USER) {
Long projectId = loginUser.getProjectId();
List<SysProjectRoleMenuVo> menuPermission = loginUser.getMenuPermission();
if (CollUtil.isNotEmpty(menuPermission)) {
if (projectId != null) {
Map<Long, List<SysProjectRoleMenuVo>> map = menuPermission.stream()
.collect(Collectors.groupingBy(SysProjectRoleMenuVo::getProjectId));
if (map.containsKey(projectId)) {
return map.get(projectId).stream()
.map(SysProjectRoleMenuVo::getProjectPermissions)
.flatMap(Set::stream)
.filter(s -> !s.isEmpty())
.distinct()
.toList();
}
} else {
List<Set<String>> list = menuPermission.stream().map(SysProjectRoleMenuVo::getProjectPermissions).toList();
return list.stream().flatMap(Set::stream).filter(s -> !s.isEmpty()).distinct().toList();
}
} else {
return new ArrayList<>();
}
}
/* else if (userType == UserType.APP_USER) {
// 其他端 自行根据业务编写
}*/
return new ArrayList<>();
// return Collections.singletonList("*");
}
@ -39,11 +66,32 @@ public class SaPermissionImpl implements StpInterface {
public List<String> getRoleList(Object loginId, String loginType) {
LoginUser loginUser = LoginHelper.getLoginUser();
UserType userType = UserType.getUserType(loginUser.getUserType());
if (userType == UserType.SYS_USER) {
return new ArrayList<>(loginUser.getRolePermission());
} else if (userType == UserType.APP_USER) {
// 其他端 自行根据业务编写
if (userType == UserType.SYS_USER || userType == UserType.APP_USER) {
Long projectId = loginUser.getProjectId();
List<SysProjectRolePermissionVo> rolePermission = loginUser.getRolePermission();
if (CollUtil.isNotEmpty(rolePermission)) {
if (projectId != null) {
Map<Long, List<SysProjectRolePermissionVo>> map = rolePermission.stream()
.collect(Collectors.groupingBy(SysProjectRolePermissionVo::getProjectId));
if (map.containsKey(projectId)) {
return map.get(projectId).stream()
.map(SysProjectRolePermissionVo::getProjectRoles)
.flatMap(Set::stream)
.filter(s -> !s.isEmpty())
.distinct()
.toList();
}
} else {
List<Set<String>> list = rolePermission.stream().map(SysProjectRolePermissionVo::getProjectRoles).toList();
return list.stream().flatMap(Set::stream).filter(s -> !s.isEmpty()).distinct().toList();
}
} else {
return new ArrayList<>();
}
}
/* else if (userType == UserType.APP_USER) {
// 其他端 自行根据业务编写
}*/
return new ArrayList<>();
}
}

View File

@ -39,6 +39,7 @@ public class LoginHelper {
public static final String DEPT_NAME_KEY = "deptName";
public static final String DEPT_CATEGORY_KEY = "deptCategory";
public static final String CLIENT_KEY = "clientid";
public static final String PROJECT_KEY = "projectId";
/**
* 登录系统 基于 设备类型
@ -131,6 +132,10 @@ public class LoginHelper {
return Convert.toStr(getExtra(DEPT_CATEGORY_KEY));
}
public static Long getProjectId() {
return Convert.toLong(getExtra(PROJECT_KEY));
}
/**
* 获取当前 Token 的扩展信息
*
@ -191,7 +196,7 @@ public class LoginHelper {
* @return 结果
*/
public static boolean isTenantAdmin() {
return Convert.toBool(isTenantAdmin(getLoginUser().getRolePermission()));
return true;
}
/**

View File

@ -18,4 +18,17 @@ public class SseProperties {
* 路径
*/
private String path;
private String wait;
private String copy;
private String project;
private String violationRecord;
private String drawing;
}

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<>();
@ -135,7 +143,7 @@ public class SseEmitterManager {
broadcastMessage.setMessage(sseMessageDto.getMessage());
broadcastMessage.setUserIds(sseMessageDto.getUserIds());
broadcastMessage.setRoute(sseMessageDto.getRoute());
broadcastMessage.setDetailId(sseMessageDto.getDetailId());
broadcastMessage.setProjectId(sseMessageDto.getProjectId());
RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> {
log.info("SSE发送主题订阅消息topic:{} session keys:{} message:{}",
SSE_TOPIC, sseMessageDto.getUserIds(), sseMessageDto.getMessage());

View File

@ -0,0 +1,25 @@
package org.dromara.common.sse.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@Data
public class SeeMessageContentDto implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 需要发送的消息
*/
private String type;
/**
* 路由
*/
private String content;
}

View File

@ -33,8 +33,13 @@ public class SseMessageDto implements Serializable {
private String route;
/**
* 详情
* 项目id
*/
private String detailId;
private Long projectId;
/**
* 是否记录
*/
private Boolean isRecord = true;
}

View File

@ -32,4 +32,60 @@ public interface TransConstant {
*/
String OSS_ID_TO_URL = "oss_id_to_url";
/**
* 项目id转名称
*/
String PROJECT_ID_TO_NAME = "project_id_to_name";
/**
* 客户id转名称
*/
String XZD_KHXX_ID_TO_NAME = "khxx_id_to_name";
/**
* 新中大项目id转名称
*/
String XZD_PROJECT_ID_TO_NAME = "xzd_project_id_to_name";
/**
* 采购合同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转名称
*/
String XZD_CS_CONTRACT_INFORMATION_ID_TO_NAME = "xzd_cs_contract_information_id_to_name";
/**
* 结算-采购合同竣工结算id转名称
*/
String XZD_JS_CG_JUNGON_ID_TO_NAME = "xzd_js_cg_jungon_id_to_name";
/**
* 新中大供应商信息-开户银行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

@ -0,0 +1,35 @@
package org.dromara.common.translation.core.impl;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.dromara.common.core.service.ProjectService;
import org.dromara.common.translation.annotation.TranslationType;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.common.translation.core.TranslationInterface;
/**
* @author lilemy
* @date 2025-09-10 16:13
*/
@AllArgsConstructor
@TranslationType(type = TransConstant.PROJECT_ID_TO_NAME)
public class ProjectNameTranslationImpl implements TranslationInterface<String> {
@Resource
private ProjectService projectService;
/**
* 翻译
*
* @param key 需要被翻译的键(不为空)
* @param other 其他参数
* @return 返回键对应的值
*/
@Override
public String translation(Object key, String other) {
if (key instanceof Long id) {
return projectService.selectProjectNameById(id);
}
return null;
}
}

View File

@ -0,0 +1,24 @@
package org.dromara.common.translation.core.impl;
import lombok.AllArgsConstructor;
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_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 xzdCbysZjhcbService.selectNmaeByIds(ids);
} else if (key instanceof Long id) {
return xzdCbysZjhcbService.selectNmaeByIds(id.toString());
}
return null;
}
}

View File

@ -0,0 +1,26 @@
package org.dromara.common.translation.core.impl;
import lombok.AllArgsConstructor;
import org.dromara.common.core.service.XzdCsContractInformationService;
import org.dromara.common.core.service.XzdPurchaseContractInformationService;
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_CS_CONTRACT_INFORMATION_ID_TO_NAME)
public class XzdCsContractInformationImpl implements TranslationInterface<String> {
private final XzdCsContractInformationService xzdCsContractInformationService;
@Override
public String translation(Object key, String other) {
if (key instanceof String ids) {
return xzdCsContractInformationService.selectNameByIds(ids);
} else if (key instanceof Long id) {
return xzdCsContractInformationService.selectNameByIds(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.XzdCustomerinformationService;
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 XzdCustomerinformationImpl implements TranslationInterface<String> {
private final XzdCustomerinformationService xzdCustomerinformationService;
@Override
public String translation(Object key, String other) {
if (key instanceof String ids) {
return xzdCustomerinformationService.selectNmaeByIds(ids);
} else if (key instanceof Long id) {
return xzdCustomerinformationService.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.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_JS_CG_JUNGON_ID_TO_NAME)
public class XzdJsCgJungonImpl implements TranslationInterface<String> {
private final XzdJsCgJungonService xzdJsCgJungonService;
@Override
public String translation(Object key, String other) {
if (key instanceof String ids) {
return xzdJsCgJungonService.selectNameByIds(ids);
} else if (key instanceof Long id) {
return xzdJsCgJungonService.selectNameByIds(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.XzdProjectService;
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_ID_TO_NAME)
public class XzdProjectImpl implements TranslationInterface<String> {
private final XzdProjectService xzdProjectService;
@Override
public String translation(Object key, String other) {
if (key instanceof String ids) {
return xzdProjectService.selectNmaeByIds(ids);
} else if (key instanceof Long id) {
return xzdProjectService.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,26 @@
package org.dromara.common.translation.core.impl;
import lombok.AllArgsConstructor;
import org.dromara.common.core.service.XzdPurchaseContractInformationService;
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_CONTRACT_ID_TO_NAME)
public class XzdPurchaseContractInformationImpl implements TranslationInterface<String> {
private final XzdPurchaseContractInformationService xzdCustomerinformationService;
@Override
public String translation(Object key, String other) {
if (key instanceof String ids) {
return xzdCustomerinformationService.selectNameByIds(ids);
} else if (key instanceof Long id) {
return xzdCustomerinformationService.selectNameByIds(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

@ -0,0 +1,23 @@
package org.dromara.common.translation.core.impl;
import lombok.AllArgsConstructor;
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_SUPPLIER_OPEN_BANK_ID_TO_NAME)
public class XzdSupplierOpenBankImpl implements TranslationInterface<String> {
private final XzdSupplierOpenBankService xzdSupplierOpenBankService;
@Override
public String translation(Object key, String other) {
if (key instanceof String ids) {
return xzdSupplierOpenBankService.selectNameByIds(ids);
} else if (key instanceof Long id) {
return xzdSupplierOpenBankService.selectNameByIds(id.toString());
}
return null;
}
}

View File

@ -4,3 +4,14 @@ org.dromara.common.translation.core.impl.DictTypeTranslationImpl
org.dromara.common.translation.core.impl.OssUrlTranslationImpl
org.dromara.common.translation.core.impl.UserNameTranslationImpl
org.dromara.common.translation.core.impl.NicknameTranslationImpl
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.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

@ -13,6 +13,7 @@ import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.server.HandshakeInterceptor;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* WebSocket 配置

View File

@ -12,6 +12,8 @@ public interface WebSocketConstants {
*/
String LOGIN_USER_KEY = "loginUser";
String PROJECT_ID = "projectId";
/**
* 订阅的频道
*/

View File

@ -13,6 +13,7 @@ import java.io.IOException;
import java.util.List;
import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY;
import static org.dromara.common.websocket.constant.WebSocketConstants.PROJECT_ID;
/**
* WebSocketHandler 实现类
@ -27,14 +28,17 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws IOException {
LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
if (ObjectUtil.isNull(loginUser)) {
// LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
Long loginUser = (Long) session.getAttributes().get(PROJECT_ID);
// if (ObjectUtil.isNull(loginUser) ) {
if (loginUser == null ) {
session.close(CloseStatus.BAD_DATA);
log.info("[connect] invalid token received. sessionId: {}", session.getId());
return;
}
WebSocketSessionHolder.addSession(loginUser.getUserId(), session);
log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
WebSocketSessionHolder.addSession(loginUser, session);
// WebSocketSessionHolder.addSession(loginUser.getUserId(), session);
// log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
}
/**
@ -47,11 +51,13 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 从WebSocket会话中获取登录用户信息
LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
// LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
Long loginUser = (Long) session.getAttributes().get(PROJECT_ID);
// 创建WebSocket消息DTO对象
WebSocketMessageDto webSocketMessageDto = new WebSocketMessageDto();
webSocketMessageDto.setSessionKeys(List.of(loginUser.getUserId()));
// webSocketMessageDto.setSessionKeys(List.of(loginUser.getUserId()));
webSocketMessageDto.setSessionKeys(List.of(loginUser));
webSocketMessageDto.setMessage(message.getPayload());
WebSocketUtils.publishMessage(webSocketMessageDto);
}
@ -100,13 +106,16 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
if (ObjectUtil.isNull(loginUser)) {
// LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
Long loginUser = (Long) session.getAttributes().get(PROJECT_ID);
// if (ObjectUtil.isNull(loginUser)) {
if (loginUser != null ) {
log.info("[disconnect] invalid token received. sessionId: {}", session.getId());
return;
}
WebSocketSessionHolder.removeSession(loginUser.getUserId());
log.info("[disconnect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
// WebSocketSessionHolder.removeSession(loginUser.getUserId());
WebSocketSessionHolder.removeSession(loginUser);
// log.info("[disconnect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
}
/**

View File

@ -15,6 +15,7 @@ import org.springframework.web.socket.server.HandshakeInterceptor;
import java.util.Map;
import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY;
import static org.dromara.common.websocket.constant.WebSocketConstants.PROJECT_ID;
/**
* WebSocket握手请求的拦截器
@ -44,6 +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(LoginHelper.PROJECT_KEY);
if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
// token 无效
throw NotLoginException.newInstance(StpUtil.getLoginType(),
@ -52,6 +54,10 @@ public class PlusWebSocketInterceptor implements HandshakeInterceptor {
}
attributes.put(LOGIN_USER_KEY, loginUser);
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

@ -26,7 +26,7 @@ public class WebSocketTopicListener implements ApplicationRunner, Ordered {
public void run(ApplicationArguments args) throws Exception {
// 订阅WebSocket消息
WebSocketUtils.subscribeMessage((message) -> {
log.info("WebSocket主题订阅收到消息session keys={} message={}", message.getSessionKeys(), message.getMessage());
// log.info("WebSocket主题订阅收到消息session keys={} message={}", message.getSessionKeys(), message.getMessage());
// 如果key不为空就按照key发消息 如果为空就群发
if (CollUtil.isNotEmpty(message.getSessionKeys())) {
message.getSessionKeys().forEach(key -> {

View File

@ -69,8 +69,8 @@ public class WebSocketUtils {
broadcastMessage.setMessage(webSocketMessage.getMessage());
broadcastMessage.setSessionKeys(unsentSessionKeys);
RedisUtils.publish(WEB_SOCKET_TOPIC, broadcastMessage, consumer -> {
log.info(" WebSocket发送主题订阅消息topic:{} session keys:{} message:{}",
WEB_SOCKET_TOPIC, unsentSessionKeys, webSocketMessage.getMessage());
// log.info(" WebSocket发送主题订阅消息topic:{} session keys:{} message:{}",
// WEB_SOCKET_TOPIC, unsentSessionKeys, webSocketMessage.getMessage());
});
}
}
@ -84,7 +84,7 @@ public class WebSocketUtils {
WebSocketMessageDto broadcastMessage = new WebSocketMessageDto();
broadcastMessage.setMessage(message);
RedisUtils.publish(WEB_SOCKET_TOPIC, broadcastMessage, consumer -> {
log.info("WebSocket发送主题订阅消息topic:{} message:{}", WEB_SOCKET_TOPIC, message);
// log.info("WebSocket发送主题订阅消息topic:{} message:{}", WEB_SOCKET_TOPIC, message);
});
}

View File

@ -42,7 +42,7 @@ snail-job:
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: true
enabled: false
url: http://192.168.110.119:9090/admin
instance:
service-host-type: IP

View File

@ -2,9 +2,9 @@ spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: root
url: jdbc:mysql://192.168.110.2:13386/xinnengyuan?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: xinnengyuan
password: mEZPC5Sdf3r2HENi
hikari:
connection-timeout: 30000
validation-timeout: 5000
@ -42,8 +42,8 @@ snail-job:
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: true
url: http://localhost:9090/admin
enabled: false
url: http://192.168.110.2:19191/admin
instance:
service-host-type: IP
metadata:

View File

@ -15,8 +15,82 @@
system系统模块
</description>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-bom</artifactId>
<version>1.0.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<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>-->
<!-- <artifactId>javax.websocket-api</artifactId>-->
<!-- <version>1.1</version>-->
<!-- <scope>provided</scope>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.drewnoakes</groupId>-->
<!-- <artifactId>metadata-extractor</artifactId>-->
<!-- <version>2.18.0</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>technology.tabula</groupId>-->
<!-- <artifactId>tabula</artifactId>-->
<!-- <version>1.0.4</version>-->
<!-- </dependency>-->
<!-- JSON解析FastJSON -->
<dependency>
<groupId>com.alibaba</groupId>
@ -73,18 +147,31 @@
</dependency>
<!-- 在pdf上生成二维码 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>layout</artifactId>
<version>7.2.5</version>
</dependency>
<!-- iText 7 核心模块必须layout依赖此模块 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
<version>7.2.5</version> <!-- 与layout版本严格一致 -->
</dependency>
<!-- 支持中文字体 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!-- iText -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.3</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.itextpdf</groupId>-->
<!-- <artifactId>itext-asian</artifactId>-->
<!-- <version>5.2.0</version>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; iText &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.itextpdf</groupId>-->
<!-- <artifactId>itextpdf</artifactId>-->
<!-- <version>5.5.13.3</version>-->
<!-- </dependency>-->
<!-- ZXing -->
<dependency>
<groupId>com.google.zxing</groupId>
@ -108,6 +195,11 @@
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-job</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mybatis</artifactId>
@ -216,6 +308,24 @@
<version>5.3.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version> <!-- 最新版本可自行调整 -->
</dependency>
</dependencies>

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

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

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