Compare commits

..

105 Commits

Author SHA1 Message Date
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
488 changed files with 15202 additions and 3108 deletions

View File

@ -36,6 +36,12 @@ snail-job:
--- # 数据源配置
spring:
ai:
dashscope:
api-key: sk-8d8df92fcbac4bd2922edba30b0bb8fa
chat:
options:
model: qwen-plus
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
@ -56,38 +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
# 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/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
# 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

View File

@ -39,6 +39,12 @@ snail-job:
--- # 数据源配置
spring:
ai:
dashscope:
api-key: xxx
chat:
options:
model: qwen-plus
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
@ -315,8 +321,8 @@ ys7:
app-key: xxx
app-secret: xxx
job:
capture-enabled: true # 控制是否启用萤石抓拍任务
device-sync-enabled: true # 控制是否同步萤石设备
capture-enabled: false # 控制是否启用萤石抓拍任务
device-sync-enabled: false # 控制是否同步萤石设备
# 斯巴达算法
sparta:
url: http://119.3.204.120:8040

View File

@ -39,6 +39,12 @@ snail-job:
--- # 数据源配置
spring:
ai:
dashscope:
api-key: xxx
chat:
options:
model: qwen-plus
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content

View File

@ -289,6 +289,8 @@ springdoc:
packages-to-scan: org.dromara.websocket
- group: 27.新中大模块
packages-to-scan: org.dromara.xzd
- group: 28.车辆模块
packages-to-scan: org.dromara.vehicle
# knife4j的增强配置不需要增强可以不配
knife4j:
enable: true
@ -306,12 +308,13 @@ xss:
- /project/project
- /xzd/contractDetails/**
- /xzd/contractChange/**
- /comprehensive/csContractChange/**
- /comprehensive/csContractInformation/**
- /hetongbiangeng/**
- /fenbaohetongbiangg/**
- /fenbaohetongxinxi/**
- /contractManagement/**
- /xzd/comprehensive/csContractChange/**
- /xzd/comprehensive/csContractInformation/**
- /xzd/hetongbiangeng/**
- /xzd/fenbaohetongjungong/**
- /xzd/fenbaohetongbiangg/**
- /xzd/fenbaohetongxinxi/**
- /xzd/contractManagement/**
# 全局线程池相关配置
# 如使用JDK21请直接使用虚拟线程 不要开启此配置

View File

@ -29,6 +29,8 @@ 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;
@ -55,6 +57,8 @@ 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;
/**
@ -112,6 +116,9 @@ public class DemoTest {
@Resource
private IOthYs7DeviceService ys7DeviceService;
@Resource
private IOthYs7DeviceImgService ys7DeviceImgService;
@Resource
private Ys7Manager ys7Manager;
@ -547,4 +554,38 @@ public class DemoTest {
}
}
@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

@ -23,7 +23,7 @@ public class RecognizerTest {
@Test
void test() {
RecognizeVo recognize = recognizerManager.recognize("http://xny.yj-3d.com:7363/file/tif/20250625160218orthophoto.png", List.of(RecognizerTypeEnum.SOLAR));
RecognizeVo recognize = recognizerManager.recognize("http://xny.yj-3d.com:7363/file/tif/20250625160218orthophoto.png", List.of(RecognizerTypeEnum.PANEL));
log.info("recognize: {}", recognize);
}
}

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

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

@ -37,4 +37,36 @@ public interface TransConstant {
*/
String PROJECT_ID_TO_NAME = "project_id_to_name";
/**
* 客户id转名称
*/
String XZD_KHXX_ID_TO_NAME = "khxx_id_to_name";
// /**
// * 供应商id转名称
// */
// String XZD_KHXX_ID_TO_NAME = "gysxx_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_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";
}

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,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,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.XzdSupplierInfoService;
import org.dromara.common.translation.annotation.TranslationType;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.common.translation.core.TranslationInterface;
@AllArgsConstructor
//@TranslationType(type = TransConstant.XZD_KHXX_ID_TO_NAME)
public class XzdSupplierInfoImpl implements TranslationInterface<String> {
private final XzdSupplierInfoService xzdSupplierInfoService;
@Override
public String translation(Object key, String other) {
if (key instanceof String ids) {
return xzdSupplierInfoService.selectNmaeByIds(ids);
} else if (key instanceof Long id) {
return xzdSupplierInfoService.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.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

@ -5,3 +5,10 @@ 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.XzdSupplierInfoImpl
org.dromara.common.translation.core.impl.XzdJsCgJungonImpl
org.dromara.common.translation.core.impl.XzdCsContractInformationImpl
org.dromara.common.translation.core.impl.XzdSupplierOpenBankImpl

View File

@ -15,16 +15,31 @@
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>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<!-- Java WebSocket 标准API -->
<!-- <dependency>-->
<!-- <groupId>javax.websocket</groupId>-->
<!-- <artifactId>javax.websocket-api</artifactId>-->
<!-- <version>1.1</version>-->
<!-- <scope>provided</scope>-->
<!-- </dependency>-->
<!-- <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>
@ -36,18 +51,18 @@
</exclusions>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.drewnoakes</groupId>-->
<!-- <artifactId>metadata-extractor</artifactId>-->
<!-- <version>2.18.0</version>-->
<!-- </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>-->
<!-- <dependency>-->
<!-- <groupId>technology.tabula</groupId>-->
<!-- <artifactId>tabula</artifactId>-->
<!-- <version>1.0.4</version>-->
<!-- </dependency>-->
<!-- JSON解析FastJSON -->
@ -119,19 +134,18 @@
</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>-->
<!-- <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>

View File

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

View File

@ -42,7 +42,7 @@ public class SysPackageController {
* 上传最新安装包及版本
*/
@GetMapping("/uploadNewVersion")
public R<SysPackage> uploadNewVersion(String version, String type, MultipartFile file) {
public R<SysPackage> uploadNewVersion(String version, String type, MultipartFile file, String context) {
String originalFileName = "apk/package/app-release.apk";
// 先查询最新记录
@ -57,11 +57,11 @@ public class SysPackageController {
}
// 分离事务:再处理数据库操作
return handleDatabaseOperations(version, type, upload, list);
return handleDatabaseOperations(version, type, upload, list, context);
}
@Transactional
public R<SysPackage> handleDatabaseOperations(String version, String type, SysOssVo upload, List<SysPackage> existingPackages) {
public R<SysPackage> handleDatabaseOperations(String version, String type, SysOssVo upload, List<SysPackage> existingPackages, String context) {
try {
// 先删除旧文件记录
if (existingPackages != null && !existingPackages.isEmpty()) {
@ -78,6 +78,7 @@ public class SysPackageController {
sysPackage.setFileId(upload.getOssId());
sysPackage.setFileUrl(upload.getUrl());
sysPackage.setType(type);
sysPackage.setContext(context);
boolean save = sysPackageService.save(sysPackage);
if (!save) {

View File

@ -30,4 +30,9 @@ public class SysPackage extends BaseEntity {
private String fileUrl;
/**
* 更新内容
*/
private String context;
}

View File

@ -27,4 +27,9 @@ public class SysPackageVo {
@ExcelProperty("安装包地址")
private String fileUrl;
/**
* 更新内容
*/
private String context;
}

View File

@ -318,11 +318,13 @@ public class BusMrpBaseServiceImpl extends ServiceImpl<BusMrpBaseMapper, BusMrpB
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
map.put("remainingQuantity",quantity.subtract(reduce));
map.put("specification",busBillofquantities.getSpecification());
map.put("suppliespriceId",limitListId);
map.put("unit",busBillofquantities.getUnit());
map.put("remark",busBillofquantities.getRemark());
map.put("name",busBillofquantities.getName());
if (busBillofquantities != null) {
map.put("specification",busBillofquantities.getSpecification());
map.put("unit",busBillofquantities.getUnit());
map.put("remark",busBillofquantities.getRemark());
map.put("name",busBillofquantities.getName());
}
return map;
}

View File

@ -1,12 +1,21 @@
package org.dromara.common.utils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.sse.dto.SseMessageDto;
import org.dromara.common.sse.utils.SseMessageUtils;
import org.dromara.contractor.domain.SubConstructionUser;
import org.dromara.mobileAttendanceMachine.DeviceMessageSender;
import org.dromara.mobileAttendanceMachine.KqjEntity;
import org.dromara.project.domain.BusAttendanceMachine;
import org.dromara.project.service.IBusAttendanceMachineService;
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysOssService;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@ -17,6 +26,16 @@ import java.util.List;
@Slf4j
public class AsyncUtil {
@Resource
@Lazy
private DeviceMessageSender deviceMessageSender;
@Resource
@Lazy
private ISysOssService ossService;
@Resource
@Lazy
private IBusAttendanceMachineService attendanceMachineService;
//发送短信
@Async
public void sendSms(List<String> mobileList, String config) {
@ -39,4 +58,27 @@ public class AsyncUtil {
}
//下发考勤人员
@Async
public void sendPersonnel(Long teamId, SubConstructionUser constructionUser) {
SysOssVo byId = ossService.getById(Long.valueOf(constructionUser.getFacePic()));
List<BusAttendanceMachine> list = attendanceMachineService.lambdaQuery().apply("FIND_IN_SET({0}, teams)", teamId).list();
for (BusAttendanceMachine machine : list) {
deviceMessageSender.sendPersonnelInformation(machine.getSn(), constructionUser.getSysUserId().toString(), constructionUser.getUserName(), byId.getUrl());
}
}
//删除考勤人员
@Async
public void deletePersonnel(SubConstructionUser constructionUser) {
List<BusAttendanceMachine> list = attendanceMachineService.lambdaQuery().apply("FIND_IN_SET({0}, teams)", constructionUser.getTeamId()).list();
for (BusAttendanceMachine machine : list) {
try {
deviceMessageSender.deleteUser(machine.getSn(), constructionUser.getSysUserId().toString());
} catch (Exception e) {
log.error("删除考勤人员异常", e);
}
}
}
}

View File

@ -0,0 +1,93 @@
package org.dromara.common.utils;
import java.util.HashMap;
import java.util.Map;
/**
* 接口错误码匹配工具(用户展示用)
*/
public class ErrorCodeMatcher {
private static final Map<String, String> ERROR_MAP = new HashMap<>();
static {
// 基础错误码
ERROR_MAP.put("1", "抱歉,出现未知错误,请您重试。若问题持续,请联系管理员。");
ERROR_MAP.put("2", "服务暂时不可用,请稍后重试。若多次尝试仍有问题,请联系管理员。");
ERROR_MAP.put("3", "调用的接口不存在,请检查请求地址是否正确(建议避免特殊字符,如手动输入重试)。");
ERROR_MAP.put("4", "当前集群请求量超限,请稍后再试。持续异常请联系管理员。");
ERROR_MAP.put("6", "暂无该接口调用权限,请联系管理员开通相关权限。");
ERROR_MAP.put("14", "鉴权失败,请检查密钥是否正确,或联系管理员协助处理。");
ERROR_MAP.put("17", "今日免费额度已用完。如需继续使用,请联系管理员获取更多资源。");
ERROR_MAP.put("18", "请求频率超限QPS限制。如需提高限制请联系管理员咨询。");
ERROR_MAP.put("19", "总请求量已达限额,请联系管理员获取更多资源。");
ERROR_MAP.put("100", "访问令牌无效,请联系管理员重新获取。");
ERROR_MAP.put("110", "访问令牌无效有效期30天请联系管理员更新。");
ERROR_MAP.put("111", "访问令牌已过期,请联系管理员重新获取。");
// 216xxx系列错误码
ERROR_MAP.put("216100", "请求中包含无效参数,请检查后重新提交。");
ERROR_MAP.put("216101", "缺少必要的请求参数,请核对后补充完整。");
ERROR_MAP.put("216102", "请求的服务暂不支持,请检查调用地址是否正确,或联系管理员确认。");
ERROR_MAP.put("216103", "部分参数长度超限,请缩短后重新尝试。");
ERROR_MAP.put("216110", "应用ID不存在请核对是否为正确ID或联系管理员确认。");
ERROR_MAP.put("216200", "上传的图片为空,请检查图片是否正确上传。");
ERROR_MAP.put("216201", "图片格式不支持目前仅支持PNG、JPG、JPEG、BMP格式请转码后重试。");
ERROR_MAP.put("216202", "图片大小不符合要求,请参考接口文档的限制重新上传,或联系管理员咨询。");
ERROR_MAP.put("216205", "请求体过大base64编码后需小于10M请压缩内容后重试。");
ERROR_MAP.put("216306", "文件上传失败,请检查请求参数是否符合要求。");
ERROR_MAP.put("216307", "图片解析失败,若多次尝试仍有问题,请联系管理员。");
ERROR_MAP.put("216308", "PDF页码参数超过实际页数请核对后修改。");
ERROR_MAP.put("216401", "请求提交失败,请稍后重试。");
ERROR_MAP.put("216402", "获取结果失败,请稍后重试或检查任务状态。");
ERROR_MAP.put("216603", "无法获取PDF页数请检查文件是否完整或编码是否正确。");
ERROR_MAP.put("216604", "请求总量已达限额,请联系管理员获取更多额度。");
ERROR_MAP.put("216630", "识别失败,请重试。若问题持续,请联系管理员。");
ERROR_MAP.put("216631", "银行卡识别失败,请确保上传的是银行卡正面完整清晰的图片(异形卡可能无法识别)。");
ERROR_MAP.put("216633", "身份证识别失败,请确保上传的是身份证完整清晰的图片(非身份证或模糊图片无法识别)。");
ERROR_MAP.put("216634", "检测失败,请重试。若持续异常,请联系管理员。");
ERROR_MAP.put("216600", "企业核验服务请求失败,请重试。持续问题请联系管理员(适用于工商信息查询、要素核验等)。");
ERROR_MAP.put("216601", "企业核验查询成功,但未找到相关结果,请确认信息是否正确后重试。");
ERROR_MAP.put("216602", "企业核验服务超时,请稍后重试。持续问题请联系管理员。");
// 282xxx系列错误码
ERROR_MAP.put("282000", "服务器内部错误。若使用通用文字识别,可能因图片文字过多导致超时,建议分割图片后重试;其他情况可稍后再试,持续问题请联系管理员。");
ERROR_MAP.put("282003", "请求缺少必要参数,请核对后补充。");
ERROR_MAP.put("282005", "批量任务处理出错,请根据具体错误提示排查。");
ERROR_MAP.put("282006", "批量任务数量超限单次最多处理10个任务请减少数量后重试。");
ERROR_MAP.put("282100", "图片压缩转码失败,请更换图片后重试。");
ERROR_MAP.put("282102", "未检测到可识别的卡证/票据,请确保图片包含清晰完整的目标(非卡证或模糊图片无法识别)。");
ERROR_MAP.put("282103", "卡证/票据识别失败,请确保图片包含清晰完整的目标(非对应类型或模糊图片无法识别)。");
ERROR_MAP.put("282110", "图片URL不存在请核对地址后重新提交。");
ERROR_MAP.put("282111", "图片URL格式错误请检查是否符合接口要求的格式。");
ERROR_MAP.put("282112", "图片URL下载超时可能因图片过大超过3M、地址无效或存在防盗链。建议更换图片地址或下载后直接上传。");
ERROR_MAP.put("282113", "图片URL返回无效内容请检查地址是否正确。");
ERROR_MAP.put("282114", "图片URL长度不符合要求需1-1024字节请修改后重试。");
ERROR_MAP.put("282134", "增值税发票验真失败,可能因系统维护,建议次日再试。持续问题请联系管理员。");
ERROR_MAP.put("282808", "请求ID不存在请核对ID是否正确。");
ERROR_MAP.put("282809", "返回结果格式错误需为excel或json请稍后重试。");
ERROR_MAP.put("282810", "图像识别失败,请重试。若问题持续,请联系管理员。");
ERROR_MAP.put("282160", "行驶证核验资源超限,请联系管理员咨询。");
ERROR_MAP.put("282161", "行驶证核验请求过于频繁,请稍后再试。");
}
/**
* 根据错误码获取用户友好的错误信息
* @param errorCode 错误码(字符串/整数)
* @return 优化后的错误提示,未匹配时返回"未知错误错误码xxx"
*/
public static String getFriendlyMessage(String errorCode) {
return ERROR_MAP.getOrDefault(errorCode, "未知错误(错误码:" + errorCode + "),请重试或联系管理员。");
}
public static String getFriendlyMessage(int errorCode) {
return getFriendlyMessage(String.valueOf(errorCode));
}
// 测试示例
public static void main(String[] args) {
System.out.println(getFriendlyMessage(1)); // 输出:抱歉,出现未知错误,请您重试...
System.out.println(getFriendlyMessage("216201")); // 输出图片格式不支持目前仅支持PNG...
System.out.println(getFriendlyMessage(9999)); // 输出未知错误错误码9999...
}
}

View File

@ -3,6 +3,7 @@ package org.dromara.common.utils.baiduUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.utils.ErrorCodeMatcher;
import org.dromara.common.utils.baiduUtil.entity.face.ComparisonRes;
import org.dromara.common.utils.baiduUtil.entity.face.HumanFaceReq;
import org.dromara.common.utils.baiduUtil.entity.face.HumanFaceRes;
@ -208,8 +209,7 @@ public class BaiDuFace {
// 8. 处理API返回错误
if (comparisonRep.getErrorCode() != 0) {
throw new RuntimeException("人脸对比失败:" + comparisonRep.getErrorMsg()
+ "(错误码:" + comparisonRep.getErrorCode() + "");
throw new RuntimeException("人脸对比失败:" + ErrorCodeMatcher.getFriendlyMessage(comparisonRep.getErrorCode()));
}
// 9. 校验对比结果

View File

@ -364,10 +364,11 @@ public class SubConstructionUserController extends BaseController {
if (user.getEntryDate() != null) {
vo.setEntryDate(DateUtils.formatDateTime(user.getEntryDate()));
}
//0男 1女 2未知
String sex = vo.getSex();
if (sex != null && sex.equals("1")) {
if (sex != null && sex.equals("0")) {
vo.setSex("");
} else if (sex != null && sex.equals("2")) {
} else if (sex != null && sex.equals("1")) {
vo.setSex("");
} else {
vo.setSex("未知");

View File

@ -36,7 +36,7 @@ public class SubConstructionUserAuthenticationReq implements Serializable {
private String phone;
/**
* 0:保密 1:男 2女
* 0男1女2未知
*/
@NotBlank(message = "性别不能为空")
private String sex;

View File

@ -101,4 +101,7 @@ public class SubConstructionUserQueryReq implements Serializable {
*/
private String userId;
private String phone;
}

View File

@ -26,6 +26,7 @@ import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.exception.OssException;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.utils.AsyncUtil;
import org.dromara.common.utils.IdCardEncryptorUtil;
import org.dromara.common.utils.baiduUtil.BaiDuFace;
import org.dromara.common.utils.baiduUtil.BaiDuOCR;
@ -46,6 +47,7 @@ import org.dromara.contractor.mapper.SubConstructionUserMapper;
import org.dromara.contractor.service.ISubConstructionUserFileService;
import org.dromara.contractor.service.ISubConstructionUserService;
import org.dromara.contractor.service.ISubContractorService;
import org.dromara.mobileAttendanceMachine.DeviceMessageSender;
import org.dromara.project.domain.*;
import org.dromara.project.domain.enums.BusAttendanceClockStatusEnum;
import org.dromara.project.domain.enums.BusAttendanceCommuterEnum;
@ -151,6 +153,11 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
@Resource
private ISysRoleService roleService;
@Resource
private AsyncUtil asyncUtil;
/**
* 查询施工人员
*
@ -202,8 +209,10 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
LambdaQueryWrapper<SubConstructionUser> lqw = Wrappers.lambdaQuery();
// 从对象中取值
String userName = req.getUserName();
String phone = req.getPhone();
// 模糊查询
lqw.like(StringUtils.isNotBlank(phone), SubConstructionUser::getPhone, phone);
lqw.like(StringUtils.isNotBlank(userName), SubConstructionUser::getUserName, userName);
lqw.isNull(SubConstructionUser::getProjectId);
lqw.isNull(SubConstructionUser::getTeamId);
@ -290,6 +299,8 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
//强退
roleService.cleanOnlineUser(Collections.singletonList(constructionUser.getSysUserId()));
asyncUtil.sendPersonnel(dto.getTeamId(), constructionUser);
return i > 0;
}

View File

@ -0,0 +1,159 @@
package org.dromara.dataTransmission;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;
import org.dromara.common.redis.utils.RedisUtils;
import javax.crypto.Cipher;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.time.Duration;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import java.io.ByteArrayOutputStream;
@Component
public class TokenUtils {
// Token过期时间25分钟与Redis存储过期时间保持一致
private static final long TOKEN_EXPIRE_SECONDS = 1500;
// HTTP请求超时时间10秒
private static final Duration HTTP_TIMEOUT = Duration.ofSeconds(10);
//通用字符
private static final String USER_NAME = "username";
private static final String PASSWORD = "password";
private static final String PUBLIC_KEY = "publicKey";
private static final String URL = "url";
//clientId
public static final String CLARITYPM = "claritypm";
//接口信息及参数
private static final Map<String, Map<String, String>> tokenMap = new HashMap<>(){
{
put(CLARITYPM, new HashMap<>(){{
put(URL, "https://claritypm.powerchina.cn/neSmartsite-api/loginCli");
put(USER_NAME, "zhangweiwei");
put(PASSWORD, "Hkrsoft@#2023");
put(PUBLIC_KEY, "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCoaejbjbttHyHuEzHL8lIX5GZZ6zIYrqJpEDlPM4V5LHn19rSAYp2FyAr8y5Ctny9uUdaYbkoFiVQgxWrAYo4X/3O0OFDsowE25FMOLQY0Mn5B6CvVR7Sdt3DqzIzM1tUnJCIbVGNfDMgxLrLwFN8RvOW8MPlB6LgOvlGMDbj+OQIDAQAB");
}});
}
};
//字段参数
private static final Map<String, Map<String, String>> paramMap = new HashMap<>(){
{
put(CLARITYPM, new HashMap<>(){{
put(USER_NAME, "username");
put(PASSWORD, "password");
}});
}
};
/**
* 优先从Redis获取Token不存在则调用接口获取并存储
* @param clientId 客户端ID
* @return 有效的Token字符串
* @throws Exception 当获取过程发生异常时抛出
*/
public static String getToken(String clientId) throws Exception {
// 1. 定义Redis中的Token键名
// String redisKey = "data_auth:token:" + clientId;
//
// // 2. 尝试从Redis获取Token
// String token = RedisUtils.getCacheObject(redisKey);
// if (token != null && !token.isBlank()) {
// // 缓存命中,直接返回
// return token;
// }
// 3. 缓存未命中调用接口获取Token
Map<String, String> map = tokenMap.get(clientId);
String token = fetchTokenFromApi(clientId,map.get(URL), map.get(USER_NAME), rsaEncrypt(map.get(PASSWORD),map.get(PUBLIC_KEY)));
// 4. 存储到Redis设置25分钟过期
// RedisUtils.setCacheObject(redisKey, token,Duration.ofSeconds(TOKEN_EXPIRE_SECONDS) );
return token;
}
/**
* 从接口获取Token的内部方法
*/
private static String fetchTokenFromApi(String clientId, String authUrl, String username, String encryptedPassword) throws Exception {
// 构建JSON请求体包含加密后的密码
// 1. 构建请求头(与原 Go 代码一致的头信息)
// Map<String, String> headers = new HashMap<>();
// headers.put(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8");
// headers.put("User-Agent", "Mozilla/5.0");
// headers.put(HttpHeaders.ACCEPT, "application/json");
// headers.put("Origin", "https://claritypm.powerchina.cn");
// headers.put("Referer", "https://claritypm.powerchina.cn/");
// 2. 构建请求体(保持你的原有逻辑)
Map<String, String> map = paramMap.get(clientId);
JSONObject requestBody = new JSONObject();
requestBody.put(map.get(USER_NAME), username); // 从 map 中获取接口要求的用户名参数名
requestBody.put(map.get(PASSWORD), encryptedPassword); // 加密后的密码
String jsonBody = requestBody.toJSONString();
System.out.println("请求体:" + jsonBody);
// 3. 带 Header 发送 POST 请求Hutool HttpUtil 重载方法)
String post = HttpUtil.createPost(authUrl)
// .addHeaders(headers) // 设置所有请求头
.body(jsonBody) // 设置请求体
.execute() // 执行请求
.body(); // 获取响应体
System.out.println("响应结果:" + post);
// 3. 解析响应(核心解析逻辑)
JSONObject responseJson = JSONObject.parseObject(post);
int code = responseJson.getIntValue("code");
String msg = responseJson.getString("msg");
String token = responseJson.getString("token");
// 4. 校验响应有效性
if (code != 200) {
throw new RuntimeException("获取 Token 失败,响应信息:" + msg + ",状态码:" + code);
}
if (token == null || token.trim().isEmpty()) {
throw new RuntimeException("响应中未包含有效 Token响应内容" + post);
}
return token;
}
/**
* RSA公钥加密核心加密方法
* @param content 待加密内容(原始密码)
* @param publicKeyStr 公钥字符串Base64编码
* @return 加密后的Base64字符串
* @throws Exception 加密过程异常
*/
public static String rsaEncrypt(String content, String publicKeyStr) throws Exception {
RSA rsa = new RSA(null, publicKeyStr);
byte[] encryptedBytes = rsa.encrypt(content, KeyType.PublicKey);
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static void main(String[] args) throws Exception {
String claritypm = getToken(CLARITYPM);
System.out.println(claritypm);
}
}

View File

@ -0,0 +1,79 @@
package org.dromara.dataTransmission.claritypm;
import org.dromara.dataTransmission.TokenUtils;
import org.dromara.dataTransmission.claritypm.dto.RealUser;
import org.springframework.stereotype.Component;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
@Component
public class ClaritypmClient {
// 接口地址
private static final String INSERT_REAL_USER_URL = "https://claritypm.powerchina.cn/neSmartsite-api/realUser/tiandong/insertRealUser";
@Autowired
private TokenUtils tokenUtils; // 依赖之前的Token获取服务
/**
* 批量新增实名制用户信息
* @param userList 用户信息列表建议单次不超过10条
* @return 接口响应结果JSON格式
* @throws Exception 调用异常
*/
public static String batchInsertRealUser(List<RealUser> userList) throws Exception {
// 1. 校验列表大小建议不超过10条
if (userList == null || userList.isEmpty()) {
throw new IllegalArgumentException("用户列表不能为空");
}
if (userList.size() > 10) {
throw new IllegalArgumentException("单次批量新增不能超过10条数据");
}
// 2. 获取Token从之前的TokenService获取
String token = TokenUtils.getToken(TokenUtils.CLARITYPM);
if ( token.trim().isEmpty()) {
throw new RuntimeException("获取Token失败无法调用接口");
}
// 3. 构建请求头包含Token认证
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json; charset=UTF-8");
headers.put("User-Agent", "Mozilla/5.0");
headers.put("Accept", "application/json");
headers.put("Origin", "https://claritypm.powerchina.cn");
headers.put("Referer", "https://claritypm.powerchina.cn/");
headers.put("Authorization", "Bearer " + token); // 假设接口使用Bearer Token认证
// 4. 构建请求体JSONArray格式
JSONArray requestBody = JSONArray.parseArray(JSON.toJSONString(userList));
String jsonBody = requestBody.toJSONString();
System.out.println("批量新增用户请求体:" + jsonBody);
// 5. 发送POST请求
String response = HttpUtil.createPost(INSERT_REAL_USER_URL)
.addHeaders(headers)
.body(jsonBody)
.execute()
.body();
System.out.println("批量新增用户响应:" + response);
// 6. 解析响应(根据实际响应结构调整,此处假设与登录接口类似)
JSONObject responseJson = JSONObject.parseObject(response);
int code = responseJson.getIntValue("code");
String msg = responseJson.getString("msg");
if (code != 200) {
throw new RuntimeException("批量新增用户失败:" + msg + "(状态码:" + code + "");
}
return response;
}
}

View File

@ -0,0 +1,92 @@
package org.dromara.dataTransmission.claritypm.dto;
import lombok.Data;
import java.time.LocalDate;
/**
* 实名制用户信息实体类(对应接口参数)
*/
@Data
public class RealUser {
// 人员姓名(必填)
private String userName;
// 是否班组长非必填0-否 1-是)
private String classManagerFlag;
// 手机号码(必填)
private String phone;
// 性别必填1.男 2.女 3.未知)
private String sex;
// 证件类型必填0.身份证)
private String cardType;
// 证件号码(必填,身份证号码)
private String cardNumber;
// 人员类型必填0.作业人员 1.管理人员)
private String userType;
// 发证机关(非必填)
private String cardDept;
// 民族(非必填)
private String nation;
// 生日非必填datetime格式
private LocalDate birthday;
// 住址(非必填)
private String address;
// 头像非必填http地址
private String avatar;
// 采集相片非必填http地址
private String pic;
// 安全教育表非必填http地址
private String safetyEdu;
// 技术交底表非必填http地址
private String technology;
// 证件有效期始非必填datetime格式
private LocalDate cardStartTime;
// 证件有效期至非必填datetime格式
private LocalDate cardEndTime;
// 学历非必填1-9对应小学至其他
private String studyLevel;
// 政治面貌非必填0-3对应党员至民主党派
private String politicsType;
// 购买保险非必填0-否 1-是)
private String insuranceFlag;
// 重大病史非必填0-否 1-是)
private String diseaseFlag;
// 劳动合同非必填0-未签订 1-已签订)
private String laborContractFlag;
// 紧急联系人(非必填)
private String contacts;
// 紧急联系人电话(非必填)
private String contactsPhone;
// 婚姻状况非必填0-3对应未婚至丧偶
private String marryRemark;
// 企业名称(非必填)
private String companyName;
}

View File

@ -1,17 +1,40 @@
package org.dromara.design.controller;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import cn.hutool.core.util.StrUtil;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.design.domain.BusDrawingreviewReceipts;
import org.dromara.design.domain.DesCollectFile;
import org.dromara.design.domain.DesDesignChange;
import org.dromara.design.domain.bo.DesUserBo;
import org.dromara.design.domain.dto.designchange.DesDesignExtendDetailDto;
import org.dromara.design.domain.vo.DesCollectFileWordVo;
import org.dromara.design.domain.vo.DesUserVo;
import org.dromara.design.domain.vo.designchange.DesDesignChangeVo;
import org.dromara.design.service.IDesDesignChangeService;
import org.dromara.design.service.IDesUserService;
import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.vo.project.BusSubProjectVo;
import org.dromara.project.service.IBusProjectService;
import org.dromara.system.service.ISysDictDataService;
import org.dromara.system.service.ISysUserService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
@ -44,6 +67,12 @@ public class BusDrawingreviewReceiptsController extends BaseController {
private final IDesUserService desUserService;
private final IDesDesignChangeService desDesignChangeService;
private final ISysDictDataService dictDataService;
private final ISysUserService userService;
/**
* 查询设计-图纸评审验证列表
*/
@ -132,4 +161,85 @@ public class BusDrawingreviewReceiptsController extends BaseController {
return R.ok(desUserService.queryList(bo));
}
private static final String TEMPLATE_PATH = "template/设计验证表.docx";
@PostMapping("/downloadWord")
public void generateDesignLeaderDoc(Long id, HttpServletResponse response) {
OutputStream outputStream = null;
try {
// 1. 调用Service生成目标模板的Word字节流
byte[] docBytes = generateDocBytes(id);
// 2. 配置响应头:确保前端正确下载(避免中文乱码、指定文件类型)
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); // 二进制流类型
// 下载文件名:格式为“[项目名]-设计负责人任命通知单.docx”此处用projectId拼接真实场景可从数据中获取项目名
String downloadFileName = URLEncoder.encode(
"设计验证表.docx",
"UTF-8"
);
response.setHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
response.setContentLength(docBytes.length); // 设置响应体长度(优化下载体验)
// 3. 将Word字节流写入响应
outputStream = response.getOutputStream();
outputStream.write(docBytes);
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
// 异常处理返回500错误状态码
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} finally {
// 关闭流,避免资源泄漏
if (outputStream != null) {
try {
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public byte[] generateDocBytes(Long id) throws Exception {
// -------------------------- 步骤1按projectId查询项目数据模拟真实业务 --------------------------
// 实际场景替换为数据库查询如调用DAO获取项目名称、负责人等
DesDesignChangeVo desDesignChangeVo = desDesignChangeService.queryById(id);
BusDrawingreviewReceipts receipts = busDrawingreviewReceiptsService.lambdaQuery()
.eq(BusDrawingreviewReceipts::getDrawingreviewId, id)
.last("limit 1")
.one();
DesDesignExtendDetailDto extendDetail = desDesignChangeVo.getExtendDetail();
String s = dictDataService.selectDictLabel("des_user_major", receipts.getProfessional());
String designerName = null;
if(StrUtil.isNotBlank(receipts.getDesigner())){
Long userId = Long.parseLong(receipts.getDesigner());
designerName= userService.queryNameById(userId);
}
Map<String, Object> placeholderData = new HashMap<>();
placeholderData.put("projectName", receipts.getProjectName());
placeholderData.put("subName",extendDetail.getSubName());
placeholderData.put("stage", receipts.getStage());
placeholderData.put("professionalName", s);
placeholderData.put("volume", receipts.getVolume());
placeholderData.put("designerName", designerName);
placeholderData.put("verificationOpinion", receipts.getVerificationOpinion());
placeholderData.put("executionOpinion", receipts.getExecutionOpinion());
// -------------------------- 步骤2用poi-tl加载目标模板并替换占位符 --------------------------
// 读取resources下的“设计项目负责人任命通知单.docx”模板
ClassPathResource templateResource = new ClassPathResource(TEMPLATE_PATH);
try (InputStream templateIs = templateResource.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
XWPFTemplate template = XWPFTemplate.compile(templateIs).render(placeholderData);
// -------------------------- 步骤3将生成的文档写入字节流 --------------------------
template.write(outputStream);
template.close(); // 关闭模板资源
return outputStream.toByteArray();
}
}
}

View File

@ -1,15 +1,31 @@
package org.dromara.design.controller;
import java.util.List;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.design.domain.DesCollectFile;
import org.dromara.design.domain.bo.DesCollectFileBo;
import org.dromara.design.domain.dto.ExportDto;
import org.dromara.design.domain.dto.designchange.DesDesignExtendDetailDto;
import org.dromara.design.domain.vo.DesCollectFileVo;
import org.dromara.design.domain.vo.DesCollectFileWordVo;
import org.dromara.design.domain.vo.designchange.DesDesignChangeVo;
import org.dromara.design.service.IDesCollectFileService;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
@ -39,6 +55,8 @@ public class DesCollectFileController extends BaseController {
private final IDesCollectFileService desCollectFileService;
private final IBusProjectService projectService;
/**
* 查询收资文件列表
*/
@ -106,7 +124,6 @@ public class DesCollectFileController extends BaseController {
return toAjax(desCollectFileService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 上传资料文件
*/
@ -119,10 +136,92 @@ public class DesCollectFileController extends BaseController {
return toAjax(desCollectFileService.addFile(file, catalogueId, projectId));
}
@PostMapping("/exportZip")
public void exportZip(ExportDto dto, HttpServletResponse response) throws Exception {
desCollectFileService.exportAsZip(dto, response);
}
private static final String TEMPLATE_PATH = "template/设计输入资料清单及评审表.docx";
@PostMapping("/downloadWord")
public void generateDesignLeaderDoc(Long projectId, HttpServletResponse response) {
OutputStream outputStream = null;
try {
// 1. 调用Service生成目标模板的Word字节流
byte[] docBytes = generateDocBytes(projectId);
// 2. 配置响应头:确保前端正确下载(避免中文乱码、指定文件类型)
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); // 二进制流类型
// 下载文件名:格式为“[项目名]-设计负责人任命通知单.docx”此处用projectId拼接真实场景可从数据中获取项目名
String downloadFileName = URLEncoder.encode(
"设计输入资料清单及评审表.docx",
"UTF-8"
);
response.setHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
response.setContentLength(docBytes.length); // 设置响应体长度(优化下载体验)
// 3. 将Word字节流写入响应
outputStream = response.getOutputStream();
outputStream.write(docBytes);
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
// 异常处理返回500错误状态码
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} finally {
// 关闭流,避免资源泄漏
if (outputStream != null) {
try {
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public byte[] generateDocBytes(Long projectId) throws Exception {
// -------------------------- 步骤1按projectId查询项目数据模拟真实业务 --------------------------
// 实际场景替换为数据库查询如调用DAO获取项目名称、负责人等
List<DesCollectFile> list = desCollectFileService.lambdaQuery()
.eq(DesCollectFile::getProjectId, projectId).list();
List<DesCollectFileWordVo> files = new ArrayList<>();
int i = 1;
for (DesCollectFile desCollectFile : list) {
DesCollectFileWordVo desCollectFileWordVo = new DesCollectFileWordVo();
desCollectFileWordVo.setNum(i);
i++;
desCollectFileWordVo.setFileName(desCollectFile.getFileName());
files.add(desCollectFileWordVo);
}
BusProject project = projectService.getById(projectId);
Map<String, Object> placeholderData = new HashMap<>();
placeholderData.put("projectName", project.getProjectName());
placeholderData.put("files",files);
// -------------------------- 步骤2用poi-tl加载目标模板并替换占位符 --------------------------
// 读取resources下的“设计项目负责人任命通知单.docx”模板
ClassPathResource templateResource = new ClassPathResource(TEMPLATE_PATH);
try (InputStream templateIs = templateResource.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
Configure config = Configure.builder()
.bind("files", policy).build();
XWPFTemplate template = XWPFTemplate.compile(templateIs, config).render(placeholderData);
// -------------------------- 步骤3将生成的文档写入字节流 --------------------------
template.write(outputStream);
template.close(); // 关闭模板资源
return outputStream.toByteArray();
}
}
}

View File

@ -2,10 +2,13 @@ package org.dromara.design.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.apache.poi.xwpf.usermodel.*;
import org.dromara.common.core.domain.R;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
@ -13,18 +16,37 @@ import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.web.core.BaseController;
import org.dromara.design.domain.DesConstructionSchedulePlan;
import org.dromara.design.domain.DesUser;
import org.dromara.design.domain.dto.constructionscheduleplan.*;
import org.dromara.design.domain.vo.DesConstructionSchedulePlanVo;
import org.dromara.design.exportUtil.plan.AttachmentPersonnel;
import org.dromara.design.service.IDesConstructionSchedulePlanService;
import org.dromara.design.service.IDesUserService;
import org.dromara.system.domain.vo.SysDictDataVo;
import org.dromara.system.service.ISysDictDataService;
import org.dromara.system.service.ISysDictTypeService;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/**
* 设计计划
*
@ -38,7 +60,10 @@ public class DesConstructionSchedulePlanController extends BaseController {
@Resource
private IDesConstructionSchedulePlanService desConstructionSchedulePlanService;
@Resource
private IDesUserService desUserService;
@Resource
private ISysDictTypeService dictTypeService;
/**
* 查询设计计划列表
*/
@ -150,4 +175,168 @@ public class DesConstructionSchedulePlanController extends BaseController {
desConstructionSchedulePlanService.exportSchedule(response,projectId);
}
private static final String TEMPLATE_RESOURCE_PATH = "template/CCCET-JL-CX-25设计计划表.docx";
// -------------------------- 2. 核心接口:修复单元格清空逻辑与数据填充 --------------------------
@PostMapping("/downloadWord")
public void fillCccetTemplate(Long projectId, HttpServletResponse response) {
// 1. 基础参数校验(避免空数据)
// 2. 读取resource中的模板+填充数据
try (
// 关键通过ClassPathResource读取resource/template下的模板
InputStream templateIs = new ClassPathResource(TEMPLATE_RESOURCE_PATH).getInputStream();
XWPFDocument doc = new XWPFDocument(templateIs); // 加载模板
OutputStream out = response.getOutputStream() // 响应流
) {
// --------------------------
// 步骤1填充第1页-主信息表索引0固定6列
// --------------------------
// XWPFTable mainTable = doc.getTables().get(0);
// // 工程名称第1行第0列
// if (mainTable.getRows().size() > 1 && mainTable.getRow(1).getCell(0) != null) {
// mainTable.getRow(1).getCell(0).setText(request.getProjectName() == null ? "" : request.getProjectName());
// }
// // 工程号第1行第1列
// if (mainTable.getRows().size() > 1 && mainTable.getRow(1).getCell(1) != null) {
// mainTable.getRow(1).getCell(1).setText(request.getProjectNo());
// }
// // 编制日期第2行第3列
// if (mainTable.getRows().size() > 2 && mainTable.getRow(2).getCell(3) != null) {
// mainTable.getRow(2).getCell(3).setText(request.getCompileDate() == null ? "" : request.getCompileDate());
// }
// // 编制人第3行第0列
// if (mainTable.getRows().size() > 3 && mainTable.getRow(3).getCell(0) != null) {
// mainTable.getRow(3).getCell(0).setText(request.getCompiler() == null ? "" : request.getCompiler());
// }
// // 批准人第3行第2列
// if (mainTable.getRows().size() > 3 && mainTable.getRow(3).getCell(2) != null) {
// mainTable.getRow(3).getCell(2).setText(request.getApprover() == null ? "" : request.getApprover());
// }
// // 设计阶段第3行第4列
// if (mainTable.getRows().size() > 3 && mainTable.getRow(3).getCell(4) != null) {
// mainTable.getRow(3).getCell(4).setText(request.getDesignStage() == null ? "" : request.getDesignStage());
// }
// // 设计规模第4行第0列
// if (mainTable.getRows().size() > 4 && mainTable.getRow(4).getCell(0) != null) {
// mainTable.getRow(4).getCell(0).setText(request.getDesignScale() == null ? "" : request.getDesignScale());
// }
// --------------------------
// 步骤2填充第3页-附件1人员配置表索引2固定11列
// --------------------------
XWPFTable staffTable = doc.getTables().get(2);
// 删除模板中附件1的空数据行保留第0行表头
while (staffTable.getRows().size() > 2) {
staffTable.removeRow(1);
}
List<AttachmentPersonnel> list = getPersonnelDataByProjectId(projectId);
for (AttachmentPersonnel staff : list) {
XWPFTableRow newRow = staffTable.createRow();
// 补全11列避免POI默认列数不足导致null
while (newRow.getTableCells().size() < 11) {
newRow.createCell();
}
// 按附件1列顺序填充
newRow.getCell(0).setText(staff.getProfessional() == null ? "" : staff.getProfessional());
newRow.getCell(1).setText(staff.getLeaderName() == null ? "" : staff.getLeaderName());
newRow.getCell(2).setText(staff.getLeaderTitle() == null ? "" : staff.getLeaderTitle());
newRow.getCell(3).setText(staff.getDesignerName() == null ? "" : staff.getDesignerName());
newRow.getCell(4).setText(staff.getDesignerTitle() == null ? "" : staff.getDesignerTitle());
newRow.getCell(5).setText(staff.getReviewerName() == null ? "" : staff.getReviewerName());
newRow.getCell(6).setText(staff.getReviewerTitle() == null ? "" : staff.getReviewerTitle());
newRow.getCell(7).setText(staff.getCheckerName() == null ? "" : staff.getCheckerName());
newRow.getCell(8).setText(staff.getCheckerTitle() == null ? "" : staff.getCheckerTitle());
newRow.getCell(9).setText(staff.getApproverName() == null ? "" : staff.getApproverName());
newRow.getCell(10).setText(staff.getApproverTitle() == null ? "" : staff.getApproverTitle());
}
// --------------------------
// 步骤3设置响应头触发前端下载
// --------------------------
response.setContentType("application/octet-stream");
// 文件名填充后_工程号_CCCET-JL-CX-25设计计划表.docx
String fileName = "CCCET-JL-CX-25设计计划表.docx";
response.setHeader("Content-Disposition",
"attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); // 允许前端获取文件名
// --------------------------
// 步骤4写出文件到前端
// --------------------------
doc.write(out);
out.flush();
} catch (Exception e) {
// 异常封装(前端可捕获具体错误)
throw new RuntimeException("CCCET-JL-CX-25模板填充失败" + e.getMessage());
}
}
/**
* 根据projectId获取数据仅针对CCCET-JL-CX-25设计计划表.docx附件1
*/
private List<AttachmentPersonnel> getPersonnelDataByProjectId(Long projectId) {
// 模拟数据库查询实际项目替换为真实Service调用
List<DesUser> userList = desUserService.list(Wrappers.<DesUser>lambdaQuery()
.eq(DesUser::getProjectId, projectId)
);
if (userList.isEmpty()) {
return Collections.emptyList();
}
// 专业字典映射(编码→名称)
List<SysDictDataVo> majorDict = dictTypeService.selectDictDataByType("des_user_major");
Map<String, String> majorMap = majorDict.stream()
.collect(Collectors.toMap(SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel));
// 按角色分组1-专业负责人2-设计人3-校审人4-审定人5-审核人)
DesUser leader = userList.stream().filter(u -> "1".equals(u.getUserType())).findFirst().orElse(null);
Map<String, List<DesUser>> designerMap = userList.stream()
.filter(u -> "2".equals(u.getUserType()))
.collect(Collectors.groupingBy(DesUser::getUserMajor));
Map<String, List<DesUser>> reviewerMap = userList.stream()
.filter(u -> "3".equals(u.getUserType()))
.collect(Collectors.groupingBy(DesUser::getUserMajor));
Map<String, List<DesUser>> checkerMap = userList.stream()
.filter(u -> "5".equals(u.getUserType()))
.collect(Collectors.groupingBy(DesUser::getUserMajor));
Map<String, List<DesUser>> approverMap = userList.stream()
.filter(u -> "4".equals(u.getUserType()))
.collect(Collectors.groupingBy(DesUser::getUserMajor));
// 构建附件1数据一个专业一行避免重复
List<AttachmentPersonnel> dataList = new ArrayList<>();
for (Map.Entry<String, List<DesUser>> entry : designerMap.entrySet()) {
String majorCode = entry.getKey();
String majorName = majorMap.getOrDefault(majorCode, majorCode);
List<DesUser> designers = entry.getValue();
// 获取对应专业的其他角色
DesUser reviewer = reviewerMap.getOrDefault(majorCode, Collections.emptyList()).stream().findFirst().orElse(null);
DesUser checker = checkerMap.getOrDefault(majorCode, Collections.emptyList()).stream().findFirst().orElse(null);
DesUser approver = approverMap.getOrDefault(majorCode, Collections.emptyList()).stream().findFirst().orElse(null);
// 封装数据(多个设计人用顿号分隔)
AttachmentPersonnel data = new AttachmentPersonnel();
data.setProfessional(majorName);
data.setLeaderName(leader != null ? leader.getUserName() : "");
//data.setLeadeTitle(leader != null ? leader.getUserTitle() : "");
data.setDesignerName(designers.stream().map(DesUser::getUserName).collect(Collectors.joining("")));
//data.setDesignerTitle(designers.stream().map(DesUser::getUserTitle).collect(Collectors.joining("、")));
data.setReviewerName(reviewer != null ? reviewer.getUserName() : "");
//data.setReviewerTitle(reviewer != null ? reviewer.getUserTitle() : "");
data.setCheckerName(checker != null ? checker.getUserName() : "");
//data.setCheckerTitle(checker != null ? checker.getUserTitle() : "");
data.setApproverName(approver != null ? approver.getUserName() : "");
//data.setApproverTitle(approver != null ? approver.getUserTitle() : "");
dataList.add(data);
}
return dataList;
}
}

View File

@ -2,6 +2,7 @@ package org.dromara.design.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.deepoove.poi.XWPFTemplate;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
@ -16,24 +17,36 @@ 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.dromara.design.domain.DesUser;
import org.dromara.design.domain.DesVolumeCatalog;
import org.dromara.design.domain.DesVolumeFile;
import org.dromara.design.domain.dto.designchange.DesDesignChangeCreateReq;
import org.dromara.design.domain.dto.designchange.DesDesignChangeQueryReq;
import org.dromara.design.domain.dto.designchange.DesDesignChangeUpdateReq;
import org.dromara.design.domain.dto.designchange.DesDesignExtendDetailDto;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogQueryReq;
import org.dromara.design.domain.vo.designchange.DesDesignChangeVo;
import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo;
import org.dromara.design.service.IDesDesignChangeService;
import org.dromara.design.service.IDesVolumeCatalogService;
import org.dromara.design.service.IDesVolumeFileService;
import org.dromara.project.domain.BusProject;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysDictDataService;
import org.dromara.system.service.ISysOssService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@ -56,6 +69,9 @@ public class DesDesignChangeController extends BaseController {
@Resource
private IDesVolumeFileService desVolumeFileService;
@Resource
private ISysDictDataService dictDataService;
/**
* 查询设计变更管理列表
*/
@ -146,4 +162,92 @@ public class DesDesignChangeController extends BaseController {
return R.ok(list);
}
private static final String TEMPLATE_PATH = "template/设计更改通知单.docx";
@PostMapping("/downloadWord")
public void generateDesignLeaderDoc(Long id, HttpServletResponse response) {
OutputStream outputStream = null;
try {
// 1. 调用Service生成目标模板的Word字节流
byte[] docBytes = generateDocBytes(id);
// 2. 配置响应头:确保前端正确下载(避免中文乱码、指定文件类型)
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); // 二进制流类型
// 下载文件名:格式为“[项目名]-设计负责人任命通知单.docx”此处用projectId拼接真实场景可从数据中获取项目名
String downloadFileName = URLEncoder.encode(
"设计更改通知单.docx",
"UTF-8"
);
response.setHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
response.setContentLength(docBytes.length); // 设置响应体长度(优化下载体验)
// 3. 将Word字节流写入响应
outputStream = response.getOutputStream();
outputStream.write(docBytes);
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
// 异常处理返回500错误状态码
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} finally {
// 关闭流,避免资源泄漏
if (outputStream != null) {
try {
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public byte[] generateDocBytes(Long id) throws Exception {
// -------------------------- 步骤1按projectId查询项目数据模拟真实业务 --------------------------
// 实际场景替换为数据库查询如调用DAO获取项目名称、负责人等
DesDesignChangeVo vo = desDesignChangeService.queryById(id);
DesDesignExtendDetailDto extendDetail = vo.getExtendDetail()==null?new DesDesignExtendDetailDto():vo.getExtendDetail();
Map<String, Object> placeholderData = new HashMap<>();
placeholderData.put("projectName", vo.getProjectName());
placeholderData.put("designPhase",extendDetail.getDesignPhase());
placeholderData.put("subName",extendDetail.getSubName());
String s = dictDataService.selectDictLabel("des_user_major", vo.getSpecialty());
placeholderData.put("specialty",s);
placeholderData.put("volumeNo",vo.getVolumeNo());
String changeReason = vo.getChangeReason();
List<String> reasons = Arrays.asList("设计漏项", "设计改进", "设计差错", "接口差错",
"业主要求", "施工承包商要求", "外部资料与最终情况不符", "材料代用或其他");
String reason = reasons.stream()
.map(item -> changeReason.contains(String.valueOf(reasons.indexOf(item) + 1)) ? "" + item : "" + item)
.collect(Collectors.joining());
placeholderData.put("changeReason", reason);
placeholderData.put("designDisposal1", "1".equals(extendDetail.getDesignDisposal())?"" : "");
placeholderData.put("designDisposal2", "2".equals(extendDetail.getDesignDisposal())?"" : "");
placeholderData.put("designDisposal3", "3".equals(extendDetail.getDesignDisposal())?"" : "");
placeholderData.put("changeContent",vo.getChangeContent());
placeholderData.put("changeCategory1", "1".equals(extendDetail.getChangeCategory())?"" : "");
placeholderData.put("changeCategory2", "2".equals(extendDetail.getChangeCategory())?"" : "");
placeholderData.put("involvingProfessions", extendDetail.getInvolvingProfessions());
// -------------------------- 步骤2用poi-tl加载目标模板并替换占位符 --------------------------
// 读取resources下的“设计项目负责人任命通知单.docx”模板
ClassPathResource templateResource = new ClassPathResource(TEMPLATE_PATH);
try (InputStream templateIs = templateResource.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
// 1. 加载模板 2. 注入替换数据 3. 渲染生成新文档
XWPFTemplate template = XWPFTemplate.compile(templateIs)
.render(placeholderData); // 自动匹配{{变量名}}占位符
// -------------------------- 步骤3将生成的文档写入字节流 --------------------------
template.write(outputStream);
template.close(); // 关闭模板资源
return outputStream.toByteArray();
}
}
}

View File

@ -129,6 +129,7 @@ public class DesExtractController extends BaseController {
@SaCheckPermission("design:extract:userMajor")
@GetMapping("/userMajor")
public R<List<DesUserVo>> selectUserMajor(DesUserBo bo) {
bo.setUserType("1");
return R.ok( deUserService.queryList(bo));
}

View File

@ -1,16 +1,18 @@
package org.dromara.design.controller;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.rmi.ServerException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.*;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.deepoove.poi.XWPFTemplate;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
@ -22,8 +24,15 @@ import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
//import org.dromara.design.domain.DesUserExcelData;
import org.dromara.design.domain.DesUser;
import org.dromara.design.domain.DesUserExcelData;
import org.dromara.design.domain.dto.desUser.DesUserBatchDto;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
@ -54,6 +63,7 @@ import org.springframework.web.multipart.MultipartFile;
public class DesUserController extends BaseController {
private final IDesUserService desUserService;
private final IBusProjectService projectService;
/**
* 查询设计人员列表
@ -142,5 +152,75 @@ public class DesUserController extends BaseController {
return toAjax(desUserService.batchAddOrUpdate(dto));
}
private static final String TEMPLATE_PATH = "template/设计项目负责人任命通知单.docx";
@PostMapping("/downloadWord")
public void generateDesignLeaderDoc( Long projectId,
HttpServletResponse response
) {
OutputStream outputStream = null;
try {
// 1. 调用Service生成目标模板的Word字节流
byte[] docBytes = generateDocBytes(projectId);
// 2. 配置响应头:确保前端正确下载(避免中文乱码、指定文件类型)
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); // 二进制流类型
// 下载文件名:格式为“[项目名]-设计负责人任命通知单.docx”此处用projectId拼接真实场景可从数据中获取项目名
String downloadFileName = URLEncoder.encode(
"设计负责人任命通知单.docx",
"UTF-8"
);
response.setHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
response.setContentLength(docBytes.length); // 设置响应体长度(优化下载体验)
// 3. 将Word字节流写入响应
outputStream = response.getOutputStream();
outputStream.write(docBytes);
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
// 异常处理返回500错误状态码
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} finally {
// 关闭流,避免资源泄漏
if (outputStream != null) {
try {
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public byte[] generateDocBytes(Long projectId) throws Exception {
// -------------------------- 步骤1按projectId查询项目数据模拟真实业务 --------------------------
// 实际场景替换为数据库查询如调用DAO获取项目名称、负责人等
BusProject byId = projectService.getById(projectId);
DesUser desUser = desUserService.lambdaQuery().eq(DesUser::getProjectId, projectId)
.eq(DesUser::getUserType, "1")
.last("limit 1").one();
Map<String, Object> placeholderData = new HashMap<>();
placeholderData.put("projectName", byId==null?"" :byId.getProjectName());
placeholderData.put("leaderName",desUser==null?"": desUser.getUserName());
// -------------------------- 步骤2用poi-tl加载目标模板并替换占位符 --------------------------
// 读取resources下的“设计项目负责人任命通知单.docx”模板
ClassPathResource templateResource = new ClassPathResource(TEMPLATE_PATH);
try (InputStream templateIs = templateResource.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
// 1. 加载模板 2. 注入替换数据 3. 渲染生成新文档
XWPFTemplate template = XWPFTemplate.compile(templateIs)
.render(placeholderData); // 自动匹配{{变量名}}占位符
// -------------------------- 步骤3将生成的文档写入字节流 --------------------------
template.write(outputStream);
template.close(); // 关闭模板资源
return outputStream.toByteArray();
}
}
}

View File

@ -0,0 +1,15 @@
package org.dromara.design.domain.vo;
import lombok.Data;
@Data
public class DesCollectFileWordVo {
private Integer num;
private String fileName;
private String opinion;
}

View File

@ -0,0 +1,25 @@
package org.dromara.design.exportUtil.plan;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AttachmentPersonnel {
String professional; // 专业及人员分工
String leaderName; // 专业负责人姓名
String leaderTitle; // 专业负责人职称
String designerName; // 设计人姓名
String designerTitle; // 设计人职称
String reviewerName; // 校审人姓名
String reviewerTitle; // 校审人职称
String checkerName; // 审核人姓名
String checkerTitle; // 审核人职称
String approverName; // 审定人姓名
String approverTitle; // 审定人职称
}

View File

@ -369,13 +369,14 @@ public class BusBillofquantitiesVersionsServiceImpl extends ServiceImpl<BusBillo
List<BusBillofquantities> dbList = busBillofquantitiesService.list(Wrappers.<BusBillofquantities>lambdaQuery()
.eq(BusBillofquantities::getVersions, versions)
.eq(BusBillofquantities::getProjectId, projectId)
.orderByAsc(BusBillofquantities::getId)
);
if (CollectionUtil.isEmpty(dbList)) {
return Collections.emptyMap();
}
// 2. 转换为导出实体并按sheet分组
Map<String, List<BillOfQuantitiesExport>> sheetMap = new HashMap<>();
Map<String, List<BillOfQuantitiesExport>> sheetMap = new LinkedHashMap<>();
for (BusBillofquantities dbItem : dbList) {
BillOfQuantitiesExport exportItem = new BillOfQuantitiesExport();
BeanUtil.copyProperties(dbItem, exportItem);

View File

@ -1,39 +0,0 @@
package org.dromara.facility.domain.vo.matrix;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryStructureVo;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* @author lilemy
* @date 2025-08-23 01:17
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FacMatrixStructureVo implements Serializable {
@Serial
private static final long serialVersionUID = 7526403047030009646L;
/**
* 主键
*/
private Long id;
/**
* 方阵名称
*/
private String name;
/**
* 分项工程
*/
private List<PgsProgressCategoryStructureVo> children;
}

View File

@ -847,7 +847,7 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
// 根据类型,更新对应数据
if (type.equals(RecognizerTypeEnum.HOLE.getValue())) {
photovoltaicPanelPointService.updateFinishNumberByCoordinate(projectIds, matchPoints);
} else if (type.equals(RecognizerTypeEnum.PILE.getValue())) {
} else if (type.equals(RecognizerTypeEnum.COLUMN.getValue())) {
photovoltaicPanelColumnService.updateFinishNumberByCoordinate(projectIds, matchPoints);
} else if (type.equals(RecognizerTypeEnum.BRACKET.getValue())) {
photovoltaicPanelSupportService.updateFinishNumberByCoordinate(projectIds, matchPoints);
@ -871,7 +871,7 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
return list.stream().map(point ->
new IdCoordinatePoint(point.getId(), point.getPositions())).toList();
}
} else if (type.equals(RecognizerTypeEnum.PILE.getValue())) {
} else if (type.equals(RecognizerTypeEnum.COLUMN.getValue())) {
List<FacPhotovoltaicPanelColumn> list = photovoltaicPanelColumnService.lambdaQuery()
.in(FacPhotovoltaicPanelColumn::getProjectId, projectIds)
.ne(FacPhotovoltaicPanelColumn::getStatus, FacFinishStatusEnum.FINISH.getValue())

View File

@ -23,7 +23,10 @@ import org.dromara.facility.constant.FacRedisKeyConstant;
import org.dromara.facility.domain.FacMatrix;
import org.dromara.facility.domain.FacPhotovoltaicPanel;
import org.dromara.facility.domain.dto.geojson.*;
import org.dromara.facility.domain.dto.photovoltaicpanel.*;
import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateByGeoJsonReq;
import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateReq;
import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelQueryReq;
import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelUpdateReq;
import org.dromara.facility.domain.enums.FacFinishStatusEnum;
import org.dromara.facility.domain.enums.FacFinishTypeEnum;
import org.dromara.facility.domain.vo.photovoltaicpanel.FacPhotovoltaicPanelVo;
@ -329,10 +332,10 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
}
Long matrixId = matrix.getId();*/
// 去掉首字母 (T/G)
String withoutPrefix = name.substring(2);
String withoutPrefix = name.substring(1);
// 如果包含".",只取第一个"."前的数字
int dotIndex = withoutPrefix.indexOf("#");
int dotIndex = withoutPrefix.indexOf(".");
if (dotIndex != -1) {
withoutPrefix = withoutPrefix.substring(0, dotIndex);
}

View File

@ -61,7 +61,7 @@ public class GpsEquipmentSonController extends BaseController {
/**
* 查询GPS设备定位日期信息列表
*/
@SaCheckPermission("gps:equipmentSon:getRlList")
// @SaCheckPermission("gps:equipmentSon:getRlList")
@GetMapping("/getRlList")
public R<List<GpsStatusVo>> getRlList(GpsEquipmentSonBo bo) {
return R.ok(gpsEquipmentSonService.getRlList(bo));

View File

@ -81,31 +81,15 @@ public interface GpsEquipmentSonMapper extends BaseMapperPlus<GpsEquipmentSon, G
" rn = 1;")
List<GpsEquipmentSonVo> getUserListByProjectId(@Param("projectId") Long projectId, @Param("startTime") LocalDateTime startOfDay, @Param("endTime") LocalDateTime now);
@Select("WITH RECURSIVE date_range AS (\n" +
" -- 1. 初始化开始日期取startTime的“年月日”部分忽略时分秒\n" +
" SELECT DATE(#{bo.startTime}) AS stat_date\n" +
" UNION ALL\n" +
" -- 2. 递归生成后续日期直到不超过endTime的“年月日”\n" +
" SELECT DATE_ADD(stat_date, INTERVAL 1 DAY)\n" +
" FROM date_range\n" +
" WHERE stat_date < DATE(#{bo.endTime})\n" +
")\n" +
"\n" +
"SELECT \n" +
" dr.stat_date AS riqi, -- 统计日期格式YYYY-MM-DD\n" +
" COUNT(ges.id) AS count -- 当天符合条件的记录数\n" +
"FROM date_range dr\n" +
"LEFT JOIN (\n" +
" SELECT \n" +
" DATE(create_time) AS data_date, -- 提取创建时间的“年月日”\n" +
" id -- 仅需主键用于计数(减少数据传输)\n" +
" FROM gps_equipment_son\n" +
" WHERE \n" +
" project_id = #{bo.projectId} -- 匹配项目ID\n" +
" AND client_id =#{bo.clientId} -- 客户端ID为空\n" +
" AND create_time BETWEEN #{bo.startTime} AND #{bo.endTime} -- 时间范围\n" +
") ges ON dr.stat_date = ges.data_date -- 按日期关联\n" +
"GROUP BY dr.stat_date -- 按统计日期分组\n" +
"ORDER BY dr.stat_date; -- 按日期升序排列")
@Select("SELECT\n" +
" DATE(create_time) AS riqi,\n" +
" COUNT(id) AS count \n" +
"FROM\n" +
" gps_equipment_son\n" +
"WHERE\n" +
" project_id = #{bo.projectId}\n" +
" AND client_id = #{bo.clientId}\n" +
" AND create_time BETWEEN #{bo.startTime} AND #{bo.endTime}\n" +
" GROUP BY DATE(create_time)")
List<GpsStatusVo> getRlList(@Param("bo") GpsEquipmentSonBo bo);
}

View File

@ -4,6 +4,7 @@ package org.dromara.job.attendance;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
@ -86,8 +87,7 @@ public class AttendanceJob {
.lt(BusAttendanceRule::getClockInResultTime, end));
}
//获取当前日期
LocalDate date = LocalDate.now();
//管理员关联多个项目,需要记录是否已生成缺卡记录
// HashSet<Long> manageUserIds = new HashSet<>();
@ -96,6 +96,8 @@ public class AttendanceJob {
for (BusAttendanceRule rule : list) {
LocalTime clockInTime = rule.getClockInTime();
LocalTime clockInResultTime = rule.getClockInResultTime();
//获取当前日期
LocalDate date = LocalDate.now();
//计算考勤日期
if (start.isAfter(end)) { // 跨天情况
@ -120,11 +122,23 @@ public class AttendanceJob {
// //查询项目下的关联人员
// List<BusUserProjectRelevancy> relevancyList = userProjectRelevancyService.list(Wrappers.lambdaQuery(BusUserProjectRelevancy.class)
// .eq(BusUserProjectRelevancy::getProjectId, rule.getProjectId()));
List<SubConstructionUser> constructionUsers = constructionUserService.list(Wrappers.<SubConstructionUser>lambdaQuery()
.eq(SubConstructionUser::getProjectId, rule.getProjectId())
.isNotNull(SubConstructionUser::getTeamId)
.eq(SubConstructionUser::getUserRole, "0") //0-施工人员 1-管理人员 2-分包管理人员
);
LambdaQueryWrapper<SubConstructionUser> queryWrapper = new LambdaQueryWrapper<>();
// 拼接条件:(role = 1 AND teamId IS NOT NULL) OR (role IN (2))
queryWrapper.eq(SubConstructionUser::getProjectId, rule.getProjectId()) // 全局条件projectId必选
// 外层nested包裹整个OR条件块
.nested(w ->
// 内层nested强制 (user_role=0 AND team_id IS NOT NULL) 作为一个整体
w.nested(inner -> inner
.eq(SubConstructionUser::getUserRole, "0")
.isNotNull(SubConstructionUser::getTeamId)
)
.or() // 连接两个子条件
.in(SubConstructionUser::getUserRole, Arrays.asList("1", "2"))
);
List<SubConstructionUser> constructionUsers = constructionUserService.list(queryWrapper);
//查询当天已打上班卡人员
@ -197,8 +211,7 @@ public class AttendanceJob {
.lt(BusAttendanceRule::getClockOutResultTime, end));
}
//获取当前日期
LocalDate date = LocalDate.now();
//管理员关联多个项目,需要记录是否已生成缺卡记录
// HashSet<Long> manageUserIds = new HashSet<>();
@ -207,6 +220,8 @@ public class AttendanceJob {
List<BusAttendance> missList = new ArrayList<>();
for (BusAttendanceRule rule : list) {
//获取当前日期
LocalDate date = LocalDate.now();
LocalTime clockOutTime = rule.getClockOutTime();
LocalTime clockOutResultTime = rule.getClockOutResultTime();
@ -235,11 +250,23 @@ public class AttendanceJob {
//查询项目下的关联人员
// List<BusUserProjectRelevancy> relevancyList = userProjectRelevancyService.list(Wrappers.lambdaQuery(BusUserProjectRelevancy.class)
// .eq(BusUserProjectRelevancy::getProjectId, rule.getProjectId()));
List<SubConstructionUser> constructionUsers = constructionUserService.list(Wrappers.<SubConstructionUser>lambdaQuery()
.eq(SubConstructionUser::getProjectId, rule.getProjectId())
.isNotNull(SubConstructionUser::getTeamId)
.eq(SubConstructionUser::getUserRole, "0") //0-施工人员 1-管理人员 2-分包管理人员
);
LambdaQueryWrapper<SubConstructionUser> queryWrapper = new LambdaQueryWrapper<>();
// 拼接条件:(role = 1 AND teamId IS NOT NULL) OR (role IN (2))
queryWrapper.eq(SubConstructionUser::getProjectId, rule.getProjectId()) // 全局条件projectId必选
// 外层nested包裹整个OR条件块
.nested(w ->
// 内层nested强制 (user_role=0 AND team_id IS NOT NULL) 作为一个整体
w.nested(inner -> inner
.eq(SubConstructionUser::getUserRole, "0")
.isNotNull(SubConstructionUser::getTeamId)
)
.or() // 连接两个子条件
.in(SubConstructionUser::getUserRole, Arrays.asList("1", "2"))
);
List<SubConstructionUser> constructionUsers = constructionUserService.list(queryWrapper);
//查询当天打卡人员
List<BusAttendance> allAttendanceList = attendanceService.list(Wrappers.lambdaQuery(BusAttendance.class)
.eq(BusAttendance::getClockDate, date)

View File

@ -1,45 +0,0 @@
package org.dromara.job.once;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.manager.ys7manager.Ys7Manager;
import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo;
import org.dromara.other.service.IOthYs7DeviceService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 同步摄像头设备数据
*
* @author lilemy
* @date 2025/6/13 11:08
*/
@Slf4j
@Component
public class FullSyncYs7DeviceData implements CommandLineRunner {
@Resource
private Ys7Manager ys7Manager;
@Resource
private IOthYs7DeviceService ys7DeviceService;
@Override
public void run(String... args) throws Exception {
log.info("开始同步摄像头设备数据");
try {
List<Ys7QueryDeviceResponseVo> ys7QueryDeviceList = ys7Manager.queryAllDeviceList();
Boolean result = ys7DeviceService.saveOrUpdateByDeviceList(ys7QueryDeviceList);
if (result) {
log.info("摄像头设备数据同步成功");
} else {
log.info("没有需要同步的设备");
}
} catch (Exception e) {
log.info("摄像头设备数据同步失败", e);
}
}
}

View File

@ -21,6 +21,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLConnection;
import java.util.List;
import java.util.Objects;
/**
* @author lilemy
@ -82,7 +83,9 @@ public class RecognizerManager {
// 画矩形框
g.drawRect(x, y, w, h);
// 写文字(类型 + 置信度)
String label = target.getType() + " (" + String.format("%.2f", target.getScore()) + ")";
RecognizerTypeEnum recognizerTypeEnum = RecognizerTypeEnum.fromValue(target.getType());
String label = recognizerTypeEnum != null ? Objects.requireNonNull(recognizerTypeEnum).getText() : target.getType()
+ " (" + String.format("%.2f", target.getScore()) + ")";
g.drawString(label, x, y - 5);
}
g.dispose();

View File

@ -12,15 +12,17 @@ import java.util.stream.Collectors;
@Getter
public enum RecognizerTypeEnum {
HARDHAT("安全帽识别", "nohelmet", "1"),
VEST("反光背心识别", "novest", ""),
SMOKING("吸烟识别", "smoking", "3"),
FIRE("火焰识别", "fire", "16"),
SMOKE("雾识别","smoke",""),
SOLAR("光伏板识别", "solar", ""),
BRACKET("光伏板支架识别", "bracket", ""),
PILE("光伏板立柱识别", "pile", ""),
HOLE("", "hole", "");
WEARING_ALL("穿戴安全帽反光衣", "wearingall", ""),
NO_EQUIPMENT("没穿安全帽反光衣", "noequipment", "1"),
NO_HELMET("有反光衣没安全帽", "nohelmet", ""),
NO_VEST("有安全帽没反光衣", "novest", ""),
SMOKE("", "smoke", "3"),
FIRE("火焰", "fire", "16"),
SMOGGY("烟雾", "smoggy", ""),
PANEL("光伏板", "solar", ""),
BRACKET("光伏板支架", "bracket", ""),
COLUMN("光伏板桩", "column", ""),
HOLE("光伏板孔", "hole", "");
private final String text;

View File

@ -0,0 +1,106 @@
package org.dromara.materials.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.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.materials.domain.bo.MatWarehouseBo;
import org.dromara.materials.domain.vo.MatWarehouseVo;
import org.dromara.materials.service.IMatWarehouseService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 物资仓库
*
* @author lilemy
* @date 2025-10-29
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/materials/warehouse")
public class MatWarehouseController extends BaseController {
private final IMatWarehouseService matWarehouseService;
/**
* 查询物资仓库列表
*/
@SaCheckPermission("materials:warehouse:list")
@GetMapping("/list")
public TableDataInfo<MatWarehouseVo> list(MatWarehouseBo bo, PageQuery pageQuery) {
return matWarehouseService.queryPageList(bo, pageQuery);
}
/**
* 导出物资仓库列表
*/
@SaCheckPermission("materials:warehouse:export")
@Log(title = "物资仓库", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(MatWarehouseBo bo, HttpServletResponse response) {
List<MatWarehouseVo> list = matWarehouseService.queryList(bo);
ExcelUtil.exportExcel(list, "物资仓库", MatWarehouseVo.class, response);
}
/**
* 获取物资仓库详细信息
*
* @param id 主键
*/
@SaCheckPermission("materials:warehouse:query")
@GetMapping("/{id}")
public R<MatWarehouseVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(matWarehouseService.queryById(id));
}
/**
* 新增物资仓库
*/
@SaCheckPermission("materials:warehouse:add")
@Log(title = "物资仓库", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody MatWarehouseBo bo) {
return toAjax(matWarehouseService.insertByBo(bo));
}
/**
* 修改物资仓库
*/
@SaCheckPermission("materials:warehouse:edit")
@Log(title = "物资仓库", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody MatWarehouseBo bo) {
return toAjax(matWarehouseService.updateByBo(bo));
}
/**
* 删除物资仓库
*
* @param ids 主键串
*/
@SaCheckPermission("materials:warehouse:remove")
@Log(title = "物资仓库", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(matWarehouseService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -68,6 +68,11 @@ public class MatMaterialIssue extends BaseEntity {
*/
private String issueUnit;
/**
* 领用人
*/
private String shipper;
/**
* 保管单位
*/

View File

@ -38,6 +38,11 @@ public class MatMaterials extends BaseEntity {
*/
private Long companyId;
/**
* 仓库id
*/
private Long warehouseId;
/**
* 项目id
*/

View File

@ -0,0 +1,91 @@
package org.dromara.materials.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;
/**
* 物资仓库对象 mat_warehouse
*
* @author lilemy
* @date 2025-10-29
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("mat_warehouse")
public class MatWarehouse extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 仓库编号
*/
private String warehouseCode;
/**
* 仓库名称
*/
private String warehouseName;
/**
* 仓库类型
*/
private String warehouseType;
/**
* 仓库地址
*/
private String address;
/**
* 经度
*/
private String lng;
/**
* 纬度
*/
private String lat;
/**
* 仓库面积
*/
private Long area;
/**
* 存放容量
*/
private Long capacity;
/**
* 负责人
*/
private String manager;
/**
* 负责人电话
*/
private String managerPhone;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,94 @@
package org.dromara.materials.domain.bo;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.materials.domain.MatWarehouse;
/**
* 物资仓库业务对象 mat_warehouse
*
* @author lilemy
* @date 2025-10-29
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = MatWarehouse.class, reverseConvertGenerate = false)
public class MatWarehouseBo extends BaseEntity {
/**
* 主键id
*/
@NotNull(message = "主键id不能为空", groups = {EditGroup.class})
private Long id;
/**
* 项目id
*/
@NotNull(message = "项目id不能为空", groups = {AddGroup.class, EditGroup.class})
private Long projectId;
/**
* 仓库编号
*/
@NotBlank(message = "仓库编号不能为空", groups = {AddGroup.class, EditGroup.class})
private String warehouseCode;
/**
* 仓库名称
*/
@NotBlank(message = "仓库名称不能为空", groups = {AddGroup.class, EditGroup.class})
private String warehouseName;
/**
* 仓库类型
*/
@NotBlank(message = "仓库类型不能为空", groups = {AddGroup.class, EditGroup.class})
private String warehouseType;
/**
* 仓库地址
*/
private String address;
/**
* 经度
*/
private String lng;
/**
* 纬度
*/
private String lat;
/**
* 仓库面积
*/
private Long area;
/**
* 存放容量
*/
private Long capacity;
/**
* 负责人
*/
private String manager;
/**
* 负责人电话
*/
private String managerPhone;
/**
* 备注
*/
private String remark;
}

View File

@ -63,6 +63,12 @@ public class MatMaterialIssueCreateReq implements Serializable {
@NotBlank(message = "领料单位不能为空")
private String issueUnit;
/**
* 领用人
*/
@NotBlank(message = "领用人不能为空")
private String shipper;
/**
* 保管单位
*/

View File

@ -57,6 +57,11 @@ public class MatMaterialIssueUpdateReq implements Serializable {
*/
private String issueUnit;
/**
* 领用人
*/
private String shipper;
/**
* 保管单位
*/

View File

@ -61,4 +61,9 @@ public class MatMaterialReceiveItemDto {
*/
private Long planId;
/**
* 仓库id
*/
private Long warehouseId;
}

View File

@ -26,6 +26,11 @@ public class MatMaterialsCreateReq implements Serializable {
*/
private Long companyId;
/**
* 仓库id
*/
private Long warehouseId;
/**
* 项目id
*/

View File

@ -25,6 +25,11 @@ public class MatMaterialsQueryReq implements Serializable {
*/
private Long companyId;
/**
* 仓库id
*/
private Long warehouseId;
/**
* 项目id
*/

View File

@ -31,6 +31,11 @@ public class MatMaterialsUpdateReq implements Serializable {
*/
private Long companyId;
/**
* 仓库id
*/
private Long warehouseId;
/**
* 项目id
*/

View File

@ -0,0 +1,108 @@
package org.dromara.materials.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.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.materials.domain.MatWarehouse;
import java.io.Serial;
import java.io.Serializable;
/**
* 物资仓库视图对象 mat_warehouse
*
* @author lilemy
* @date 2025-10-29
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = MatWarehouse.class)
public class MatWarehouseVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long id;
/**
* 项目id
*/
@ExcelProperty(value = "项目id")
private Long projectId;
/**
* 仓库编号
*/
@ExcelProperty(value = "仓库编号")
private String warehouseCode;
/**
* 仓库名称
*/
@ExcelProperty(value = "仓库名称")
private String warehouseName;
/**
* 仓库类型
*/
@ExcelProperty(value = "仓库类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "mat_warehouse_type")
private String warehouseType;
/**
* 仓库地址
*/
@ExcelProperty(value = "仓库地址")
private String address;
/**
* 经度
*/
@ExcelProperty(value = "经度")
private String lng;
/**
* 纬度
*/
@ExcelProperty(value = "纬度")
private String lat;
/**
* 仓库面积
*/
@ExcelProperty(value = "仓库面积")
private Long area;
/**
* 存放容量
*/
@ExcelProperty(value = "存放容量")
private Long capacity;
/**
* 负责人
*/
@ExcelProperty(value = "负责人")
private String manager;
/**
* 负责人电话
*/
@ExcelProperty(value = "负责人电话")
private String managerPhone;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@ -69,6 +69,11 @@ public class MatMaterialIssueVo implements Serializable {
*/
private String issueUnit;
/**
* 领用人
*/
private String shipper;
/**
* 保管单位
*/

View File

@ -1,13 +1,11 @@
package org.dromara.materials.domain.vo.materials;
import lombok.Data;
import org.dromara.materials.domain.vo.materialsinventory.MatMaterialsInventoryOutVo;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* @author lilemy
@ -48,9 +46,4 @@ public class MatMaterialsNumberVo implements Serializable {
* 创建时间
*/
private Date createTime;
/**
* 出库列表
*/
private List<MatMaterialsInventoryOutVo> outList;
}

View File

@ -28,6 +28,16 @@ public class MatMaterialsUseDetailVo implements Serializable {
*/
private String materialsName;
/**
* 仓库id
*/
private Long warehouseId;
/**
* 仓库名称
*/
private String warehouseName;
/**
* 计划数量
*/

View File

@ -47,6 +47,11 @@ public class MatMaterialsVo implements Serializable {
@ExcelProperty(value = "公司id")
private Long companyId;
/**
* 仓库id
*/
private Long warehouseId;
/**
* 公司信息
*/

View File

@ -0,0 +1,15 @@
package org.dromara.materials.mapper;
import org.dromara.materials.domain.MatWarehouse;
import org.dromara.materials.domain.vo.MatWarehouseVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 物资仓库Mapper接口
*
* @author lilemy
* @date 2025-10-29
*/
public interface MatWarehouseMapper extends BaseMapperPlus<MatWarehouse, MatWarehouseVo> {
}

View File

@ -8,6 +8,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.materials.domain.MatMaterials;
import org.dromara.materials.domain.MatMaterialsInventory;
import org.dromara.materials.domain.MatMaterialsUseRecord;
import org.dromara.materials.domain.MatWarehouse;
import org.dromara.materials.domain.dto.materialreceiveitem.MatMaterialReceiveItemDto;
import org.dromara.materials.domain.dto.materials.MatMaterialsCreateReq;
import org.dromara.materials.domain.dto.materials.MatMaterialsGisReq;
@ -117,11 +118,8 @@ public interface IMatMaterialsService extends IService<MatMaterials> {
* @param supplierUnit 供应商单位
* @param nickname 操作用户昵称
*/
void create(Long projectId,
List<MatMaterialReceiveItemDto> itemList,
String formCode,
String supplierUnit,
String nickname
void create(Long projectId, List<MatMaterialReceiveItemDto> itemList,
String formCode, String supplierUnit, String nickname
);
/**
@ -169,16 +167,18 @@ public interface IMatMaterialsService extends IService<MatMaterials> {
/**
* 获取材料使用详情列表
*
* @param materials 材料
* @param putList 材料入库列表
* @param outList 材料出库列表
* @param useList 材料使用列表
* @param materials 材料
* @param putList 材料入库列表
* @param outList 材料出库列表
* @param useList 材料使用列表
* @param warehouseList 仓库列表
* @return 材料使用详情列表
*/
List<MatMaterialsUseDetailVo> getUseDetailList(List<MatMaterials> materials,
List<MatMaterialsInventory> putList,
List<MatMaterialsInventory> outList,
List<MatMaterialsUseRecord> useList);
List<MatMaterialsUseRecord> useList,
List<MatWarehouse> warehouseList);
/**
* 获取材料库存数据列表

View File

@ -0,0 +1,70 @@
package org.dromara.materials.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.materials.domain.MatWarehouse;
import org.dromara.materials.domain.bo.MatWarehouseBo;
import org.dromara.materials.domain.vo.MatWarehouseVo;
import java.util.Collection;
import java.util.List;
/**
* 物资仓库Service接口
*
* @author lilemy
* @date 2025-10-29
*/
public interface IMatWarehouseService extends IService<MatWarehouse> {
/**
* 查询物资仓库
*
* @param id 主键
* @return 物资仓库
*/
MatWarehouseVo queryById(Long id);
/**
* 分页查询物资仓库列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 物资仓库分页列表
*/
TableDataInfo<MatWarehouseVo> queryPageList(MatWarehouseBo bo, PageQuery pageQuery);
/**
* 查询符合条件的物资仓库列表
*
* @param bo 查询条件
* @return 物资仓库列表
*/
List<MatWarehouseVo> queryList(MatWarehouseBo bo);
/**
* 新增物资仓库
*
* @param bo 物资仓库
* @return 是否新增成功
*/
Boolean insertByBo(MatWarehouseBo bo);
/**
* 修改物资仓库
*
* @param bo 物资仓库
* @return 是否修改成功
*/
Boolean updateByBo(MatWarehouseBo bo);
/**
* 校验并批量删除物资仓库信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -23,6 +23,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.exception.OssException;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.utils.DocumentUtil;
import org.dromara.materials.constants.MatMaterialsConstant;
import org.dromara.materials.domain.MatMaterialIssue;
@ -35,6 +36,7 @@ import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueUpdateReq;
import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueWordDto;
import org.dromara.materials.domain.dto.materialissueitem.MatMaterialIssueItemDto;
import org.dromara.materials.domain.dto.materialissueitem.MatMaterialIssueItemWordDto;
import org.dromara.materials.domain.enums.MatMaterialsInventoryOutPutEnum;
import org.dromara.materials.domain.vo.materialissue.MatMaterialIssueVo;
import org.dromara.materials.domain.vo.materialsinventory.MatMaterialsInventoryListVo;
import org.dromara.materials.mapper.MatMaterialIssueMapper;
@ -238,14 +240,12 @@ public class MatMaterialIssueServiceImpl extends ServiceImpl<MatMaterialIssueMap
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(MatMaterialIssueCreateReq req) {
String nickname = Objects.requireNonNull(LoginHelper.getLoginUser()).getNickname();
MatMaterialIssue materialIssue = new MatMaterialIssue();
BeanUtils.copyProperties(req, materialIssue);
validEntityBeforeSave(materialIssue, true);
getFileSize(materialIssue,
req.getLicenseCountFileId(),
req.getReportCountFileId(),
req.getTechDocCountFileId(),
req.getCertCountFileId());
validEntityBeforeSave(materialIssue);
getFileSize(materialIssue, req.getLicenseCountFileId(),
req.getReportCountFileId(), req.getTechDocCountFileId(), req.getCertCountFileId());
boolean save = this.save(materialIssue);
if (!save) {
throw new ServiceException("物料领料单新增失败", HttpStatus.ERROR);
@ -263,7 +263,7 @@ public class MatMaterialIssueServiceImpl extends ServiceImpl<MatMaterialIssueMap
if (!result) {
throw new ServiceException("物料领料单明细项新增失败", HttpStatus.ERROR);
}
/* // 创建设备材料出库记录
// 创建设备材料出库记录
List<MatMaterialsInventory> inventoryList = itemList.stream().map(item -> {
MatMaterialsInventory inventory = new MatMaterialsInventory();
inventory.setNumber(item.getIssuedQuantity().longValue());
@ -271,7 +271,7 @@ public class MatMaterialIssueServiceImpl extends ServiceImpl<MatMaterialIssueMap
inventory.setResidue(item.getRemainingQuantity().longValue());
inventory.setOperator(nickname);
inventory.setRecipient(materialIssue.getIssueUnit());
inventory.setShipper(nickname);
inventory.setShipper(materialIssue.getShipper());
inventory.setMaterialsId(item.getMaterialsId());
inventory.setProjectId(materialIssue.getProjectId());
inventory.setOutPut(MatMaterialsInventoryOutPutEnum.OUT.getValue());
@ -281,7 +281,7 @@ public class MatMaterialIssueServiceImpl extends ServiceImpl<MatMaterialIssueMap
boolean saved = materialsInventoryService.saveBatch(inventoryList);
if (!saved) {
throw new ServiceException("物料出库记录新增失败", HttpStatus.ERROR);
}*/
}
}
return true;
}
@ -302,7 +302,7 @@ public class MatMaterialIssueServiceImpl extends ServiceImpl<MatMaterialIssueMap
}
MatMaterialIssue materialIssue = new MatMaterialIssue();
BeanUtils.copyProperties(req, materialIssue);
validEntityBeforeSave(materialIssue, false);
validEntityBeforeSave(materialIssue);
getFileSize(materialIssue,
req.getLicenseCountFileId(),
req.getReportCountFileId(),
@ -341,18 +341,9 @@ public class MatMaterialIssueServiceImpl extends ServiceImpl<MatMaterialIssueMap
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(MatMaterialIssue entity, Boolean create) {
private void validEntityBeforeSave(MatMaterialIssue entity) {
// 做一些数据校验,如唯一约束
Long projectId = entity.getProjectId();
String materialSource = entity.getMaterialSource();
if (create) {
if (projectId == null) {
throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST);
}
if (StringUtils.isEmpty(materialSource)) {
throw new ServiceException("物料来源不能为空", HttpStatus.BAD_REQUEST);
}
}
// 查询项目是否存在
if (projectId != null && projectService.getById(projectId) == null) {
throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND);

View File

@ -26,16 +26,20 @@ import org.dromara.common.utils.DocumentUtil;
import org.dromara.materials.constants.MatMaterialsConstant;
import org.dromara.materials.domain.MatMaterialReceive;
import org.dromara.materials.domain.MatMaterialReceiveItem;
import org.dromara.materials.domain.MatMaterials;
import org.dromara.materials.domain.MatMaterialsInventory;
import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveCreateReq;
import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveQueryReq;
import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveUpdateReq;
import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveWordDto;
import org.dromara.materials.domain.dto.materialreceiveitem.MatMaterialReceiveItemDto;
import org.dromara.materials.domain.dto.materialreceiveitem.MatMaterialReceiveItemWordDto;
import org.dromara.materials.domain.enums.MatMaterialsInventoryOutPutEnum;
import org.dromara.materials.domain.vo.materialreceive.MatMaterialReceiveVo;
import org.dromara.materials.mapper.MatMaterialReceiveMapper;
import org.dromara.materials.service.IMatMaterialReceiveItemService;
import org.dromara.materials.service.IMatMaterialReceiveService;
import org.dromara.materials.service.IMatMaterialsInventoryService;
import org.dromara.materials.service.IMatMaterialsService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.system.domain.vo.SysOssVo;
@ -53,6 +57,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;
/**
@ -81,6 +86,9 @@ public class MatMaterialReceiveServiceImpl extends ServiceImpl<MatMaterialReceiv
@Resource
private IMatMaterialsService materialsService;
@Resource
private IMatMaterialsInventoryService materialsInventoryService;
/**
* 查询物料接收单
*
@ -233,7 +241,7 @@ public class MatMaterialReceiveServiceImpl extends ServiceImpl<MatMaterialReceiv
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(MatMaterialReceiveCreateReq req) {
String nickname = LoginHelper.getLoginUser().getNickname();
String nickname = Objects.requireNonNull(LoginHelper.getLoginUser()).getNickname();
MatMaterialReceive materialReceive = new MatMaterialReceive();
BeanUtils.copyProperties(req, materialReceive);
validEntityBeforeSave(materialReceive, true);
@ -274,11 +282,8 @@ public class MatMaterialReceiveServiceImpl extends ServiceImpl<MatMaterialReceiv
}
//生成库存
materialsService.create(
materialReceive.getProjectId(),
itemList,
materialReceive.getFormCode(),
materialReceive.getSupplierUnit(),
nickname
materialReceive.getProjectId(), itemList, materialReceive.getFormCode(),
materialReceive.getSupplierUnit(), nickname
);
}
return true;
@ -366,12 +371,37 @@ public class MatMaterialReceiveServiceImpl extends ServiceImpl<MatMaterialReceiv
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteByIds(Collection<Long> ids) {
List<MatMaterialReceive> receiveList = this.listByIds(ids);
List<MatMaterialReceiveItem> itemList = materialReceiveItemService.lambdaQuery()
.in(MatMaterialReceiveItem::getReceiveId, ids)
.list();
if (CollUtil.isNotEmpty(itemList)) {
materialReceiveItemService.removeBatchByIds(itemList);
}
// 关联删除材料数据
Set<String> formCode = receiveList.stream().map(MatMaterialReceive::getFormCode).collect(Collectors.toSet());
List<MatMaterials> materials = materialsService.lambdaQuery()
.in(MatMaterials::getFormCode, formCode)
.list();
if (CollUtil.isNotEmpty(materials)) {
for (MatMaterials material : materials) {
List<MatMaterialsInventory> inventoryList = materialsInventoryService.lambdaQuery()
.eq(MatMaterialsInventory::getMaterialsId, material.getId())
.eq(MatMaterialsInventory::getOutPut, MatMaterialsInventoryOutPutEnum.OUT.getValue())
.list();
if (CollUtil.isNotEmpty(inventoryList)) {
throw new ServiceException("存在关联的库存数据,无法删除", HttpStatus.BAD_REQUEST);
}
Set<Long> materialIds = materials.stream().map(MatMaterials::getId).collect(Collectors.toSet());
List<MatMaterialsInventory> allInventoryList = materialsInventoryService.lambdaQuery()
.in(MatMaterialsInventory::getMaterialsId, materialIds)
.list();
if (CollUtil.isNotEmpty(allInventoryList)) {
materialsInventoryService.removeBatchByIds(allInventoryList);
}
}
materialsService.removeBatchByIds(materials);
}
return this.removeBatchByIds(ids);
}
@ -484,7 +514,7 @@ public class MatMaterialReceiveServiceImpl extends ServiceImpl<MatMaterialReceiv
* @param reportCountFileId 报表文件id
* @param techDocCountFileId 技术文档文件id
* @param certCountFileId 证书文件id
* @param attachmentId
* @param attachmentId 附件id
*/
private void getFileSize(MatMaterialReceive materialReceive, String licenseCountFileId,
String reportCountFileId, String techDocCountFileId, String certCountFileId, String attachmentId) {

View File

@ -1,7 +1,6 @@
package org.dromara.materials.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -18,10 +17,7 @@ import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.materials.domain.MatMaterialReceive;
import org.dromara.materials.domain.MatMaterials;
import org.dromara.materials.domain.MatMaterialsInventory;
import org.dromara.materials.domain.MatMaterialsUseRecord;
import org.dromara.materials.domain.*;
import org.dromara.materials.domain.dto.materialreceiveitem.MatMaterialReceiveItemDto;
import org.dromara.materials.domain.dto.materials.MatMaterialsCreateReq;
import org.dromara.materials.domain.dto.materials.MatMaterialsGisReq;
@ -29,10 +25,8 @@ import org.dromara.materials.domain.dto.materials.MatMaterialsQueryReq;
import org.dromara.materials.domain.dto.materials.MatMaterialsUpdateReq;
import org.dromara.materials.domain.dto.materialsinventory.MatMaterialsInventoryCreateReq;
import org.dromara.materials.domain.enums.MatMaterialsInventoryOutPutEnum;
import org.dromara.materials.domain.enums.MatMaterialsInventoryReceiveStatusEnum;
import org.dromara.materials.domain.vo.materials.*;
import org.dromara.materials.domain.vo.materialsinventory.MatMaterialsInventoryOutUseVo;
import org.dromara.materials.domain.vo.materialsinventory.MatMaterialsInventoryOutVo;
import org.dromara.materials.domain.vo.materialsinventory.MatMaterialsInventoryVo;
import org.dromara.materials.domain.vo.materialsuserecord.MatMaterialsUseRecordByOutVo;
import org.dromara.materials.mapper.MatMaterialsMapper;
@ -81,6 +75,9 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
@Resource
private IMatCompanyService companyService;
@Resource
private IMatWarehouseService warehouseService;
/**
* 查询材料名称
@ -317,6 +314,7 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
// 从对象中取值
String materialsName = req.getMaterialsName();
Long companyId = req.getCompanyId();
Long warehouseId = req.getWarehouseId();
Long projectId = req.getProjectId();
String typeSpecificationName = req.getTypeSpecificationName();
String weightId = req.getWeightId();
@ -331,7 +329,7 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
lqw.eq(ObjectUtils.isNotEmpty(status), MatMaterials::getStatus, status);
lqw.eq(ObjectUtils.isNotEmpty(projectId), MatMaterials::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(companyId), MatMaterials::getCompanyId, companyId);
lqw.eq(ObjectUtils.isNotEmpty(warehouseId), MatMaterials::getWarehouseId, warehouseId);
lqw.orderByDesc(MatMaterials::getCreateTime);
return lqw;
}
@ -368,9 +366,10 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
*/
@Async
@Override
public void create(Long projectId, List<MatMaterialReceiveItemDto> itemList, String formCode, String supplierUnit, String nickname) {
public void create(Long projectId, List<MatMaterialReceiveItemDto> itemList,
String formCode, String supplierUnit, String nickname) {
for (MatMaterialReceiveItemDto item : itemList) {
if(item.getAcceptedQuantity().compareTo(BigDecimal.ZERO) <= 0){
if (item.getAcceptedQuantity().compareTo(BigDecimal.ZERO) <= 0) {
continue;
}
MatMaterials matMaterials = new MatMaterials();
@ -380,6 +379,7 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
matMaterials.setWeightId(item.getUnit());
matMaterials.setQuantityCount(item.getQuantity().toString());
matMaterials.setFormCode(formCode);
matMaterials.setWarehouseId(item.getWarehouseId());
save(matMaterials);
Long materialsId = matMaterials.getId();
MatMaterialsInventoryCreateReq req = new MatMaterialsInventoryCreateReq();
@ -448,18 +448,6 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
.selectLatestByMaterialIds(materialIds)
.stream()
.collect(Collectors.toMap(MatMaterialsInventory::getMaterialsId, Function.identity(), (a, b) -> a));
// 查询出库记录
List<MatMaterialsInventory> outList = materialsInventoryService.lambdaQuery()
.in(MatMaterialsInventory::getMaterialsId, materialIds)
.eq(MatMaterialsInventory::getOutPut, MatMaterialsInventoryOutPutEnum.OUT.getValue())
.eq(MatMaterialsInventory::getIsReceive, MatMaterialsInventoryReceiveStatusEnum.NOT.getValue())
.list();
Map<Long, List<MatMaterialsInventory>> outMap = new HashMap<>();
if (CollUtil.isNotEmpty(outList)) {
outMap = outList.stream()
.collect(Collectors.groupingBy(MatMaterialsInventory::getMaterialsId));
}
Map<Long, List<MatMaterialsInventory>> finalOutMap = outMap;
// 按 formCode 分组
Map<String, List<MatMaterials>> formCodeMap = materials.stream()
.collect(Collectors.groupingBy(MatMaterials::getFormCode));
@ -474,11 +462,18 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
for (Map.Entry<String, List<MatMaterials>> entry : formCodeMap.entrySet()) {
String formCode = entry.getKey();
// 过滤库存为 0 的材料
List<MatMaterials> validMaterials = entry.getValue().stream()
.filter(m -> {
List<MatMaterialsNumberVo> validMaterials = entry.getValue().stream().map(m -> {
MatMaterialsNumberVo numberVo = new MatMaterialsNumberVo();
MatMaterialsInventory inv = inventoryMap.get(m.getId());
return inv != null && inv.getResidue() > 0;
if (inv == null) {
return null;
}
BeanUtils.copyProperties(m, numberVo);
numberVo.setInventoryNumber(BigDecimal.valueOf(inv.getResidue()));
return numberVo;
})
.filter(Objects::nonNull)
.filter(m -> m.getInventoryNumber().compareTo(BigDecimal.ZERO) > 0)
.toList();
if (CollUtil.isEmpty(validMaterials)) {
continue;
@ -490,29 +485,7 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
if (receive != null) {
BeanUtils.copyProperties(receive, vo);
}
List<MatMaterialsNumberVo> numberVos = new ArrayList<>();
for (MatMaterials m : validMaterials) {
MatMaterialsNumberVo numberVo = new MatMaterialsNumberVo();
BeanUtils.copyProperties(m, numberVo);
MatMaterialsInventory inv = inventoryMap.get(m.getId());
if (inv != null) {
numberVo.setInventoryNumber(BigDecimal.valueOf(inv.getNumber()));
}
if (CollUtil.isNotEmpty(finalOutMap) && finalOutMap.containsKey(m.getId())) {
List<MatMaterialsInventory> outs = finalOutMap.get(m.getId());
numberVo.setOutList(outs.stream().map(out -> {
MatMaterialsInventoryOutVo outVo = new MatMaterialsInventoryOutVo();
BeanUtils.copyProperties(out, outVo);
return outVo;
}).toList());
}
if(CollectionUtil.isNotEmpty(numberVo.getOutList())){
numberVos.add(numberVo);
}
}
vo.setMaterials(numberVos);
vo.setMaterials(validMaterials);
resultList.add(vo);
}
return resultList;
@ -641,7 +614,15 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
.in(MatMaterialsUseRecord::getInventoryId, outIds)
.list();
}
List<MatMaterialsUseDetailVo> useDetailList = this.getUseDetailList(materialsList, putList, outList, useList);
// 查询仓库列表
Set<Long> warehouseIds = materialsList.stream().map(MatMaterials::getWarehouseId).collect(Collectors.toSet());
List<MatWarehouse> warehouseList = new ArrayList<>();
if (CollUtil.isNotEmpty(warehouseIds)) {
warehouseList = warehouseService.lambdaQuery()
.in(MatWarehouse::getId, warehouseIds)
.list();
}
List<MatMaterialsUseDetailVo> useDetailList = this.getUseDetailList(materialsList, putList, outList, useList, warehouseList);
materialsVoPage.setRecords(useDetailList);
return TableDataInfo.build(materialsVoPage);
}
@ -649,17 +630,19 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
/**
* 获取材料使用详情列表
*
* @param materials 材料
* @param putList 材料入库列表
* @param outList 材料出库列表
* @param useList 材料使用列表
* @param materials 材料
* @param putList 材料入库列表
* @param outList 材料出库列表
* @param useList 材料使用列表
* @param warehouseList 仓库列表
* @return 材料使用详情列表
*/
@Override
public List<MatMaterialsUseDetailVo> getUseDetailList(List<MatMaterials> materials,
List<MatMaterialsInventory> putList,
List<MatMaterialsInventory> outList,
List<MatMaterialsUseRecord> useList) {
List<MatMaterialsUseRecord> useList,
List<MatWarehouse> warehouseList) {
Map<Long, MatMaterialsInventory> putMap = putList.stream()
.collect(Collectors.toMap(MatMaterialsInventory::getMaterialsId, inventory -> inventory,
(existing, replacement) -> replacement));
@ -668,11 +651,13 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
BeanUtils.copyProperties(material, vo);
Long id = material.getId();
MatMaterialsInventory put = putMap.get(id);
vo.setSupplier(put.getRecipient());
vo.setInventoryId(put.getId());
vo.setNumber(put.getNumber());
vo.setOperator(put.getOperator());
vo.setEnterTime(put.getCreateTime());
if (put != null) {
vo.setSupplier(put.getRecipient());
vo.setInventoryId(put.getId());
vo.setNumber(put.getNumber());
vo.setOperator(put.getOperator());
vo.setEnterTime(put.getCreateTime());
}
if (CollUtil.isNotEmpty(outList)) {
List<MatMaterialsInventory> outs = outList.stream()
.filter(inventory -> inventory.getMaterialsId().equals(id))
@ -698,6 +683,15 @@ public class MatMaterialsServiceImpl extends ServiceImpl<MatMaterialsMapper, Mat
}
}
// 获取仓库名称
Long warehouseId = material.getWarehouseId();
if (CollUtil.isNotEmpty(warehouseList) && warehouseId != null) {
MatWarehouse warehouse = warehouseList.stream()
.filter(w -> w.getId().equals(warehouseId))
.findFirst()
.orElse(null);
vo.setWarehouseName(warehouse != null ? warehouse.getWarehouseName() : null);
}
return vo;
}).toList();
}

View File

@ -0,0 +1,140 @@
package org.dromara.materials.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.materials.domain.MatWarehouse;
import org.dromara.materials.domain.bo.MatWarehouseBo;
import org.dromara.materials.domain.vo.MatWarehouseVo;
import org.dromara.materials.mapper.MatWarehouseMapper;
import org.dromara.materials.service.IMatWarehouseService;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 物资仓库Service业务层处理
*
* @author lilemy
* @date 2025-10-29
*/
@RequiredArgsConstructor
@Service
public class MatWarehouseServiceImpl extends ServiceImpl<MatWarehouseMapper, MatWarehouse>
implements IMatWarehouseService {
/**
* 查询物资仓库
*
* @param id 主键
* @return 物资仓库
*/
@Override
public MatWarehouseVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 分页查询物资仓库列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 物资仓库分页列表
*/
@Override
public TableDataInfo<MatWarehouseVo> queryPageList(MatWarehouseBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<MatWarehouse> lqw = buildQueryWrapper(bo);
Page<MatWarehouseVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的物资仓库列表
*
* @param bo 查询条件
* @return 物资仓库列表
*/
@Override
public List<MatWarehouseVo> queryList(MatWarehouseBo bo) {
LambdaQueryWrapper<MatWarehouse> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<MatWarehouse> buildQueryWrapper(MatWarehouseBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<MatWarehouse> lqw = Wrappers.lambdaQuery();
lqw.orderByDesc(MatWarehouse::getId);
lqw.eq(bo.getProjectId() != null, MatWarehouse::getProjectId, bo.getProjectId());
lqw.eq(StringUtils.isNotBlank(bo.getWarehouseCode()), MatWarehouse::getWarehouseCode, bo.getWarehouseCode());
lqw.like(StringUtils.isNotBlank(bo.getWarehouseName()), MatWarehouse::getWarehouseName, bo.getWarehouseName());
lqw.eq(StringUtils.isNotBlank(bo.getWarehouseType()), MatWarehouse::getWarehouseType, bo.getWarehouseType());
lqw.eq(StringUtils.isNotBlank(bo.getAddress()), MatWarehouse::getAddress, bo.getAddress());
lqw.eq(StringUtils.isNotBlank(bo.getLng()), MatWarehouse::getLng, bo.getLng());
lqw.eq(StringUtils.isNotBlank(bo.getLat()), MatWarehouse::getLat, bo.getLat());
lqw.eq(bo.getArea() != null, MatWarehouse::getArea, bo.getArea());
lqw.eq(bo.getCapacity() != null, MatWarehouse::getCapacity, bo.getCapacity());
lqw.eq(StringUtils.isNotBlank(bo.getManager()), MatWarehouse::getManager, bo.getManager());
lqw.eq(StringUtils.isNotBlank(bo.getManagerPhone()), MatWarehouse::getManagerPhone, bo.getManagerPhone());
return lqw;
}
/**
* 新增物资仓库
*
* @param bo 物资仓库
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(MatWarehouseBo bo) {
MatWarehouse add = MapstructUtils.convert(bo, MatWarehouse.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改物资仓库
*
* @param bo 物资仓库
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(MatWarehouseBo bo) {
MatWarehouse update = MapstructUtils.convert(bo, MatWarehouse.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(MatWarehouse entity) {
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除物资仓库信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

View File

@ -5,6 +5,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import java.util.stream.Stream;
@Configuration
public class WebSocketConfig {

View File

@ -220,7 +220,17 @@ public class OthYs7DeviceImgServiceImpl extends ServiceImpl<OthYs7DeviceImgMappe
othYs7DeviceImg.setDeviceName(img.getDeviceName());
othYs7DeviceImg.setUrl(ossUrl);
// 将抓取的图片进行识别
List<RecognizerTypeEnum> recTypes = List.of(RecognizerTypeEnum.HARDHAT, RecognizerTypeEnum.SMOKING, RecognizerTypeEnum.FIRE);
// List<RecognizerTypeEnum> recTypes = List.of(RecognizerTypeEnum.NO_EQUIPMENT,
// RecognizerTypeEnum.NO_HELMET,
// RecognizerTypeEnum.NO_EQUIPMENT,
// RecognizerTypeEnum.NO_VEST,
// RecognizerTypeEnum.SMOKE,
// RecognizerTypeEnum.FIRE);
List<RecognizerTypeEnum> recTypes = List.of(
RecognizerTypeEnum.COLUMN,
RecognizerTypeEnum.PANEL,
RecognizerTypeEnum.BRACKET,
RecognizerTypeEnum.HOLE);
RecognizeVo recognizeVo = null;
try {
recognizeVo = recognizerManager.recognize(ossUrl, recTypes);

View File

@ -41,6 +41,12 @@ public class OutConstructionValueRangeVo implements Serializable {
@ExcelProperty(value = "项目ID")
private Long projectId;
/**
* 第N周
*/
@ExcelProperty(value = "第N周")
private int week;
/**
* 开始日期
*/

View File

@ -31,15 +31,15 @@ import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import java.time.format.DateTimeFormatter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.time.temporal.WeekFields;
import java.util.*;
/**
* 施工产值范围Service业务层处理
@ -61,6 +61,22 @@ public class OutConstructionValueRangeServiceImpl extends ServiceImpl<OutConstru
@Resource
private IPgsProgressPlanDetailService progressPlanDetailService;
/**
* 获取指定日期所在的周数(根据中国周规则)
*
* @param dateStr 日期字符串格式yyyy-MM-dd
* @return 指定日期所在的周数1-52
*/
public Integer getCurrentWeekOfYear(String dateStr) {
// 解析为 LocalDate可根据需要调整日期格式
LocalDate specifiedDate = LocalDate.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE);
// 2. 定义周规则(可选,默认使用系统区域,也可指定)
// 示例2中国规则周一为第一天第一周包含1月1日即可
WeekFields chinaWeekFields = WeekFields.of(Locale.CHINA);
// 3. 获取指定时间在当年的周数(根据需要选择周规则)
return specifiedDate.get(chinaWeekFields.weekOfYear());
}
/**
* 查询施工产值范围
*
@ -87,6 +103,10 @@ public class OutConstructionValueRangeServiceImpl extends ServiceImpl<OutConstru
public TableDataInfo<OutConstructionValueRangeVo> queryPageList(OutConstructionValueRangeBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<OutConstructionValueRange> lqw = buildQueryWrapper(bo);
Page<OutConstructionValueRangeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
//增加第N周
result.getRecords().forEach(item -> {
item.setWeek(getCurrentWeekOfYear(item.getStartDate().toString()));
});
return TableDataInfo.build(result);
}

View File

@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.contractor.domain.SubContractor;
import org.dromara.contractor.service.ISubContractorService;
import org.springframework.stereotype.Service;
import org.dromara.out.domain.bo.OutSettlementValueSubcontractBo;
@ -59,7 +60,11 @@ public class OutSettlementValueSubcontractServiceImpl extends ServiceImpl<OutSet
LambdaQueryWrapper<OutSettlementValueSubcontract> lqw = buildQueryWrapper(bo);
Page<OutSettlementValueSubcontractVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
result.getRecords().forEach(e -> {
e.setContractorName(contractorService.queryById(e.getContractorId()).getName());
SubContractor contractor = contractorService.getById(e.getContractorId());
if(contractor != null) {
e.setContractorName(contractor.getName());
}
});
return TableDataInfo.build(result);
}

View File

@ -15,6 +15,7 @@ import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.excel.core.DefaultExcelListener;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
@ -39,6 +40,7 @@ import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
@ -257,21 +259,30 @@ public class PgsProgressCategoryController extends BaseController {
List<PgsProgressCategoryVo> list = sheetListener.getExcelResult().getList();
List<PgsProgressCategoryVo> newList = list.stream().filter(vo -> vo.getId() == null).toList();
List<PgsProgressCategoryVo> oldList = list.stream().filter(vo -> vo.getId() != null).toList();
// 将当前sheet的数据添加到总数据中
allData.addAll(oldList);
if (CollUtil.isNotEmpty(newList)) {
if (CollUtil.isNotEmpty(oldList)) {
PgsProgressCategoryVo first = oldList.getFirst();
PgsProgressCategory category = pgsProgressCategoryService.getById(first.getId());
newList.forEach(vo -> {
vo.setParentId(category.getParentId());
vo.setProjectId(category.getProjectId());
vo.setMatrixId(category.getMatrixId());
vo.setAncestors(category.getAncestors());
vo.setRelevancyStructure(category.getRelevancyStructure());
});
allData.addAll(newList);
Set<Long> ids = oldList.stream().map(PgsProgressCategoryVo::getId).collect(Collectors.toSet());
List<PgsProgressCategory> categoryList = pgsProgressCategoryService.listByIds(ids);
// 筛选出关联设计图的数据
List<PgsProgressCategoryVo> oldListVo = oldList.stream().filter(vo -> {
PgsProgressCategory category = categoryList.stream().filter(c -> c.getId().equals(vo.getId())).findFirst().orElse(null);
if (category == null) {
return true;
}
String workType = category.getWorkType();
return StringUtils.isBlank(workType);
}).toList();
// 将当前sheet的数据添加到总数据中
allData.addAll(oldListVo);
if (CollUtil.isNotEmpty(newList) && CollUtil.isNotEmpty(oldList)) {
PgsProgressCategoryVo first = oldList.getFirst();
PgsProgressCategory category = pgsProgressCategoryService.getById(first.getId());
newList.forEach(vo -> {
vo.setParentId(category.getParentId());
vo.setProjectId(category.getProjectId());
vo.setMatrixId(category.getMatrixId());
vo.setAncestors(category.getAncestors());
vo.setRelevancyStructure(category.getRelevancyStructure());
});
allData.addAll(newList);
}
}

View File

@ -1,37 +0,0 @@
package org.dromara.progress.domain.vo.progresscategory;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* @author lilemy
* @date 2025-08-23 01:19
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PgsProgressCategoryStructureVo implements Serializable {
@Serial
private static final long serialVersionUID = -8392912623299656962L;
/**
* 主键id
*/
private Long id;
/**
* 类别名称
*/
private String name;
/**
* 子类别
*/
private List<PgsProgressCategoryStructureVo> children;
}

View File

@ -1149,8 +1149,8 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
}
List<Long> projectIds = projects.stream().map(BusProject::getId).distinct().toList();
// 识别类型:洞、桩、架、架子
List<RecognizerTypeEnum> enumList = List.of(RecognizerTypeEnum.HOLE, RecognizerTypeEnum.SOLAR,
RecognizerTypeEnum.PILE, RecognizerTypeEnum.BRACKET);
List<RecognizerTypeEnum> enumList = List.of(RecognizerTypeEnum.HOLE, RecognizerTypeEnum.PANEL,
RecognizerTypeEnum.COLUMN, RecognizerTypeEnum.BRACKET);
// 调用识别算法
RecognizeVo recognizeVo = null;
try {
@ -1187,10 +1187,10 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
}
log.info("类型:{},识别到的设施:{},转换坐标:{}", type, value, coordinateList);
// 处理对应设施
if (type.equals(RecognizerTypeEnum.SOLAR.getValue())) {
if (type.equals(RecognizerTypeEnum.PANEL.getValue())) {
photovoltaicPanelService.updateFinishNumberByCoordinate(projectIds, coordinateList);
} else if (type.equals(RecognizerTypeEnum.HOLE.getValue())
|| type.equals(RecognizerTypeEnum.PILE.getValue())
|| type.equals(RecognizerTypeEnum.COLUMN.getValue())
|| type.equals(RecognizerTypeEnum.BRACKET.getValue())) {
photovoltaicPanelPartsService.updateFinishNumberByCoordinate(projectIds, coordinateList, type);
} else {

View File

@ -162,6 +162,12 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
Long id = progressPlan.getId();
List<PgsProgressPlanDetailCreateDto> detailList = req.getDetailList();
if (CollUtil.isNotEmpty(detailList)) {
// 判断详情数量是否合法
boolean isAnyEmpty = detailList.stream()
.allMatch(detail -> detail.getPlanNumber().compareTo(BigDecimal.ZERO) <= 0);
if (isAnyEmpty) {
throw new ServiceException("新增进度计划详情失败,请进行均分", HttpStatus.BAD_REQUEST);
}
List<PgsProgressPlanDetail> newDetailList = detailList.stream().map(detail -> {
PgsProgressPlanDetail progressPlanDetail = new PgsProgressPlanDetail();
BeanUtils.copyProperties(detail, progressPlanDetail);

View File

@ -1,10 +1,13 @@
package org.dromara.project.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.dromara.common.core.domain.R;
import org.dromara.common.web.core.BaseController;
import org.dromara.project.domain.BusAttendanceMachine;
import org.dromara.project.domain.dto.attendance.*;
@ -13,10 +16,15 @@ import org.dromara.project.service.IBusAttendanceMachineService;
import org.dromara.project.service.IBusAttendanceService;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@ -70,6 +78,7 @@ public class BusAttendanceDeviceController extends BaseController {
req.setUserId(userId);
req.setPunchTime(localDateTime);
req.setSource("1");
req.setSn(dto.getSn());
//打印req
log.info("请求参数:{}", req);
//base64转MultipartFile
@ -84,6 +93,43 @@ public class BusAttendanceDeviceController extends BaseController {
}
}
@PostMapping("/api/v1/recordvisit")
@SaIgnore
public DeviceResult recordvisit(@RequestBody DeviceUserInfo dto) {
try {
log.info("设备上报数据:{}", dto);
// 1. 将对象转为 JSON 字符串(带格式)
String json = JSONUtil.toJsonPrettyStr(dto);
log.info("JSON数据{}", json);
// 2. 构建保存路径(按日期区分文件)
String dateStr = DateUtil.format(DateUtil.date(), "yyyyMMdd");
String fileName = StrUtil.format("device_record_{}.txt", dateStr);
// 3. 路径:项目根目录 /logs/device-data/
File dir = FileUtil.mkdir("logs/device-data");
File file = FileUtil.file(dir, fileName);
// 4. 生成时间戳+分隔符
String timePrefix = DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss");
String data = StrUtil.format(
"[{}]\n{}\n{}\n",
timePrefix,
json,
StrUtil.repeat("-", 80)
);
// 5. 追加到文件中
FileUtil.appendString(data, file, StandardCharsets.UTF_8);
log.info("✅ 设备上报数据已保存: {}", file.getAbsolutePath());
return new DeviceResult(0, "保存成功");
} catch (Exception e) {
log.error("❌ 保存设备数据失败", e);
return new DeviceResult(-2, "保存失败:" + e.getMessage());
}
}
public static MultipartFile convert(String base64String, String fileName) throws IOException {
// 先进行URL解码如果是URL编码过的数据

View File

@ -91,4 +91,17 @@ public class BusAttendanceMachineController extends BaseController {
@PathVariable Long[] ids) {
return toAjax(busAttendanceMachineService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 批量重新下发
*/
@SaCheckPermission("project:attendanceMachine:reissue")
@RepeatSubmit()
@PostMapping("/reissue/{ids}")
public R<Void> reissue(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids){
busAttendanceMachineService.reissue(List.of(ids));
return R.ok("已开始执行,请稍后刷新");
}
}

View File

@ -1,6 +1,7 @@
package org.dromara.project.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
@ -13,10 +14,12 @@ 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.dromara.project.domain.BusProjectTeam;
import org.dromara.project.domain.dto.leave.BusLeaveManagerReviewReq;
import org.dromara.project.domain.dto.leave.BusLeaveQueryReq;
import org.dromara.project.domain.vo.leave.BusLeaveVo;
import org.dromara.project.service.IBusLeaveService;
import org.dromara.project.service.IBusProjectTeamService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -36,6 +39,8 @@ public class BusLeaveController extends BaseController {
private final IBusLeaveService busLeaveService;
private final IBusProjectTeamService projectTeamService;
/**
* 查询施工人员请假申请列表
*/
@ -91,4 +96,17 @@ public class BusLeaveController extends BaseController {
@PathVariable Long[] ids) {
return toAjax(busLeaveService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 获取项目下所有班组
*/
@GetMapping("/teamList")
public R<List<BusProjectTeam>> add(Long projectId) {
List<BusProjectTeam> list = projectTeamService.list(Wrappers.lambdaQuery(BusProjectTeam.class)
.select(BusProjectTeam::getId, BusProjectTeam::getTeamName)
.eq(BusProjectTeam::getProjectId, projectId)
);
return R.ok(list);
}
}

View File

@ -1,6 +1,7 @@
package org.dromara.project.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
@ -13,9 +14,12 @@ 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.dromara.project.domain.BusProjectTeam;
import org.dromara.project.domain.dto.reissuecard.BusReissueCardAddReq;
import org.dromara.project.domain.dto.reissuecard.BusReissueCardManagerReviewReq;
import org.dromara.project.domain.dto.reissuecard.BusReissueCardQueryReq;
import org.dromara.project.domain.vo.reissuecard.BusReissueCardVo;
import org.dromara.project.service.IBusProjectTeamService;
import org.dromara.project.service.IBusReissueCardService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -36,6 +40,8 @@ public class BusReissueCardController extends BaseController {
private final IBusReissueCardService busReissueCardService;
private final IBusProjectTeamService projectTeamService;
/**
* 查询施工人员补卡申请列表
*/
@ -91,4 +97,16 @@ public class BusReissueCardController extends BaseController {
@PathVariable Long[] ids) {
return toAjax(busReissueCardService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 获取项目下所有班组
*/
@GetMapping("/teamList")
public R<List<BusProjectTeam>> add(Long projectId) {
List<BusProjectTeam> list = projectTeamService.list(Wrappers.lambdaQuery(BusProjectTeam.class)
.select(BusProjectTeam::getId, BusProjectTeam::getTeamName)
.eq(BusProjectTeam::getProjectId, projectId)
);
return R.ok(list);
}
}

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