大图合并、进度计划日报

This commit is contained in:
lcj
2025-11-17 19:22:17 +08:00
parent 891c205233
commit c3ce1c22d3
20 changed files with 399 additions and 79 deletions

View File

@ -336,8 +336,8 @@ ys7:
app-key: 3acf9f1a43dc4209841e0893003db0a2
app-secret: 09e29c70ae1161fbc3ce2030fc09ba2e
job:
capture-enabled: true # 控制是否启用萤石抓拍任务
device-sync-enabled: true # 控制是否同步萤石设备
capture-enabled: false # 控制是否启用萤石抓拍任务
device-sync-enabled: false # 控制是否同步萤石设备
# 斯巴达算法
sparta:
url: http://119.3.204.120:8040

View File

@ -33,6 +33,11 @@ public class DroDroneBigPicture extends BaseEntity {
*/
private Long projectId;
/**
* 任务ID
*/
private String taskId;
/**
* 任务名称
*/

View File

@ -35,13 +35,18 @@ public class DroDroneBigPictureBo extends BaseEntity {
/**
* 项目ID
*/
@NotNull(message = "项目ID不能为空", groups = {AddGroup.class, EditGroup.class})
@NotNull(message = "项目ID不能为空", groups = {AddGroup.class})
private Long projectId;
/**
* 任务ID
*/
private String taskId;
/**
* 任务名称
*/
@NotBlank(message = "任务名称不能为空", groups = {AddGroup.class, EditGroup.class})
@NotBlank(message = "任务名称不能为空", groups = {AddGroup.class})
private String taskName;
/**

View File

@ -38,6 +38,12 @@ public class DroDroneBigPictureVo implements Serializable {
@ExcelProperty(value = "项目ID")
private Long projectId;
/**
* 任务ID
*/
@ExcelProperty(value = "任务ID")
private String taskId;
/**
* 任务名称
*/

View File

@ -75,4 +75,18 @@ public interface IDroDroneBigPictureService extends IService<DroDroneBigPicture>
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 是否合成完成
*
* @param picture 大图信息
*/
String isSynthesisCompleted(DroDroneBigPicture picture);
/**
* 是否合成完成
*
* @param pictureVo 大图信息
*/
String isSynthesisCompleted(DroDroneBigPictureVo pictureVo);
}

View File

@ -1,11 +1,13 @@
package org.dromara.drone.service.impl;
import cn.hutool.core.collection.CollUtil;
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 jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
@ -16,11 +18,16 @@ import org.dromara.drone.domain.bo.DroDroneBigPictureBo;
import org.dromara.drone.domain.vo.DroDroneBigPictureVo;
import org.dromara.drone.mapper.DroDroneBigPictureMapper;
import org.dromara.drone.service.IDroDroneBigPictureService;
import org.dromara.manager.dronemanager.DroneManager;
import org.dromara.manager.dronemanager.vo.DroneImgMergeProgressVo;
import org.dromara.manager.dronemanager.vo.DroneImgMergeUrlVo;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailAINumberReq;
import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@ -31,6 +38,7 @@ import java.util.Map;
* @author lilemy
* @date 2025-11-15
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictureMapper, DroDroneBigPicture>
@ -40,6 +48,9 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
@Resource
private IPgsProgressPlanDetailService progressPlanDetailService;
@Resource
private DroneManager droneManager;
/**
* 查询无人机大图信息
*
@ -48,7 +59,19 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
*/
@Override
public DroDroneBigPictureVo queryById(Long id) {
return baseMapper.selectVoById(id);
DroDroneBigPictureVo pictureVo = baseMapper.selectVoById(id);
if (pictureVo != null) {
String synthesisCompleted = null;
try {
synthesisCompleted = this.isSynthesisCompleted(pictureVo);
if (StringUtils.isNotBlank(synthesisCompleted)) {
pictureVo.setStatus(synthesisCompleted);
}
} catch (Exception e) {
log.error("查询图片合成进度异常", e);
}
}
return pictureVo;
}
/**
@ -62,6 +85,23 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
public TableDataInfo<DroDroneBigPictureVo> queryPageList(DroDroneBigPictureBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<DroDroneBigPicture> lqw = buildQueryWrapper(bo);
Page<DroDroneBigPictureVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
List<DroDroneBigPictureVo> records = result.getRecords();
if (CollUtil.isNotEmpty(records)) {
// 处理数据,判断合成中的图片是否完成合成
for (DroDroneBigPictureVo pictureVo : records) {
try {
String synthesisCompleted = this.isSynthesisCompleted(pictureVo);
if (StringUtils.isNotBlank(synthesisCompleted)) {
pictureVo.setStatus(synthesisCompleted);
}
} catch (Exception e) {
pictureVo.setStatus("4");
pictureVo.setRemark(e.getMessage());
log.error("查询图片合成进度异常", e);
}
}
}
result.setRecords(records);
return TableDataInfo.build(result);
}
@ -133,11 +173,32 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
if (bigPicture == null) {
throw new ServiceException("无人机大图数据不存在");
}
// todo 创建识别进度
// 判断当前状态是否可以进行识别
String status = bigPicture.getStatus();
if (!"3".equals(status) && !"7".equals(status)) {
throw new ServiceException("当前状态无法进行识别");
}
String fileUrl;
String tifUrl;
String taskId = bigPicture.getTaskId();
// 获取识别图片地址
if (StringUtils.isNotBlank(taskId)) {
DroneImgMergeUrlVo mergeUrlVo = droneManager.getMergedFileUrl(taskId);
fileUrl = mergeUrlVo.getPngUrl();
tifUrl = mergeUrlVo.getTifUrl();
} else {
fileUrl = bigPicture.getBigPic();
tifUrl = bigPicture.getTifFile();
}
// 创建进度识别
PgsProgressPlanDetailAINumberReq ai = new PgsProgressPlanDetailAINumberReq();
ai.setFileUrl(bigPicture.getBigPic());
ai.setTifUrl(bigPicture.getTifFile());
Boolean b = progressPlanDetailService.insertNumberDetailByAI(ai);
ai.setFileUrl(fileUrl);
ai.setTifUrl(tifUrl);
ai.setProjectId(bigPicture.getProjectId());
Boolean b = progressPlanDetailService.insertNumberDetailByAI(ai, bigPicture);
if (!b) {
throw new ServiceException("创建识别进度失败");
}
return true;
}
@ -162,4 +223,54 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 是否合成完成
*
* @param picture 大图信息
*/
@Override
public String isSynthesisCompleted(DroDroneBigPicture picture) {
String newStatus = "";
String status = picture.getStatus();
String taskId = picture.getTaskId();
if (taskId == null) {
return newStatus;
}
if (!status.equals("2")) {
return newStatus;
}
DroneImgMergeProgressVo progress = droneManager.getImgMergeProgress(taskId);
if (progress == null) {
return newStatus;
}
BigDecimal msg = progress.getMsg();
if (msg != null && msg.compareTo(BigDecimal.ONE) == 0) {
newStatus = "3";
picture.setStatus(newStatus);
} else if (msg != null && msg.compareTo(BigDecimal.ZERO) >= 0 && msg.compareTo(BigDecimal.ONE) < 0) {
return newStatus;
} else {
newStatus = "4";
picture.setStatus(newStatus);
}
// 修改状态
boolean b = this.updateById(picture);
if (!b) {
log.error("修改无人机大图信息状态失败");
}
return newStatus;
}
/**
* 是否合成完成
*
* @param pictureVo 大图信息
*/
@Override
public String isSynthesisCompleted(DroDroneBigPictureVo pictureVo) {
DroDroneBigPicture picture = new DroDroneBigPicture();
BeanUtils.copyProperties(pictureVo, picture);
return this.isSynthesisCompleted(picture);
}
}

View File

@ -44,7 +44,6 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -825,7 +824,6 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
* @param coordinateList 识别结果
* @param type 类型
*/
@Async
@Override
@Transactional(rollbackFor = Exception.class)
public void updateFinishNumberByCoordinate(List<Long> projectIds,

View File

@ -50,7 +50,6 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -764,7 +763,6 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
* @param coordinateList 坐标列表
* @param type 类型
*/
@Async
@Override
@Transactional(rollbackFor = Exception.class)
public void updateFinishNumberByCoordinate(List<Long> projectIds,
@ -791,17 +789,18 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
}
}
if (CollUtil.isNotEmpty(finishPanelList)) {
LocalDate now = LocalDate.now();
// 更新完成状态
boolean update = this.lambdaUpdate()
.in(FacPhotovoltaicPanel::getId, finishPanelList.stream().map(FacPhotovoltaicPanel::getId).toList())
.set(FacPhotovoltaicPanel::getStatus, FacFinishStatusEnum.FINISH.getValue())
.set(FacPhotovoltaicPanel::getFinishType, FacFinishTypeEnum.AI.getValue())
.set(FacPhotovoltaicPanel::getFinishDate, now)
.update();
if (update) {
Map<Long, List<FacPhotovoltaicPanel>> mapByCategory = finishPanelList.stream()
.collect(Collectors.groupingBy(FacPhotovoltaicPanel::getProgressCategoryId));
// 判断当天是否有存在的计划
LocalDate now = LocalDate.now();
for (Map.Entry<Long, List<FacPhotovoltaicPanel>> entry : mapByCategory.entrySet()) {
Long categoryId = entry.getKey();
PgsProgressCategory category = progressCategoryService.getById(categoryId);
@ -836,9 +835,10 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
}
// 更新计划数量
Long planId = planDetail.getProgressPlanId();
PgsProgressPlan oldPlan = progressPlanService.getById(planId);
PgsProgressPlan plan = new PgsProgressPlan();
plan.setId(planId);
plan.setFinishedNumber(plan.getFinishedNumber().add(size));
plan.setFinishedNumber(oldPlan.getFinishedNumber().add(size));
boolean result2 = progressPlanService.updateById(plan);
if (!result2) {
throw new ServiceException("更新进度计划失败,数据库操作失败", HttpStatus.ERROR);

View File

@ -18,15 +18,15 @@ public interface DroneConstant {
String CREATE_IMG_MERGE_TASK = "/pure/image/synthesis/createTask";
/**
* 下载图片合成结果 GET
* 获取图片合成结果 GET
*
*/
String DOWNLOAD_MERGED_FILE = "/pure/image/synthesis/download";
String GET_MERGED_FILE_URL = "/pure/image/synthesis/getResultUrls";
/**
* 查询图片合成进度 GET
*
*/
String GET_IMG_MERGE_PROGRESS = "/pure/image/synthesis/queryProgress";
String GET_IMG_MERGE_PROGRESS = "/pure/image/synthesis/queryGeneralTaskProgress";
}

View File

@ -2,6 +2,8 @@ package org.dromara.manager.dronemanager;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.manager.dronemanager.vo.DroneImgMergeProgressVo;
import org.dromara.manager.dronemanager.vo.DroneImgMergeUrlVo;
import org.springframework.stereotype.Component;
import java.util.List;
@ -33,18 +35,8 @@ public class DroneManager {
* @param businessName 业务名称
* @param imageUrls 图片URL列表
*/
public void createImageMergeTask(String businessName, List<String> imageUrls) {
DroneRequestUtils.createImgMergeTask(droneProperties.getUrl(), businessName, imageUrls);
}
/**
* 获取图片合成结果
*
* @param taskId 任务ID
* @param fileType 文件类型(png/tif)
*/
public void downloadMergedFile(String taskId, String fileType) {
DroneRequestUtils.downloadMergedFile(droneProperties.getUrl(), taskId, fileType);
public String createImageMergeTask(String businessName, List<String> imageUrls) {
return DroneRequestUtils.createImgMergeTask(droneProperties.getUrl(), businessName, imageUrls);
}
/**
@ -52,8 +44,17 @@ public class DroneManager {
*
* @param taskId 任务ID
*/
public void getImgMergeProgress(String taskId) {
DroneRequestUtils.getImgMergeProgress(droneProperties.getUrl(), taskId);
public DroneImgMergeUrlVo getMergedFileUrl(String taskId) {
return DroneRequestUtils.getMergedFileUrl(droneProperties.getUrl(), taskId);
}
/**
* 获取图片合成结果
*
* @param taskId 任务ID
*/
public DroneImgMergeProgressVo getImgMergeProgress(String taskId) {
return DroneRequestUtils.getImgMergeProgress(droneProperties.getUrl(), taskId);
}
}

View File

@ -10,6 +10,8 @@ import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.manager.dronemanager.vo.DroneImgMergeProgressVo;
import org.dromara.manager.dronemanager.vo.DroneImgMergeUrlVo;
import java.util.List;
@ -66,7 +68,7 @@ public class DroneRequestUtils {
* @param businessName 业务名称
* @param imageUrls 图片URL列表
*/
public static void createImgMergeTask(String url, String businessName, List<String> imageUrls) {
public static String createImgMergeTask(String url, String businessName, List<String> imageUrls) {
if (StringUtils.isBlank(businessName) || CollUtil.isEmpty(imageUrls)) {
throw new ServiceException("创建图片合成任务请求参数错误", HttpStatus.BAD_REQUEST);
}
@ -89,28 +91,24 @@ public class DroneRequestUtils {
log.error("{},状态码:{},错误信息:{}", errorMsg, obj.get("code"), obj.get("msg"));
throw new ServiceException(errorMsg + obj.get("msg"));
}
log.info("创建图片合成任务请求成功");
log.info("创建图片合成任务请求成功taskId => {}", obj.get("data"));
return obj.getStr("data");
}
}
/**
* 下载图片合成结果
*
* @param taskId 任务ID
* @param fileType 文件类型(png/tif)
* @param taskId 任务ID
*/
public static void downloadMergedFile(String url, String taskId, String fileType) {
if (StringUtils.isAnyBlank(taskId, fileType)) {
public static DroneImgMergeUrlVo getMergedFileUrl(String url, String taskId) {
if (StringUtils.isAnyBlank(taskId)) {
throw new ServiceException("下载图片合成结果请求参数错误", HttpStatus.BAD_REQUEST);
}
if (!fileType.equals("png") && !fileType.equals("tif")) {
throw new ServiceException("无此文件类型", HttpStatus.BAD_REQUEST);
}
// 完整 URL
String fullUrl = url + DroneConstant.DOWNLOAD_MERGED_FILE + "/" + taskId + "/" + fileType;
String fullUrl = url + DroneConstant.GET_MERGED_FILE_URL + "/" + taskId;
String errorMsg = "下载图片合成结果请求失败";
try (HttpResponse response = HttpRequest.get(fullUrl)
.execute()) {
try (HttpResponse response = HttpRequest.get(fullUrl).execute()) {
if (!response.isOk()) {
log.error("{}{}", errorMsg, response.getStatus());
throw new ServiceException(errorMsg + response.getStatus());
@ -121,7 +119,10 @@ public class DroneRequestUtils {
log.error("{},状态码:{},错误信息:{}", errorMsg, obj.get("code"), obj.get("msg"));
throw new ServiceException(errorMsg + obj.get("msg"));
}
log.info("下载图片合成结果请求成功");
String data = obj.getStr("data");
DroneImgMergeUrlVo mergeUrlVo = JSONUtil.toBean(data, DroneImgMergeUrlVo.class);
log.info("下载图片合成结果请求成功:{}", mergeUrlVo);
return mergeUrlVo;
}
}
@ -130,7 +131,7 @@ public class DroneRequestUtils {
*
* @param taskId 任务ID
*/
public static void getImgMergeProgress(String url, String taskId) {
public static DroneImgMergeProgressVo getImgMergeProgress(String url, String taskId) {
if (StringUtils.isBlank(taskId)) {
throw new ServiceException("查询图片合成进度请求参数错误", HttpStatus.BAD_REQUEST);
}
@ -141,15 +142,20 @@ public class DroneRequestUtils {
.execute()) {
if (!response.isOk()) {
log.error("{}{}", errorMsg, response.getStatus());
throw new ServiceException(errorMsg + response.getStatus());
throw new ServiceException(errorMsg + "" + response.getStatus());
}
String body = response.body();
JSONObject obj = JSONUtil.parseObj(body);
if (!obj.getStr("code").equals("200")) {
log.error("{},状态码:{},错误信息:{}", errorMsg, obj.get("code"), obj.get("msg"));
throw new ServiceException(errorMsg + obj.get("msg"));
throw new ServiceException(errorMsg + "" + obj.get("msg"));
}
log.info("查询图片合成进度请求成功");
DroneImgMergeProgressVo progress = JSONUtil.toBean(obj, DroneImgMergeProgressVo.class);
if (progress == null) {
throw new ServiceException(errorMsg);
}
log.info("查询图片合成进度请求成功:{}", progress);
return progress;
}
}

View File

@ -0,0 +1,27 @@
package org.dromara.manager.dronemanager.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-11-17 14:41
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DroneImgMergeProgressVo {
/**
* 进度
*/
private BigDecimal msg;
/**
* 状态
*/
private String code;
}

View File

@ -0,0 +1,25 @@
package org.dromara.manager.dronemanager.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author lilemy
* @date 2025-11-17 17:13
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DroneImgMergeUrlVo {
/**
* png url
*/
private String pngUrl;
/**
* tif url
*/
private String tifUrl;
}

View File

@ -64,7 +64,7 @@ public class PgsProgressPlanDetailController extends BaseController {
*/
@PostMapping("/insert/numberAI")
public R<Void> insertNumberDetailByAI(@Validated @RequestBody PgsProgressPlanDetailAINumberReq req) {
return toAjax(pgsProgressPlanDetailService.insertNumberDetailByAI(req));
return toAjax(pgsProgressPlanDetailService.insertNumberDetailByAI(req, null));
}
/**

View File

@ -1,6 +1,5 @@
package org.dromara.progress.domain.dto.progressplandetail;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@ -20,7 +19,6 @@ public class PgsProgressPlanDetailAINumberReq implements Serializable {
/**
* 大图
*/
@NotBlank(message = "大图不能为空")
private String file;
/**
@ -31,7 +29,6 @@ public class PgsProgressPlanDetailAINumberReq implements Serializable {
/**
* tif文件
*/
@NotBlank(message = "tif文件不能为空")
private String tif;
/**

View File

@ -54,4 +54,9 @@ public class PgsProgressCategoryByDayVo {
* 总数
*/
private Integer size;
/**
* 下日计划
*/
private String nextPlanStr;
}

View File

@ -54,4 +54,9 @@ public class PgsProgressCategoryDetailByDayVo {
* 施工完成
*/
private BigDecimal constructionCompleted;
/**
* 下日计划
*/
private BigDecimal nextDayPlan;
}

View File

@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.drone.domain.DroDroneBigPicture;
import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.domain.dto.progressplandetail.*;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo;
@ -14,6 +15,7 @@ import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailVo
import java.time.LocalDate;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* 进度计划详情Service接口
@ -132,8 +134,20 @@ public interface IPgsProgressPlanDetailService extends IService<PgsProgressPlanD
/**
* 使用AI识别计划详情设施数量
*
* @param req AI识别计划详情设施数量参数
* @param req AI识别计划详情设施数量参数
* @param bigPicture 大图对象
* @return 是否成功
*/
Boolean insertNumberDetailByAI(PgsProgressPlanDetailAINumberReq req);
Boolean insertNumberDetailByAI(PgsProgressPlanDetailAINumberReq req, DroDroneBigPicture bigPicture);
/**
* 使用AI识别计划详情设施数量
*
* @param bigPictureId 大图id
* @param fileUrl 文件url
* @param tifUrl tif文件url
* @param projectIds 项目id列表
* @return 是否成功
*/
CompletableFuture<Boolean> recognizeAsync(Long bigPictureId, String fileUrl, String tifUrl, List<Long> projectIds);
}

View File

@ -2296,6 +2296,11 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
.in(PgsProgressPlanDetail::getProjectId, allProjectIds)
.eq(PgsProgressPlanDetail::getDate, date)
.list();
// 获取指定日期后一天的计划详情
List<PgsProgressPlanDetail> nextDayDetailList = progressPlanDetailService.lambdaQuery()
.in(PgsProgressPlanDetail::getProjectId, allProjectIds)
.eq(PgsProgressPlanDetail::getDate, date.plusDays(1))
.list();
// 根据项目id进行分类
Map<Long, String> projectMap = projects.stream()
.collect(Collectors.toMap(BusProject::getId, BusProject::getProjectName));
@ -2328,8 +2333,18 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
List<PgsProgressPlanDetail> planDetailList = detailList.stream()
.filter(detail -> childIds.contains(detail.getProgressCategoryId()))
.toList();
List<PgsProgressPlanDetail> nextPlanDetailList = nextDayDetailList.stream()
.filter(detail -> childIds.contains(detail.getProgressCategoryId()))
.toList();
// 将子类根据名称进行分类
List<PgsProgressCategoryDetailByDayVo> detail = this.getChildrenDetailByName(children, planDetailList);
List<PgsProgressCategoryDetailByDayVo> detail = this.getChildrenDetailByName(children, planDetailList, nextPlanDetailList);
String nextDayPlanStr = "";
if (CollUtil.isNotEmpty(detail)) {
nextDayPlanStr = detail.stream()
.map(item -> item.getName() + item.getNextDayPlan().stripTrailingZeros().toPlainString() + item.getUnit())
.collect(Collectors.joining(""));
}
vo.setNextPlanStr(nextDayPlanStr);
vo.setSize(detail.size());
switch (PgsProgressCategoryTypeEnum.fromText(nameKey)) {
case BOOSTER_STATION:
@ -2998,12 +3013,14 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
/**
* 根据子级名称分类并统计数据
*
* @param children 子级
* @param planList 计划
* @param children 子级
* @param planList 计划
* @param nextPlanList 后一天计划
* @return 分类后的数据
*/
private List<PgsProgressCategoryDetailByDayVo> getChildrenDetailByName(List<PgsProgressCategory> children,
List<PgsProgressPlanDetail> planList) {
List<PgsProgressPlanDetail> planList,
List<PgsProgressPlanDetail> nextPlanList) {
// 将子类根据名称进行分类
Map<String, List<PgsProgressCategory>> childrenMap = children.stream()
.collect(Collectors.groupingBy(PgsProgressCategory::getName));
@ -3013,6 +3030,12 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
.collect(Collectors.groupingBy(PgsProgressPlanDetail::getProgressCategoryId));
}
Map<Long, List<PgsProgressPlanDetail>> finalDetailMap = detailMap;
Map<Long, List<PgsProgressPlanDetail>> nextDetailMap = new HashMap<>();
if (CollUtil.isNotEmpty(nextPlanList)) {
nextDetailMap = nextPlanList.stream()
.collect(Collectors.groupingBy(PgsProgressPlanDetail::getProgressCategoryId));
}
Map<Long, List<PgsProgressPlanDetail>> finalNextDetailMap = detailMap;
return childrenMap.entrySet().stream()
.map(c -> {
String name = c.getKey();
@ -3034,12 +3057,15 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
.map(PgsProgressCategory::getUnit)
.filter(Objects::nonNull)
.findFirst().orElse(null);
// 获取ids
List<Long> ids = list.stream()
.map(PgsProgressCategory::getId)
.filter(Objects::nonNull)
.toList();
// 获取施工计划数量
BigDecimal constructionPlan = BigDecimal.ZERO;
if (CollUtil.isNotEmpty(finalDetailMap)) {
constructionPlan = list.stream()
.map(PgsProgressCategory::getId)
.filter(Objects::nonNull)
constructionPlan = ids.stream()
.map(finalDetailMap::get)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
@ -3050,9 +3076,7 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
// 获取施工完成数量
BigDecimal constructionCompleted = BigDecimal.ZERO;
if (CollUtil.isNotEmpty(finalDetailMap)) {
constructionPlan = list.stream()
.map(PgsProgressCategory::getId)
.filter(Objects::nonNull)
constructionPlan = ids.stream()
.map(finalDetailMap::get)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
@ -3060,6 +3084,17 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
// 获取后一天的计划
BigDecimal nextDayPlan = BigDecimal.ZERO;
if (CollUtil.isNotEmpty(finalNextDetailMap)) {
nextDayPlan = ids.stream()
.map(finalNextDetailMap::get)
.filter(Objects::nonNull)
.flatMap(List::stream)
.map(PgsProgressPlanDetail::getPlanNumber)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
// 封装结果
PgsProgressCategoryDetailByDayVo vo = new PgsProgressCategoryDetailByDayVo();
vo.setConstructionPlan(constructionPlan);
@ -3070,6 +3105,7 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
vo.setTotal(total);
vo.setCompleted(completed);
vo.setCompletedPercentage(BigDecimalUtil.toPercentage(completed, total));
vo.setNextDayPlan(nextDayPlan);
return vo;
}).filter(Objects::nonNull)
.sorted(Comparator.comparing(PgsProgressCategoryDetailByDayVo::getId)).toList();

View File

@ -3,6 +3,7 @@ package org.dromara.progress.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@ -59,6 +60,7 @@ import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysOssService;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -71,6 +73,7 @@ import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -136,6 +139,10 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
@Resource
private IOutConstructionValueRangeService constructionValueRangeService;
@Lazy
@Resource
private IPgsProgressPlanDetailService self;
/**
* 分页查询进度计划详情列表
*
@ -1131,11 +1138,12 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
/**
* 使用AI识别计划详情设施数量
*
* @param req AI识别计划详情设施数量参数
* @param req AI识别计划详情设施数量参数
* @param bigPicture 大图对象
* @return 是否成功
*/
@Override
public Boolean insertNumberDetailByAI(PgsProgressPlanDetailAINumberReq req) {
public Boolean insertNumberDetailByAI(PgsProgressPlanDetailAINumberReq req, DroDroneBigPicture bigPicture) {
String fileUrl;
String tifUrl;
String file = req.getFile();
@ -1150,15 +1158,69 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
} else {
tifUrl = req.getTifUrl();
}
if (StringUtils.isAnyBlank(fileUrl, tifUrl)) {
throw new ServiceException("请上传图片", HttpStatus.ERROR);
}
Long projectId = req.getProjectId();
// 获取所有子项
List<BusProject> projects = projectService.lambdaQuery()
.eq(BusProject::getPId, projectId)
.list();
if (CollUtil.isEmpty(projects)) {
return true;
return false;
}
List<Long> projectIds = projects.stream().map(BusProject::getId).distinct().toList();
// 保存识别数据
Long id;
if (bigPicture != null) {
bigPicture.setBigPic(fileUrl);
bigPicture.setTifFile(tifUrl);
bigPicture.setStatus("5");
boolean update = droDroneBigPictureService.updateById(bigPicture);
if (!update) {
throw new ServiceException("保存识别数据失败,数据库异常", HttpStatus.ERROR);
}
id = bigPicture.getId();
} else {
DroDroneBigPicture droDroneBigPicture = new DroDroneBigPicture();
droDroneBigPicture.setTaskName("无人机任务 - " + RandomUtil.randomString(12));
droDroneBigPicture.setProjectId(projectId);
droDroneBigPicture.setBigPic(fileUrl);
droDroneBigPicture.setTifFile(tifUrl);
droDroneBigPicture.setStatus("5");
boolean save = droDroneBigPictureService.save(droDroneBigPicture);
if (!save) {
throw new ServiceException("保存识别数据失败,数据库异常", HttpStatus.ERROR);
}
id = droDroneBigPicture.getId();
}
// 异步执行数据同步
self.recognizeAsync(id, fileUrl, tifUrl, projectIds)
.thenAccept(result -> log.info("识别数据[{}]异步执行成功", id))
.exceptionally(ex -> {
log.error("识别数据[{}]异步执行失败", id, ex);
// 修改状态
droDroneBigPictureService.lambdaUpdate()
.eq(DroDroneBigPicture::getId, id)
.set(DroDroneBigPicture::getStatus, "7")
.update();
return null;
});
return true;
}
/**
* 使用AI识别计划详情设施数量
*
* @param bigPictureId 大图id
* @param fileUrl 文件url
* @param tifUrl tif文件url
* @param projectIds 项目id列表
* @return 是否成功
*/
@Async
@Override
public CompletableFuture<Boolean> recognizeAsync(Long bigPictureId, String fileUrl, String tifUrl, List<Long> projectIds) {
// 调用识别算法
RecognizeVo recognizeVo = null;
try {
@ -1167,11 +1229,11 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
log.error("识别失败:{}", e.getMessage());
}
if (recognizeVo == null) {
return false;
return CompletableFuture.completedFuture(false);
}
if (recognizeVo.getHasTarget().equals(RecognizerHasTargetEnum.NO.getValue())) {
log.info("没有识别到设施");
return true;
return CompletableFuture.completedFuture(true);
}
String fileName = FileNameUtil.getName(fileUrl);
List<RecognizeTargetVo> targets = recognizeVo.getTargets();
@ -1182,7 +1244,7 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
String type = entry.getKey();
List<RecognizeTargetVo> value = entry.getValue();
// 调用工具获取经纬度
List<RecognizeConvertCoordinateResult> coordinateList = new ArrayList<>();
List<RecognizeConvertCoordinateResult> coordinateList;
try {
coordinateList = recognizerManager.convertCoordinate(tifUrl, targets);
if (CollUtil.isEmpty(coordinateList)) {
@ -1190,6 +1252,7 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
}
} catch (Exception e) {
log.error("转换坐标失败:{}", e.getMessage());
return CompletableFuture.completedFuture(false);
}
log.info("类型:{},识别到的设施:{},转换坐标:{}", type, value, coordinateList);
// 处理对应设施
@ -1217,14 +1280,16 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
} catch (IOException | URISyntaxException e) {
throw new ServiceException("将识别数据同步到图片上失败", HttpStatus.ERROR);
}
// 保存识别数据
DroDroneBigPicture droDroneBigPicture = new DroDroneBigPicture();
droDroneBigPicture.setProjectId(projectId);
droDroneBigPicture.setBigPic(fileUrl);
droDroneBigPicture.setTifFile(tifUrl);
droDroneBigPicture.setRecognizePic(recognizePic);
droDroneBigPictureService.save(droDroneBigPicture);
return true;
// 更新数据和状态
boolean update = droDroneBigPictureService.lambdaUpdate()
.eq(DroDroneBigPicture::getId, bigPictureId)
.set(DroDroneBigPicture::getStatus, "6")
.set(DroDroneBigPicture::getRecognizePic, recognizePic)
.update();
if (!update) {
return CompletableFuture.completedFuture(false);
}
return CompletableFuture.completedFuture(true);
}
/**