Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
2025-12-03 22:23:20 +08:00
76 changed files with 3699 additions and 63 deletions

View File

@ -309,6 +309,10 @@ springdoc:
packages-to-scan: org.dromara.mechanical.jxgl packages-to-scan: org.dromara.mechanical.jxgl
- group: 32.设备模块 - group: 32.设备模块
packages-to-scan: org.dromara.device packages-to-scan: org.dromara.device
- group: 33.摄像头模块
packages-to-scan: org.dromara.other
- group: 34.机械安全模块
packages-to-scan: org.dromara.mechanical.jxaqgl
# knife4j的增强配置不需要增强可以不配 # knife4j的增强配置不需要增强可以不配
knife4j: knife4j:
enable: true enable: true

View File

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

View File

@ -46,7 +46,7 @@ public class BusComplaintBoxController extends BaseController {
/** /**
* 查询意见箱列表 * 查询意见箱列表
*/ */
// @SaCheckPermission("complaintBox:complaintBox:list") @SaCheckPermission("complaintBox:complaintBox:list")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo<BusComplaintBoxVo> list(BusComplaintBoxBo bo, PageQuery pageQuery) { public TableDataInfo<BusComplaintBoxVo> list(BusComplaintBoxBo bo, PageQuery pageQuery) {
return busComplaintBoxService.queryPageList(bo, pageQuery); return busComplaintBoxService.queryPageList(bo, pageQuery);
@ -54,7 +54,7 @@ public class BusComplaintBoxController extends BaseController {
/** /**
* web获取各个处理状态数量 * web获取各个处理状态数量
*/ */
// @SaCheckPermission("complaintBox:complaintBox:list") @SaCheckPermission("complaintBox:complaintBox:list")
@GetMapping("/getCount") @GetMapping("/getCount")
public R<List<ComplaintBoxCountVo>> getCount(BusComplaintBoxBo bo) { public R<List<ComplaintBoxCountVo>> getCount(BusComplaintBoxBo bo) {
return R.ok(busComplaintBoxService.getCount(bo)); return R.ok(busComplaintBoxService.getCount(bo));
@ -75,7 +75,7 @@ public class BusComplaintBoxController extends BaseController {
/** /**
* 新增意见回复 * 新增意见回复
*/ */
// @SaCheckPermission("complaintBox:complaintBox:add") @SaCheckPermission("complaintBox:complaintBox:add")
@Log(title = "意见箱", businessType = BusinessType.INSERT) @Log(title = "意见箱", businessType = BusinessType.INSERT)
@RepeatSubmit() @RepeatSubmit()
@PostMapping("/postAReply") @PostMapping("/postAReply")
@ -87,7 +87,7 @@ public class BusComplaintBoxController extends BaseController {
/** /**
* 修改意见阅读状态 * 修改意见阅读状态
*/ */
// @SaCheckPermission("complaintBox:complaintBox:edit") @SaCheckPermission("complaintBox:complaintBox:edit")
@Log(title = "意见箱", businessType = BusinessType.UPDATE) @Log(title = "意见箱", businessType = BusinessType.UPDATE)
@RepeatSubmit() @RepeatSubmit()
@PutMapping("/editCheckStatus") @PutMapping("/editCheckStatus")
@ -98,7 +98,7 @@ public class BusComplaintBoxController extends BaseController {
/** /**
* 修改意见阅读状态 * 修改意见阅读状态
*/ */
// @SaCheckPermission("complaintBox:complaintBox:edit") @SaCheckPermission("complaintBox:complaintBox:edit")
@Log(title = "意见箱", businessType = BusinessType.UPDATE) @Log(title = "意见箱", businessType = BusinessType.UPDATE)
@RepeatSubmit() @RepeatSubmit()
@PutMapping("/editStatus") @PutMapping("/editStatus")

View File

@ -327,7 +327,13 @@ public class BusComplaintBoxServiceImpl extends ServiceImpl<BusComplaintBoxMappe
if ("14".equals(busComplaintBoxVo.getStatus())){ if ("14".equals(busComplaintBoxVo.getStatus())){
throw new ServiceException("该意见已经关闭,不允许再修改状态"); throw new ServiceException("该意见已经关闭,不允许再修改状态");
} }
return baseMapper.update(new LambdaUpdateWrapper<BusComplaintBox>().set(BusComplaintBox::getStatus,bo.getStatus()).eq(BusComplaintBox::getId, bo.getId())); LambdaUpdateWrapper<BusComplaintBox> lqw = new LambdaUpdateWrapper<BusComplaintBox>();
lqw.set(BusComplaintBox::getStatus, bo.getStatus());
lqw.eq(BusComplaintBox::getId, bo.getId());
if ("0".equals(bo.getStatus())){
lqw.set(BusComplaintBox::getCurrentDisposeUserId, null);
}
return baseMapper.update(lqw);
} }
} }

View File

@ -26,6 +26,7 @@ import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogCreateReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogQueryReq; import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogQueryReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogUpdateReq; import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogUpdateReq;
import org.dromara.design.domain.vo.CopyUserVo; import org.dromara.design.domain.vo.CopyUserVo;
import org.dromara.design.domain.vo.DelayContVo;
import org.dromara.design.domain.vo.DesUserVo; import org.dromara.design.domain.vo.DesUserVo;
import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo; import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileVo; import org.dromara.design.domain.vo.volumefile.DesVolumeFileVo;
@ -45,10 +46,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -131,6 +129,16 @@ public class DesVolumeCatalogController extends BaseController {
return toAjax(desVolumeCatalogService.viewerFile(id)); return toAjax(desVolumeCatalogService.viewerFile(id));
} }
/**
* 计划过期统计
*/
@GetMapping("/delayCont/{projectId}")
public R<DelayContVo> delayCont(@PathVariable Long projectId) {
return R.ok(desVolumeCatalogService.delayCont(projectId));
}
/** /**
* 新增卷册目录 * 新增卷册目录
*/ */
@ -167,6 +175,9 @@ public class DesVolumeCatalogController extends BaseController {
} }
/** /**
* 收资清单模板导出 * 收资清单模板导出
*/ */

View File

@ -46,4 +46,9 @@ public class DesVolumeCatalogQueryReq implements Serializable {
*/ */
private String designSubitem; private String designSubitem;
/**
* 0-不延期1-延期
*/
private String delay;
} }

View File

@ -0,0 +1,23 @@
package org.dromara.design.domain.vo;
import lombok.Data;
@Data
public class DelayContVo {
/**
* 总数
*/
private Integer total;
/**
* 延迟数
*/
private Integer delay;
/**
* 今日数
*/
private Integer today;
}

View File

@ -11,7 +11,9 @@ import org.dromara.design.domain.DesVolumeFile;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogCreateReq; import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogCreateReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogQueryReq; import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogQueryReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogUpdateReq; import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogUpdateReq;
import org.dromara.design.domain.vo.DelayContVo;
import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo; import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -130,4 +132,9 @@ public interface IDesVolumeCatalogService extends IService<DesVolumeCatalog> {
* @return 设计子项列表 * @return 设计子项列表
*/ */
List<String> listDesignSubitem(Long projectId); List<String> listDesignSubitem(Long projectId);
/**
* 统计
*/
DelayContVo delayCont(Long projectId);
} }

View File

@ -100,4 +100,7 @@ public interface IDesVolumeFileService extends IService<DesVolumeFile> {
TableDataInfo<DesVolumeFileAppVo> queryAppPageList(DesVolumeFileAppPageDto dto, PageQuery pageQuery); TableDataInfo<DesVolumeFileAppVo> queryAppPageList(DesVolumeFileAppPageDto dto, PageQuery pageQuery);
AuditFileVo auditFile(AuditFileDto dto); AuditFileVo auditFile(AuditFileDto dto);
} }

View File

@ -28,6 +28,7 @@ import org.dromara.design.domain.bo.DesUserBo;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogCreateReq; import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogCreateReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogQueryReq; import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogQueryReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogUpdateReq; import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogUpdateReq;
import org.dromara.design.domain.vo.DelayContVo;
import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo; import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo;
import org.dromara.design.mapper.DesVolumeCatalogMapper; import org.dromara.design.mapper.DesVolumeCatalogMapper;
import org.dromara.design.service.*; import org.dromara.design.service.*;
@ -43,6 +44,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.io.IOException; import java.io.IOException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -236,6 +239,17 @@ public class DesVolumeCatalogServiceImpl extends ServiceImpl<DesVolumeCatalogMap
return list.stream().map(DesVolumeCatalog::getDesignSubitem).toList(); return list.stream().map(DesVolumeCatalog::getDesignSubitem).toList();
} }
@Override
public DelayContVo delayCont(Long projectId) {
List<DesVolumeCatalog> list = this.lambdaQuery()
.eq(DesVolumeCatalog::getProjectId, projectId).list();
DelayContVo delayContVo = new DelayContVo();
delayContVo.setTotal(list.size());
delayContVo.setDelay((int)list.stream().filter(item -> item.getPlannedCompletion().isBefore(LocalDate.now()) && item.getDesignState().equals("2")).count());
delayContVo.setToday((int)list.stream().filter(item -> item.getPlannedCompletion().isEqual(LocalDate.now())).count());
return delayContVo;
}
/** /**
* 修改卷册目录 * 修改卷册目录
* *
@ -353,6 +367,7 @@ public class DesVolumeCatalogServiceImpl extends ServiceImpl<DesVolumeCatalogMap
String auditStatus = req.getAuditStatus(); String auditStatus = req.getAuditStatus();
String isUpload = req.getIsUpload(); String isUpload = req.getIsUpload();
String designSubitem = req.getDesignSubitem(); String designSubitem = req.getDesignSubitem();
String delay = req.getDelay();
// lqw.orderByDesc(DesVolumeCatalog::getCreateTime); // lqw.orderByDesc(DesVolumeCatalog::getCreateTime);
lqw.orderByAsc(DesVolumeCatalog::getSerialNumber); lqw.orderByAsc(DesVolumeCatalog::getSerialNumber);
lqw.like(StringUtils.isNotBlank(documentName), DesVolumeCatalog::getDocumentName, documentName); lqw.like(StringUtils.isNotBlank(documentName), DesVolumeCatalog::getDocumentName, documentName);
@ -363,6 +378,16 @@ public class DesVolumeCatalogServiceImpl extends ServiceImpl<DesVolumeCatalogMap
lqw.exists("1".equals(isUpload), "SELECT 1 FROM des_volume_file WHERE volume_catalog_id = des_volume_catalog.design"); lqw.exists("1".equals(isUpload), "SELECT 1 FROM des_volume_file WHERE volume_catalog_id = des_volume_catalog.design");
lqw.notExists("0".equals(isUpload), "SELECT 1 FROM des_volume_file WHERE volume_catalog_id = des_volume_catalog.design"); lqw.notExists("0".equals(isUpload), "SELECT 1 FROM des_volume_file WHERE volume_catalog_id = des_volume_catalog.design");
if("1".equals(delay)){
lqw.lt(DesVolumeCatalog::getPlannedCompletion, LocalDateTime.now());
lqw.eq(DesVolumeCatalog::getDesignState, "2");
}
if("0".equals(delay)){
lqw.and(wrapper -> wrapper.gt(DesVolumeCatalog::getPlannedCompletion, LocalDateTime.now())
.or()
.eq(DesVolumeCatalog::getDesignState, "1")
);
}
return lqw; return lqw;
} }

View File

@ -61,4 +61,14 @@ public interface Ys7Constant {
*/ */
String setDeviceVideoUrlByPost = "https://open.ys7.com/api/lapp/device/fullday/record/switch/set"; String setDeviceVideoUrlByPost = "https://open.ys7.com/api/lapp/device/fullday/record/switch/set";
/**
* 摄像头查询设备本地录像 Get
*/
String getDeviceLocalVideoUrlByGet = "https://open.ys7.com/api/v3/device/local/video/unify/query";
/**
* 获取播放地址 POST
*/
String getDeviceLappVideoUrlByPost = "https://open.ys7.com/api/lapp/v2/live/address/get";
} }

View File

@ -4,17 +4,20 @@ import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.manager.ys7manager.vo.Ys7NoDataResponseVo; import org.dromara.common.core.utils.TimestampUtils;
import org.dromara.manager.ys7manager.vo.Ys7PageResponseVo; import org.dromara.manager.ys7manager.dto.DeviceLocalVideoRequstDto;
import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo; import org.dromara.manager.ys7manager.dto.DevicePlayBackUrlRequstDto;
import org.dromara.manager.ys7manager.vo.Ys7ResponseVo; import org.dromara.manager.ys7manager.vo.*;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* @author lilemy * @author lilemy
@ -290,4 +293,159 @@ public class Ys7RequestUtils {
} }
} }
/**
* 获取播放地址
* @param dto
* @return
*/
public static String getDevicePlayBackUrl(DevicePlayBackUrlRequstDto dto) {
if (StringUtils.isAnyBlank(dto.getAccessToken(), dto.getDeviceSerial())) {
throw new ServiceException("获取回放录像参数为空", HttpStatus.BAD_REQUEST);
}
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("accessToken", dto.getAccessToken());
paramMap.put("deviceSerial", dto.getDeviceSerial());
if (dto.getChannelNo() != null) {
paramMap.put("channelNo", dto.getChannelNo());
}
if (dto.getQuality() != null) {
paramMap.put("quality", dto.getQuality());
}
if (dto.getProtocol() != null) {
paramMap.put("protocol", dto.getProtocol());
}
if (dto.getStartTime() != null) {
paramMap.put("startTime", dto.getStartTime());
}
if (dto.getEndTime() != null) {
paramMap.put("stopTime", dto.getEndTime());
}
if (dto.getType() != null) {
paramMap.put("type", dto.getType());
}
if (dto.getExpireTime() != null) {
paramMap.put("expireTime", dto.getExpireTime());
}
if (dto.getRecType() != null) {
paramMap.put("recType", dto.getRecType());
}
if (dto.getCode() != null) {
paramMap.put("code", dto.getCode());
}
if (dto.getSupportH265() != null) {
paramMap.put("supportH265", dto.getSupportH265());
}
if (dto.getPlaybackSpeed() != null) {
paramMap.put("playbackSpeed", dto.getPlaybackSpeed());
}
if (dto.getGbchannel() != null) {
paramMap.put("gbchannel", dto.getGbchannel());
}
String errorMsg = "获取回放录像请求失败";
try (HttpResponse response = HttpRequest.post(Ys7Constant.getDeviceLappVideoUrlByPost)
.form(paramMap)
.execute()) {
if (!response.isOk()) {
log.error("{}{}", errorMsg, response.getStatus());
throw new ServiceException(errorMsg + response.getStatus());
}
String body = response.body();
log.info("本地录像body{}",body);
Ys7ResponseVo responseVo = JSONUtil.toBean(body, Ys7ResponseVo.class);
if (!responseVo.getCode().equals("200")) {
log.error("{},状态码:{}{}", errorMsg, responseVo.getCode(), responseVo.getMsg());
throw new ServiceException(errorMsg + responseVo.getMsg());
}
String data = responseVo.getData();
String picUrl = JSONUtil.parseObj(data).getStr("url");
log.info("获取回放录像请求成功,设备[{}]回放成功,通道:{}url{}", dto.getDeviceSerial(), dto.getChannelNo(), picUrl);
return picUrl;
}
}
/**
* 查询设备某天的本地录像
* @param dto
* @return
*/
public static List<DeviceLocalVideoRecordsVo> getDeviceLocalVideo(DeviceLocalVideoRequstDto dto) {
if (StringUtils.isAnyBlank(dto.getAccessToken(), dto.getDeviceSerial(),dto.getStartTime(), dto.getEndTime())) {
throw new ServiceException("查询设备本地录像参数为空", HttpStatus.BAD_REQUEST);
}
dto.setStartTime(Objects.requireNonNull(TimestampUtils.parseDateToTimestamp(dto.getStartTime())).toString());
dto.setEndTime(Objects.requireNonNull(TimestampUtils.parseDateToTimestamp(dto.getEndTime())).toString());
List<DeviceLocalVideoRecordsVo> vos = new ArrayList<>();
getRexords(dto, vos);
return vos;
}
private static void getRexords(DeviceLocalVideoRequstDto dto, List<DeviceLocalVideoRecordsVo> vos) {
String errorMsg = "查询设备本地录像请求失败";
String body = getDevicceLocalVideoBody(dto);
log.info("本地录像body{}",body);
JSONObject jsonObject = JSONUtil.parseObj(body);
DeviceLocalVideoMetaVo meta = JSONUtil.toBean(jsonObject.getJSONObject("meta"), DeviceLocalVideoMetaVo.class);
if (!meta.getCode().equals("200")) {
log.error("{},状态码:{}{}", errorMsg, meta.getCode(), meta.getMessage());
throw new ServiceException(errorMsg + meta.getMessage());
}
DeviceLocalVideoDataVo data = JSONUtil.toBean(jsonObject.getJSONObject("data"), DeviceLocalVideoDataVo.class);
if (data != null) {
List<DeviceLocalVideoRecordsVo> list = JSONUtil.toList(data.getRecords(), DeviceLocalVideoRecordsVo.class);
if (list != null && !list.isEmpty()) {
list.forEach(vo -> {
vo.setStartTime(TimestampUtils.extractTime(vo.getStartTime()));
vo.setEndTime(TimestampUtils.extractTime(vo.getEndTime()));
});
vos.addAll(list);
}
if (data.getHasMore()){
dto.setStartTime(data.getNextFileTime());
if (Long.parseLong(dto.getStartTime()) > Long.parseLong(dto.getEndTime())){
return;
}
getRexords(dto, vos);
}
}
}
private static String getDevicceLocalVideoBody(DeviceLocalVideoRequstDto dto) {
// 2. 构建Header参数接口文档的Header部分
HttpRequest request = HttpRequest.get(Ys7Constant.getDeviceLocalVideoUrlByGet)
.header("accessToken", dto.getAccessToken()) // Header参数accessToken
.header("deviceSerial", dto.getDeviceSerial());// Header参数deviceSerial
// 可选HeaderlocalIndex对应dto的channelNo
if (dto.getChannelNo() != null) {
request.header("channelNo", dto.getChannelNo().toString());
}
// 3. 构建Query参数接口文档的query部分
request.form("startTime", dto.getStartTime()) // Query必传startTime
.form("endTime", dto.getEndTime()); // Query必传endTime
// 可选Query参数
if (dto.getRecordType() != null) {
request.form("recordType", dto.getRecordType().toString());
}
if (dto.getIsQueryByNvr() != null) {
request.form("isQueryByNvr", dto.getIsQueryByNvr().toString());
}
if (dto.getLocation() != null) {
request.form("location", dto.getLocation().toString());
}
if (dto.getPageSize() != null) {
request.form("pageSize", dto.getPageSize().toString());
}
String errorMsg = "查询设备本地录像请求失败";
try (HttpResponse response = request.execute()) {
if (!response.isOk()) {
log.error("{}{}", errorMsg, response.getStatus());
throw new ServiceException(errorMsg + response.getStatus());
}
return response.body();
}
}
} }

View File

@ -0,0 +1,18 @@
package org.dromara.manager.ys7manager.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class DeviceLocalVideoRequstDto implements Serializable {
private String accessToken; //toke
private String deviceSerial; //设备序列号
private Integer channelNo; // 通道号默认1
private Integer recordType; // 1:定时录像 2:事件录像 3:智能-车 4:智能-人形 5:自动浓缩录像,不填默认查询所有类型
private String startTime; // 回放开始时间格式yyyy-MM-dd HH:mm:ss
private String endTime; // 回放结束时间格式yyyy-MM-dd HH:mm:ss
private Integer isQueryByNvr; // 是否反查NVR录像0-不反查(默认)1-反查NVR
private Integer location; // 录像检索位置1-本地录像检索(默认)2-CVR中心录像检索
private Integer pageSize; // 分页的页面大小默认50最大200
}

View File

@ -0,0 +1,23 @@
package org.dromara.manager.ys7manager.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class DevicePlayBackUrlRequstDto implements Serializable {
private String accessToken; //toke
private String deviceSerial; //设备序列号
private Integer channelNo; // 通道号默认1
private Integer protocol; // 流协议1-ezopen、2-hls、3-rtmp、4-flv默认1
private String code; // 视频加密密码
private Integer expireTime; // 过期时长30秒-720天
private String type; // 地址类型1-预览2-本地录像回放3-云存储录像回放默认1
private Integer quality; // 清晰度1-高清2-流畅
private String startTime; // 回放开始时间格式yyyy-MM-dd HH:mm:ss
private String endTime; // 回放结束时间格式yyyy-MM-dd HH:mm:ss
private Integer supportH265; // 是否需要H265编码1-是0-否
private Integer recType; // 回放源0-系统自动选择1-云存储2-本地录像。非必选默认为0
private String playbackSpeed; // 回放倍速:-1、0.5、1、2、4、8、16仅支持flv协议+回放类型)
private String gbchannel; // 国标设备通道编号
}

View File

@ -0,0 +1,29 @@
package org.dromara.manager.ys7manager.vo;
import lombok.Data;
/**
* @author lilemy
* @date 2025/6/12 17:14
*/
@Data
public class DeviceLocalVideoDataVo {
/**
* 响应内容
*/
private String records;
//该录像文件是否来自关联的nvr
private String fromNvr;
// fromNvr为true则返回关联NVR设备序列号否则返回入参填的设备序列号。
private String deviceSerial;
// fromNvr为true则返回关联NVR设备通道号否则返回入参填的设备通道号
private String localIndex;
//是否存在更多录像文件
private Boolean hasMore;
// hasMore为true时该参数值为下一个录像文件的开始时间。如需分页查询该参数值可作为下一页录像文件查询的开始时间。
private String nextFileTime;
}

View File

@ -0,0 +1,27 @@
package org.dromara.manager.ys7manager.vo;
import lombok.Data;
/**
* @author lilemy
* @date 2025/6/12 17:14
*/
@Data
public class DeviceLocalVideoMetaVo {
/**
* 响应码
*/
private String code;
/**
* 响应信息
*/
private String message;
/**
* 响应信息
*/
private String moreInfo;
}

View File

@ -0,0 +1,27 @@
package org.dromara.manager.ys7manager.vo;
import lombok.Data;
/**
* @author lilemy
* @date 2025/6/12 17:14
*/
@Data
public class DeviceLocalVideoRecordsVo {
/**
* 开始时间
*/
private String startTime;
/**
* 结束时间
*/
private String endTime;
//录像类型
private String type;
//录像文件大小,单位:字节
private String size;
}

View File

@ -8,6 +8,7 @@ import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.validate.EditGroup; import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil; import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit; import org.dromara.common.idempotent.annotation.RepeatSubmit;
@ -17,9 +18,20 @@ import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController; import org.dromara.common.web.core.BaseController;
import org.dromara.manager.ys7manager.Ys7Manager; import org.dromara.manager.ys7manager.Ys7Manager;
import org.dromara.manager.ys7manager.dto.DeviceLocalVideoRequstDto;
import org.dromara.manager.ys7manager.vo.DeviceLocalVideoRecordsVo;
import org.dromara.other.domain.dto.ys7device.*; import org.dromara.other.domain.dto.ys7device.*;
import org.dromara.other.domain.dto.ys7deviceimg.AddViolattionRecordReq;
import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCaptureReq;
import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgQueryReq;
import org.dromara.other.domain.vo.ys7device.DateAndDeviceLocalVideoVo;
import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo; import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo;
import org.dromara.other.domain.vo.ys7deviceimg.OthYs7DeviceImgVo;
import org.dromara.other.service.IOthYs7DeviceImgService;
import org.dromara.other.service.IOthYs7DeviceService; import org.dromara.other.service.IOthYs7DeviceService;
import org.dromara.safety.domain.vo.violationrecord.HseViolationRecordVo;
import org.dromara.safety.service.IHseViolationRecordService;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -46,6 +58,73 @@ public class OthYs7DeviceController extends BaseController {
@Resource @Resource
private Ys7Manager ys7Manager; private Ys7Manager ys7Manager;
@Resource
private IOthYs7DeviceImgService othYs7DeviceImgService;
@Lazy
@Resource
private IHseViolationRecordService hseViolationRecordService;
/**
* 获取违规记录详细信息
*
* @param id 主键
*/
@SaCheckPermission("other:ys7Device:list")
@GetMapping("/getViolationRecordInfo/{id}")
public R<HseViolationRecordVo> getViolationRecordInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(hseViolationRecordService.queryById(id));
}
/**
* 萤石摄像头图片抓图
*/
@SaCheckPermission("other:ys7Device:list")
@Log(title = "萤石摄像头图片", businessType = BusinessType.INSERT)
@PostMapping("/capture")
public R<Void> capture(@RequestBody OthYs7DeviceImgCaptureReq req) {
return toAjax(othYs7DeviceImgService.addHMCapturePic(req));
}
/**
* 萤石摄像头图片识别
*/
@SaCheckPermission("other:ys7Device:list")
@Log(title = "萤石摄像头图片", businessType = BusinessType.INSERT)
@PostMapping("/discernImg")
public R<Void> discernImg(@RequestBody OthYs7DeviceImgCaptureReq req) {
return toAjax(othYs7DeviceImgService.discernImg(req));
}
/**
* 下发工单
*/
@SaCheckPermission("other:ys7Device:list")
@Log(title = "萤石摄像头图片", businessType = BusinessType.INSERT)
@PostMapping("/addViolationRecord")
public R<Void> addViolationRecord(@RequestBody AddViolattionRecordReq req) {
return toAjax(othYs7DeviceImgService.addViolationRecord(req));
}
/**
* 查询萤石摄像头图片列表
*/
@SaCheckPermission("other:ys7Device:list")
@GetMapping("/getImgList")
public TableDataInfo<OthYs7DeviceImgVo> list(OthYs7DeviceImgQueryReq req, PageQuery pageQuery) {
return othYs7DeviceImgService.queryPageList(req, pageQuery);
}
/**
* 删除萤石摄像头图片
*
* @param ids 主键串
*/
@SaCheckPermission("other:ys7Device:remove")
@Log(title = "萤石摄像头图片", businessType = BusinessType.DELETE)
@DeleteMapping("/img/{ids}")
public R<Void> imgRemove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(othYs7DeviceImgService.deleteWithValidByIds(List.of(ids)));
}
/** /**
* 查询萤石摄像头列表 * 查询萤石摄像头列表
@ -157,4 +236,50 @@ public class OthYs7DeviceController extends BaseController {
return ResponseEntity.ok(JSONUtil.toJsonStr(result)); return ResponseEntity.ok(JSONUtil.toJsonStr(result));
} }
/**
* 获取回放录像播放地址
* @return
*/
@GetMapping("/getPlayBackUrl")
public R<String> getPlayBackUrl(OthYs7DevicePlayBackUrlReq req){
if (req.getDeviceSerial() == null){
throw new ServiceException("设备序列号不能为空!!!");
}
if (req.getStartTime() == null || req.getEndTime() == null){
throw new ServiceException("开始时间和结束时间不能为空!!!");
}
return R.ok(othYs7DeviceService.getPlayBackUrl(req));
}
/**
* 查询设备本地录像
* @return
*/
@GetMapping("/getDeviceLocalVideo")
public R<List<DeviceLocalVideoRecordsVo>> getDeviceLocalVideo(OthYs7DevicePlayBackUrlReq req){
if (req.getDeviceSerial() == null){
throw new ServiceException("设备序列号不能为空!!!");
}
if (req.getStartTime() == null || req.getEndTime() == null){
throw new ServiceException("开始时间和结束时间不能为空!!!");
}
return R.ok(othYs7DeviceService.getDeviceLocalVideo(req));
}
/**
* 查询范围日期和设备本地录像列表
* @return
*/
@GetMapping("/getDateAndDeviceLocalVideo")
public R<DateAndDeviceLocalVideoVo> getDateAndDeviceLocalVideo(OthYs7DevicePlayBackUrlReq req){
if (req.getDeviceSerial() == null){
throw new ServiceException("设备序列号不能为空!!!");
}
if (req.getStartTime() == null || req.getEndTime() == null){
throw new ServiceException("开始时间和结束时间不能为空!!!");
}
return R.ok(othYs7DeviceService.getDateAndDeviceLocalVideo(req));
}
} }

View File

@ -72,6 +72,12 @@ public class OthYs7DeviceImg implements Serializable {
*/ */
private String recognizeUrl; private String recognizeUrl;
/**
* 图片状态0、未识别1、已识别未违规2、已识别有违规3、已下发工单
*/
private String imgStatus;
/** /**
* 备注 * 备注
*/ */

View File

@ -0,0 +1,31 @@
package org.dromara.other.domain.dto.ys7device;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @author lilemy
* @date 2025/6/13 10:19
*/
@Data
public class OthYs7DevicePlayBackUrlReq implements Serializable {
/**
* 设备序列号
*/
private String deviceSerial;
/**
* 开始时间
*/
private String startTime;
/**
* 结束时间
*/
private String endTime;
}

View File

@ -0,0 +1,36 @@
package org.dromara.other.domain.dto.ys7deviceimg;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lilemy
* @date 2025-10-10 19:14
*/
@Data
public class AddViolattionRecordReq implements Serializable {
/**
* 项目id
*/
@NotNull(message = "图片id不能为空")
private Long projectId;
/**
* 设备序列号
*/
@NotBlank(message = "设备序列号不能为空")
private String deviceSerial;
/**
* 图片id
*/
@NotNull(message = "图片id不能为空")
private Long originalUrlId;
}

View File

@ -21,4 +21,8 @@ public class OthYs7DeviceImgCaptureReq implements Serializable {
*/ */
@NotBlank(message = "设备序列号不能为空") @NotBlank(message = "设备序列号不能为空")
private String deviceSerial; private String deviceSerial;
/**
* 图片id
*/
private Long imgId;
} }

View File

@ -0,0 +1,29 @@
package org.dromara.other.domain.vo.ys7device;
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.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.manager.ys7manager.vo.DeviceLocalVideoRecordsVo;
import org.dromara.other.domain.OthYs7Device;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 查询范围日期和设备本地录像列表
*/
@Data
public class DateAndDeviceLocalVideoVo implements Serializable {
private List<String> dateList;
private List<DeviceLocalVideoRecordsVo> deviceList;
}

View File

@ -55,6 +55,11 @@ public class OthYs7DeviceImgVo implements Serializable {
@ExcelProperty(value = "图片地址") @ExcelProperty(value = "图片地址")
private String url; private String url;
/**
* 识别结果图片地址
*/
private String recognizeUrl;
/** /**
* 识别算法模型 * 识别算法模型
*/ */
@ -77,4 +82,9 @@ public class OthYs7DeviceImgVo implements Serializable {
@ExcelProperty(value = "创建时间") @ExcelProperty(value = "创建时间")
private Date createTime; private Date createTime;
/**
* 图片状态0、未识别1、已识别2、已下发工单
*/
private String imgStatus;
} }

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.other.domain.OthYs7DeviceImg; import org.dromara.other.domain.OthYs7DeviceImg;
import org.dromara.other.domain.dto.ys7deviceimg.AddViolattionRecordReq;
import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCaptureReq; import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCaptureReq;
import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCreateByCapture; import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCreateByCapture;
import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgQueryReq; import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgQueryReq;
@ -102,4 +103,25 @@ public interface IOthYs7DeviceImgService extends IService<OthYs7DeviceImg> {
* @return 是否抓拍成功 * @return 是否抓拍成功
*/ */
Boolean capturePic(OthYs7DeviceImgCaptureReq req); Boolean capturePic(OthYs7DeviceImgCaptureReq req);
/**
* 手动抓拍(不需要识别)
* @param req
* @return
*/
int addHMCapturePic(OthYs7DeviceImgCaptureReq req);
/**
* 识别抓拍图片
* @param req
* @return
*/
int discernImg(OthYs7DeviceImgCaptureReq req);
/**
* 手动下发安全工单
* @param req
* @return
*/
int addViolationRecord(AddViolattionRecordReq req);
} }

View File

@ -5,9 +5,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.manager.ys7manager.vo.DeviceLocalVideoRecordsVo;
import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo; import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo;
import org.dromara.other.domain.OthYs7Device; import org.dromara.other.domain.OthYs7Device;
import org.dromara.other.domain.dto.ys7device.*; import org.dromara.other.domain.dto.ys7device.*;
import org.dromara.other.domain.vo.ys7device.DateAndDeviceLocalVideoVo;
import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo; import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo;
import java.util.Collection; import java.util.Collection;
@ -143,4 +145,24 @@ public interface IOthYs7DeviceService extends IService<OthYs7Device> {
*/ */
void webhook(WebhookMessage receiveMessage); void webhook(WebhookMessage receiveMessage);
/**
* 获取回放录像播放地址
* @param req
* @return
*/
String getPlayBackUrl(OthYs7DevicePlayBackUrlReq req);
/**
* 查询设备本地录像
* @param req
* @return
*/
List<DeviceLocalVideoRecordsVo> getDeviceLocalVideo(OthYs7DevicePlayBackUrlReq req);
/**
* 查询范围日期和设备本地录像列表
* @param req
* @return
*/
DateAndDeviceLocalVideoVo getDateAndDeviceLocalVideo(OthYs7DevicePlayBackUrlReq req);
} }

View File

@ -24,6 +24,7 @@ import org.dromara.manager.ys7manager.Ys7Manager;
import org.dromara.other.constant.Ys7DeviceImgConstant; import org.dromara.other.constant.Ys7DeviceImgConstant;
import org.dromara.other.domain.OthYs7Device; import org.dromara.other.domain.OthYs7Device;
import org.dromara.other.domain.OthYs7DeviceImg; import org.dromara.other.domain.OthYs7DeviceImg;
import org.dromara.other.domain.dto.ys7deviceimg.AddViolattionRecordReq;
import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCaptureReq; import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCaptureReq;
import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCreateByCapture; import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCreateByCapture;
import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgQueryReq; import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgQueryReq;
@ -31,14 +32,18 @@ import org.dromara.other.domain.vo.ys7deviceimg.OthYs7DeviceImgVo;
import org.dromara.other.mapper.OthYs7DeviceImgMapper; import org.dromara.other.mapper.OthYs7DeviceImgMapper;
import org.dromara.other.service.IOthYs7DeviceImgService; import org.dromara.other.service.IOthYs7DeviceImgService;
import org.dromara.other.service.IOthYs7DeviceService; import org.dromara.other.service.IOthYs7DeviceService;
import org.dromara.safety.domain.HseRecognizeRecord;
import org.dromara.safety.domain.HseViolationLevel; import org.dromara.safety.domain.HseViolationLevel;
import org.dromara.safety.domain.dto.recognizerecord.HseRecognizeRecordCreateDto; import org.dromara.safety.domain.dto.recognizerecord.HseRecognizeRecordCreateDto;
import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordCreateDto;
import org.dromara.safety.domain.enums.HseRecordCategoryEnum; import org.dromara.safety.domain.enums.HseRecordCategoryEnum;
import org.dromara.safety.service.IHseRecognizeRecordService; import org.dromara.safety.service.IHseRecognizeRecordService;
import org.dromara.safety.service.IHseViolationLevelService; import org.dromara.safety.service.IHseViolationLevelService;
import org.dromara.safety.service.IHseViolationRecordService;
import org.dromara.system.domain.vo.SysOssUploadVo; import org.dromara.system.domain.vo.SysOssUploadVo;
import org.dromara.system.service.ISysOssService; import org.dromara.system.service.ISysOssService;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -79,6 +84,10 @@ public class OthYs7DeviceImgServiceImpl extends ServiceImpl<OthYs7DeviceImgMappe
@Resource @Resource
private Ys7Manager ys7Manager; private Ys7Manager ys7Manager;
@Lazy
@Resource
private IHseViolationRecordService violationRecordService;
/** /**
* 查询萤石摄像头图片 * 查询萤石摄像头图片
* *
@ -266,7 +275,12 @@ public class OthYs7DeviceImgServiceImpl extends ServiceImpl<OthYs7DeviceImgMappe
} }
if (CollUtil.isEmpty(recTypes)) { if (CollUtil.isEmpty(recTypes)) {
log.error("项目:{},未设置安全等级", img.getProjectId()); log.error("项目:{},未设置安全等级", img.getProjectId());
boolean save = this.save(othYs7DeviceImg);
if (!save) {
log.error("保存图片失败:{}", othYs7DeviceImg);
} else {
saveList.add(othYs7DeviceImg); saveList.add(othYs7DeviceImg);
}
continue; continue;
} }
RecognizeVo recognizeVo = null; RecognizeVo recognizeVo = null;
@ -412,6 +426,175 @@ public class OthYs7DeviceImgServiceImpl extends ServiceImpl<OthYs7DeviceImgMappe
return true; return true;
} }
@Override
@Transactional(rollbackFor = Exception.class)
public int addHMCapturePic(OthYs7DeviceImgCaptureReq req) {
OthYs7Device ys7Device = ys7DeviceService.lambdaQuery()
.eq(OthYs7Device::getDeviceSerial, req.getDeviceSerial())
.last("limit 1")
.one();
if (ys7Device == null) {
throw new ServiceException("设备不存在", HttpStatus.ERROR);
}
String deviceSerial = ys7Device.getDeviceSerial();
String url = null;
try {
url = ys7Manager.getCaptureDevicePic(deviceSerial, 1, 2);
} catch (Exception e) {
log.error("摄像头 {} 抓图失败:{}", deviceSerial, e.getMessage());
throw new ServiceException("摄像头 " + deviceSerial + " 抓图失败:" + e.getMessage(), HttpStatus.ERROR);
}
OthYs7DeviceImg othYs7DeviceImg = new OthYs7DeviceImg();
String originalFilename = extractFilename(url);
String deviceImgOssPath = Ys7DeviceImgConstant.getDeviceImgOssPath(originalFilename, deviceSerial);
SysOssUploadVo uploadVo = ossService.uploadFileUrlWithNoSave(url, deviceImgOssPath);
String ossUrl = uploadVo.getUrl();
if (StringUtils.isNotBlank(ossUrl)) {
othYs7DeviceImg.setProjectId(ys7Device.getProjectId());
othYs7DeviceImg.setDeviceSerial(deviceSerial);
othYs7DeviceImg.setCreateTime(new Date());
othYs7DeviceImg.setDeviceName(ys7Device.getDeviceName());
othYs7DeviceImg.setUrl(ossUrl);
othYs7DeviceImg.setImgStatus("0");
}
return baseMapper.insert(othYs7DeviceImg);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int discernImg(OthYs7DeviceImgCaptureReq req) {
OthYs7DeviceImg img = baseMapper.selectById(req.getImgId());
if (img == null) {
throw new ServiceException("识别图片不存在!!");
}
// 获取安全等级设置
List<HseViolationLevel> levelList = violationLevelService.lambdaQuery()
.eq(HseViolationLevel::getProjectId, img.getProjectId())
.list();
Map<Long, List<RecognizerTypeEnum>> level = new HashMap<>();
if (CollUtil.isNotEmpty(levelList)) {
Map<Long, List<HseViolationLevel>> levelMap = levelList.stream()
.collect(Collectors.groupingBy(HseViolationLevel::getProjectId));
for (Map.Entry<Long, List<HseViolationLevel>> entry : levelMap.entrySet()) {
List<RecognizerTypeEnum> recognizerTypeEnums = entry.getValue().stream().map(l -> {
List<String> levels = StringUtils.splitList(l.getViolationType());
return RecognizerTypeEnum.listFromCodes(levels);
}).filter(CollUtil::isNotEmpty)
.flatMap(Collection::stream)
.distinct()
.toList();
level.put(entry.getKey(), recognizerTypeEnums);
}
}
if (CollUtil.isEmpty(level)) {
log.error("未设置安全等级");
}
// 将抓取的图片进行识别
List<RecognizerTypeEnum> recTypes = new ArrayList<>();
if (CollUtil.isNotEmpty(level)) {
recTypes = level.get(img.getProjectId());
}
if (CollUtil.isEmpty(recTypes)) {
log.error("项目:{},未设置安全等级", img.getProjectId());
throw new ServiceException("项目未设置安全等级无法识别,请设置安全等级之后再进行识别");
}
RecognizeVo recognizeVo = null;
try {
recognizeVo = recognizerManager.recognize(img.getUrl(), recTypes);
} catch (Exception e) {
log.error("图片识别异常", e);
}
if (recognizeVo != null && recognizeVo.getHasTarget().equals(RecognizerHasTargetEnum.YES.getValue())) {
// 记录识别信息
HseRecognizeRecord record = new HseRecognizeRecord();
record.setOriginalPicture(img.getUrl());
record.setOriginalUrlId(img.getId());
record.setCreateTime(new Date());
List<RecognizeTargetVo> targets = recognizeVo.getTargets();
img.setTargets(JSONUtil.toJsonStr(targets));
img.setImgSize(JSONUtil.toJsonStr(recognizeVo.getOriginalImgSize()));
img.setIsRecognize(RecognizerHasTargetEnum.YES.getValue());
List<String> recTypeList = targets.stream().map(RecognizeTargetVo::getType).distinct().toList();
img.setRecType(JSONUtil.toJsonStr(recTypeList));
String targetUrl = null;
try {
RecognizeImageStreamResult imageStreamResult = RecognizerManager.drawImageToStream(img.getUrl(), targets);
InputStream inputStream = imageStreamResult.getInputStream();
String contentType = imageStreamResult.getContentType();
String originalFilename = extractFilename(img.getUrl());
long length = imageStreamResult.getLength();
String targetImgPath = Ys7DeviceImgConstant.getTargetImgOssPath(originalFilename, img.getDeviceSerial());
SysOssUploadVo drawImageUploadVo = ossService.uploadFileUrlWithNoSave(inputStream, targetImgPath, contentType, length);
targetUrl = drawImageUploadVo.getUrl();
if (StringUtils.isNotBlank(targetUrl)) {
img.setRecognizeUrl(targetUrl);
}
} catch (Exception e) {
log.error("图片绘制失败", e);
}
List<String> codeList = targets.stream()
.map(RecognizeTargetVo::getType).distinct()
.map(RecognizerTypeEnum::fromValue).filter(Objects::nonNull)
.map(RecognizerTypeEnum::getCode).filter(Objects::nonNull)
.toList();
String codeStr = String.join(",", codeList);
record.setViolationType(codeStr);
record.setNum(targets.size());
record.setDeviceSerial(img.getDeviceSerial());
record.setDeviceName(img.getDeviceName());
record.setPicture(targetUrl);
record.setOriginalPicture(img.getUrl());
record.setRecordCategory(HseRecordCategoryEnum.MONITOR.getValue());
record.setProjectId(img.getProjectId());
// 保存识别记录
boolean result = recognizeRecordService.save(record);
if (!result) {
throw new ServiceException("保存识别记录失败");
}
}
img.setImgStatus(recognizeVo.getHasTarget().equals(RecognizerHasTargetEnum.YES.getValue()) ? "2" : "1");
img.setUpdateTime(new Date());
return baseMapper.updateById(img);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int addViolationRecord(AddViolattionRecordReq req) {
HseRecognizeRecord recognizeRecord = recognizeRecordService.getBaseMapper().selectOne(new LambdaQueryWrapper<HseRecognizeRecord>()
.eq(HseRecognizeRecord::getDeviceSerial, req.getDeviceSerial())
.eq(HseRecognizeRecord::getProjectId, req.getProjectId())
.eq(HseRecognizeRecord::getOriginalUrlId, req.getOriginalUrlId()));
if (recognizeRecord == null) {
throw new ServiceException("找不到识别记录!");
}
List<HseViolationRecordCreateDto> violationRecordList = new ArrayList<>();
String violationType = recognizeRecord.getViolationType();
if (StringUtils.isNotBlank(violationType)) {
List<String> list = StringUtils.splitList(violationType);
for (String s : list) {
if (recognizeRecord.getProjectId() != null) {
HseViolationRecordCreateDto violationRecord = new HseViolationRecordCreateDto();
violationRecord.setProjectId(recognizeRecord.getProjectId());
violationRecord.setRecognizeId(recognizeRecord.getId());
violationRecord.setViolationType(s);
violationRecord.setViolationTime(recognizeRecord.getCreateTime());
violationRecordList.add(violationRecord);
}
}
}
if (CollUtil.isNotEmpty(violationRecordList)) {
violationRecordService.insertByMonitor(violationRecordList);
}
OthYs7DeviceImg img = baseMapper.selectById(req.getOriginalUrlId());
if (img != null) {
img.setImgStatus("3");
return baseMapper.updateById(img);
}
return 1;
}
/** /**
* 提取文件名 * 提取文件名
* *

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -16,15 +17,21 @@ import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.manager.ys7manager.Ys7Constant; import org.dromara.manager.ys7manager.Ys7Constant;
import org.dromara.manager.ys7manager.Ys7Manager; import org.dromara.manager.ys7manager.Ys7Manager;
import org.dromara.manager.ys7manager.Ys7RequestUtils;
import org.dromara.manager.ys7manager.dto.DeviceLocalVideoRequstDto;
import org.dromara.manager.ys7manager.dto.DevicePlayBackUrlRequstDto;
import org.dromara.manager.ys7manager.enums.DeviceOnOffLineEnum; import org.dromara.manager.ys7manager.enums.DeviceOnOffLineEnum;
import org.dromara.manager.ys7manager.vo.DeviceLocalVideoRecordsVo;
import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo; import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo;
import org.dromara.other.domain.OthYs7Device; import org.dromara.other.domain.OthYs7Device;
import org.dromara.other.domain.dto.ys7device.*; import org.dromara.other.domain.dto.ys7device.*;
import org.dromara.other.domain.enums.OthDeviceStatusEnum; import org.dromara.other.domain.enums.OthDeviceStatusEnum;
import org.dromara.other.domain.enums.OthVideoEncryptedEnum; import org.dromara.other.domain.enums.OthVideoEncryptedEnum;
import org.dromara.other.domain.vo.ys7device.DateAndDeviceLocalVideoVo;
import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo; import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo;
import org.dromara.other.mapper.OthYs7DeviceMapper; import org.dromara.other.mapper.OthYs7DeviceMapper;
import org.dromara.other.service.IOthYs7DeviceService; import org.dromara.other.service.IOthYs7DeviceService;
import org.dromara.other.utils.DateRangeUtils;
import org.dromara.project.domain.BusProject; import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService; import org.dromara.project.service.IBusProjectService;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
@ -433,6 +440,53 @@ public class OthYs7DeviceServiceImpl extends ServiceImpl<OthYs7DeviceMapper, Oth
} }
} }
@Override
public String getPlayBackUrl(OthYs7DevicePlayBackUrlReq req) {
String token = ys7Manager.getToken();
DevicePlayBackUrlRequstDto dto = new DevicePlayBackUrlRequstDto();
dto.setAccessToken(token);
dto.setDeviceSerial(req.getDeviceSerial());
dto.setStartTime(req.getStartTime());
dto.setEndTime(req.getEndTime());
dto.setProtocol(1);
dto.setQuality(2);
dto.setType("2");
dto.setRecType(0);
dto.setExpireTime(36000);
return Ys7RequestUtils.getDevicePlayBackUrl(dto);
}
@Override
public List<DeviceLocalVideoRecordsVo> getDeviceLocalVideo(OthYs7DevicePlayBackUrlReq req) {
String token = ys7Manager.getToken();
DeviceLocalVideoRequstDto dto = new DeviceLocalVideoRequstDto();
dto.setAccessToken(token);
dto.setDeviceSerial(req.getDeviceSerial());
dto.setStartTime(req.getStartTime());
dto.setEndTime(req.getEndTime());
return Ys7RequestUtils.getDeviceLocalVideo(dto);
}
/**
* 查询范围日期和设备本地录像列表
* @param req
* @return
*/
@Override
public DateAndDeviceLocalVideoVo getDateAndDeviceLocalVideo(OthYs7DevicePlayBackUrlReq req) {
DateAndDeviceLocalVideoVo vo = new DateAndDeviceLocalVideoVo();
List<String> dateList = DateRangeUtils.getDatesBetweenStrings(req.getStartTime(), req.getEndTime());
vo.setDateList(dateList);
if (CollectionUtils.isNotEmpty(dateList) && dateList.size() > 1) {
String first = dateList.getFirst();
req.setStartTime(first+" 00:00:00");
req.setEndTime(first+" 23:59:59");
}
List<DeviceLocalVideoRecordsVo> deviceLocalVideo = getDeviceLocalVideo(req);
vo.setDeviceList(deviceLocalVideo);
return vo;
}
/** /**
* 验证萤石摄像对象是否发生更改 * 验证萤石摄像对象是否发生更改
* *

View File

@ -0,0 +1,166 @@
package org.dromara.other.utils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
/**
* 日期范围工具类
*/
public class DateRangeUtils {
// 默认时区(东八区)
private static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone("GMT+8");
// 日期格式
private static final String DATE_FORMAT = "yyyy-MM-dd";
// 完整日期时间格式
private static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
/**
* 获取两个时间戳之间的所有日期(包含起止日期)
* @param startTimestamp 开始时间戳(秒级/毫秒级字符串或数字)
* @param endTimestamp 结束时间戳(秒级/毫秒级字符串或数字)
* @return 日期列表格式yyyy-MM-dd
*/
public static List<String> getDatesBetweenTimestamps(Object startTimestamp, Object endTimestamp) {
// 转换为毫秒级时间戳
long start = convertToMilliseconds(startTimestamp);
long end = convertToMilliseconds(endTimestamp);
return getDatesBetweenDates(new Date(start), new Date(end));
}
/**
* 获取两个日期之间的所有日期(包含起止日期)
* @param startDate 开始日期
* @param endDate 结束日期
* @return 日期列表格式yyyy-MM-dd
*/
public static List<String> getDatesBetweenDates(Date startDate, Date endDate) {
List<String> dates = new ArrayList<>();
Calendar calendar = Calendar.getInstance(DEFAULT_TIME_ZONE);
// 设置开始日期
calendar.setTime(startDate);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
// 循环添加日期直到结束日期
while (!calendar.getTime().after(endDate)) {
dates.add(DateUtil.format(calendar.getTime(), DATE_FORMAT));
// 日期加1天
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
return dates;
}
/**
* 获取两个日期字符串之间的所有日期
* @param startDateStr 开始日期yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss
* @param endDateStr 结束日期yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss
* @return 日期列表
*/
public static List<String> getDatesBetweenStrings(String startDateStr, String endDateStr) {
Date startDate = parseDateString(startDateStr);
Date endDate = parseDateString(endDateStr);
return getDatesBetweenDates(startDate, endDate);
}
/**
* 将时间戳转换为日期yyyy-MM-dd
*/
public static String timestampToDate(Object timestamp) {
long time = convertToMilliseconds(timestamp);
return DateUtil.format(new Date(time), DATE_FORMAT);
}
/**
* 解析日期字符串为Date对象
*/
private static Date parseDateString(String dateStr) {
try {
if (dateStr.contains(" ")) {
SimpleDateFormat sdf = new SimpleDateFormat(DATETIME_FORMAT);
sdf.setTimeZone(DEFAULT_TIME_ZONE);
return sdf.parse(dateStr);
} else {
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
sdf.setTimeZone(DEFAULT_TIME_ZONE);
return sdf.parse(dateStr);
}
} catch (ParseException e) {
throw new IllegalArgumentException("日期格式错误:" + dateStr);
}
}
/**
* 将各种时间戳格式转换为毫秒级时间戳
*/
private static long convertToMilliseconds(Object timestamp) {
if (timestamp == null) {
throw new IllegalArgumentException("时间戳不能为空");
}
String timestampStr = timestamp.toString().trim();
if (StrUtil.isBlank(timestampStr)) {
throw new IllegalArgumentException("时间戳不能为空");
}
try {
long time = Long.parseLong(timestampStr);
// 10位秒级时间戳转为13位毫秒级
if (timestampStr.length() == 10) {
time *= 1000;
}
return time;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("时间戳格式错误:" + timestampStr);
}
}
/**
* 获取指定日期的开始时间戳当天00:00:00
*/
public static long getStartOfDayTimestamp(Object timestamp) {
long time = convertToMilliseconds(timestamp);
Calendar calendar = Calendar.getInstance(DEFAULT_TIME_ZONE);
calendar.setTime(new Date(time));
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTimeInMillis() / 1000; // 返回秒级时间戳
}
/**
* 获取指定日期的结束时间戳当天23:59:59
*/
public static long getEndOfDayTimestamp(Object timestamp) {
long time = convertToMilliseconds(timestamp);
Calendar calendar = Calendar.getInstance(DEFAULT_TIME_ZONE);
calendar.setTime(new Date(time));
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999);
return calendar.getTimeInMillis() / 1000; // 返回秒级时间戳
}
}

View File

@ -8,7 +8,6 @@ import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup; import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup; 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.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log; import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType; import org.dromara.common.log.enums.BusinessType;
@ -18,6 +17,7 @@ import org.dromara.common.web.core.BaseController;
import org.dromara.out.domain.bo.OutConstructionValueBo; import org.dromara.out.domain.bo.OutConstructionValueBo;
import org.dromara.out.domain.bo.OutConstructionValueFacilityReq; import org.dromara.out.domain.bo.OutConstructionValueFacilityReq;
import org.dromara.out.domain.vo.OutConstructionAllValueVo; import org.dromara.out.domain.vo.OutConstructionAllValueVo;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueTotalVo;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueVo; import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueVo;
import org.dromara.out.service.IOutConstructionValueService; import org.dromara.out.service.IOutConstructionValueService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -49,14 +49,13 @@ public class OutConstructionValueController extends BaseController {
} }
/** /**
* 导出施工产值列表 * 查询施工产值合计列表
*/ */
@SaCheckPermission("out:constructionValue:export") @SaCheckPermission("out:constructionValue:list")
@Log(title = "施工产值", businessType = BusinessType.EXPORT) @GetMapping("/totalList")
@PostMapping("/export") public R<List<OutConstructionValueTotalVo>> totalList(OutConstructionValueBo bo) {
public void export(OutConstructionValueBo bo, HttpServletResponse response) { List<OutConstructionValueTotalVo> list = outConstructionValueService.queryList(bo);
List<OutConstructionValueVo> list = outConstructionValueService.queryList(bo); return R.ok(list);
ExcelUtil.exportExcel(list, "施工产值", OutConstructionValueVo.class, response);
} }
/** /**

View File

@ -109,5 +109,9 @@ public class OutConstructionValueBo extends BaseEntity {
*/ */
private LocalDate endDate; private LocalDate endDate;
/**
* 项目类型
*/
private String projectType;
} }

View File

@ -57,6 +57,21 @@ public class OutConstructionValueMatrixVo {
@ExcelProperty(value = "数量") @ExcelProperty(value = "数量")
private BigDecimal number; private BigDecimal number;
/**
* 人工填报数量
*/
private Integer artificialNum;
/**
* 无人机识别数量
*/
private Integer uavNum;
/**
* 确认数量
*/
private Integer confirmNum;
/** /**
* 对甲产值 * 对甲产值
*/ */

View File

@ -45,6 +45,21 @@ public class OutConstructionValueProjectVo {
@ExcelProperty(value = "数量") @ExcelProperty(value = "数量")
private BigDecimal number; private BigDecimal number;
/**
* 人工填报数量
*/
private Integer artificialNum;
/**
* 无人机识别数量
*/
private Integer uavNum;
/**
* 确认数量
*/
private Integer confirmNum;
/** /**
* 对甲产值 * 对甲产值
*/ */

View File

@ -51,6 +51,21 @@ public class OutConstructionValueSubProjectVo {
@ExcelProperty(value = "数量") @ExcelProperty(value = "数量")
private BigDecimal number; private BigDecimal number;
/**
* 人工填报数量
*/
private Integer artificialNum;
/**
* 无人机识别数量
*/
private Integer uavNum;
/**
* 确认数量
*/
private Integer confirmNum;
/** /**
* 对甲产值 * 对甲产值
*/ */

View File

@ -0,0 +1,73 @@
package org.dromara.out.domain.vo.outconstructionvalue;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-12-03 11:24
*/
@Data
public class OutConstructionValueTotalVo {
/**
* 项目名
*/
private String projectName;
/**
* 子项目名
*/
private String subProjectName;
/**
* 方阵名称
*/
private String matrixName;
/**
* 分项工程名称
*/
private String progressCategoryName;
/**
* 计量方式0无 1数量 2百分比
*/
private String unitType;
/**
* 单位
*/
private String unit;
/**
* 数量
*/
private BigDecimal number;
/**
* 人工填报数量
*/
private Integer artificialNum;
/**
* 无人机识别数量
*/
private Integer uavNum;
/**
* 确认数量
*/
private Integer confirmNum;
/**
* 对甲产值
*/
private BigDecimal ownerValue;
/**
* 产值
*/
private BigDecimal outValue;
}

View File

@ -7,7 +7,7 @@ import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat; import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert; import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.out.domain.OutConstructionValueRange; import org.dromara.out.domain.OutConstructionValueRange;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueVo; import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueTotalVo;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
@ -82,6 +82,6 @@ public class OutConstructionValueRangeVo implements Serializable {
/** /**
* 子项列表 * 子项列表
*/ */
private List<OutConstructionValueVo> constructionValueVoList; private List<OutConstructionValueTotalVo> constructionValueVoList;
} }

View File

@ -9,6 +9,7 @@ import org.dromara.out.domain.bo.OutConstructionValueBo;
import org.dromara.out.domain.bo.OutConstructionValueFacilityReq; import org.dromara.out.domain.bo.OutConstructionValueFacilityReq;
import org.dromara.out.domain.vo.OutConstructionAllValueVo; import org.dromara.out.domain.vo.OutConstructionAllValueVo;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueCategoryVo; import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueCategoryVo;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueTotalVo;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueVo; import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueVo;
import org.dromara.progress.domain.PgsProgressCategory; import org.dromara.progress.domain.PgsProgressCategory;
@ -47,7 +48,7 @@ public interface IOutConstructionValueService extends IService<OutConstructionVa
* @param bo 查询条件 * @param bo 查询条件
* @return 施工产值列表 * @return 施工产值列表
*/ */
List<OutConstructionValueVo> queryList(OutConstructionValueBo bo); List<OutConstructionValueTotalVo> queryList(OutConstructionValueBo bo);
/** /**
* 新增施工产值 * 新增施工产值

View File

@ -40,7 +40,6 @@ import org.dromara.out.service.IOutConstructionValueRangeService;
import org.dromara.out.service.IOutConstructionValueService; import org.dromara.out.service.IOutConstructionValueService;
import org.dromara.progress.domain.PgsProgressCategory; import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.PgsProgressPlanDetail; import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.progress.service.IPgsProgressPlanDetailService; import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.dromara.project.domain.BusProject; import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService; import org.dromara.project.service.IBusProjectService;
@ -472,12 +471,8 @@ public class OutConstructionValueRangeServiceImpl extends ServiceImpl<OutConstru
* @param summary 合计 * @param summary 合计
* @return 项目VO * @return 项目VO
*/ */
private OutConstructionValueRangeProjectVo buildProjectVo( private OutConstructionValueRangeProjectVo buildProjectVo(BusProject project, String name, String childName,
BusProject project, List<OutConstructionValueCategoryVo> list, Summary summary) {
String name,
String childName,
List<OutConstructionValueCategoryVo> list,
Summary summary) {
OutConstructionValueRangeProjectVo vo = new OutConstructionValueRangeProjectVo(); OutConstructionValueRangeProjectVo vo = new OutConstructionValueRangeProjectVo();
vo.setProjectName(project.getProjectName()); vo.setProjectName(project.getProjectName());
vo.setProgressCategoryName(name + "/" + childName); vo.setProgressCategoryName(name + "/" + childName);
@ -499,13 +494,9 @@ public class OutConstructionValueRangeServiceImpl extends ServiceImpl<OutConstru
* @param summary 合计 * @param summary 合计
* @return 子项VO * @return 子项VO
*/ */
private OutConstructionValueRangeSubProjectVo buildSubProjectVo( private OutConstructionValueRangeSubProjectVo buildSubProjectVo(BusProject project, String name, String childName,
BusProject project,
String name,
String childName,
Map.Entry<Long, List<OutConstructionValueCategoryVo>> entry, Map.Entry<Long, List<OutConstructionValueCategoryVo>> entry,
Map<Long, String> projectNameMap, Map<Long, String> projectNameMap, Summary summary) {
Summary summary) {
OutConstructionValueRangeSubProjectVo vo = new OutConstructionValueRangeSubProjectVo(); OutConstructionValueRangeSubProjectVo vo = new OutConstructionValueRangeSubProjectVo();
vo.setProjectName(project.getProjectName()); vo.setProjectName(project.getProjectName());
vo.setSubProjectName(projectNameMap.get(entry.getKey())); vo.setSubProjectName(projectNameMap.get(entry.getKey()));
@ -529,13 +520,9 @@ public class OutConstructionValueRangeServiceImpl extends ServiceImpl<OutConstru
* @param summary 合计 * @param summary 合计
* @return 方阵VO * @return 方阵VO
*/ */
private OutConstructionValueRangeMatrixVo buildMatrixVo( private OutConstructionValueRangeMatrixVo buildMatrixVo(BusProject project, String name, String childName,
BusProject project,
String name,
String childName,
Map.Entry<String, List<OutConstructionValueCategoryVo>> entry, Map.Entry<String, List<OutConstructionValueCategoryVo>> entry,
Map<Long, String> projectNameMap, Map<Long, String> projectNameMap, Summary summary) {
Summary summary) {
List<OutConstructionValueCategoryVo> list = entry.getValue(); List<OutConstructionValueCategoryVo> list = entry.getValue();
OutConstructionValueRangeMatrixVo vo = new OutConstructionValueRangeMatrixVo(); OutConstructionValueRangeMatrixVo vo = new OutConstructionValueRangeMatrixVo();
vo.setProjectName(project.getProjectName()); vo.setProjectName(project.getProjectName());

View File

@ -36,6 +36,7 @@ import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailCreateReq; import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq; import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq; import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq;
import org.dromara.progress.domain.enums.PgsRelevancyStructureEnum;
import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryVo; import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryVo;
import org.dromara.progress.service.IPgsProgressCategoryService; import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.progress.service.IPgsProgressPlanDetailService; import org.dromara.progress.service.IPgsProgressPlanDetailService;
@ -115,11 +116,179 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
* @return 施工产值列表 * @return 施工产值列表
*/ */
@Override @Override
public List<OutConstructionValueVo> queryList(OutConstructionValueBo bo) { public List<OutConstructionValueTotalVo> queryList(OutConstructionValueBo bo) {
Long projectId = bo.getProjectId();
if (projectId == null) {
throw new ServiceException("请选择项目");
}
BusProject project = projectService.getById(projectId);
if (project == null) {
throw new ServiceException("项目不存在");
}
// 获取子项目
List<BusProject> projectList = projectService.lambdaQuery()
.eq(BusProject::getPId, projectId)
.list();
projectList.add(project);
Map<Long, String> projectNameMap = projectList.stream()
.collect(Collectors.toMap(BusProject::getId, BusProject::getProjectName));
LambdaQueryWrapper<OutConstructionValue> lqw = buildQueryWrapper(bo); LambdaQueryWrapper<OutConstructionValue> lqw = buildQueryWrapper(bo);
List<OutConstructionValueVo> outConstructionValueVos = baseMapper.selectVoList(lqw); List<OutConstructionValue> valueList = this.list(lqw);
supplementaryData(outConstructionValueVos); if (CollUtil.isEmpty(valueList)) {
return outConstructionValueVos; return Collections.emptyList();
}
if (StringUtils.isNotBlank(bo.getProjectType())) {
List<OutConstructionValueCategoryVo> valueCategoryList = new ArrayList<>();
List<PgsProgressCategory> topList = new ArrayList<>();
this.buildExportData(valueList, valueCategoryList, topList);
// 汇总数据
List<OutConstructionValueProjectVo> projectVoList = new ArrayList<>();
List<OutConstructionValueSubProjectVo> subProjectVoList = new ArrayList<>();
List<OutConstructionValueMatrixVo> matrixVoList = new ArrayList<>();
// 合计
BigDecimal totalNumber = BigDecimal.ZERO;
Integer totalArtificialNum = 0;
Integer totalUavNum = 0;
Integer totalConfirmNum = 0;
BigDecimal totalOwnerValue = BigDecimal.ZERO;
BigDecimal totalOutValue = BigDecimal.ZERO;
BigDecimal subTotalNumber = BigDecimal.ZERO;
Integer subTotalArtificialNum = 0;
Integer subTotalUavNum = 0;
Integer subTotalConfirmNum = 0;
BigDecimal subTotalOwnerValue = BigDecimal.ZERO;
BigDecimal subTotalOutValue = BigDecimal.ZERO;
BigDecimal matrixTotalNumber = BigDecimal.ZERO;
Integer matrixTotalArtificialNum = 0;
Integer matrixTotalUavNum = 0;
Integer matrixTotalConfirmNum = 0;
BigDecimal matrixTotalOwnerValue = BigDecimal.ZERO;
BigDecimal matrixTotalOutValue = BigDecimal.ZERO;
// 根据名称+结构分类
Map<String, List<PgsProgressCategory>> topNameMap =
topList.stream().collect(Collectors.groupingBy(item -> item.getName() + "_" + item.getRelevancyStructure()));
for (Map.Entry<String, List<PgsProgressCategory>> entry : topNameMap.entrySet()) {
String[] keys = entry.getKey().split("_");
String name = keys[0];
String structure = keys[1];
List<PgsProgressCategory> topNodes = entry.getValue();
List<Long> topIds = topNodes.stream().map(PgsProgressCategory::getId).toList();
// 找出全部子孙节点
List<OutConstructionValueCategoryVo> children = findChildren(valueCategoryList, topIds);
// 子类按名称分组
Map<String, List<OutConstructionValueCategoryVo>> childrenMap =
children.stream().collect(Collectors.groupingBy(OutConstructionValueCategoryVo::getName));
for (Map.Entry<String, List<OutConstructionValueCategoryVo>> childrenEntry : childrenMap.entrySet()) {
String childName = childrenEntry.getKey();
List<OutConstructionValueCategoryVo> childrenEntryValue = childrenEntry.getValue();
// ======= 构建项目级数据 =======
Summary summary = calculateSummary(childrenEntryValue);
OutConstructionValueProjectVo projectVo =
buildProjectVo(project, name, childName, childrenEntryValue, summary);
projectVoList.add(projectVo);
totalNumber = totalNumber.add(BigDecimal.valueOf(summary.number));
totalArtificialNum += summary.artificialNum;
totalUavNum += summary.uavNum;
totalConfirmNum += summary.confirmNum;
totalOwnerValue = totalOwnerValue.add(summary.ownerValue);
totalOutValue = totalOutValue.add(summary.outValue);
// ======= 构建子项目级数据 =======
if ((structure.equals("1") || structure.equals("2")) && bo.getProjectType().equals("1")) {
Map<Long, List<OutConstructionValueCategoryVo>> subMap =
childrenEntryValue.stream().collect(Collectors.groupingBy(OutConstructionValueCategoryVo::getProjectId));
for (Map.Entry<Long, List<OutConstructionValueCategoryVo>> subEntry : subMap.entrySet()) {
Summary subSummary = calculateSummary(subEntry.getValue());
OutConstructionValueSubProjectVo subVo =
buildSubProjectVo(project, name, childName, subEntry, projectNameMap, subSummary);
subProjectVoList.add(subVo);
subTotalNumber = subTotalNumber.add(BigDecimal.valueOf(subSummary.number));
subTotalArtificialNum += subSummary.artificialNum;
subTotalUavNum += subSummary.uavNum;
subTotalConfirmNum += subSummary.confirmNum;
subTotalOwnerValue = subTotalOwnerValue.add(subSummary.ownerValue);
subTotalOutValue = subTotalOutValue.add(subSummary.outValue);
}
}
// ======= 构建方阵级数据 =======
if (structure.equals("2") && bo.getProjectType().equals("2")) {
Map<String, List<OutConstructionValueCategoryVo>> matrixMap =
childrenEntryValue.stream().collect(Collectors.groupingBy(OutConstructionValueCategoryVo::getMatrixName));
for (Map.Entry<String, List<OutConstructionValueCategoryVo>> matrixEntry : matrixMap.entrySet()) {
Summary matrixSummary = calculateSummary(matrixEntry.getValue());
OutConstructionValueMatrixVo matrixVo =
buildMatrixVo(project, name, childName, matrixEntry, projectNameMap, matrixSummary);
matrixVoList.add(matrixVo);
matrixTotalNumber = matrixTotalNumber.add(BigDecimal.valueOf(matrixSummary.number));
matrixTotalArtificialNum += matrixSummary.artificialNum;
matrixTotalUavNum += matrixSummary.uavNum;
matrixTotalConfirmNum += matrixSummary.confirmNum;
matrixTotalOwnerValue = matrixTotalOwnerValue.add(matrixSummary.ownerValue);
matrixTotalOutValue = matrixTotalOutValue.add(matrixSummary.outValue);
}
}
}
}
// 排序
projectVoList.sort(Comparator.comparing(OutConstructionValueProjectVo::getProgressCategoryName));
subProjectVoList.sort(Comparator.comparing(OutConstructionValueSubProjectVo::getSubProjectName)
.thenComparing(OutConstructionValueSubProjectVo::getProgressCategoryName));
matrixVoList.sort(Comparator.comparing(OutConstructionValueMatrixVo::getSubProjectName)
.thenComparing(OutConstructionValueMatrixVo::getMatrixName)
.thenComparing(OutConstructionValueMatrixVo::getProgressCategoryName));
// 填充合计
OutConstructionValueProjectVo rangeProjectVo = new OutConstructionValueProjectVo();
rangeProjectVo.setProjectName("合计");
rangeProjectVo.setNumber(totalNumber);
rangeProjectVo.setArtificialNum(totalArtificialNum);
rangeProjectVo.setUavNum(totalUavNum);
rangeProjectVo.setConfirmNum(totalConfirmNum);
rangeProjectVo.setOwnerValue(totalOwnerValue);
rangeProjectVo.setOutValue(totalOutValue);
projectVoList.add(rangeProjectVo);
OutConstructionValueSubProjectVo rangeSubProjectVo = new OutConstructionValueSubProjectVo();
rangeSubProjectVo.setProjectName("合计");
rangeSubProjectVo.setNumber(subTotalNumber);
rangeSubProjectVo.setArtificialNum(subTotalArtificialNum);
rangeSubProjectVo.setUavNum(subTotalUavNum);
rangeSubProjectVo.setConfirmNum(subTotalConfirmNum);
rangeSubProjectVo.setOwnerValue(subTotalOwnerValue);
rangeSubProjectVo.setOutValue(subTotalOutValue);
subProjectVoList.add(rangeSubProjectVo);
OutConstructionValueMatrixVo rangeMatrixVo = new OutConstructionValueMatrixVo();
rangeMatrixVo.setProjectName("合计");
rangeMatrixVo.setNumber(matrixTotalNumber);
rangeMatrixVo.setArtificialNum(matrixTotalArtificialNum);
rangeMatrixVo.setUavNum(matrixTotalUavNum);
rangeMatrixVo.setConfirmNum(matrixTotalConfirmNum);
rangeMatrixVo.setOwnerValue(matrixTotalOwnerValue);
rangeMatrixVo.setOutValue(matrixTotalOutValue);
matrixVoList.add(rangeMatrixVo);
return switch (bo.getProjectType()) {
case "3" -> projectVoList.stream().map(p -> {
OutConstructionValueTotalVo vo = new OutConstructionValueTotalVo();
BeanUtils.copyProperties(p, vo);
return vo;
}).toList();
case "1" -> subProjectVoList.stream().map(p -> {
OutConstructionValueTotalVo vo = new OutConstructionValueTotalVo();
BeanUtils.copyProperties(p, vo);
return vo;
}).toList();
case "2" -> matrixVoList.stream().map(p -> {
OutConstructionValueTotalVo vo = new OutConstructionValueTotalVo();
BeanUtils.copyProperties(p, vo);
return vo;
}).toList();
case null, default -> Collections.emptyList();
};
}
return valueList.stream().map(p -> {
OutConstructionValueTotalVo vo = new OutConstructionValueTotalVo();
BeanUtils.copyProperties(p, vo);
return vo;
}).toList();
} }
private LambdaQueryWrapper<OutConstructionValue> buildQueryWrapper(OutConstructionValueBo bo) { private LambdaQueryWrapper<OutConstructionValue> buildQueryWrapper(OutConstructionValueBo bo) {
@ -155,9 +324,16 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
categoryLqw.select(PgsProgressCategory::getId); categoryLqw.select(PgsProgressCategory::getId);
categoryLqw.eq(PgsProgressCategory::getUnitType, bo.getUnitType()); categoryLqw.eq(PgsProgressCategory::getUnitType, bo.getUnitType());
categoryLqw.eq(bo.getMatrixId() != null, PgsProgressCategory::getMatrixId, bo.getMatrixId()); categoryLqw.eq(bo.getMatrixId() != null, PgsProgressCategory::getMatrixId, bo.getMatrixId());
if (CollUtil.isNotEmpty(ids)) { categoryLqw.in(CollUtil.isNotEmpty(ids), PgsProgressCategory::getProjectId, ids);
categoryLqw.in(PgsProgressCategory::getProjectId, ids); if (StringUtils.isNotBlank(bo.getProjectType())) {
if (bo.getProjectType().equals("1")) {
categoryLqw.in(PgsProgressCategory::getRelevancyStructure,
PgsRelevancyStructureEnum.SUB_PROJECT.getValue(), PgsRelevancyStructureEnum.MATRIX.getValue());
} else if (bo.getProjectType().equals("2")) {
categoryLqw.eq(PgsProgressCategory::getRelevancyStructure, PgsRelevancyStructureEnum.MATRIX.getValue());
} }
}
categoryLqw.eq(StringUtils.isNotBlank(bo.getProjectType()), PgsProgressCategory::getRelevancyStructure, bo.getProjectType());
List<PgsProgressCategory> progressCategories = pgsProgressCategoryService.list(categoryLqw); List<PgsProgressCategory> progressCategories = pgsProgressCategoryService.list(categoryLqw);
if (CollUtil.isNotEmpty(progressCategories)) { if (CollUtil.isNotEmpty(progressCategories)) {
List<Long> categoryIds = progressCategories.stream().map(PgsProgressCategory::getId).toList(); List<Long> categoryIds = progressCategories.stream().map(PgsProgressCategory::getId).toList();
@ -441,7 +617,7 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
OutConstructionValueProjectVo projectVo = OutConstructionValueProjectVo projectVo =
buildProjectVo(project, name, childName, childrenEntryValue, summary); buildProjectVo(project, name, childName, childrenEntryValue, summary);
projectVoList.add(projectVo); projectVoList.add(projectVo);
totalNumber = totalNumber.add(summary.number); totalNumber = totalNumber.add(BigDecimal.valueOf(summary.number));
totalOwnerValue = totalOwnerValue.add(summary.ownerValue); totalOwnerValue = totalOwnerValue.add(summary.ownerValue);
totalOutValue = totalOutValue.add(summary.outValue); totalOutValue = totalOutValue.add(summary.outValue);
// ======= 构建子项目级数据 ======= // ======= 构建子项目级数据 =======
@ -453,7 +629,7 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
OutConstructionValueSubProjectVo subVo = OutConstructionValueSubProjectVo subVo =
buildSubProjectVo(project, name, childName, subEntry, projectNameMap, subSummary); buildSubProjectVo(project, name, childName, subEntry, projectNameMap, subSummary);
subProjectVoList.add(subVo); subProjectVoList.add(subVo);
subTotalNumber = subTotalNumber.add(subSummary.number); subTotalNumber = subTotalNumber.add(BigDecimal.valueOf(subSummary.number));
subTotalOwnerValue = subTotalOwnerValue.add(subSummary.ownerValue); subTotalOwnerValue = subTotalOwnerValue.add(subSummary.ownerValue);
subTotalOutValue = subTotalOutValue.add(subSummary.outValue); subTotalOutValue = subTotalOutValue.add(subSummary.outValue);
} }
@ -467,7 +643,7 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
OutConstructionValueMatrixVo matrixVo = OutConstructionValueMatrixVo matrixVo =
buildMatrixVo(project, name, childName, matrixEntry, projectNameMap, matrixSummary); buildMatrixVo(project, name, childName, matrixEntry, projectNameMap, matrixSummary);
matrixVoList.add(matrixVo); matrixVoList.add(matrixVo);
matrixTotalNumber = matrixTotalNumber.add(matrixSummary.number); matrixTotalNumber = matrixTotalNumber.add(BigDecimal.valueOf(matrixSummary.number));
matrixTotalOwnerValue = matrixTotalOwnerValue.add(matrixSummary.ownerValue); matrixTotalOwnerValue = matrixTotalOwnerValue.add(matrixSummary.ownerValue);
matrixTotalOutValue = matrixTotalOutValue.add(matrixSummary.outValue); matrixTotalOutValue = matrixTotalOutValue.add(matrixSummary.outValue);
} }
@ -587,7 +763,10 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
* 汇总静态类 * 汇总静态类
*/ */
static class Summary { static class Summary {
BigDecimal number; Integer number;
Integer artificialNum;
Integer uavNum;
Integer confirmNum;
BigDecimal ownerValue; BigDecimal ownerValue;
BigDecimal outValue; BigDecimal outValue;
} }
@ -600,7 +779,10 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
*/ */
private Summary calculateSummary(List<OutConstructionValueCategoryVo> list) { private Summary calculateSummary(List<OutConstructionValueCategoryVo> list) {
Summary s = new Summary(); Summary s = new Summary();
s.number = BigDecimal.ZERO; s.number = 0;
s.artificialNum = 0;
s.uavNum = 0;
s.confirmNum = 0;
s.ownerValue = BigDecimal.ZERO; s.ownerValue = BigDecimal.ZERO;
s.outValue = BigDecimal.ZERO; s.outValue = BigDecimal.ZERO;
for (OutConstructionValueCategoryVo c : list) { for (OutConstructionValueCategoryVo c : list) {
@ -608,7 +790,10 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
? c.getArtificialNum() + c.getUavNum() ? c.getArtificialNum() + c.getUavNum()
: c.getConfirmNum(); : c.getConfirmNum();
s.number = s.number.add(BigDecimal.valueOf(num)); s.number = s.number + num;
s.artificialNum = s.artificialNum + c.getArtificialNum();
s.uavNum = s.uavNum + c.getUavNum();
s.confirmNum = s.confirmNum + c.getConfirmNum();
s.ownerValue = s.ownerValue.add(c.getOwnerValue()); s.ownerValue = s.ownerValue.add(c.getOwnerValue());
s.outValue = s.outValue.add(c.getOutValue()); s.outValue = s.outValue.add(c.getOutValue());
} }
@ -652,7 +837,10 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
vo.setProgressCategoryName(name + "/" + childName); vo.setProgressCategoryName(name + "/" + childName);
vo.setUnit(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnit)); vo.setUnit(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnit));
vo.setUnitType(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnitType)); vo.setUnitType(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnitType));
vo.setNumber(summary.number); vo.setNumber(BigDecimal.valueOf(summary.number));
vo.setArtificialNum(summary.artificialNum);
vo.setUavNum(summary.uavNum);
vo.setConfirmNum(summary.confirmNum);
vo.setOwnerValue(summary.ownerValue); vo.setOwnerValue(summary.ownerValue);
vo.setOutValue(summary.outValue); vo.setOutValue(summary.outValue);
return vo; return vo;
@ -681,7 +869,10 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
vo.setProgressCategoryName(name + "/" + childName); vo.setProgressCategoryName(name + "/" + childName);
vo.setUnit(getFirstNonNull(entry.getValue(), OutConstructionValueCategoryVo::getUnit)); vo.setUnit(getFirstNonNull(entry.getValue(), OutConstructionValueCategoryVo::getUnit));
vo.setUnitType(getFirstNonNull(entry.getValue(), OutConstructionValueCategoryVo::getUnitType)); vo.setUnitType(getFirstNonNull(entry.getValue(), OutConstructionValueCategoryVo::getUnitType));
vo.setNumber(summary.number); vo.setNumber(BigDecimal.valueOf(summary.number));
vo.setArtificialNum(summary.artificialNum);
vo.setUavNum(summary.uavNum);
vo.setConfirmNum(summary.confirmNum);
vo.setOwnerValue(summary.ownerValue); vo.setOwnerValue(summary.ownerValue);
vo.setOutValue(summary.outValue); vo.setOutValue(summary.outValue);
return vo; return vo;
@ -717,7 +908,10 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
vo.setSubProjectName(projectNameMap.getOrDefault(pid, project.getProjectName())); vo.setSubProjectName(projectNameMap.getOrDefault(pid, project.getProjectName()));
vo.setUnit(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnit)); vo.setUnit(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnit));
vo.setUnitType(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnitType)); vo.setUnitType(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnitType));
vo.setNumber(summary.number); vo.setNumber(BigDecimal.valueOf(summary.number));
vo.setArtificialNum(summary.artificialNum);
vo.setUavNum(summary.uavNum);
vo.setConfirmNum(summary.confirmNum);
vo.setOwnerValue(summary.ownerValue); vo.setOwnerValue(summary.ownerValue);
vo.setOutValue(summary.outValue); vo.setOutValue(summary.outValue);
return vo; return vo;

View File

@ -34,6 +34,11 @@ public class QltQualityConstructionLog extends BaseEntity {
*/ */
private Long projectId; private Long projectId;
/**
* 类型 1-文字2-文件
*/
private String type;
/** /**
* 标题 * 标题
*/ */
@ -44,6 +49,11 @@ public class QltQualityConstructionLog extends BaseEntity {
*/ */
private LocalDate happenDate; private LocalDate happenDate;
/**
* 结束日期
*/
private LocalDate endDate;
/** /**
* 生产情况 * 生产情况
*/ */

View File

@ -21,11 +21,21 @@ public class QltQualityConstructionLogCreateReq implements Serializable {
*/ */
private Long projectId; private Long projectId;
/**
* 类型 1-文字2-文件
*/
private String type;
/** /**
* 发生日期 * 发生日期
*/ */
private LocalDate happenDate; private LocalDate happenDate;
/**
* 结束日期
*/
private LocalDate endDate;
/** /**
* 生产情况 * 生产情况
*/ */

View File

@ -40,6 +40,11 @@ public class QltQualityConstructionLogVo implements Serializable {
*/ */
private Long projectId; private Long projectId;
/**
* 类型 1-文字2-文件
*/
private String type;
/** /**
* 项目名称 * 项目名称
*/ */
@ -52,6 +57,12 @@ public class QltQualityConstructionLogVo implements Serializable {
@ExcelProperty(value = "发生日期") @ExcelProperty(value = "发生日期")
private LocalDate happenDate; private LocalDate happenDate;
/**
* 结束日期
*/
private LocalDate endDate;
/** /**
* 生产情况 * 生产情况
*/ */

View File

@ -224,6 +224,8 @@ public class QltQualityConstructionLogServiceImpl extends ServiceImpl<QltQuality
Long projectId = req.getProjectId(); Long projectId = req.getProjectId();
LocalDate happenDate = req.getHappenDate(); LocalDate happenDate = req.getHappenDate();
// 精准查询 // 精准查询
lqw.orderByDesc(QltQualityConstructionLog::getHappenDate);
lqw.orderByDesc(QltQualityConstructionLog::getId);
lqw.eq(ObjectUtils.isNotEmpty(projectId), QltQualityConstructionLog::getProjectId, projectId); lqw.eq(ObjectUtils.isNotEmpty(projectId), QltQualityConstructionLog::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(happenDate), QltQualityConstructionLog::getHappenDate, happenDate); lqw.eq(ObjectUtils.isNotEmpty(happenDate), QltQualityConstructionLog::getHappenDate, happenDate);
lqw.like(StringUtils.isNotBlank(req.getTitle()), QltQualityConstructionLog::getTitle, req.getTitle()); lqw.like(StringUtils.isNotBlank(req.getTitle()), QltQualityConstructionLog::getTitle, req.getTitle());

View File

@ -0,0 +1,162 @@
package org.dromara.safety.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.safety.domain.bo.HazardRuleBo;
import org.dromara.safety.domain.dto.EvaluateDto;
import org.dromara.safety.domain.vo.HazardRuleVo;
import org.dromara.safety.domain.vo.HiddenDangerCountVo;
import org.dromara.safety.service.IHazardRuleService;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
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.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.safety.domain.vo.HazardHiddenDangerVo;
import org.dromara.safety.domain.bo.HazardHiddenDangerBo;
import org.dromara.safety.service.IHazardHiddenDangerService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* 隐患信息
*
* @author Lion Li
* @date 2025-12-03
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/safety/hiddenDanger")
public class HazardHiddenDangerController extends BaseController {
private final IHazardHiddenDangerService hazardHiddenDangerService;
private final IHazardRuleService hazardRuleService;
/**
* 查询隐患信息列表
*/
@SaCheckPermission("safety:hiddenDanger:list")
@GetMapping("/list")
public TableDataInfo<HazardHiddenDangerVo> list(HazardHiddenDangerBo bo, PageQuery pageQuery) {
return hazardHiddenDangerService.queryPageList(bo, pageQuery);
}
/**
* 导出隐患信息列表
*/
@SaCheckPermission("safety:hiddenDanger:export")
@Log(title = "隐患信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HazardHiddenDangerBo bo, HttpServletResponse response) {
List<HazardHiddenDangerVo> list = hazardHiddenDangerService.queryList(bo);
ExcelUtil.exportExcel(list, "隐患信息", HazardHiddenDangerVo.class, response);
}
/**
* 获取隐患信息详细信息
*
* @param id 主键
*/
@SaCheckPermission("safety:hiddenDanger:query")
@GetMapping("/{id}")
public R<HazardHiddenDangerVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(hazardHiddenDangerService.queryById(id));
}
/**
* 新增隐患信息
*/
@SaCheckPermission("safety:hiddenDanger:add")
@Log(title = "隐患信息", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody HazardHiddenDangerBo bo) {
return toAjax(hazardHiddenDangerService.insertByBo(bo));
}
/**
* 修改隐患信息
*/
@SaCheckPermission("safety:hiddenDanger:edit")
@Log(title = "隐患信息", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody HazardHiddenDangerBo bo) {
return toAjax(hazardHiddenDangerService.updateByBo(bo));
}
/**
* 删除隐患信息
*
* @param ids 主键串
*/
@SaCheckPermission("safety:hiddenDanger:remove")
@Log(title = "隐患信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(hazardHiddenDangerService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 隐患统计
*/
@GetMapping("/dangerCount/{projectId}")
public R<HiddenDangerCountVo> dangerCount(@PathVariable Long projectId) {
HiddenDangerCountVo count = hazardHiddenDangerService.dangerCount(projectId);
return R.ok(count);
}
/**
* 隐患级别列表
*/
@GetMapping("/levelList")
public R<List<HazardRuleVo>> export(HazardRuleBo bo) {
List<HazardRuleVo> list = hazardRuleService.queryList(bo);
return R.ok(list);
}
/**
* 评估隐患
*/
@SaCheckPermission("safety:hiddenDanger:edit")
@Log(title = "隐患信息", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/evaluate")
public R<Void> evaluate(@RequestBody EvaluateDto dto) {
return toAjax(hazardHiddenDangerService.evaluate(dto));
}
}

View File

@ -0,0 +1,105 @@
package org.dromara.safety.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
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.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.safety.domain.vo.HazardRuleVo;
import org.dromara.safety.domain.bo.HazardRuleBo;
import org.dromara.safety.service.IHazardRuleService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* 隐患分级通知规则
*
* @author lilemy
* @date 2025-12-03
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/safety/rule")
public class HazardRuleController extends BaseController {
private final IHazardRuleService hazardRuleService;
/**
* 查询隐患分级通知规则列表
*/
@SaCheckPermission("safety:rule:list")
@GetMapping("/list")
public TableDataInfo<HazardRuleVo> list(HazardRuleBo bo, PageQuery pageQuery) {
return hazardRuleService.queryPageList(bo, pageQuery);
}
/**
* 导出隐患分级通知规则列表
*/
@SaCheckPermission("safety:rule:export")
@Log(title = "隐患分级通知规则", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HazardRuleBo bo, HttpServletResponse response) {
List<HazardRuleVo> list = hazardRuleService.queryList(bo);
ExcelUtil.exportExcel(list, "隐患分级通知规则", HazardRuleVo.class, response);
}
/**
* 获取隐患分级通知规则详细信息
*
* @param id 主键
*/
@SaCheckPermission("safety:rule:query")
@GetMapping("/{id}")
public R<HazardRuleVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(hazardRuleService.queryById(id));
}
/**
* 新增隐患分级通知规则
*/
@SaCheckPermission("safety:rule:add")
@Log(title = "隐患分级通知规则", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody HazardRuleBo bo) {
return toAjax(hazardRuleService.insertByBo(bo));
}
/**
* 修改隐患分级通知规则
*/
@SaCheckPermission("safety:rule:edit")
@Log(title = "隐患分级通知规则", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody HazardRuleBo bo) {
return toAjax(hazardRuleService.updateByBo(bo));
}
/**
* 删除隐患分级通知规则
*
* @param ids 主键串
*/
@SaCheckPermission("safety:rule:remove")
@Log(title = "隐患分级通知规则", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(hazardRuleService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,152 @@
package org.dromara.safety.domain;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.time.LocalDateTime;
/**
* 隐患信息对象 hazard_hidden_danger
*
* @author Lion Li
* @date 2025-12-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("hazard_hidden_danger")
public class HazardHiddenDanger extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
// 待评估
public static final String EVALUATE = "1";
// 待整改
public static final String RECTIFY = "2";
// 待复查
public static final String REVIEW = "3";
// 已闭环
public static final String CLOSED = "4";
/**
* 角色ID
*/
@TableId(value = "id")
private Long id;
/**
* 项目ID
*/
private Long projectId;
/**
* 隐患编号
*/
private String dangerCode;
/**
* 隐患名称
*/
private String dangerName;
/**
* 隐患类型
*/
private String dangerType;
/**
* 隐患描述
*/
private String dangerDes;
/**
* 隐患附件
*/
private String dangerFile;
/**
* 上报位置
*/
private String reportLocation;
/**
* 上报人
*/
private Long reporter;
/**
* 上报人电话
*/
private String reporterPhone;
/**
* 上报时间
*/
private LocalDateTime reportTime;
/**
* 隐患等级ID
*/
private Long dangerLevelId;
/**
* 评估人
*/
private Long evaluator;
/**
* 评估时间
*/
private LocalDateTime evaluateTime;
/**
* 评估依据
*/
private String evaluateBasis;
/**
* 评估意见
*/
private String reporterOpinion;
/**
* 评估附件
*/
private String reporterFile;
/**
* 整改时间
*/
private LocalDateTime rectifyTime;
/**
* 整改单位 1-班组 2-分包
*/
private String rectifyUnit;
/**
* 整改单位ID
*/
private Long rectifyUnitId;
/**
* 整改负责人Id
*/
private Long rectifyUserId;
/**
* 状态1-待评估2-待整改3-待复查4-已闭环)
*/
private String status;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,77 @@
package org.dromara.safety.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;
/**
* 隐患分级通知规则对象 hazard_rule
*
* @author lilemy
* @date 2025-12-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("hazard_rule")
public class HazardRule extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 隐患级别
*/
private String hazardLevel;
/**
* 隐患权重
*/
private Integer hazardWeight;
/**
* 响应时限数值
*/
private Integer responseTime;
/**
* 响应时效单位
*/
private String responseUnit;
/**
* 通知方式
*/
private String notifyMethod;
/**
* 超时处理方式
*/
private String timeoutAction;
/**
* 额外设置
*/
private String extraSetting;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,37 @@
package org.dromara.safety.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 隐患规则通知对象对象 hazard_rule_notify_object
*
* @author lilemy
* @date 2025-12-03
*/
@Data
@TableName("hazard_rule_notify_object")
public class HazardRuleNotifyObject implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 规则ID
*/
private Long ruleId;
/**
* 通知ID
*/
private Long notifyId;
/**
* 通知类型
*/
private String notifyType;
}

View File

@ -52,6 +52,11 @@ public class HseRecognizeRecord implements Serializable {
*/ */
private String violationType; private String violationType;
/**
* 原始图片id
*/
private Long originalUrlId;
/** /**
* 原始图片 * 原始图片
*/ */

View File

@ -33,11 +33,21 @@ public class HseSafetyLog extends BaseEntity {
*/ */
private Long projectId; private Long projectId;
/**
* 类型 1-文字2-文件
*/
private String type;
/** /**
* 发生日期 * 发生日期
*/ */
private String dateOfOccurrence; private String dateOfOccurrence;
/**
* 结束日期
*/
private String endDate;
/** /**
* 最高气温 * 最高气温
*/ */

View File

@ -0,0 +1,142 @@
package org.dromara.safety.domain.bo;
import org.dromara.safety.domain.HazardHiddenDanger;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.time.LocalDateTime;
/**
* 隐患信息业务对象 hazard_hidden_danger
*
* @author Lion Li
* @date 2025-12-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = HazardHiddenDanger.class, reverseConvertGenerate = false)
public class HazardHiddenDangerBo extends BaseEntity {
/**
* ID
*/
@NotNull(message = "ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 隐患编号
*/
private String dangerCode;
/**
* 隐患类型
*/
private String dangerType;
/**
* 隐患名称
*/
private String dangerName;
/**
* 隐患描述
*/
private String dangerDes;
/**
* 隐患附件
*/
private String dangerFile;
/**
* 上报位置
*/
private String reportLocation;
/**
* 上报人
*/
private Long reporter;
/**
* 上报人电话
*/
private String reporterPhone;
/**
* 上报时间
*/
private LocalDateTime reportTime;
/**
* 隐患等级ID
*/
private Long dangerLevelId;
/**
* 评估人
*/
private Long evaluator;
/**
* 评估时间
*/
private LocalDateTime evaluateTime;
/**
* 评估依据
*/
private String evaluateBasis;
/**
* 评估意见
*/
private String reporterOpinion;
/**
* 评估附件
*/
private String reporterFile;
/**
* 整改时间
*/
private LocalDateTime rectifyTime;
/**
* 整改单位 1-班组 2-分包
*/
private String rectifyUnit;
/**
* 整改单位ID
*/
private Long rectifyUnitId;
/**
* 整改负责人Id
*/
private Long rectifyUserId;
/**
* 状态1-待评估2-待整改3-待复查4-已闭环)
*/
private String status;
/**
* 备注
*/
private String remark;
/**
* 项目ID
*/
private Long projectId;
}

View File

@ -0,0 +1,83 @@
package org.dromara.safety.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.safety.domain.HazardRule;
/**
* 隐患分级通知规则业务对象 hazard_rule
*
* @author lilemy
* @date 2025-12-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = HazardRule.class, reverseConvertGenerate = false)
public class HazardRuleBo extends BaseEntity {
/**
* 主键
*/
@NotNull(message = "主键不能为空", 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 hazardLevel;
/**
* 隐患权重
*/
@NotNull(message = "隐患权重不能为空", groups = {AddGroup.class, EditGroup.class})
private Integer hazardWeight;
/**
* 响应时限数值
*/
@NotNull(message = "响应时限数值不能为空", groups = {AddGroup.class, EditGroup.class})
private Integer responseTime;
/**
* 响应时效单位
*/
@NotBlank(message = "响应时效单位不能为空", groups = {AddGroup.class, EditGroup.class})
private String responseUnit;
/**
* 通知方式
*/
@NotBlank(message = "通知方式不能为空", groups = {AddGroup.class, EditGroup.class})
private String notifyMethod;
/**
* 超时处理方式
*/
@NotBlank(message = "超时处理方式不能为空", groups = {AddGroup.class, EditGroup.class})
private String timeoutAction;
/**
* 额外设置
*/
@NotBlank(message = "额外设置不能为空", groups = {AddGroup.class, EditGroup.class})
private String extraSetting;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,42 @@
package org.dromara.safety.domain.bo;
import org.dromara.safety.domain.HazardRuleNotifyObject;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 隐患规则通知对象业务对象 hazard_rule_notify_object
*
* @author lilemy
* @date 2025-12-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = HazardRuleNotifyObject.class, reverseConvertGenerate = false)
public class HazardRuleNotifyObjectBo extends BaseEntity {
/**
* 规则ID
*/
@NotNull(message = "规则ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long ruleId;
/**
* 通知ID
*/
@NotNull(message = "通知ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long notifyId;
/**
* 通知类型
*/
@NotBlank(message = "通知类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String notifyType;
}

View File

@ -0,0 +1,59 @@
package org.dromara.safety.domain.dto;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.safety.domain.HazardHiddenDanger;
import java.time.LocalDateTime;
/**
* 隐患信息业务对象 hazard_hidden_danger
*
* @author Lion Li
* @date 2025-12-03
*/
@Data
@AutoMapper(target = HazardHiddenDanger.class, reverseConvertGenerate = false)
public class EvaluateDto {
/**
* ID
*/
private Long id;
/**
* 隐患等级ID
*/
private Long dangerLevelId;
/**
* 评估人
*/
private Long evaluator;
/**
* 评估时间
*/
private LocalDateTime evaluateTime;
/**
* 评估依据
*/
private String evaluateBasis;
/**
* 评估意见
*/
private String reporterOpinion;
/**
* 评估附件
*/
private String reporterFile;
/**
* 整改时间
*/
private LocalDateTime rectifyTime;
}

View File

@ -37,6 +37,11 @@ public class HseRecognizeRecordCreateDto {
*/ */
private String recordCategory; private String recordCategory;
/**
* 原始图片id
*/
private Long originalUrlId;
/** /**
* 原始图片 * 原始图片
*/ */

View File

@ -23,12 +23,22 @@ public class HseSafetyLogCreateReq implements Serializable {
@NotNull(message = "项目id不能为空") @NotNull(message = "项目id不能为空")
private Long projectId; private Long projectId;
/**
* 类型 1-文字2-文件
*/
private String type;
/** /**
* 发生日期 * 发生日期
*/ */
@NotBlank(message = "发生日期不能为空") @NotBlank(message = "发生日期不能为空")
private String dateOfOccurrence; private String dateOfOccurrence;
/**
* 结束日期
*/
private String endDate;
/** /**
* 最高气温 * 最高气温
*/ */

View File

@ -0,0 +1,200 @@
package org.dromara.safety.domain.vo;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.safety.domain.HazardHiddenDanger;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
/**
* 隐患信息视图对象 hazard_hidden_danger
*
* @author Lion Li
* @date 2025-12-03
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = HazardHiddenDanger.class)
public class HazardHiddenDangerVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 角色ID
*/
@ExcelProperty(value = "角色ID")
private Long id;
/**
* 项目ID
*/
private Long projectId;
/**
* 隐患编号
*/
@ExcelProperty(value = "隐患编号")
private String dangerCode;
/**
* 隐患名称
*/
@ExcelProperty(value = "隐患名称")
private String dangerName;
/**
* 上报位置
*/
@ExcelProperty(value = "上报位置")
private String reportLocation;
/**
* 上报人
*/
@ExcelProperty(value = "上报人")
private Long reporter;
/**
* 上报人名字
*/
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "reporter")
private String reporterName;
/**
* 上报人电话
*/
private String reporterPhone;
/**
* 上报时间
*/
@ExcelProperty(value = "上报时间")
private LocalDateTime reportTime;
/**
* 隐患等级ID
*/
@ExcelProperty(value = "隐患等级ID")
private Long dangerLevelId;
/**
* 隐患类型
*/
private String dangerType;
/**
* 隐患描述
*/
private String dangerDes;
/**
* 隐患附件
*/
private String dangerFile;
/**
* 隐患附件地址
*/
@Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "dangerFile")
private String dangerFileUrl;
/**
* 评估人
*/
@ExcelProperty(value = "评估人")
private Long evaluator;
/**
* 评估人名字
*/
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "evaluator")
private String evaluatorName;
/**
* 评估时间
*/
@ExcelProperty(value = "评估时间")
private LocalDateTime evaluateTime;
/**
* 评估依据
*/
@ExcelProperty(value = "评估依据")
private String evaluateBasis;
/**
* 评估意见
*/
@ExcelProperty(value = "评估意见")
private String reporterOpinion;
/**
* 评估附件
*/
@ExcelProperty(value = "评估附件")
private String reporterFile;
/**
* 评估附件地址
*/
@Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "reporterFile")
private String reporterFileUrl;
/**
* 整改时间
*/
@ExcelProperty(value = "整改时间")
private LocalDateTime rectifyTime;
/**
* 整改单位 1-班组 2-分包
*/
@ExcelProperty(value = "整改单位 1-班组 2-分包")
private String rectifyUnit;
/**
* 整改单位ID
*/
@ExcelProperty(value = "整改单位ID")
private Long rectifyUnitId;
/**
* 整改负责人Id
*/
@ExcelProperty(value = "整改负责人Id")
private Long rectifyUserId;
/**
* 整改负责人名字
*/
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "rectifyUserId")
private String rectifyUserName;
/**
* 状态1-待评估2-待整改3-待复查4-已闭环)
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "1=-待评估2-待整改3-待复查4-已闭环")
private String status;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@ -0,0 +1,46 @@
package org.dromara.safety.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.safety.domain.HazardRuleNotifyObject;
import java.io.Serial;
import java.io.Serializable;
/**
* 隐患规则通知对象视图对象 hazard_rule_notify_object
*
* @author lilemy
* @date 2025-12-03
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = HazardRuleNotifyObject.class)
public class HazardRuleNotifyObjectVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 规则ID
*/
@ExcelProperty(value = "规则ID")
private Long ruleId;
/**
* 通知ID
*/
@ExcelProperty(value = "通知ID")
private Long notifyId;
/**
* 通知类型
*/
@ExcelProperty(value = "通知类型")
private String notifyType;
}

View File

@ -0,0 +1,93 @@
package org.dromara.safety.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.safety.domain.HazardRule;
import java.io.Serial;
import java.io.Serializable;
/**
* 隐患分级通知规则视图对象 hazard_rule
*
* @author lilemy
* @date 2025-12-03
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = HazardRule.class)
public class HazardRuleVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ExcelProperty(value = "主键")
private Long id;
/**
* 项目id
*/
@ExcelProperty(value = "项目id")
private Long projectId;
/**
* 隐患级别
*/
@ExcelProperty(value = "隐患级别")
private String hazardLevel;
/**
* 隐患权重
*/
@ExcelProperty(value = "隐患权重")
private Integer hazardWeight;
/**
* 响应时限数值
*/
@ExcelProperty(value = "响应时限数值")
private Integer responseTime;
/**
* 响应时效单位
*/
@ExcelProperty(value = "响应时效单位", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "time_unit")
private String responseUnit;
/**
* 通知方式
*/
@ExcelProperty(value = "通知方式", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "notify_method")
private String notifyMethod;
/**
* 超时处理方式
*/
@ExcelProperty(value = "超时处理方式", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "hazard_timeout_action")
private String timeoutAction;
/**
* 额外设置
*/
@ExcelProperty(value = "额外设置")
private String extraSetting;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@ -0,0 +1,33 @@
package org.dromara.safety.domain.vo;
import lombok.Data;
@Data
public class HiddenDangerCountVo {
/**
* 总数量
*/
private Integer total;
/**
* 待评估数量
*/
private Long waitEvaluate;
/**
* 待整改数量
*/
private Long waitRectify;
/**
* 待复查数量
*/
private Long waitReview;
/**
* 已闭环数量
*/
private Long closed;
/**
* 逾期数量
*/
private Long overdue;
}

View File

@ -66,6 +66,11 @@ public class HseRecognizeRecordVo implements Serializable {
@ExcelDictFormat(dictType = "violation_level_type") @ExcelDictFormat(dictType = "violation_level_type")
private String violationType; private String violationType;
/**
* 原始图片id
*/
private Long originalUrlId;
/** /**
* 原始图片 * 原始图片
*/ */

View File

@ -41,12 +41,24 @@ public class HseSafetyLogVo implements Serializable {
@ExcelProperty(value = "项目id") @ExcelProperty(value = "项目id")
private Long projectId; private Long projectId;
/**
* 类型 1-文字2-文件
*/
private String type;
/** /**
* 发生日期 * 发生日期
*/ */
@ExcelProperty(value = "发生日期") @ExcelProperty(value = "发生日期")
private String dateOfOccurrence; private String dateOfOccurrence;
/**
* 结束日期
*/
private String endDate;
/** /**
* 最高气温 * 最高气温
*/ */

View File

@ -0,0 +1,15 @@
package org.dromara.safety.mapper;
import org.dromara.safety.domain.HazardHiddenDanger;
import org.dromara.safety.domain.vo.HazardHiddenDangerVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 隐患信息Mapper接口
*
* @author Lion Li
* @date 2025-12-03
*/
public interface HazardHiddenDangerMapper extends BaseMapperPlus<HazardHiddenDanger, HazardHiddenDangerVo> {
}

View File

@ -0,0 +1,15 @@
package org.dromara.safety.mapper;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.safety.domain.HazardRule;
import org.dromara.safety.domain.vo.HazardRuleVo;
/**
* 隐患分级通知规则Mapper接口
*
* @author lilemy
* @date 2025-12-03
*/
public interface HazardRuleMapper extends BaseMapperPlus<HazardRule, HazardRuleVo> {
}

View File

@ -0,0 +1,15 @@
package org.dromara.safety.mapper;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.safety.domain.HazardRuleNotifyObject;
import org.dromara.safety.domain.vo.HazardRuleNotifyObjectVo;
/**
* 隐患规则通知对象Mapper接口
*
* @author lilemy
* @date 2025-12-03
*/
public interface HazardRuleNotifyObjectMapper extends BaseMapperPlus<HazardRuleNotifyObject, HazardRuleNotifyObjectVo> {
}

View File

@ -0,0 +1,92 @@
package org.dromara.safety.service;
import org.dromara.safety.domain.dto.EvaluateDto;
import org.dromara.safety.domain.vo.HazardHiddenDangerVo;
import org.dromara.safety.domain.bo.HazardHiddenDangerBo;
import org.dromara.safety.domain.HazardHiddenDanger;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.safety.domain.vo.HiddenDangerCountVo;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.Collection;
import java.util.List;
/**
* 隐患信息Service接口
*
* @author Lion Li
* @date 2025-12-03
*/
public interface IHazardHiddenDangerService extends IService<HazardHiddenDanger>{
/**
* 查询隐患信息
*
* @param id 主键
* @return 隐患信息
*/
HazardHiddenDangerVo queryById(Long id);
/**
* 分页查询隐患信息列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 隐患信息分页列表
*/
TableDataInfo<HazardHiddenDangerVo> queryPageList(HazardHiddenDangerBo bo, PageQuery pageQuery);
/**
* 查询符合条件的隐患信息列表
*
* @param bo 查询条件
* @return 隐患信息列表
*/
List<HazardHiddenDangerVo> queryList(HazardHiddenDangerBo bo);
/**
* 新增隐患信息
*
* @param bo 隐患信息
* @return 是否新增成功
*/
Boolean insertByBo(HazardHiddenDangerBo bo);
/**
* 修改隐患信息
*
* @param bo 隐患信息
* @return 是否修改成功
*/
Boolean updateByBo(HazardHiddenDangerBo bo);
/**
* 校验并批量删除隐患信息信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 隐患统计
*
* @param projectId 项目ID
* @return 隐患统计信息
*/
HiddenDangerCountVo dangerCount(Long projectId);
/**
* 评估隐患
*
* @param dto 评估信息
* @return 是否评估成功
*/
Boolean evaluate(EvaluateDto dto);
}

View File

@ -0,0 +1,70 @@
package org.dromara.safety.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.safety.domain.HazardRuleNotifyObject;
import org.dromara.safety.domain.bo.HazardRuleNotifyObjectBo;
import org.dromara.safety.domain.vo.HazardRuleNotifyObjectVo;
import java.util.Collection;
import java.util.List;
/**
* 隐患规则通知对象Service接口
*
* @author lilemy
* @date 2025-12-03
*/
public interface IHazardRuleNotifyObjectService extends IService<HazardRuleNotifyObject> {
/**
* 查询隐患规则通知对象
*
* @param ruleId 主键
* @return 隐患规则通知对象
*/
HazardRuleNotifyObjectVo queryById(Long ruleId);
/**
* 分页查询隐患规则通知对象列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 隐患规则通知对象分页列表
*/
TableDataInfo<HazardRuleNotifyObjectVo> queryPageList(HazardRuleNotifyObjectBo bo, PageQuery pageQuery);
/**
* 查询符合条件的隐患规则通知对象列表
*
* @param bo 查询条件
* @return 隐患规则通知对象列表
*/
List<HazardRuleNotifyObjectVo> queryList(HazardRuleNotifyObjectBo bo);
/**
* 新增隐患规则通知对象
*
* @param bo 隐患规则通知对象
* @return 是否新增成功
*/
Boolean insertByBo(HazardRuleNotifyObjectBo bo);
/**
* 修改隐患规则通知对象
*
* @param bo 隐患规则通知对象
* @return 是否修改成功
*/
Boolean updateByBo(HazardRuleNotifyObjectBo bo);
/**
* 校验并批量删除隐患规则通知对象信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -0,0 +1,70 @@
package org.dromara.safety.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.safety.domain.HazardRule;
import org.dromara.safety.domain.bo.HazardRuleBo;
import org.dromara.safety.domain.vo.HazardRuleVo;
import java.util.Collection;
import java.util.List;
/**
* 隐患分级通知规则Service接口
*
* @author lilemy
* @date 2025-12-03
*/
public interface IHazardRuleService extends IService<HazardRule> {
/**
* 查询隐患分级通知规则
*
* @param id 主键
* @return 隐患分级通知规则
*/
HazardRuleVo queryById(Long id);
/**
* 分页查询隐患分级通知规则列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 隐患分级通知规则分页列表
*/
TableDataInfo<HazardRuleVo> queryPageList(HazardRuleBo bo, PageQuery pageQuery);
/**
* 查询符合条件的隐患分级通知规则列表
*
* @param bo 查询条件
* @return 隐患分级通知规则列表
*/
List<HazardRuleVo> queryList(HazardRuleBo bo);
/**
* 新增隐患分级通知规则
*
* @param bo 隐患分级通知规则
* @return 是否新增成功
*/
Boolean insertByBo(HazardRuleBo bo);
/**
* 修改隐患分级通知规则
*
* @param bo 隐患分级通知规则
* @return 是否修改成功
*/
Boolean updateByBo(HazardRuleBo bo);
/**
* 校验并批量删除隐患分级通知规则信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -0,0 +1,194 @@
package org.dromara.safety.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.safety.domain.HazardRule;
import org.dromara.safety.domain.dto.EvaluateDto;
import org.dromara.safety.domain.vo.HiddenDangerCountVo;
import org.dromara.safety.service.IHazardRuleService;
import org.springframework.stereotype.Service;
import org.dromara.safety.domain.bo.HazardHiddenDangerBo;
import org.dromara.safety.domain.vo.HazardHiddenDangerVo;
import org.dromara.safety.domain.HazardHiddenDanger;
import org.dromara.safety.mapper.HazardHiddenDangerMapper;
import org.dromara.safety.service.IHazardHiddenDangerService;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 隐患信息Service业务层处理
*
* @author Lion Li
* @date 2025-12-03
*/
@RequiredArgsConstructor
@Service
public class HazardHiddenDangerServiceImpl extends ServiceImpl<HazardHiddenDangerMapper, HazardHiddenDanger>
implements IHazardHiddenDangerService {
private final HazardHiddenDangerMapper baseMapper;
private final IHazardRuleService hazardRuleService;
/**
* 查询隐患信息
*
* @param id 主键
* @return 隐患信息
*/
@Override
public HazardHiddenDangerVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 分页查询隐患信息列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 隐患信息分页列表
*/
@Override
public TableDataInfo<HazardHiddenDangerVo> queryPageList(HazardHiddenDangerBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<HazardHiddenDanger> lqw = buildQueryWrapper(bo);
Page<HazardHiddenDangerVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的隐患信息列表
*
* @param bo 查询条件
* @return 隐患信息列表
*/
@Override
public List<HazardHiddenDangerVo> queryList(HazardHiddenDangerBo bo) {
LambdaQueryWrapper<HazardHiddenDanger> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<HazardHiddenDanger> buildQueryWrapper(HazardHiddenDangerBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<HazardHiddenDanger> lqw = Wrappers.lambdaQuery();
lqw.orderByDesc(HazardHiddenDanger::getId);
lqw.eq(bo.getProjectId()!=null, HazardHiddenDanger::getProjectId, bo.getProjectId());
lqw.eq(StringUtils.isNotBlank(bo.getDangerType()), HazardHiddenDanger::getDangerType, bo.getDangerType());
lqw.eq(StringUtils.isNotBlank(bo.getDangerCode()), HazardHiddenDanger::getDangerCode, bo.getDangerCode());
lqw.like(StringUtils.isNotBlank(bo.getDangerName()), HazardHiddenDanger::getDangerName, bo.getDangerName());
lqw.eq(StringUtils.isNotBlank(bo.getReportLocation()), HazardHiddenDanger::getReportLocation, bo.getReportLocation());
lqw.eq(bo.getReporter() != null, HazardHiddenDanger::getReporter, bo.getReporter());
lqw.eq(bo.getReportTime() != null, HazardHiddenDanger::getReportTime, bo.getReportTime());
lqw.eq(bo.getDangerLevelId() != null, HazardHiddenDanger::getDangerLevelId, bo.getDangerLevelId());
lqw.eq(bo.getEvaluator() != null, HazardHiddenDanger::getEvaluator, bo.getEvaluator());
lqw.eq(bo.getEvaluateTime() != null, HazardHiddenDanger::getEvaluateTime, bo.getEvaluateTime());
lqw.eq(StringUtils.isNotBlank(bo.getEvaluateBasis()), HazardHiddenDanger::getEvaluateBasis, bo.getEvaluateBasis());
lqw.eq(StringUtils.isNotBlank(bo.getReporterOpinion()), HazardHiddenDanger::getReporterOpinion, bo.getReporterOpinion());
lqw.eq(StringUtils.isNotBlank(bo.getReporterFile()), HazardHiddenDanger::getReporterFile, bo.getReporterFile());
lqw.eq(bo.getRectifyTime() != null, HazardHiddenDanger::getRectifyTime, bo.getRectifyTime());
lqw.eq(StringUtils.isNotBlank(bo.getRectifyUnit()), HazardHiddenDanger::getRectifyUnit, bo.getRectifyUnit());
lqw.eq(bo.getRectifyUnitId() != null, HazardHiddenDanger::getRectifyUnitId, bo.getRectifyUnitId());
lqw.eq(bo.getRectifyUserId() != null, HazardHiddenDanger::getRectifyUserId, bo.getRectifyUserId());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), HazardHiddenDanger::getStatus, bo.getStatus());
return lqw;
}
/**
* 新增隐患信息
*
* @param bo 隐患信息
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(HazardHiddenDangerBo bo) {
HazardHiddenDanger add = MapstructUtils.convert(bo, HazardHiddenDanger.class);
validEntityBeforeSave(add);
Snowflake snowflake = IdUtil.getSnowflake(1, 1);
long id = snowflake.nextId();
add.setDangerCode("YH-"+id);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改隐患信息
*
* @param bo 隐患信息
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(HazardHiddenDangerBo bo) {
HazardHiddenDanger update = MapstructUtils.convert(bo, HazardHiddenDanger.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(HazardHiddenDanger entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除隐患信息信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
@Override
public HiddenDangerCountVo dangerCount(Long projectId) {
List<HazardHiddenDanger> list = lambdaQuery().eq(HazardHiddenDanger::getProjectId, projectId).list();
HiddenDangerCountVo count = new HiddenDangerCountVo();
count.setTotal(list.size());
count.setWaitEvaluate(list.stream().filter(item -> item.getStatus().equals(HazardHiddenDanger.EVALUATE)).count());
count.setWaitRectify(list.stream().filter(item -> item.getStatus().equals(HazardHiddenDanger.RECTIFY)).count());
count.setWaitReview(list.stream().filter(item -> item.getStatus().equals(HazardHiddenDanger.REVIEW)).count());
count.setClosed(list.stream().filter(item -> item.getStatus().equals(HazardHiddenDanger.CLOSED)).count());
count.setOverdue(list.stream().filter(item ->item.getRectifyTime()!=null && item.getRectifyTime().isBefore(LocalDateTime.now())
&& item.getStatus().equals(HazardHiddenDanger.RECTIFY)).count());
return count;
}
@Override
public Boolean evaluate(EvaluateDto dto) {
HazardHiddenDanger hazardHiddenDanger = baseMapper.selectById(dto.getId());
BeanUtil.copyProperties(dto,hazardHiddenDanger);
HazardRule byId = hazardRuleService.getById(hazardHiddenDanger.getDangerLevelId());
String responseUnit = byId.getResponseUnit();
hazardHiddenDanger.setStatus(HazardHiddenDanger.RECTIFY);
LocalDateTime now = LocalDateTime.now();
if (responseUnit.equals("3")) {
hazardHiddenDanger.setRectifyTime(now.plusDays(byId.getResponseTime()));
} else if (responseUnit.equals("2")) {
hazardHiddenDanger.setRectifyTime(now.plusHours(byId.getResponseTime()));
} else if (responseUnit.equals("1")) {
hazardHiddenDanger.setRectifyTime(now.plusMinutes(byId.getResponseTime()));
}
return baseMapper.updateById(hazardHiddenDanger) > 0;
}
}

View File

@ -0,0 +1,131 @@
package org.dromara.safety.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.safety.domain.HazardRuleNotifyObject;
import org.dromara.safety.domain.bo.HazardRuleNotifyObjectBo;
import org.dromara.safety.domain.vo.HazardRuleNotifyObjectVo;
import org.dromara.safety.mapper.HazardRuleNotifyObjectMapper;
import org.dromara.safety.service.IHazardRuleNotifyObjectService;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 隐患规则通知对象Service业务层处理
*
* @author lilemy
* @date 2025-12-03
*/
@RequiredArgsConstructor
@Service
public class HazardRuleNotifyObjectServiceImpl extends ServiceImpl<HazardRuleNotifyObjectMapper, HazardRuleNotifyObject>
implements IHazardRuleNotifyObjectService {
/**
* 查询隐患规则通知对象
*
* @param ruleId 主键
* @return 隐患规则通知对象
*/
@Override
public HazardRuleNotifyObjectVo queryById(Long ruleId) {
return baseMapper.selectVoById(ruleId);
}
/**
* 分页查询隐患规则通知对象列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 隐患规则通知对象分页列表
*/
@Override
public TableDataInfo<HazardRuleNotifyObjectVo> queryPageList(HazardRuleNotifyObjectBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<HazardRuleNotifyObject> lqw = buildQueryWrapper(bo);
Page<HazardRuleNotifyObjectVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的隐患规则通知对象列表
*
* @param bo 查询条件
* @return 隐患规则通知对象列表
*/
@Override
public List<HazardRuleNotifyObjectVo> queryList(HazardRuleNotifyObjectBo bo) {
LambdaQueryWrapper<HazardRuleNotifyObject> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<HazardRuleNotifyObject> buildQueryWrapper(HazardRuleNotifyObjectBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<HazardRuleNotifyObject> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getRuleId() != null, HazardRuleNotifyObject::getRuleId, bo.getRuleId());
lqw.eq(bo.getNotifyId() != null, HazardRuleNotifyObject::getNotifyId, bo.getNotifyId());
lqw.eq(StringUtils.isNotBlank(bo.getNotifyType()), HazardRuleNotifyObject::getNotifyType, bo.getNotifyType());
return lqw;
}
/**
* 新增隐患规则通知对象
*
* @param bo 隐患规则通知对象
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(HazardRuleNotifyObjectBo bo) {
HazardRuleNotifyObject add = MapstructUtils.convert(bo, HazardRuleNotifyObject.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setRuleId(add.getRuleId());
}
return flag;
}
/**
* 修改隐患规则通知对象
*
* @param bo 隐患规则通知对象
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(HazardRuleNotifyObjectBo bo) {
HazardRuleNotifyObject update = MapstructUtils.convert(bo, HazardRuleNotifyObject.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(HazardRuleNotifyObject entity) {
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除隐患规则通知对象信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

View File

@ -0,0 +1,137 @@
package org.dromara.safety.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.safety.domain.HazardRule;
import org.dromara.safety.domain.bo.HazardRuleBo;
import org.dromara.safety.domain.vo.HazardRuleVo;
import org.dromara.safety.mapper.HazardRuleMapper;
import org.dromara.safety.service.IHazardRuleService;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 隐患分级通知规则Service业务层处理
*
* @author lilemy
* @date 2025-12-03
*/
@RequiredArgsConstructor
@Service
public class HazardRuleServiceImpl extends ServiceImpl<HazardRuleMapper, HazardRule>
implements IHazardRuleService {
/**
* 查询隐患分级通知规则
*
* @param id 主键
* @return 隐患分级通知规则
*/
@Override
public HazardRuleVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 分页查询隐患分级通知规则列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 隐患分级通知规则分页列表
*/
@Override
public TableDataInfo<HazardRuleVo> queryPageList(HazardRuleBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<HazardRule> lqw = buildQueryWrapper(bo);
Page<HazardRuleVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的隐患分级通知规则列表
*
* @param bo 查询条件
* @return 隐患分级通知规则列表
*/
@Override
public List<HazardRuleVo> queryList(HazardRuleBo bo) {
LambdaQueryWrapper<HazardRule> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<HazardRule> buildQueryWrapper(HazardRuleBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<HazardRule> lqw = Wrappers.lambdaQuery();
lqw.orderByDesc(HazardRule::getId);
lqw.eq(bo.getProjectId() != null, HazardRule::getProjectId, bo.getProjectId());
lqw.eq(StringUtils.isNotBlank(bo.getHazardLevel()), HazardRule::getHazardLevel, bo.getHazardLevel());
lqw.eq(bo.getHazardWeight() != null, HazardRule::getHazardWeight, bo.getHazardWeight());
lqw.eq(bo.getResponseTime() != null, HazardRule::getResponseTime, bo.getResponseTime());
lqw.eq(StringUtils.isNotBlank(bo.getResponseUnit()), HazardRule::getResponseUnit, bo.getResponseUnit());
lqw.eq(StringUtils.isNotBlank(bo.getNotifyMethod()), HazardRule::getNotifyMethod, bo.getNotifyMethod());
lqw.eq(StringUtils.isNotBlank(bo.getTimeoutAction()), HazardRule::getTimeoutAction, bo.getTimeoutAction());
lqw.eq(StringUtils.isNotBlank(bo.getExtraSetting()), HazardRule::getExtraSetting, bo.getExtraSetting());
return lqw;
}
/**
* 新增隐患分级通知规则
*
* @param bo 隐患分级通知规则
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(HazardRuleBo bo) {
HazardRule add = MapstructUtils.convert(bo, HazardRule.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改隐患分级通知规则
*
* @param bo 隐患分级通知规则
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(HazardRuleBo bo) {
HazardRule update = MapstructUtils.convert(bo, HazardRule.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(HazardRule 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

@ -198,7 +198,7 @@ public class HseSafetyInspectionServiceImpl extends ServiceImpl<HseSafetyInspect
if (CollUtil.isNotEmpty(teamMeetings)) { if (CollUtil.isNotEmpty(teamMeetings)) {
// 获取最新的班组列表 // 获取最新的班组列表
List<HseTeamMeeting> topList = teamMeetings.stream() List<HseTeamMeeting> topList = teamMeetings.stream()
.sorted(Comparator.comparing(HseTeamMeeting::getCreateTime).reversed()) .sorted(Comparator.comparing(HseTeamMeeting::getMeetingDate).reversed())
.limit(Optional.ofNullable(req.getPageSize()).orElse(20)) .limit(Optional.ofNullable(req.getPageSize()).orElse(20))
.toList(); .toList();
List<Long> teamIds = topList.stream().map(HseTeamMeeting::getTeamId).toList(); List<Long> teamIds = topList.stream().map(HseTeamMeeting::getTeamId).toList();
@ -224,6 +224,7 @@ public class HseSafetyInspectionServiceImpl extends ServiceImpl<HseSafetyInspect
.eq(HseSafetyInspection::getProjectId, projectId) .eq(HseSafetyInspection::getProjectId, projectId)
.list(); .list();
List<HseSafetyInspection> passList = safetyInspectionList.stream() List<HseSafetyInspection> passList = safetyInspectionList.stream()
.sorted(Comparator.comparing(HseSafetyInspection::getCheckTime).reversed())
.filter(q -> "1".equals(q.getIsReply())) .filter(q -> "1".equals(q.getIsReply()))
.filter(q -> !q.getStatus().equals(HseSafetyInspectionStatusEnum.INFORM.getValue())) .filter(q -> !q.getStatus().equals(HseSafetyInspectionStatusEnum.INFORM.getValue()))
.toList(); .toList();
@ -234,6 +235,7 @@ public class HseSafetyInspectionServiceImpl extends ServiceImpl<HseSafetyInspect
}).toList(); }).toList();
List<HseSafetyInspectionGis> inspections = safetyInspectionList.stream() List<HseSafetyInspectionGis> inspections = safetyInspectionList.stream()
// .filter(q -> "2".equals(q.getIsReply())) // .filter(q -> "2".equals(q.getIsReply()))
.sorted(Comparator.comparing(HseSafetyInspection::getCheckTime).reversed())
.toList() .toList()
.stream().map(p -> { .stream().map(p -> {
HseSafetyInspectionGis gis = new HseSafetyInspectionGis(); HseSafetyInspectionGis gis = new HseSafetyInspectionGis();

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.safety.mapper.HazardHiddenDangerMapper">
</mapper>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.safety.mapper.HazardRuleMapper">
</mapper>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.safety.mapper.HazardRuleNotifyObjectMapper">
</mapper>

View File

@ -1974,3 +1974,53 @@ CREATE TABLE `gps_safety_user_record`
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id' INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id'
) comment '安全员轨迹信息'; ) comment '安全员轨迹信息';
CREATE TABLE hazard_rule
(
`id` bigint not null auto_increment comment '主键',
`project_id` bigint not null comment '项目id',
`hazard_level` varchar(64) not null comment '隐患级别',
`hazard_weight` int not null comment '隐患权重',
`response_time` int not null comment '响应时限数值',
`response_unit` varchar(20) not null comment '响应时效单位',
`notify_method` varchar(20) not null comment '通知方式',
`timeout_action` varchar(50) not null comment '超时处理方式',
`extra_setting` varchar(20) not null comment '额外设置',
`remark` varchar(512) null comment '备注',
`create_by` bigint null comment '创建者',
`update_by` bigint null comment '更新者',
`create_dept` bigint null comment '创建部门',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
PRIMARY KEY (`id`) USING BTREE,
index `idx_project_id` (`project_id` asc) using btree comment '项目ID'
) comment '隐患分级通知规则';
CREATE TABLE hazard_rule_notify_object
(
rule_id BIGINT NOT NULL COMMENT '规则ID',
notify_id BIGINT NOT NULL COMMENT '通知ID',
notify_type VARCHAR(20) NOT NULL COMMENT '通知类型',
index `idx_rule_id` (`rule_id` asc) using btree comment '规则ID'
) comment '隐患规则通知对象';
-- 菜单 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1996139632219136001, '隐患分级通知规则', '1996118434672001025', '1', 'rule', 'safety/rule/index', 1, 0, 'C', '0', '0', 'safety:rule:list', '#', 103, 1, sysdate(), null, null, '隐患分级通知规则菜单');
-- 按钮 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1996139632219136002, '隐患分级通知规则查询', 1996139632219136001, '1', '#', '', 1, 0, 'F', '0', '0', 'safety:rule:query', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1996139632219136003, '隐患分级通知规则新增', 1996139632219136001, '2', '#', '', 1, 0, 'F', '0', '0', 'safety:rule:add', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1996139632219136004, '隐患分级通知规则修改', 1996139632219136001, '3', '#', '', 1, 0, 'F', '0', '0', 'safety:rule:edit', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1996139632219136005, '隐患分级通知规则删除', 1996139632219136001, '4', '#', '', 1, 0, 'F', '0', '0', 'safety:rule:remove', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1996139632219136006, '隐患分级通知规则导出', 1996139632219136001, '5', '#', '', 1, 0, 'F', '0', '0', 'safety:rule:export', '#', 103, 1, sysdate(), null, null, '');