From 66bfbdb9251c22ffa2b5f05595a76a3547a2f5eb Mon Sep 17 00:00:00 2001
From: rain <1679827795@qq.com>
Date: Mon, 09 Feb 2026 11:00:44 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 drone-ops/drone-resource/src/main/java/org/sxkj/resource/service/impl/AttachServiceImpl.java |  190 ++++++++++++++++++++++++++++++++--------------
 1 files changed, 131 insertions(+), 59 deletions(-)

diff --git a/drone-ops/drone-resource/src/main/java/org/sxkj/resource/service/impl/AttachServiceImpl.java b/drone-ops/drone-resource/src/main/java/org/sxkj/resource/service/impl/AttachServiceImpl.java
index 37c5f53..97ea791 100644
--- a/drone-ops/drone-resource/src/main/java/org/sxkj/resource/service/impl/AttachServiceImpl.java
+++ b/drone-ops/drone-resource/src/main/java/org/sxkj/resource/service/impl/AttachServiceImpl.java
@@ -23,6 +23,8 @@
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import io.minio.GetObjectArgs;
+import io.minio.MinioClient;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.ibatis.annotations.Param;
@@ -41,6 +43,7 @@
 import org.sxkj.common.enums.AttachResultTypeEnum;
 import org.sxkj.common.enums.TypeOfOutcome;
 import org.sxkj.common.func.Streams;
+import org.sxkj.common.model.ResponseResult;
 import org.sxkj.common.query.PaginationUtils;
 import org.sxkj.common.redis.RedisOpsUtils;
 import org.sxkj.common.utils.*;
@@ -52,6 +55,7 @@
 import org.sxkj.resource.model.FileMetadataDTO;
 import org.sxkj.resource.model.MinioPojo;
 import org.sxkj.resource.model.PositionDTO;
+import org.sxkj.resource.param.AttachPageParam;
 import org.sxkj.resource.service.IAttachService;
 import org.sxkj.resource.util.MinioFileDownloader;
 import org.sxkj.resource.vo.*;
@@ -62,6 +66,9 @@
 import org.sxkj.tools.model.TifConvertResult;
 
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZoneId;
@@ -69,6 +76,9 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
+import java.util.zip.Deflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 
 /**
  * 附件表 服务实现类
@@ -104,15 +114,13 @@
 
 
 	@Override
-	public IPage<AttachVO> selectAttachPage(IPage<AttachVO> page, AttachVO attach) {
-		Integer resultType = attach.getResultType();
-		List<AttachVO> attachVOS = Collections.emptyList();
-		if (Objects.nonNull(resultType) && Attach.RESULT_TYPE_AI.equals(resultType)) {
-			attachVOS = baseMapper.selectEventAttachPage(page, attach);
-		} else {
-			attachVOS = baseMapper.selectAttachPage(page, attach);
+	public IPage<AttachVO> selectAttachPage(IPage<AttachVO> page, AttachPageParam attach) {
+		// 创建部门
+		if (!AuthUtil.isAdministrator()) {
+			List<Long> deptList = SysCache.getDeptChildIds(Long.valueOf(AuthUtil.getDeptId()));
+			attach.setDeptList(deptList);
 		}
-
+		List<AttachVO> attachVOS = baseMapper.selectAttachPage(page, attach);
 		return page.setRecords(attachVOS);
 	}
 
@@ -445,36 +453,6 @@
 
 
 	@Override
-	public List<AnalysisAttachVo> contrastiveAnalysis(Long id) {
-		Attach attach = getById(id);
-		ValidUtil.assertNull(attach, "数据不能为空!");
-		ValidUtil.assertNull(attach.getMetadata(), "媒体数据不存在经纬度!");
-		FileMetadataDTO metadata = JSON.parseObject(attach.getMetadata().toString(), FileMetadataDTO.class);
-		PositionDTO shootPosition = metadata.getShootPosition();
-		ValidUtil.assertNull(shootPosition, "媒体数据不存在经纬度!");
-		Double lat = attach.getLatitude() != null && attach.getLatitude() > 0 ? attach.getLatitude() : shootPosition.getLat();
-		Double lng = attach.getLongitude() != null && attach.getLongitude() > 0 ? attach.getLongitude() : shootPosition.getLng();
-		Date createTime = attach.getCreateTime();
-		// 转换为 LocalDateTime(保留时间部分)
-		LocalDateTime ldt = createTime.toInstant()
-			.atZone(ZoneId.systemDefault())
-			.toLocalDateTime();
-// 计算前后两个月
-		LocalDateTime twoMonthsBefore = ldt.minusMonths(2); // 前2个月
-		LocalDateTime twoMonthsAfter = ldt.plusMonths(2);   // 后2个月
-
-// 如果需要转回 Date 类型
-		Date beforeDate = Date.from(twoMonthsBefore.atZone(ZoneId.systemDefault()).toInstant());
-		Date afterDate = Date.from(twoMonthsAfter.atZone(ZoneId.systemDefault()).toInstant());
-		List<AnalysisAttachVo> pointAttachList = baseMapper.findPointAttach(lat, lng, beforeDate, afterDate, id);
-		return Streams.toList(pointAttachList, entity -> {
-			entity.setIsCheck(entity.getId().equals(id));
-			return entity;
-		});
-
-	}
-
-	@Override
 	public AttachInfoVO getAttachInfo(Long id) {
 		AttachInfoVO attachVO = baseMapper.getAttachInfo(id);
 		if (attachVO != null) {
@@ -484,16 +462,8 @@
 				PositionDTO shootPosition = metadata.getShootPosition();
 				ValidUtil.assertNull(shootPosition, "媒体数据不存在经纬度!");
 				Double lat = shootPosition.getLat();
-				attachVO.setLatitude(lat);
 				Double lng = shootPosition.getLng();
-				attachVO.setLongitude(lng);
 			}
-			// 文件类型,通过文件名称有_T,则是红外,包含_W|_V 则是可见光
-//			if (attachVO.getName().contains("_T")) {
-//				attachVO.setPhotoType("ir");
-//			} else if (attachVO.getName().contains("_W") || attachVO.getName().contains("_V")) {
-//				attachVO.setPhotoType("visible");
-//			}
 		}
 		return attachVO;
 	}
@@ -507,19 +477,8 @@
 				FileMetadataDTO metadata = JSON.parseObject(item.getMetadata().toString(), FileMetadataDTO.class);
 				PositionDTO shootPosition = metadata.getShootPosition();
 				Double lat = shootPosition.getLat();
-				item.setLatitude(lat);
 				Double lng = shootPosition.getLng();
-				item.setLongitude(lng);
 			}
-		});
-		// 把result_type=0和把result_type=2数据进行用经度和纬度对比,如果有相同的,则把result_type=0的数据删除
-		boolean removed = attachVO.removeIf(item -> {
-			return item.getResultType() == 0 &&
-				attachVO.stream().anyMatch(
-					item1 -> item1.getResultType() == 2
-						&& item1.getLatitude().equals(item.getLatitude())
-						&& item1.getLongitude().equals(item.getLongitude())
-				);
 		});
 		return attachVO;
 	}
@@ -575,9 +534,8 @@
 	@Override
 	public Long findResultNumByJobId(String jobId) {
 		return baseMapper.selectCount(Wrappers.<Attach>lambdaQuery()
-			.eq(Attach::getIsGenerateAiImg, 0)
 			.eq(Attach::getIsDeleted, 0)
-			.eq(Attach::getWayLineJobId, jobId).in(Attach::getResultType, AttachResultTypeEnum.getTheAttachmentType()));
+			.eq(Attach::getPatrolTaskId, jobId).in(Attach::getResultType, AttachResultTypeEnum.getTheAttachmentType()));
 	}
 
 	@Override
@@ -825,4 +783,118 @@
 		return attachTypeStatisticsVOS;
 	}
 
+	/**
+	 * 下载附件
+	 *
+	 * @param param        下载参数
+	 * @param outputStream 输出流
+	 * @return
+	 * @throws IOException
+	 */
+	@Override
+	public Boolean downloadByByte(String param, OutputStream outputStream) throws IOException {
+		AttachmentDownloadParam attachmentDownloadParam = new AttachmentDownloadParam();
+		attachmentDownloadParam.setAttachIds(Func.toLongList(param));
+		// 获取附件列表
+		List<AttachVO> attachList = getAttachList(attachmentDownloadParam);
+		if (CollectionUtils.isEmpty(attachList)) {
+			return false;
+		}
+
+		try {
+			// 直接使用传入的输出流创建ZipOutputStream
+			ZipOutputStream zos = new ZipOutputStream(outputStream);
+			// 使用BEST_SPEED而不是BEST_COMPRESSION,提高速度
+			zos.setLevel(Deflater.BEST_SPEED);
+
+			// 使用较小的缓冲区,减少内存使用
+			final int BUFFER_SIZE = 1024 * 1024; // 1MB
+			byte[] buffer = new byte[BUFFER_SIZE];
+
+			// 创建Minio客户端
+			MinioClient minioClient = MinioClient.builder()
+				.endpoint(minioPojo.getPath())
+				.credentials(minioPojo.getAccessKey(), minioPojo.getSecretKey())
+				.build();
+
+			// 创建一个Set来跟踪已经使用的文件名,避免重名
+			Set<String> usedFileNames = new HashSet<>();
+
+			// 直接遍历所有附件,不再按任务分组
+			for (AttachVO attachVO : attachList) {
+				String objectName = attachVO.getName();
+				try {
+					// 从MinIO获取文件流
+					InputStream is = minioClient.getObject(
+						GetObjectArgs.builder()
+							.bucket(minioPojo.getBucket())
+							.object(objectName)
+							.build());
+
+					// 提取文件名(不包含路径)
+					String fileName = objectName.substring(objectName.lastIndexOf("/") + 1);
+
+					// 处理文件名冲突
+					String uniqueFileName = fileName;
+					int counter = 1;
+					while (usedFileNames.contains(uniqueFileName)) {
+						// 如果文件名已存在,在文件名和扩展名之间添加计数器
+						int dotIndex = fileName.lastIndexOf(".");
+						if (dotIndex > 0) {
+							uniqueFileName = fileName.substring(0, dotIndex) + "_" + counter + fileName.substring(dotIndex);
+						} else {
+							uniqueFileName = fileName + "_" + counter;
+						}
+						counter++;
+					}
+
+					// 将文件名添加到已使用集合中
+					usedFileNames.add(uniqueFileName);
+
+					// 创建zip条目(直接放在根目录下)
+					ZipEntry zipEntry = new ZipEntry(uniqueFileName);
+					zos.putNextEntry(zipEntry);
+
+					// 将文件内容写入zip
+					int length;
+					while ((length = is.read(buffer)) > 0) {
+						zos.write(buffer, 0, length);
+						// 每写入一块数据后刷新,确保数据及时发送到客户端
+						zos.flush();
+					}
+
+					// 关闭资源
+					zos.closeEntry();
+					is.close();
+				} catch (Exception e) {
+					log.error("处理文件 {} 失败: {}", objectName, e.getMessage());
+				}
+			}
+			// 确保所有数据都被写入
+			zos.finish();
+			zos.flush();
+			// 注意:不要关闭ZipOutputStream,因为它会关闭底层的OutputStream
+			// 让调用者负责关闭输出流
+
+			return true;
+
+		} catch (Exception e) {
+			log.error("创建zip文件失败", e);
+			return false;
+		} finally {
+			if (outputStream != null) {
+				try {
+					outputStream.flush();
+				} catch (IOException e) {
+					log.error("Error flushing output stream: {}", e.getMessage());
+				}
+				try {
+					outputStream.close();
+				} catch (IOException e) {
+					log.error("Error closing output stream: {}", e.getMessage());
+				}
+			}
+		}
+	}
+
 }

--
Gitblit v1.9.3