diff --git a/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java b/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java new file mode 100644 index 0000000..5cb5e08 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java @@ -0,0 +1,176 @@ +package com.yfd.platform.data.service; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +@Service +public class AttachmentUploadService { + + private static final String UPLOAD_URL = "https://211.99.26.225:12125/upload"; + private static final String VIDEO_URL = "https://211.99.26.225:12125/upload"; + + private final HttpClient httpClient; + + public AttachmentUploadService() { + this.httpClient = HttpClient.newBuilder() + .build(); + } + + public String uploadFile(File file) throws IOException, InterruptedException { + if (file == null || !file.exists()) { + log.warn("文件不存在或为空: {}", file); + return null; + } + + String boundary = "----FormBoundary" + System.currentTimeMillis(); + byte[] fileContent = Files.readAllBytes(file.toPath()); + String fileName = file.getName(); + + String header = "--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"" + fileName + "\"\r\n" + + "Content-Type: application/octet-stream\r\n\r\n"; + String footer = "\r\n--" + boundary + "--\r\n"; + + byte[] body; + if (fileName.toLowerCase().endsWith(".mp4") || fileName.toLowerCase().endsWith(".avi") || + fileName.toLowerCase().endsWith(".mov") || fileName.toLowerCase().endsWith(".wmv")) { + body = new byte[header.getBytes().length + fileContent.length + footer.getBytes().length]; + System.arraycopy(header.getBytes(), 0, body, 0, header.getBytes().length); + System.arraycopy(fileContent, 0, body, header.getBytes().length, fileContent.length); + System.arraycopy(footer.getBytes(), 0, body, header.getBytes().length + fileContent.length, footer.getBytes().length); + } else { + body = new byte[header.getBytes().length + fileContent.length + footer.getBytes().length]; + System.arraycopy(header.getBytes(), 0, body, 0, header.getBytes().length); + System.arraycopy(fileContent, 0, body, header.getBytes().length, fileContent.length); + System.arraycopy(footer.getBytes(), 0, body, header.getBytes().length + fileContent.length, footer.getBytes().length); + } + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(UPLOAD_URL)) + .header("Content-Type", "multipart/form-data; boundary=" + boundary) + .POST(HttpRequest.BodyPublishers.ofByteArray(body)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200) { + String responseBody = response.body(); + return parseAttachmentId(responseBody); + } else { + log.error("上传文件失败: {}, 状态码: {}", fileName, response.statusCode()); + return null; + } + } + + public String uploadVideo(File file) throws IOException, InterruptedException { + return uploadFile(file); + } + + public String uploadImage(File file) throws IOException, InterruptedException { + return uploadFile(file); + } + + public Map uploadImages(Map imageMap) { + Map result = new ConcurrentHashMap<>(); + for (Map.Entry entry : imageMap.entrySet()) { + String fileName = entry.getKey(); + String filePath = entry.getValue(); + try { + File file = new File(filePath); + if (file.exists()) { + String attachmentId = uploadFile(file); + if (attachmentId != null) { + result.put(fileName, attachmentId); + log.info("图片上传成功: {} -> {}", fileName, attachmentId); + } else { + log.warn("图片上传返回空ID: {}", fileName); + } + } else { + log.warn("图片文件不存在: {}", filePath); + } + } catch (Exception e) { + log.error("上传图片失败: {}", fileName, e); + } + } + return result; + } + + public Map uploadVideos(Map videoMap) { + Map result = new ConcurrentHashMap<>(); + for (Map.Entry entry : videoMap.entrySet()) { + String fileName = entry.getKey(); + String filePath = entry.getValue(); + try { + File file = new File(filePath); + if (file.exists()) { + String attachmentId = uploadFile(file); + if (attachmentId != null) { + result.put(fileName, attachmentId); + log.info("视频上传成功: {} -> {}", fileName, attachmentId); + } else { + log.warn("视频上传返回空ID: {}", fileName); + } + } else { + log.warn("视频文件不存在: {}", filePath); + } + } catch (Exception e) { + log.error("上传视频失败: {}", fileName, e); + } + } + return result; + } + + private String parseAttachmentId(String jsonResponse) { + if (jsonResponse == null || jsonResponse.isEmpty()) { + return null; + } + + try { + if (jsonResponse.contains("\"message\":")) { + int start = jsonResponse.indexOf("\"message\":\"") + 11; + int end = jsonResponse.indexOf("\"", start); + if (start > 10 && end > start) { + return jsonResponse.substring(start, end); + } + } + if (jsonResponse.contains("\"message\":\"")) { + int start = jsonResponse.indexOf("\"message\":\"") + 11; + int end = jsonResponse.indexOf("\"", start); + if (start > 10 && end > start) { + return jsonResponse.substring(start, end); + } + } + } catch (Exception e) { + log.error("解析附件ID失败: {}", jsonResponse, e); + } + return null; + } + + public String uploadFileAndGetId(String filePath) { + if (filePath == null || filePath.isEmpty()) { + return null; + } + File file = new File(filePath); + if (!file.exists()) { + log.warn("文件不存在: {}", filePath); + return null; + } + try { + return uploadFile(file); + } catch (Exception e) { + log.error("上传文件失败: {}", filePath, e); + return null; + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/data/service/impl/FishImportServiceImpl.java b/backend/src/main/java/com/yfd/platform/data/service/impl/FishImportServiceImpl.java index fb6b136..3848f80 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/impl/FishImportServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/data/service/impl/FishImportServiceImpl.java @@ -3,6 +3,7 @@ package com.yfd.platform.data.service.impl; import com.yfd.platform.data.domain.FishDraftData; import com.yfd.platform.data.domain.FishImportRequest; import com.yfd.platform.data.domain.FishImportResult; +import com.yfd.platform.data.service.AttachmentUploadService; import com.yfd.platform.data.service.IFishImportService; import com.yfd.platform.data.utils.ZipFileUtil; import com.yfd.platform.env.domain.*; @@ -50,6 +51,9 @@ public class FishImportServiceImpl implements IFishImportService { @Resource private ISysDictionaryItemsService sysDictionaryItemsService; + @Resource + private AttachmentUploadService attachmentUploadService; + private static final Map EXCEL_COLUMN_MAPPING = new LinkedHashMap<>(); private static final Map EXCEL_COLUMN_INDEX_MAPPING = new LinkedHashMap<>(); @@ -143,8 +147,6 @@ public class FishImportServiceImpl implements IFishImportService { Map columnIndexMap = new HashMap<>(EXCEL_COLUMN_INDEX_MAPPING); int totalRows = sheet.getLastRowNum(); - result.setTotalCount(totalRows); - for (int i = 1; i <= totalRows; i++) { Row row = sheet.getRow(i); if (row == null || isRowEmpty(row)) { @@ -152,6 +154,7 @@ public class FishImportServiceImpl implements IFishImportService { } FishImportResult.FishImportRow importRow = parseRow(row, columnIndexMap, i); + result.setTotalCount(result.getTotalCount() + 1); if (importRow.getData() != null && importRow.getWarnings().isEmpty()) { result.getSuccessRows().add(importRow); result.setSuccessCount(result.getSuccessCount() + 1); @@ -160,9 +163,8 @@ public class FishImportServiceImpl implements IFishImportService { result.setFailedCount(result.getFailedCount() + 1); } } - - result.setSummary(String.format("共解析%d条数据,成功%d条,失败%d条,未识别字段:%s", - result.getTotalCount(), result.getSuccessCount(), result.getFailedCount(), + result.setSummary(String.format("共解析%d条数据,失败%d条,未识别字段:%s", + result.getSuccessCount(), result.getFailedCount(), unrecognizedHeaders.isEmpty() ? "无" : String.join(", ", unrecognizedHeaders))); return result; @@ -714,6 +716,8 @@ public class FishImportServiceImpl implements IFishImportService { result.setExcelFileName(zipContent.excelFileName); result.setExcelFilePath(zipContent.excelFilePath); + processAttachments(result, zipContent); + result.setSummary(result.getSummary() + String.format("\nZIP内容: 发现%d张图片, %d个视频, 临时目录: %s", zipContent.images.size(), zipContent.videos.size(), zipContent.tempDir)); @@ -726,4 +730,120 @@ public class FishImportServiceImpl implements IFishImportService { return result; } } + + private void processAttachments(FishImportResult result, ZipFileUtil.ZipContent zipContent) { + if (result.getSuccessRows() == null || result.getSuccessRows().isEmpty()) { + return; + } + + for (FishImportResult.FishImportRow importRow : result.getSuccessRows()) { + FishDraftData data = importRow.getData(); + if (data == null) { + continue; + } + + String vdpth = data.getVdpth(); + String picpth = data.getPicpth(); + + if (StringUtils.hasText(vdpth)) { + String uploadedVdpth = processVideoAttachments(vdpth, zipContent.videos); + data.setVdpth(uploadedVdpth); + } + + if (StringUtils.hasText(picpth)) { + String uploadedPicpth = processImageAttachments(picpth, zipContent.images); + data.setPicpth(uploadedPicpth); + } + } + } + + private String processVideoAttachments(String videoNames, Map videoMap) { + if (videoNames == null || videoNames.isEmpty() || videoMap == null || videoMap.isEmpty()) { + return videoNames; + } + + String[] fileNames = videoNames.split(";"); + List attachmentIds = new ArrayList<>(); + + for (String fileName : fileNames) { + fileName = fileName.trim(); + if (fileName.isEmpty()) { + continue; + } + + String actualPath = findFilePath(fileName, videoMap); + if (actualPath != null) { + try { + String attachmentId = attachmentUploadService.uploadFileAndGetId(actualPath); + if (attachmentId != null) { + attachmentIds.add(attachmentId); + } else { + attachmentIds.add(fileName); + } + } catch (Exception e) { + attachmentIds.add(fileName); + } + } else { + attachmentIds.add(fileName); + } + } + + return String.join(",", attachmentIds); + } + + private String processImageAttachments(String imageNames, Map imageMap) { + if (imageNames == null || imageNames.isEmpty() || imageMap == null || imageMap.isEmpty()) { + return imageNames; + } + + String[] fileNames = imageNames.split(";"); + List attachmentIds = new ArrayList<>(); + + for (String fileName : fileNames) { + fileName = fileName.trim(); + if (fileName.isEmpty()) { + continue; + } + + String actualPath = findFilePath(fileName, imageMap); + if (actualPath != null) { + try { + String attachmentId = attachmentUploadService.uploadFileAndGetId(actualPath); + if (attachmentId != null) { + attachmentIds.add(attachmentId); + } else { + attachmentIds.add(fileName); + } + } catch (Exception e) { + attachmentIds.add(fileName); + } + } else { + attachmentIds.add(fileName); + } + } + + return String.join(",", attachmentIds); + } + + private String findFilePath(String fileName, Map fileMap) { + if (fileName == null || fileMap == null || fileMap.isEmpty()) { + return null; + } + + for (Map.Entry entry : fileMap.entrySet()) { + String entryName = entry.getKey(); + if (entryName.equals(fileName) || entryName.endsWith("/" + fileName) || entryName.endsWith("\\" + fileName)) { + return entry.getValue(); + } + String entryFileName = entryName; + int lastSep = Math.max(entryName.lastIndexOf('/'), entryName.lastIndexOf('\\')); + if (lastSep >= 0) { + entryFileName = entryName.substring(lastSep + 1); + } + if (entryFileName.equals(fileName)) { + return entry.getValue(); + } + } + return null; + } } \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/env/controller/SdRvcdDicController.java b/backend/src/main/java/com/yfd/platform/env/controller/SdRvcdDicController.java index c6b2b1c..c4f0890 100644 --- a/backend/src/main/java/com/yfd/platform/env/controller/SdRvcdDicController.java +++ b/backend/src/main/java/com/yfd/platform/env/controller/SdRvcdDicController.java @@ -2,9 +2,11 @@ package com.yfd.platform.env.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.annotation.Log; +import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.config.ResponseResult; import com.yfd.platform.env.domain.SdRvcdDic; import com.yfd.platform.env.service.ISdRvcdDicService; +import com.yfd.platform.utils.DataSourceRequestUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.web.bind.annotation.*; @@ -43,6 +45,13 @@ public class SdRvcdDicController { return ResponseResult.successData(rvcdDicService.list()); } + @PostMapping("/queryList") + @Operation(summary = "查询流域") + public ResponseResult queryList(@RequestBody DataSourceRequest dataSourceRequest) { + List sdRvcdDics = DataSourceRequestUtil.executeList(dataSourceRequest, SdRvcdDic.class, rvcdDicService); + return ResponseResult.successData(sdRvcdDics); + } + @GetMapping("/getByPrvcd") @Operation(summary = "根据父编码查询流域") public ResponseResult getByPrvcd(@RequestParam(required = false) String prvcd) { @@ -62,6 +71,14 @@ public class SdRvcdDicController { return ResponseResult.successData(rvcdDicService.getById(rvcd)); } + @GetMapping("/tree") + @Operation(summary = "获取流域树形结构") + public ResponseResult getTree( + @RequestParam(required = false) String rvcd, + @RequestParam(required = false) String rvnm) { + return ResponseResult.successData(rvcdDicService.getTree(rvcd, rvnm)); + } + // @Log(module = "流域管理", value = "新增流域") @PostMapping("/add") @Operation(summary = "新增流域") diff --git a/backend/src/main/java/com/yfd/platform/env/domain/SdRvcdDic.java b/backend/src/main/java/com/yfd/platform/env/domain/SdRvcdDic.java index 239cc4d..9f3a967 100644 --- a/backend/src/main/java/com/yfd/platform/env/domain/SdRvcdDic.java +++ b/backend/src/main/java/com/yfd/platform/env/domain/SdRvcdDic.java @@ -6,6 +6,7 @@ import lombok.EqualsAndHashCode; import java.io.Serializable; import java.util.Date; +import java.util.List; /** *

@@ -114,4 +115,10 @@ public class SdRvcdDic implements Serializable { * 地图专题流域标识:1=是 0否 */ private Integer ismap; + + /** + * 子节点(用于树形结构,不映射数据库字段) + */ + @TableField(exist = false) + private List children; } diff --git a/backend/src/main/java/com/yfd/platform/env/service/ISdRvcdDicService.java b/backend/src/main/java/com/yfd/platform/env/service/ISdRvcdDicService.java index a66fb6a..ea8da57 100644 --- a/backend/src/main/java/com/yfd/platform/env/service/ISdRvcdDicService.java +++ b/backend/src/main/java/com/yfd/platform/env/service/ISdRvcdDicService.java @@ -42,4 +42,11 @@ public interface ISdRvcdDicService extends IService { * 删除流域 */ boolean deleteRvcdDic(String rvcd); + + /** + * 获取流域树形结构 + * @param rvcd 流域编码(可选,为空则返回全部) + * @param rvnm 流域名称(可选,用于模糊搜索) + */ + List getTree(String rvcd, String rvnm); } diff --git a/backend/src/main/java/com/yfd/platform/env/service/impl/SdRvcdDicServiceImpl.java b/backend/src/main/java/com/yfd/platform/env/service/impl/SdRvcdDicServiceImpl.java index 51e4b69..85f77a4 100644 --- a/backend/src/main/java/com/yfd/platform/env/service/impl/SdRvcdDicServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/env/service/impl/SdRvcdDicServiceImpl.java @@ -6,8 +6,10 @@ import com.yfd.platform.env.domain.SdRvcdDic; import com.yfd.platform.env.mapper.SdRvcdDicMapper; import com.yfd.platform.env.service.ISdRvcdDicService; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** *

@@ -58,4 +60,58 @@ public class SdRvcdDicServiceImpl extends ServiceImpl getTree(String rvcd, String rvnm) { + List result = new ArrayList<>(); + + List rootList; + Set rootRvcdSet = new HashSet<>(); + + if (StringUtils.hasText(rvcd)) { + SdRvcdDic singleRvcd = this.getById(rvcd); + if (singleRvcd != null) { + rootList = new ArrayList<>(); + rootList.add(singleRvcd); + rootRvcdSet.add(singleRvcd.getRvcd()); + } else { + return result; + } + } else { + rootList = getRootList(); + for (SdRvcdDic root : rootList) { + rootRvcdSet.add(root.getRvcd()); + } + } + + List allList = this.lambdaQuery() + .like(StringUtils.hasText(rvnm), SdRvcdDic::getRvnm, rvnm) + .orderByAsc(SdRvcdDic::getOrderIndex) + .list(); + + Map> childrenMap = allList.stream() + .filter(item -> item.getPrvcd() != null) + .collect(Collectors.groupingBy(SdRvcdDic::getPrvcd)); + + for (SdRvcdDic root : rootList) { + if (rootRvcdSet.contains(root.getRvcd())) { + buildTreeRecursive(root, childrenMap, rootRvcdSet); + result.add(root); + } + } + + return result; + } + + private void buildTreeRecursive(SdRvcdDic parent, Map> childrenMap, Set rootRvcdSet) { + List children = childrenMap.get(parent.getRvcd()); + if (children != null && !children.isEmpty()) { + for (SdRvcdDic child : children) { + buildTreeRecursive(child, childrenMap, rootRvcdSet); + } + parent.setChildren(children); + } else { + parent.setChildren(new ArrayList<>()); + } + } +} \ No newline at end of file diff --git a/backend/src/main/resources/mapper/env/SdEngInfoBHMapper.xml b/backend/src/main/resources/mapper/env/SdEngInfoBHMapper.xml index 06101d4..a1b6923 100644 --- a/backend/src/main/resources/mapper/env/SdEngInfoBHMapper.xml +++ b/backend/src/main/resources/mapper/env/SdEngInfoBHMapper.xml @@ -234,7 +234,7 @@