From b501965d25579800704af2860eb4cb6f221c8f7d Mon Sep 17 00:00:00 2001 From: lcj <2331845269@qq.com> Date: Mon, 17 Nov 2025 09:08:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=A7=E5=9B=BE=E5=90=88=E5=B9=B6=E3=80=81?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6=E8=AE=A1=E5=88=92=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dromara/test/RecognizerTest.java | 5 + .../excel/handler/LockColumnHandler.java | 40 +++++ .../excel/handler/SheetProtectHandler.java | 26 +++ .../dromara/common/excel/utils/ExcelUtil.java | 143 +++++++++++++++- .../DroDroneBigPictureController.java | 49 ++++-- .../drone/domain/DroDroneBigPicture.java | 34 ++-- .../drone/domain/bo/DroDroneBigPictureBo.java | 45 ++++- .../drone/domain/vo/DroDroneBigPictureVo.java | 35 +++- .../mapper/DroDroneBigPictureMapper.java | 2 +- .../service/IDroDroneBigPictureService.java | 10 +- .../impl/DroDroneBigPictureServiceImpl.java | 40 ++++- .../manager/dronemanager/DroneConstant.java | 20 ++- .../manager/dronemanager/DroneManager.java | 29 ++++ .../dronemanager/DroneRequestUtils.java | 97 ++++++++++- .../recognizermanager/RecognizerUtils.java | 4 +- .../PgsProgressCategoryController.java | 68 +++++++- .../PgsProgressCategoryEnterTemplateVo.java | 77 +++++++++ .../service/IPgsProgressCategoryService.java | 16 ++ .../impl/PgsProgressCategoryServiceImpl.java | 161 ++++++++++++++++++ .../PgsProgressPlanDetailServiceImpl.java | 15 +- 20 files changed, 855 insertions(+), 61 deletions(-) create mode 100644 xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/LockColumnHandler.java create mode 100644 xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/SheetProtectHandler.java create mode 100644 xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryEnterTemplateVo.java diff --git a/xinnengyuan/ruoyi-admin/src/test/java/org/dromara/test/RecognizerTest.java b/xinnengyuan/ruoyi-admin/src/test/java/org/dromara/test/RecognizerTest.java index 95bf9ab1..6706007f 100644 --- a/xinnengyuan/ruoyi-admin/src/test/java/org/dromara/test/RecognizerTest.java +++ b/xinnengyuan/ruoyi-admin/src/test/java/org/dromara/test/RecognizerTest.java @@ -26,4 +26,9 @@ public class RecognizerTest { RecognizeVo recognize = recognizerManager.recognize("http://xny.yj-3d.com:7363/file/tif/20250625160218orthophoto.png", List.of(RecognizerTypeEnum.PANEL)); log.info("recognize: {}", recognize); } + + @Test + void testChange() { + recognizerManager.convertCoordinate("http://xny.yj-3d.com:9000/xinnengyuan-dev/2025/11/11/d48767a62bc04867a552e06ba6712004.tif", List.of()); + } } diff --git a/xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/LockColumnHandler.java b/xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/LockColumnHandler.java new file mode 100644 index 00000000..27f18947 --- /dev/null +++ b/xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/LockColumnHandler.java @@ -0,0 +1,40 @@ +package org.dromara.common.excel.handler; + +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.context.CellWriteHandlerContext; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Workbook; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public class LockColumnHandler implements CellWriteHandler { + + private final Set lockColumns; + + public LockColumnHandler(Collection lockColumns) { + this.lockColumns = new HashSet<>(lockColumns); + } + + @Override + public void afterCellDispose(CellWriteHandlerContext context) { + Cell cell = context.getCell(); + if (cell == null) return; + + Workbook workbook = cell.getSheet().getWorkbook(); + + // 必须为所有单元格创建一个新的 CellStyle + CellStyle style = workbook.createCellStyle(); + + // 锁定指定列 + if (lockColumns.contains(cell.getColumnIndex())) { + style.setLocked(true); + } else { + style.setLocked(false); // 非锁定列必须明确设置为 false! + } + + cell.setCellStyle(style); + } +} diff --git a/xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/SheetProtectHandler.java b/xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/SheetProtectHandler.java new file mode 100644 index 00000000..44b0685e --- /dev/null +++ b/xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/SheetProtectHandler.java @@ -0,0 +1,26 @@ +package org.dromara.common.excel.handler; + +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import org.apache.poi.ss.usermodel.Sheet; + +/** + * @author lilemy + * @date 2025-11-14 15:05 + */ +public class SheetProtectHandler implements SheetWriteHandler { + + private final String password; + + public SheetProtectHandler(String password) { + this.password = password; + } + + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, + WriteSheetHolder writeSheetHolder) { + Sheet sheet = writeSheetHolder.getSheet(); + sheet.protectSheet(password); // 可为空字符串 + } +} diff --git a/xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java b/xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java index 3ef4742b..ddaf66c9 100644 --- a/xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java +++ b/xinnengyuan/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java @@ -4,7 +4,10 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.resource.ClassPathResource; import cn.hutool.core.util.IdUtil; import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.read.builder.ExcelReaderBuilder; +import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.fill.FillConfig; @@ -14,26 +17,27 @@ import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletResponse; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.file.FileUtils; import org.dromara.common.excel.convert.ExcelBigNumberConvert; import org.dromara.common.excel.core.*; import org.dromara.common.excel.handler.DataWriteHandler; +import org.dromara.common.excel.handler.LockColumnHandler; +import org.dromara.common.excel.handler.SheetProtectHandler; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; /** * Excel相关处理 * * @author Lion Li */ +@Slf4j @NoArgsConstructor(access = AccessLevel.PRIVATE) public class ExcelUtil { @@ -47,6 +51,41 @@ public class ExcelUtil { return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync(); } + /** + * 同步读取 Excel(支持读取多个 Sheet) + * + * @param is 输入流(一次性读取) + * @param clazz Excel 映射实体类 + * @return 所有 Sheet 的数据汇总 + */ + public static List importExcelAllSheet(InputStream is, Class clazz) { + // 用于存放所有 sheet 的数据 + List allData = new ArrayList<>(); + // 1. 构建 ExcelReader + ExcelReaderBuilder readerBuilder = EasyExcel.read(is); + ExcelReader reader = readerBuilder.build(); + // 2. 获取 Excel 中全部 Sheet 信息(包含 SheetNo、页名等) + List readSheets = reader.excelExecutor().sheetList(); + // 3. 遍历每一个 Sheet + for (ReadSheet sheet : readSheets) { + // 为每个 Sheet 创建独立监听器,用于接收读取结果 + DefaultExcelListener listener = new DefaultExcelListener<>(false); + // 4. 构建当前 Sheet 的读取器 使用 sheet.getSheetNo() 指定当前 sheet + ReadSheet readSheet = EasyExcel.readSheet(sheet.getSheetNo()) + // 设置头映射实体类 + .head(clazz) + // 注册读取监听器 + .registerReadListener(listener) + .build(); + // 5. 开始读取当前 Sheet + reader.read(readSheet); + // 6. 收集当前 Sheet 读取的数据 + allData.addAll(listener.getExcelResult().getList()); + } + // 7. 关闭读取器,释放资源 + reader.finish(); + return allData; + } /** * 使用校验监听器 异步导入 同步返回 @@ -204,6 +243,37 @@ public class ExcelUtil { builder.doWrite(list); } + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param lockColumns 锁定列 + * @param merge 是否合并单元格 + * @param os 输出流 + */ + public static void exportExcel(List list, String sheetName, Class clazz, List lockColumns, + boolean merge, OutputStream os, List options) { + ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz) + .registerWriteHandler(new LockColumnHandler(lockColumns)) // 锁定第3列 + .registerWriteHandler(new SheetProtectHandler("dawdawdwad")) // 保护整张 sheet + .autoCloseStream(false) + // 自动适配 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .registerWriteHandler(new DataWriteHandler(clazz)) + .sheet(sheetName); + if (merge) { + // 合并处理器 + builder.registerWriteHandler(new CellMergeStrategy(list, true)); + } + // 添加下拉框操作 + builder.registerWriteHandler(new ExcelDownHandler(options)); + builder.doWrite(list); + } + /** * 导出多sheet excel(增强版,解决XML安全问题) * @@ -212,7 +282,9 @@ public class ExcelUtil { * @param clazz 实体类 * @param optionsList 级联下拉选内容列表 */ - public static void exportMultiSheetExcelEnhanced(List> sheetData, List sheetNames, Class clazz, List> optionsList, HttpServletResponse response) throws IOException { + public static void exportMultiSheetExcelEnhanced(List> sheetData, List sheetNames, + Class clazz, List> optionsList, + HttpServletResponse response) throws IOException { resetResponse("file", response); ExcelWriter excelWriter = null; ServletOutputStream os = response.getOutputStream(); @@ -254,12 +326,71 @@ public class ExcelUtil { excelWriter.finish(); } catch (Exception e) { // 记录日志但不中断主流程 - e.printStackTrace(); + log.error("Excel 导出错误", e); } } } } + /** + * 导出多sheet excel(增强版,解决XML安全问题) + * + * @param sheetData 多个sheet的数据 + * @param sheetNames 多个sheet的名称 + * @param clazz 实体类 + * @param optionsList 级联下拉选内容列表 + */ + public static void exportExcel(List> sheetData, List sheetNames, List lockColumns, + Class clazz, List> optionsList, + HttpServletResponse response) throws IOException { + resetResponse("file", response); + ExcelWriter excelWriter = null; + ServletOutputStream os = response.getOutputStream(); + + try { + // 使用SXSSFWorkbook避免内存问题,并减少XML处理复杂度 + excelWriter = EasyExcel.write(os) + .head(clazz) + .registerWriteHandler(new LockColumnHandler(lockColumns)) // 锁定第3列 +// .registerWriteHandler(new SheetProtectHandler("dawdawdwad")) // 保护整张 sheet + .autoCloseStream(false) + .registerConverter(new ExcelBigNumberConvert()) + // 自动适配 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + .registerWriteHandler(new DataWriteHandler(clazz)) + .build(); + + + // 为每个sheet写入数据 + for (int i = 0; i < sheetData.size(); i++) { + // 创建基本sheet配置 + WriteSheet writeSheet = EasyExcel.writerSheet(i, sheetNames.get(i)) + .head(clazz) + .build(); + + // 添加下拉选项(如果存在) + if (optionsList != null && optionsList.size() > i && optionsList.get(i) != null) { + ExcelDownHandler handler = new ExcelDownHandler(optionsList.get(i)); + writeSheet.setCustomWriteHandlerList( + Collections.singletonList(handler)); + } + + // 写入数据 + excelWriter.write(sheetData.get(i), writeSheet); + } + + } finally { + // 确保资源正确释放 + if (excelWriter != null) { + try { + excelWriter.finish(); + } catch (Exception e) { + // 记录日志但不中断主流程 + log.error("Excel 导出错误", e); + } + } + } + } /** * 单表多数据模板导出 模板格式为 {.属性} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/controller/DroDroneBigPictureController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/controller/DroDroneBigPictureController.java index bb19f80c..18bbc326 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/controller/DroDroneBigPictureController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/controller/DroDroneBigPictureController.java @@ -1,32 +1,33 @@ package org.dromara.drone.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 jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; import org.dromara.common.core.domain.R; import org.dromara.common.core.validate.AddGroup; import org.dromara.common.core.validate.EditGroup; -import org.dromara.common.log.enums.BusinessType; import org.dromara.common.excel.utils.ExcelUtil; -import org.dromara.drone.domain.vo.DroDroneBigPictureVo; -import org.dromara.drone.domain.bo.DroDroneBigPictureBo; -import org.dromara.drone.service.IDroDroneBigPictureService; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.drone.domain.bo.DroDroneBigPictureBo; +import org.dromara.drone.domain.vo.DroDroneBigPictureVo; +import org.dromara.drone.service.IDroDroneBigPictureService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; /** * 无人机大图信息 * * @author lilemy - * @date 2025-09-17 + * @date 2025-11-15 */ @Validated @RequiredArgsConstructor @@ -64,7 +65,7 @@ public class DroDroneBigPictureController extends BaseController { @SaCheckPermission("drone:droneBigPicture:query") @GetMapping("/{id}") public R getInfo(@NotNull(message = "主键不能为空") - @PathVariable Long id) { + @PathVariable Long id) { return R.ok(droDroneBigPictureService.queryById(id)); } @@ -90,6 +91,20 @@ public class DroDroneBigPictureController extends BaseController { return toAjax(droDroneBigPictureService.updateByBo(bo)); } + /** + * 创建识别进度 + * + * @param id 主键 + */ + @SaCheckPermission("drone:droneBigPicture:add") + @Log(title = "无人机大图信息", businessType = BusinessType.OTHER) + @RepeatSubmit + @PostMapping("/createProgressRecognize/{id}") + public R createProgressRecognize(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return toAjax(droDroneBigPictureService.createProgressRecognize(id)); + } + /** * 删除无人机大图信息 * diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/DroDroneBigPicture.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/DroDroneBigPicture.java index c9fcccff..feb4d9da 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/DroDroneBigPicture.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/DroDroneBigPicture.java @@ -3,20 +3,21 @@ package org.dromara.drone.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; -import java.io.Serializable; -import java.util.Date; /** * 无人机大图信息对象 dro_drone_big_picture * * @author lilemy - * @date 2025-09-17 + * @date 2025-11-15 */ @Data +@EqualsAndHashCode(callSuper = true) @TableName("dro_drone_big_picture") -public class DroDroneBigPicture implements Serializable { +public class DroDroneBigPicture extends BaseEntity { @Serial private static final long serialVersionUID = 1L; @@ -32,6 +33,16 @@ public class DroDroneBigPicture implements Serializable { */ private Long projectId; + /** + * 任务名称 + */ + private String taskName; + + /** + * 小图片列表 + */ + private String smallPic; + /** * 大图 */ @@ -47,19 +58,14 @@ public class DroDroneBigPicture implements Serializable { */ private String tifFile; + /** + * 状态 + */ + private String status; + /** * 备注 */ private String remark; - /** - * 创建时间 - */ - private Date createTime; - - /** - * 更新时间 - */ - private Date updateTime; - } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/bo/DroDroneBigPictureBo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/bo/DroDroneBigPictureBo.java index f2242e43..5e8f4db7 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/bo/DroDroneBigPictureBo.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/bo/DroDroneBigPictureBo.java @@ -1,26 +1,30 @@ package org.dromara.drone.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.drone.domain.DroDroneBigPicture; import java.io.Serial; -import java.io.Serializable; /** * 无人机大图信息业务对象 dro_drone_big_picture * * @author lilemy - * @date 2025-09-17 + * @date 2025-11-15 */ @Data +@EqualsAndHashCode(callSuper = true) @AutoMapper(target = DroDroneBigPicture.class, reverseConvertGenerate = false) -public class DroDroneBigPictureBo implements Serializable { +public class DroDroneBigPictureBo extends BaseEntity { @Serial - private static final long serialVersionUID = -2648698305265339936L; + private static final long serialVersionUID = 1498586685367891721L; /** * 主键ID @@ -31,9 +35,40 @@ public class DroDroneBigPictureBo implements Serializable { /** * 项目ID */ - @NotNull(message = "项目ID不能为空", groups = {EditGroup.class}) + @NotNull(message = "项目ID不能为空", groups = {AddGroup.class, EditGroup.class}) private Long projectId; + /** + * 任务名称 + */ + @NotBlank(message = "任务名称不能为空", groups = {AddGroup.class, EditGroup.class}) + private String taskName; + + /** + * 小图片列表 + */ + private String smallPic; + + /** + * 大图 + */ + private String bigPic; + + /** + * 识别结果图片 + */ + private Long recognizePic; + + /** + * tif文件 + */ + private String tifFile; + + /** + * 状态 + */ + private String status; + /** * 备注 */ diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/vo/DroDroneBigPictureVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/vo/DroDroneBigPictureVo.java index e7e0e68e..e121e521 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/vo/DroDroneBigPictureVo.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/vo/DroDroneBigPictureVo.java @@ -16,7 +16,7 @@ import java.io.Serializable; * 无人机大图信息视图对象 dro_drone_big_picture * * @author lilemy - * @date 2025-09-17 + * @date 2025-11-15 */ @Data @ExcelIgnoreUnannotated @@ -38,6 +38,24 @@ public class DroDroneBigPictureVo implements Serializable { @ExcelProperty(value = "项目ID") private Long projectId; + /** + * 任务名称 + */ + @ExcelProperty(value = "任务名称") + private String taskName; + + /** + * 小图片列表 + */ + @ExcelProperty(value = "小图片列表") + private String smallPic; + + /** + * 小图片列表 Url + */ + @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "smallPic") + private String smallPicList; + /** * 大图 */ @@ -48,13 +66,7 @@ public class DroDroneBigPictureVo implements Serializable { * 识别结果图片 */ @ExcelProperty(value = "识别结果图片") - private String recognizePic; - - /** - * 识别结果图片Url - */ - @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "recognizePic") - private String recognizePicUrl; + private Long recognizePic; /** * tif文件 @@ -62,11 +74,16 @@ public class DroDroneBigPictureVo implements Serializable { @ExcelProperty(value = "tif文件") private String tifFile; + /** + * 状态 + */ + @ExcelProperty(value = "状态") + private String status; + /** * 备注 */ @ExcelProperty(value = "备注") private String remark; - } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/mapper/DroDroneBigPictureMapper.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/mapper/DroDroneBigPictureMapper.java index d85d724f..862976db 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/mapper/DroDroneBigPictureMapper.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/mapper/DroDroneBigPictureMapper.java @@ -8,7 +8,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; * 无人机大图信息Mapper接口 * * @author lilemy - * @date 2025-09-17 + * @date 2025-11-15 */ public interface DroDroneBigPictureMapper extends BaseMapperPlus { diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/IDroDroneBigPictureService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/IDroDroneBigPictureService.java index ddc32f5e..0149d6e9 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/IDroDroneBigPictureService.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/IDroDroneBigPictureService.java @@ -14,7 +14,7 @@ import java.util.List; * 无人机大图信息Service接口 * * @author lilemy - * @date 2025-09-17 + * @date 2025-11-15 */ public interface IDroDroneBigPictureService extends IService { @@ -59,6 +59,14 @@ public interface IDroDroneBigPictureService extends IService */ Boolean updateByBo(DroDroneBigPictureBo bo); + /** + * 创建识别进度 + * + * @param id 主键 + * @return 是否创建成功 + */ + Boolean createProgressRecognize(Long id); + /** * 校验并批量删除无人机大图信息信息 * diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/impl/DroDroneBigPictureServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/impl/DroDroneBigPictureServiceImpl.java index 6904bb26..b92fce62 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/impl/DroDroneBigPictureServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/impl/DroDroneBigPictureServiceImpl.java @@ -4,8 +4,11 @@ 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 org.dromara.common.core.exception.ServiceException; 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.drone.domain.DroDroneBigPicture; @@ -13,22 +16,30 @@ 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.progress.domain.dto.progressplandetail.PgsProgressPlanDetailAINumberReq; +import org.dromara.progress.service.IPgsProgressPlanDetailService; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import java.util.Collection; import java.util.List; +import java.util.Map; /** * 无人机大图信息Service业务层处理 * * @author lilemy - * @date 2025-09-17 + * @date 2025-11-15 */ @RequiredArgsConstructor @Service public class DroDroneBigPictureServiceImpl extends ServiceImpl implements IDroDroneBigPictureService { + @Lazy + @Resource + private IPgsProgressPlanDetailService progressPlanDetailService; + /** * 查询无人机大图信息 * @@ -67,9 +78,16 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl buildQueryWrapper(DroDroneBigPictureBo bo) { + Map params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.orderByDesc(DroDroneBigPicture::getId); lqw.eq(bo.getProjectId() != null, DroDroneBigPicture::getProjectId, bo.getProjectId()); + lqw.like(StringUtils.isNotBlank(bo.getTaskName()), DroDroneBigPicture::getTaskName, bo.getTaskName()); + lqw.eq(StringUtils.isNotBlank(bo.getSmallPic()), DroDroneBigPicture::getSmallPic, bo.getSmallPic()); + lqw.eq(StringUtils.isNotBlank(bo.getBigPic()), DroDroneBigPicture::getBigPic, bo.getBigPic()); + lqw.eq(bo.getRecognizePic() != null, DroDroneBigPicture::getRecognizePic, bo.getRecognizePic()); + lqw.eq(StringUtils.isNotBlank(bo.getTifFile()), DroDroneBigPicture::getTifFile, bo.getTifFile()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), DroDroneBigPicture::getStatus, bo.getStatus()); return lqw; } @@ -103,6 +121,26 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl 0; } + /** + * 创建识别进度 + * + * @param id 主键 + * @return 是否创建成功 + */ + @Override + public Boolean createProgressRecognize(Long id) { + DroDroneBigPicture bigPicture = this.getById(id); + if (bigPicture == null) { + throw new ServiceException("无人机大图数据不存在"); + } + // todo 创建识别进度 + PgsProgressPlanDetailAINumberReq ai = new PgsProgressPlanDetailAINumberReq(); + ai.setFileUrl(bigPicture.getBigPic()); + ai.setTifUrl(bigPicture.getTifFile()); + Boolean b = progressPlanDetailService.insertNumberDetailByAI(ai); + return true; + } + /** * 保存前的数据校验 */ diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneConstant.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneConstant.java index 5f4ef216..ba3edb4e 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneConstant.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneConstant.java @@ -7,8 +7,26 @@ package org.dromara.manager.dronemanager; public interface DroneConstant { /** - * 添加无人机项目信息 + * 添加无人机项目信息 POST */ String ADD_DRONE_INFO_BY_PROJECT = "/dj/project/addProjectAndGatewayInfo"; + /** + * 创建图片合成任务 POST + * + */ + String CREATE_IMG_MERGE_TASK = "/pure/image/synthesis/createTask"; + + /** + * 下载图片合成结果 GET + * + */ + String DOWNLOAD_MERGED_FILE = "/pure/image/synthesis/download"; + + /** + * 查询图片合成进度 GET + * + */ + String GET_IMG_MERGE_PROGRESS = "/pure/image/synthesis/queryProgress"; + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneManager.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneManager.java index 401a366e..b22484ba 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneManager.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneManager.java @@ -27,4 +27,33 @@ public class DroneManager { DroneRequestUtils.addAirportInfoByProject(droneProperties.getUrl(), gateways, projectId); } + /** + * 创建图片合成任务 + * + * @param businessName 业务名称 + * @param imageUrls 图片URL列表 + */ + public void createImageMergeTask(String businessName, List 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); + } + + /** + * 获取图片合成结果 + * + * @param taskId 任务ID + */ + public void getImgMergeProgress(String taskId) { + DroneRequestUtils.getImgMergeProgress(droneProperties.getUrl(), taskId); + } + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneRequestUtils.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneRequestUtils.java index bec341a0..8a7d4a0b 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneRequestUtils.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/dronemanager/DroneRequestUtils.java @@ -3,11 +3,13 @@ package org.dromara.manager.dronemanager; import cn.hutool.core.collection.CollUtil; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; 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 java.util.List; @@ -51,11 +53,104 @@ public class DroneRequestUtils { String body = response.body(); JSONObject obj = JSONUtil.parseObj(body); if (!obj.getStr("code").equals("200")) { - log.error("{},状态码:{},{}", errorMsg, obj.get("code"), obj.get("msg")); + log.error("{},状态码:{},错误信息:{}", errorMsg, obj.get("code"), obj.get("msg")); throw new ServiceException(errorMsg + obj.get("msg")); } log.info("添加项目机场信息请求成功"); } } + /** + * 创建图片合成任务 + * + * @param businessName 业务名称 + * @param imageUrls 图片URL列表 + */ + public static void createImgMergeTask(String url, String businessName, List imageUrls) { + if (StringUtils.isBlank(businessName) || CollUtil.isEmpty(imageUrls)) { + throw new ServiceException("创建图片合成任务请求参数错误", HttpStatus.BAD_REQUEST); + } + // 完整 URL + String fullUrl = url + DroneConstant.CREATE_IMG_MERGE_TASK + "?" + "businessName=" + businessName; + // 构造 body 中的 imageUrls 数组 + JSONArray urls = new JSONArray(); + urls.addAll(imageUrls); + String errorMsg = "创建图片合成任务请求失败"; + try (HttpResponse response = HttpRequest.post(fullUrl) + .body(urls.toString()) + .execute()) { + if (!response.isOk()) { + log.error("{}:{}", 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")); + } + log.info("创建图片合成任务请求成功"); + } + } + + /** + * 下载图片合成结果 + * + * @param taskId 任务ID + * @param fileType 文件类型(png/tif) + */ + public static void downloadMergedFile(String url, String taskId, String fileType) { + if (StringUtils.isAnyBlank(taskId, fileType)) { + 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 errorMsg = "下载图片合成结果请求失败"; + try (HttpResponse response = HttpRequest.get(fullUrl) + .execute()) { + if (!response.isOk()) { + log.error("{}:{}", 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")); + } + log.info("下载图片合成结果请求成功"); + } + } + + /** + * 查询图片合成进度 + * + * @param taskId 任务ID + */ + public static void getImgMergeProgress(String url, String taskId) { + if (StringUtils.isBlank(taskId)) { + throw new ServiceException("查询图片合成进度请求参数错误", HttpStatus.BAD_REQUEST); + } + // 完整 URL + String fullUrl = url + DroneConstant.GET_IMG_MERGE_PROGRESS + "/" + taskId; + String errorMsg = "查询图片合成进度请求失败"; + try (HttpResponse response = HttpRequest.get(fullUrl) + .execute()) { + if (!response.isOk()) { + log.error("{}:{}", 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")); + } + log.info("查询图片合成进度请求成功"); + } + } + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerUtils.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerUtils.java index 7f8c23b2..ff97f3d4 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerUtils.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerUtils.java @@ -159,8 +159,8 @@ public class RecognizerUtils { List results = positionList.stream() .map(o -> (JSONObject) o) .map(p -> new RecognizeConvertCoordinateResult( - String.valueOf(p.getDouble("x")), // x 映射到 lng - String.valueOf(p.getDouble("y")) // y 映射到 lat + p.getStr("x"), // x 映射到 lng + p.getStr("y") // y 映射到 lat )) .toList(); log.info("坐标转换请求成功:{}", body); diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressCategoryController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressCategoryController.java index f6fd1e15..ce272dfd 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressCategoryController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressCategoryController.java @@ -1,12 +1,14 @@ package org.dromara.progress.controller; import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; import org.dromara.common.idempotent.annotation.RepeatSubmit; import org.dromara.common.log.annotation.Log; import org.dromara.common.log.enums.BusinessType; @@ -18,6 +20,10 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.ArrayList; import java.util.List; /** @@ -117,11 +123,34 @@ public class PgsProgressCategoryController extends BaseController { pgsProgressCategoryService.exportTotalByNameParent(parentId, response); } + /** + * 导出进度类别录入模板 + */ + @SaIgnore + @SaCheckPermission("progress:progressCategory:export") + @Log(title = "进度类别", businessType = BusinessType.EXPORT) + @PostMapping("/export/enterTemplate/{projectId}") + public void exportEnterTemplate(@NotNull(message = "项目主键不能为空") + @PathVariable Long projectId, HttpServletResponse response) { + pgsProgressCategoryService.exportEnterTemplate(projectId, response); + } + + /** + * 导入进度类别录入数据 + */ + @SaIgnore + @SaCheckPermission("progress:progressCategory:import") + @Log(title = "进度类别", businessType = BusinessType.IMPORT) + @PostMapping("/import/enterData") + public R importEnterData(@RequestParam("file") MultipartFile file, Long projectId) { + return R.ok(pgsProgressCategoryService.importEnterData(projectId, file)); + } + /*** * 导入 */ @SaCheckPermission("progress:progressCategory:import") - @Log(title = "进度类别导入", businessType = BusinessType.IMPORT) + @Log(title = "进度类别", businessType = BusinessType.IMPORT) @PostMapping("/import") public R importData(@RequestParam("file") MultipartFile file) { return R.ok(pgsProgressCategoryService.importData(file)); @@ -255,4 +284,41 @@ public class PgsProgressCategoryController extends BaseController { return toAjax(pgsProgressCategoryService.deleteWithValidByIds(List.of(ids), true)); } + /** + * 获取进度类别日进度信息 + */ + @SaIgnore + @GetMapping("/day/vo") + public R getDayTotal() { + return R.ok(pgsProgressCategoryService.getProgressCategoryByDay(1897160897167638529L, LocalDate.now())); + } + + /** + * 测试 + */ + @SaIgnore + @GetMapping("/test") + public void getTest(HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + List sheetNames = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + List list1 = new ArrayList<>(); + for (int j = 0; j < 5; j++) { + PgsProgressCategoryEnterTemplateVo vo = new PgsProgressCategoryEnterTemplateVo(); + vo.setName("测试" + i); + vo.setUnitType("1"); + vo.setTotal(BigDecimal.ONE); + vo.setCompleted(BigDecimal.ONE); + vo.setStatus("1"); + vo.setUnit("1"); + vo.setRemark("测试" + i); + list1.add(vo); + } + sheetNames.add("测试" + i); + list.add(list1); + } + List item = List.of(0, 1, 3); + ExcelUtil.exportExcel(list, sheetNames, item, PgsProgressCategoryEnterTemplateVo.class, null, response); + } + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryEnterTemplateVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryEnterTemplateVo.java new file mode 100644 index 00000000..6e9f5df4 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryEnterTemplateVo.java @@ -0,0 +1,77 @@ +package org.dromara.progress.domain.vo.progresscategory; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @author lilemy + * @date 2025-11-14 14:23 + */ +@Data +public class PgsProgressCategoryEnterTemplateVo implements Serializable { + + @Serial + private static final long serialVersionUID = 6899658199225024466L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键(请勿修改)") + private Long id; + + /** + * 类别名称 + */ + @ExcelProperty(value = "类别名称") + private String name; + + /** + * 计量方式(0无 1数量 2百分比) + */ + @ExcelProperty(value = "计量方式", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=无,1=数量,2=百分比") + private String unitType; + + /** + * 计量单位 + */ + @ExcelProperty(value = "计量单位") + private String unit; + + /** + * 总数量 + */ + @ExcelProperty(value = "总数量") + private BigDecimal total; + + /** + * 已完成数量 + */ + @ExcelProperty(value = "已完成数量") + private BigDecimal completed; + + /** + * 完成数量 + */ + @ExcelProperty(value = "完成数量") + private BigDecimal completionCount; + + /** + * 完成状态(0未开始 1进行中 2已完成) + */ + @ExcelProperty(value = "完成状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=未开始,1=进行中,2=已完成") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressCategoryService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressCategoryService.java index 3796766f..741c29c9 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressCategoryService.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressCategoryService.java @@ -318,6 +318,22 @@ public interface IPgsProgressCategoryService extends IService projects = projectService.lambdaQuery() + .eq(BusProject::getPId, projectId) + .list(); + projects.add(project); + List allProjectIds = projects.stream().map(BusProject::getId).toList(); + // 获取当前项目的所有父级进度类别 + List allList = this.lambdaQuery() + .in(PgsProgressCategory::getProjectId, allProjectIds) + .eq(PgsProgressCategory::getParentId, PgsProgressCategoryConstant.TOP_PARENT_ID) + .list(); + if (CollUtil.isEmpty(allList)) { + throw new ServiceException("没有数据"); + } + List ids = allList.stream().map(PgsProgressCategory::getId).toList(); + // 记录每个 sheet 的表名 + List names = new ArrayList<>(); + // 获取当前父级下的所有子类 + List allChildren = this.getLeafNodesByTopIds(ids); + List> list = allList.stream().map(p -> { + names.add(StringUtils.isNotBlank(p.getMatrixName()) ? p.getMatrixName() + " - " + p.getName() : p.getName()); + List c = this.getLeafNodesByTopId(p.getId(), allChildren); + if (CollUtil.isEmpty(c)) { + return new ArrayList(); + } + // 封装数据 + return c.stream().map(cc -> { + PgsProgressCategoryEnterTemplateVo vo = new PgsProgressCategoryEnterTemplateVo(); + vo.setId(cc.getId()); + vo.setName(cc.getName()); + vo.setUnitType(cc.getUnitType()); + vo.setUnit(cc.getUnit()); + vo.setTotal(cc.getTotal()); + vo.setCompleted(cc.getCompleted()); + vo.setCompletionCount(BigDecimal.ZERO); + vo.setStatus(cc.getStatus()); + vo.setRemark(cc.getRemark()); + return vo; + }).toList(); + }).toList(); + // 需要锁定的列 + List lockedColumns = new ArrayList<>(); + try { + ExcelUtil.exportExcel(list, names, lockedColumns, PgsProgressCategoryEnterTemplateVo.class, null, response); + } catch (IOException e) { + log.error("导出失败", e); + throw new ServiceException("导出失败"); + } + } + + /** + * 导入项目进度类别列表 + * + * @param projectId 项目id + * @param file 文件 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public String importEnterData(Long projectId, MultipartFile file) { + // 检查文件是否为空 + if (file == null || file.isEmpty()) { + throw new ServiceException("上传文件不能为空"); + } + // 检查文件大小 + if (file.getSize() == 0) { + throw new ServiceException("上传文件不能为空文件"); + } + // 检查文件名 + if (file.getOriginalFilename() == null || file.getOriginalFilename().isEmpty()) { + throw new ServiceException("文件名不能为空"); + } + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目不存在"); + } + List voList; + try { + // 获取所有 sheet 的数据 + voList = ExcelUtil.importExcelAllSheet(file.getInputStream(), PgsProgressCategoryEnterTemplateVo.class); + } catch (IOException e) { + log.error("导入失败", e); + throw new ServiceException("导入失败"); + } + if (CollUtil.isEmpty(voList)) { + throw new ServiceException("表格中没有数据"); + } + log.info("导入数据:{}", voList); + // 获取当前的所有旧数据 + List ids = voList.stream().map(PgsProgressCategoryEnterTemplateVo::getId).toList(); + List categoryList = this.listByIds(ids); + if (CollUtil.isEmpty(categoryList)) { + throw new ServiceException("数据错误,当前项目无此数据"); + } + Map progressCategoryMap = categoryList.stream() + .collect(Collectors.toMap(PgsProgressCategory::getId, Function.identity())); + // 获取当前项目的子项目 + List projects = projectService.lambdaQuery() + .eq(BusProject::getPId, projectId) + .list(); + projects.add(project); + List allProjectIds = projects.stream().map(BusProject::getId).toList(); + List list = voList.stream().map(vo -> { + PgsProgressCategory update = new PgsProgressCategory(); + Long id = vo.getId(); + update.setId(id); + if (progressCategoryMap.containsKey(id)) { + PgsProgressCategory old = progressCategoryMap.get(id); + // 如果不是当前项目,或当前项目的子项目,则返回 null + if (!allProjectIds.contains(old.getProjectId())) { + return null; + } + // 当已完成数据等于总数,返回 null + if (old.getCompleted().compareTo(old.getTotal()) >= 0) { + return null; + } + // 如果完成数量小于等于0,则返回 null + BigDecimal completionCount = vo.getCompletionCount(); + if (completionCount == null || completionCount.compareTo(BigDecimal.ZERO) <= 0) { + return null; + } + // 计算完成数量 + BigDecimal add = old.getCompleted().add(completionCount); + // 确保完成数量小于等于总数 + BigDecimal minVal = add.min(old.getTotal()); + update.setCompleted(minVal); + } else { + log.warn("未匹配的值 => id:{},name:{}", id, vo.getName()); + return null; + } + return update; + }).filter(Objects::nonNull).toList(); + if (CollUtil.isEmpty(list)) { + throw new ServiceException("没有需要更新的数据"); + } + + boolean b = this.updateBatchById(list); + if (!b) { + throw new ServiceException("更新失败"); + } + List updateList = list.stream().map(PgsProgressCategory::getId).toList(); + log.info("更新数据:{},共 {} 条", updateList, list.size()); + // 获取需要更新的计划数据 + List detailList = progressPlanDetailService.lambdaQuery() + .in(PgsProgressPlanDetail::getProgressCategoryId, updateList) + .list(); + return "导入成功,共更新" + list.size() + "条数据"; + } + /** * 导入项目进度类别列表 * diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressPlanDetailServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressPlanDetailServiceImpl.java index 32b1c0fc..7c15eab5 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressPlanDetailServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressPlanDetailServiceImpl.java @@ -16,6 +16,7 @@ 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.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.utils.PageConvertUtil; @@ -1135,10 +1136,20 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl projects = projectService.lambdaQuery()