From 6ee6386344d4c5c986c43bc3057d386c474c91ad Mon Sep 17 00:00:00 2001 From: lilin Date: Mon, 23 Jun 2025 18:02:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- java/pom.xml | 3 + .../controller/TsNodesController.java | 59 ++++- .../controller/TsTaskController.java | 51 +++- .../domain/MoveCopyFileFolderRequest.java | 1 + .../service/ITsTaskService.java | 8 +- .../service/impl/TsFilesServiceImpl.java | 248 ++++++++++++++---- .../service/impl/TsNodesServiceImpl.java | 159 +++++++---- .../service/impl/TsTaskServiceImpl.java | 201 ++++++++++++-- .../controller/NodesController.java | 51 +++- .../controller/ProjectController.java | 50 +++- .../specialDocument/mapper/ProjectMapper.java | 7 + .../service/IProjectService.java | 8 +- .../service/impl/FilesServiceImpl.java | 2 +- .../service/impl/NodesServiceImpl.java | 43 ++- .../service/impl/ProjectServiceImpl.java | 219 ++++++++++++---- .../impl/StorageSourceConvertImpl.java | 80 ++++-- .../storage/service/StorageSourceService.java | 46 +++- 17 files changed, 1007 insertions(+), 229 deletions(-) diff --git a/java/pom.xml b/java/pom.xml index 8d6c87c..49eab6e 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -19,11 +19,14 @@ 1.8 + + org.springframework.boot spring-boot-starter-web + com.google.zxing diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsNodesController.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsNodesController.java index 0df063b..f8bf704 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsNodesController.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsNodesController.java @@ -8,11 +8,16 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.yfd.platform.annotation.Log; import com.yfd.platform.component.TaskStatusHolder; import com.yfd.platform.config.ResponseResult; +import com.yfd.platform.modules.experimentalData.domain.TsFiles; import com.yfd.platform.modules.experimentalData.domain.TsNodes; +import com.yfd.platform.modules.experimentalData.domain.TsTask; +import com.yfd.platform.modules.experimentalData.service.ITsFilesService; import com.yfd.platform.modules.experimentalData.service.ITsNodesService; import com.yfd.platform.modules.experimentalData.service.ITsTaskService; +import com.yfd.platform.modules.specialDocument.domain.Files; import com.yfd.platform.modules.specialDocument.domain.Nodes; import com.yfd.platform.system.domain.LoginUser; +import com.yfd.platform.utils.TableNameContextHolder; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; @@ -42,6 +47,14 @@ public class TsNodesController { @Resource private ITsNodesService tsNodesService; + //试验任务节点服务类 + @Resource + private ITsFilesService tsFilesService; + + //试验任务节点服务类 + @Resource + private ITsTaskService tsTaskService; + @Autowired private TaskStatusHolder taskStatusHolder; @@ -164,7 +177,7 @@ public class TsNodesController { // 原子性启动新任务 if (taskStatusHolder.startTaskIfAbsent(asyncKey)) { // 直接异步执行并推送结果 - tsNodesService.testDataScanByIdAsync(id,loginuser); + tsNodesService.testDataScanByIdAsync(id, loginuser); return ResponseResult.success("验数据扫描任务开始处理!"); } else { return ResponseResult.success("验数据扫描任务已由其他请求启动!"); @@ -206,7 +219,6 @@ public class TsNodesController { } - /********************************** * 用途说明: 查询可不可以初始化试验任务扫描 * 参数说明 taskId 试验任务ID @@ -216,17 +228,56 @@ public class TsNodesController { @PostMapping("/selectTsNodesByTskeId") @ApiOperation("查询可不可以初始化试验任务扫描") @PreAuthorize("@el.check('del:tsnodes')") - public ResponseResult selectTsNodesByTskeId( String taskId) { + public ResponseResult selectTsNodesByTskeId(String taskId) { if (StrUtil.isBlank(taskId)) { return ResponseResult.error("参数为空"); } List tsNodesList = tsNodesService.list(new QueryWrapper().eq("task_id", taskId)); //如果节点不为空 就不能初始化了 - if (tsNodesList.size()>0) { + if (tsNodesList.size() > 0) { return ResponseResult.success("该项目已经初始化完成,局部更新请选择节点上传文件!"); } else { return ResponseResult.success("可以初始化!"); } } + /********************************** + * 用途说明: 查询可不可以初始化专项文档扫描 + * 参数说明 projectId 所属项目ID + * 返回值说明: com.yfd.platform.config.ResponseResult + ***********************************/ + @Log(module = "查询可不可以修改项目", value = "查询可不可以修改项目!") + @PostMapping("/selectTsNodesById") + @ApiOperation("查询可不可以修改项目") + public ResponseResult selectTsNodesById(String taskId) { + try { + if (StrUtil.isBlank(taskId)) { + return ResponseResult.error("参数为空"); + } + TsTask tsTask = tsTaskService.getById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + List tsNodesList = tsNodesService.list(new QueryWrapper().eq("task_id", taskId)); + // 如果节点不为空 就不能初始化了 + if (tsNodesList.size() > 0) { + return ResponseResult.successData(false); + } else { + // 如果节点为空 就判断文件表 + List filesList = tsFilesService.list(new QueryWrapper().eq("task_id", taskId)); + if (filesList.size() > 0) { + return ResponseResult.successData(false); + } else { + return ResponseResult.successData(true); + } + } + } catch (Exception e) { + // 捕获所有异常并记录日志 + // log.error("查询可不可以修改项目时发生异常: {}", e.getMessage(), e); + return ResponseResult.error("系统异常,请稍后再试"); + }finally { + TableNameContextHolder.clear(); + + } + + } + } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java index 35f67a4..b6556c6 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java @@ -3,6 +3,8 @@ package com.yfd.platform.modules.experimentalData.controller; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.annotation.Log; @@ -10,14 +12,20 @@ import com.yfd.platform.config.ResponseResult; import com.yfd.platform.modules.experimentalData.domain.TsTask; import com.yfd.platform.modules.experimentalData.service.ITsTaskService; import com.yfd.platform.modules.specialDocument.domain.Project; +import com.yfd.platform.utils.StringUtils; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; /** *

@@ -56,9 +64,42 @@ public class TsTaskController { @GetMapping("/page") @ApiOperation("分页查询试验数据管理试验任务管理") @PreAuthorize("@el.check('select:tsTask')") - public ResponseResult getTsTaskPage(String taskName, String startDate, String endDate, String taskPlace, String taskPerson, String taskCode, String taskType, String carrierName, String deviceCode, String testDescribe, String sensorDescribe, Page page) { + public ResponseResult getTsTaskPage(String taskName, String startDate, String endDate, String taskPlace, String taskPerson, String taskCode, String taskType, String carrierName, String deviceCode, String testDescribe, String sensorDescribe, Page page, String attributeContentJson) { + // 双重解码处理 + if (attributeContentJson != null) { + try { + // 第二次解码:%5B → [ + attributeContentJson = URLDecoder.decode(attributeContentJson, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + return ResponseResult.error("参数解码错误"); + } + } + + // 将JSON字符串转换为List> + List> attributeContent = null; + if (StringUtils.isNotEmpty(attributeContentJson)) { + try { + // 使用 TypeReference 指定精确类型 + attributeContent = JSON.parseObject( + attributeContentJson, + new TypeReference>>() { + } + ); + + // 遍历并移除空值字段 + if (attributeContent != null) { + for (Map item : attributeContent) { + // 遍历 Map,移除值为空的键值对 + item.entrySet().removeIf(entry -> entry.getValue() == null || entry.getValue().isEmpty()); + } + } + } catch (Exception e) { + return ResponseResult.error("属性参数格式错误"); + } + } + //分页查询 - Page sdProjectPage = tsTaskService.getTsTaskPage(taskName, startDate, endDate, taskPlace, taskPerson, taskCode, taskType, carrierName, deviceCode, testDescribe, sensorDescribe, page); + Page sdProjectPage = tsTaskService.getTsTaskPage(taskName, startDate, endDate, taskPlace, taskPerson, taskCode, taskType, carrierName, deviceCode, testDescribe, sensorDescribe, page, attributeContent); return ResponseResult.successData(sdProjectPage); } @@ -73,12 +114,12 @@ public class TsTaskController { @ApiOperation("新增试验数据管理试验任务管理") @ResponseBody @PreAuthorize("@el.check('add:tsTask')") - public ResponseResult addtsTask(@RequestBody TsTask tsTask) { + public ResponseResult addtsTask(@RequestBody TsTask tsTask) throws IOException { //对象不能为空 if (ObjUtil.isEmpty(tsTask)) { return ResponseResult.error("参数为空"); } - Boolean isOk = tsTaskService.addSdproject(tsTask); + Boolean isOk = tsTaskService.addtsTask(tsTask); if (isOk) { return ResponseResult.success(); } else { @@ -96,7 +137,7 @@ public class TsTaskController { @PostMapping("/updatetsTask") @ApiOperation("修改试验数据管理试验任务管理") @PreAuthorize("@el.check('update:tsTask')") - public ResponseResult updatetsTask(@RequestBody TsTask tsTask) { + public ResponseResult updatetsTask(@RequestBody TsTask tsTask) throws IOException { //对象不能为空 if (ObjUtil.isEmpty(tsTask) && StrUtil.isBlank(tsTask.getId())) { return ResponseResult.error("参数为空"); diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/MoveCopyFileFolderRequest.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/MoveCopyFileFolderRequest.java index d3c68c7..4b0dd01 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/MoveCopyFileFolderRequest.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/MoveCopyFileFolderRequest.java @@ -13,5 +13,6 @@ public class MoveCopyFileFolderRequest { private String rename; private String type; private String taskId; + private String nodeId; } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java index 492ee06..acc5f83 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java @@ -4,7 +4,9 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.modules.experimentalData.domain.TsTask; import com.baomidou.mybatisplus.extension.service.IService; +import java.io.IOException; import java.util.List; +import java.util.Map; /** *

@@ -34,7 +36,7 @@ public interface ITsTaskService extends IService { * pageNum 当前页 * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 ***********************************/ - Page getTsTaskPage(String taskName, String startDate, String endDate, String taskPlace, String taskPerson, String taskCode, String taskType,String carrierName,String deviceCode,String testDescribe,String sensorDescribe, Page page); + Page getTsTaskPage(String taskName, String startDate, String endDate, String taskPlace, String taskPerson, String taskCode, String taskType,String carrierName,String deviceCode,String testDescribe,String sensorDescribe, Page page,List> attributeContent); /*********************************** * 用途说明:新增试验数据管理-试验任务管理 @@ -42,7 +44,7 @@ public interface ITsTaskService extends IService { * TsTask 试验任务管理 * 返回值说明: com.yfd.platform.config.ResponseResult 返回新增成功或者失败 ***********************************/ - Boolean addSdproject(TsTask tsTask); + Boolean addtsTask(TsTask tsTask) throws IOException; /********************************** * 用途说明: 修改试验数据管理-试验任务管理 @@ -50,7 +52,7 @@ public interface ITsTaskService extends IService { * TsTask 试验任务管理 * 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败 ***********************************/ - boolean updatetsTask(TsTask tsTask); + boolean updatetsTask(TsTask tsTask) throws IOException; /********************************** * 用途说明: 批量删除试验数据管理-试验任务管理 diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java index d939f7a..6764a15 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java @@ -3333,7 +3333,10 @@ public class TsFilesServiceImpl extends ServiceImpl impl StorageSourceConfig storageSourceConfig = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); StorageSourceConfig storageSourceConfig1 = getStorageSourceConfig("bucketName", "minio",tsTask.getBackupStorageId()); List parameterLists = parameter.getParameterLists(); - + // 设置当前时间 + LocalDateTime now = LocalDateTime.now(); + // 转换为 Timestamp + Timestamp currentTime = Timestamp.valueOf(now); // 在循环前记录开始时间 long startTime = System.currentTimeMillis(); //循环一条一条上传 @@ -3370,16 +3373,16 @@ public class TsFilesServiceImpl extends ServiceImpl impl if (flag) { LOGGER.info("同步本地到minio,minio文件夹创建成功"); value = true; -// currentFile.setUpdateTime(currentTime); -// currentFile.setBackupPath(minioPath); -// int valueAdded = tsFilesMapper.updateById(currentFile); -// if (valueAdded == 1) { -// LOGGER.info("同步本地到minio,minio文件夹创建成功,表结构修改成功。"); -// value = true; -// } else { -// LOGGER.error("同步本地到minio,minio文件夹创建成功,表结构修改失败"); -// value = false; -// } + currentFile.setUpdateTime(currentTime); + currentFile.setBackupPath(minioPath); + int valueAdded = tsFilesMapper.updateById(currentFile); + if (valueAdded == 1) { + LOGGER.info("同步本地到minio,minio文件夹创建成功,表结构修改成功。"); + value = true; + } else { + LOGGER.error("同步本地到minio,minio文件夹创建成功,表结构修改失败"); + value = false; + } } else { LOGGER.error("同步本地到minio,minio文件夹创建失败"); @@ -3421,16 +3424,151 @@ public class TsFilesServiceImpl extends ServiceImpl impl LOGGER.info("同步本地到minio,minio文件创建成功"); value = true; -// currentFile.setUpdateTime(currentTime); -// currentFile.setBackupPath(minioPath); -// int valueAdded = tsFilesMapper.updateById(currentFile); -// if (valueAdded == 1) { -// LOGGER.info("同步本地到minio,minio文件创建成功,表结构修改成功。"); -// value = true; -// } else { -// LOGGER.error("同步本地到minio,minio文件创建成功,表结构修改失败"); -// value = false; -// } + currentFile.setUpdateTime(currentTime); + currentFile.setBackupPath(minioPath); + int valueAdded = tsFilesMapper.updateById(currentFile); + if (valueAdded == 1) { + LOGGER.info("同步本地到minio,minio文件创建成功,表结构修改成功。"); + value = true; + } else { + LOGGER.error("同步本地到minio,minio文件创建成功,表结构修改失败"); + value = false; + } + } else { + LOGGER.error("同步本地到minio,minio文件创建失败"); + value = false; + } + } + } + // 计算总耗时 + long endTime = System.currentTimeMillis(); + long totalTime = endTime - startTime; + LOGGER.info("把本地文件放到minio循环执行耗时: {} 毫秒 (约 {} 秒)", totalTime, totalTime / 1000.0); + + return value; + } catch (Exception e) { + LOGGER.error("上传到备份空间时发生异常: {}", e.getMessage(), e); + return false; + } finally { + TableNameContextHolder.clear(); + } + } + + + + /********************************** + * 用途说明: 将文件上传到备份空间 其他接口使用 + * 参数说明 parameter 数据集合 + * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败 + ***********************************/ + public Boolean uploadToBackupData(Parameter parameter) { + Boolean value = false; + try { + TsTask tsTask = tsTaskMapper.selectById(parameter.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + StorageSource storageSourceLocal = getStorageConfig(tsTask.getLocalStorageId()); + StorageSource storageSourceMinio = getStorageConfig(tsTask.getBackupStorageId()); + StorageSourceConfig storageSourceConfig = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + StorageSourceConfig storageSourceConfig1 = getStorageSourceConfig("bucketName", "minio",tsTask.getBackupStorageId()); + List parameterLists = parameter.getParameterLists(); + + // 在循环前记录开始时间 + long startTime = System.currentTimeMillis(); + //循环一条一条上传 + for (ParameterList parameterListData : parameterLists) { + if ("FOLDER".equals(parameterListData.getType())) { + String name = parameterListData.getName(); + // 处理路径格式 + String path = normalizePath(parameterListData.getPath()); + + String minioPath = path;//// MinIO上传目标路径 + // 使用Java NIO的Path类来构造压缩文件的完整路径,存储在localPath目录下 + // 查询当前文件记录 + TsFiles currentFile = getFileRecord(name, path); + if (currentFile == null) return false; + + // 递归创建父文件夹 + boolean parentsCreated = createParentFolders(currentFile.getParentId()); + if (!parentsCreated) { + LOGGER.error("父文件夹创建失败"); + return false; + } + + //新增节点的时候 创建文件夹 + NewFolderRequest newFolderRequest = new NewFolderRequest(); + newFolderRequest.setName(currentFile.getFileName());//新建的文件夹名称,示例值(/a/b/c) + newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) + newFolderRequest.setPath(minioPath);//请求路径,示例值(/) + newFolderRequest.setStorageKey(storageSourceMinio.getKey());//存储源 key,示例值(local minio) + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); + boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); + LOGGER.info("同步本地到minio文件夹路径加名称" + newFolderRequest.getPath() + newFolderRequest.getName()); + + //如果文件夹创建成功 + if (flag) { + LOGGER.info("同步本地到minio,minio文件夹创建成功"); + value = true; +// currentFile.setUpdateTime(currentTime); +// currentFile.setBackupPath(minioPath); +// int valueAdded = tsFilesMapper.updateById(currentFile); +// if (valueAdded == 1) { +// LOGGER.info("同步本地到minio,minio文件夹创建成功,表结构修改成功。"); +// value = true; +// } else { +// LOGGER.error("同步本地到minio,minio文件夹创建成功,表结构修改失败"); +// value = false; +// } + + } else { + LOGGER.error("同步本地到minio,minio文件夹创建失败"); + value = false; + } + } else { + + String name = parameterListData.getName(); + // 处理路径格式 + String path = normalizePath(parameterListData.getPath()); + + String localPath = storageSourceConfig.getValue() + path;//localPath是本地的路径 + String minioPath = path;//// MinIO上传目标路径 + + // 使用Java NIO的Path类来构造压缩文件的完整路径,存储在localPath目录下 + Path FilePath = Paths.get(localPath, name); + // 4. 上传压缩文件到MinIO + File zipFile = FilePath.toFile(); // 获取本地文件 + + // 查询当前文件记录 + TsFiles currentFile = getFileRecord(name, path); + if (currentFile == null) { + return false; + } + + // 递归创建父文件夹 + boolean parentsCreated = createParentFolders(currentFile.getParentId()); + if (!parentsCreated) { + LOGGER.error("父文件夹创建失败"); + return false; + } + //把本地文件上传到minio + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey("minio"); + boolean flag1 = fileService.UploadFiles(storageSourceConfig1.getValue(), minioPath + name, zipFile); + LOGGER.info("同步本地到minio文件路径加名称" + storageSourceConfig1.getValue() + minioPath + name); + + //如果上传成功 修改 表结构 + if (flag1) { + LOGGER.info("同步本地到minio,minio文件创建成功"); + value = true; + +// currentFile.setUpdateTime(currentTime); +// currentFile.setBackupPath(minioPath); +// int valueAdded = tsFilesMapper.updateById(currentFile); +// if (valueAdded == 1) { +// LOGGER.info("同步本地到minio,minio文件创建成功,表结构修改成功。"); +// value = true; +// } else { +// LOGGER.error("同步本地到minio,minio文件创建成功,表结构修改失败"); +// value = false; +// } } else { LOGGER.error("同步本地到minio,minio文件创建失败"); value = false; @@ -3603,7 +3741,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl fileParameterlist.add(parameterList); fileParameter.setParameterLists(fileParameterlist); fileParameter.setTaskId(taskId); - Boolean value = uploadToBackup(fileParameter); + Boolean value = uploadToBackupData(fileParameter); if (value) { BackupsFileCount++; } @@ -3616,7 +3754,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl FolderParameterlist.add(parameterList); FolderParameter.setParameterLists(FolderParameterlist); FolderParameter.setTaskId(taskId); - Boolean value = uploadToBackup(FolderParameter); + Boolean value = uploadToBackupData(FolderParameter); if (value) { BackupsFolderCount++; } @@ -3711,7 +3849,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl fileParameterlist.add(parameterList); fileParameter.setParameterLists(fileParameterlist); fileParameter.setTaskId(taskId); - Boolean value = uploadToBackup(fileParameter); + Boolean value = uploadToBackupData(fileParameter); if (value) { BackupsFileCount++; } @@ -3724,7 +3862,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl FolderParameterlist.add(parameterList); FolderParameter.setParameterLists(FolderParameterlist); FolderParameter.setTaskId(taskId); - Boolean value = uploadToBackup(FolderParameter); + Boolean value = uploadToBackupData(FolderParameter); if (value) { BackupsFolderCount++; } @@ -4005,6 +4143,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 参数说明 newFileName * 参数说明 Rename 重命名的文件名称 * 参数说明 type 覆盖还是重命名 0 1 + * 参数说明 nodeId 跨节点移动以后的节点ID */ @Override @Transactional(rollbackFor = Exception.class) @@ -4022,6 +4161,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl String parentId = reques.getParentId(); String rename = reques.getRename(); String type = reques.getType(); + String nodeId = reques.getNodeId(); String[] newFileNames = reques.getNewFileName().split(","); // 数组转集合 List newFileNameList = Arrays.asList(newFileNames); @@ -4063,7 +4203,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl moveFile(sourcePath, targetPath, type); // 更新数据库记录 - updateDatabase(parentId, oldpaths, fileName, newPath, targetFileName, type); + updateDatabase(parentId, oldpaths, fileName, newPath, targetFileName, type,nodeId); } return "移动成功"; } catch (NoSuchFileException e) { @@ -4159,7 +4299,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 更新数据库中的父ID和路径 */ private void updateDatabase(String parentId, String oldpaths, String fileName, - String newPath, String targetFileName, String type) { + String newPath, String targetFileName, String type,String nodeId) { TsFiles tsFilesData = tsFilesMapper.selectById(parentId); LOGGER.info("移动的时候删除Redis"); @@ -4194,6 +4334,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl if (newfileRecord != null) { // 更新目标记录 newfileRecord.setParentId(parentId); + newfileRecord.setNodeId(nodeId); newfileRecord.setWorkPath(newWorkPath); newfileRecord.setFileName(targetFileName); newfileRecord.setUpdateTime(new Timestamp(System.currentTimeMillis())); // 更新时间 @@ -4203,7 +4344,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl } else { // 插入新记录 TsFiles newRecord = new TsFiles(); - newRecord.setNodeId(fileRecord.getNodeId()); + newRecord.setNodeId(nodeId); newRecord.setTaskId(fileRecord.getTaskId()); newRecord.setIsFile(fileRecord.getIsFile()); newRecord.setParentId(parentId); @@ -4219,7 +4360,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl // 如果是文件夹,递归删除子项 if ("FOLDER".equals(fileRecord.getIsFile())) { // 先移动子项再删除原记录 - moveChildrenRecords(oldWorkPath, newWorkPath + targetFileName + "/", newRecord.getId(), type, fileRecord.getId()); + moveChildrenRecords(oldWorkPath, newWorkPath + targetFileName + "/", newRecord.getId(), type, fileRecord.getId(),nodeId); } // 删除原记录 tsFilesMapper.deleteById(fileRecord.getId()); @@ -4229,7 +4370,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl } else { // 重命名模式:插入新记录 TsFiles newRecord = new TsFiles(); - newRecord.setNodeId(fileRecord.getNodeId()); + newRecord.setNodeId(nodeId); newRecord.setTaskId(fileRecord.getTaskId()); newRecord.setIsFile(fileRecord.getIsFile()); newRecord.setParentId(parentId); @@ -4250,7 +4391,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl /** * 递归移动子项记录(覆盖模式下先移动后删除) */ - private void moveChildrenRecords(String oldPrefix, String newPrefix, String parentId, String type, String oldparentId) { + private void moveChildrenRecords(String oldPrefix, String newPrefix, String parentId, String type, String oldparentId,String nodeId) { //查询原来的 List children = tsFilesMapper.selectList( new QueryWrapper().eq("parent_id", oldparentId)); @@ -4268,12 +4409,13 @@ public class TsFilesServiceImpl extends ServiceImpl impl if (existingChild != null) { existingChild.setParentId(parentId); + existingChild.setNodeId(nodeId); existingChild.setWorkPath(childNewPath); existingChild.setUpdateTime(new Timestamp(System.currentTimeMillis())); tsFilesMapper.updateById(existingChild); } else { TsFiles newChild = new TsFiles(); - newChild.setNodeId(child.getNodeId()); + newChild.setNodeId(nodeId); newChild.setTaskId(child.getTaskId()); newChild.setIsFile(child.getIsFile()); newChild.setParentId(parentId); @@ -4288,9 +4430,12 @@ public class TsFilesServiceImpl extends ServiceImpl impl tsFilesMapper.insert(newChild); // 递归处理子文件夹 if ("FOLDER".equals(child.getIsFile())) { - moveChildrenRecords(oldPrefix, newPrefix + newChild.getFileName() + "/", newChild.getId(), type, child.getId()); + moveChildrenRecords(oldPrefix, newPrefix + newChild.getFileName() + "/", newChild.getId(), type, child.getId(),nodeId); } + // 删除原记录 + tsFilesMapper.deleteById(child.getId()); } + } } } @@ -4331,6 +4476,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl String parentId = reques.getParentId(); String rename = reques.getRename(); String type = reques.getType(); + String nodeId = reques.getNodeId(); String[] newFileNames = reques.getNewFileName().split(","); // 数组转集合 List newFileNameList = Arrays.asList(newFileNames); @@ -4369,7 +4515,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl copyPhysicalFile(sourcePath, targetPath, type); // 5. 插入新记录到数据库 - insertDatabaseRecord(parentId, oldpaths, fileName, newPath, targetFileName, type); + insertDatabaseRecord(parentId, oldpaths, fileName, newPath, targetFileName, type,nodeId); } return "复制成功"; } catch (IllegalArgumentException e) { @@ -4417,7 +4563,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 插入数据库记录(主记录) */ private void insertDatabaseRecord(String parentId, String oldpaths, String fileName, - String newPath, String targetFileName, String type) { + String newPath, String targetFileName, String type,String nodeId) { TsFiles tsFilesData = tsFilesMapper.selectById(parentId); LOGGER.info("复制的时候删除Redis"); @@ -4460,14 +4606,15 @@ public class TsFilesServiceImpl extends ServiceImpl impl formatDbPath(newPath), original.getId(), neworiginal.getId(), - type + type, + nodeId ); } } else { // 创建新记录 TsFiles newRecord = new TsFiles(); - newRecord.setNodeId(original.getNodeId()); + newRecord.setNodeId(nodeId); newRecord.setTaskId(original.getTaskId()); newRecord.setIsFile(original.getIsFile()); newRecord.setParentId(parentId); @@ -4487,7 +4634,8 @@ public class TsFilesServiceImpl extends ServiceImpl impl formatDbPath(newPath + newRecord.getFileName() + "/"), original.getId(), newRecord.getId(), - type + type, + nodeId ); } } @@ -4499,7 +4647,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 递归复制子项数据库记录(关键优化点) */ private void copyChildrenRecords(String oldPrefix, String newPrefix, - String originalParentId, String newParentId, String type) { + String originalParentId, String newParentId, String type,String nodeId) { List children = tsFilesMapper.selectList( new QueryWrapper().eq("parent_id", originalParentId) ); @@ -4512,7 +4660,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl for (TsFiles child : children) { // 处理当前子项 TsFiles processedChild = processChildRecord( - child, newParentId, newPrefix, oldPrefix, type, loginuser, currentTime + child, newParentId, newPrefix, oldPrefix, type, loginuser, currentTime, nodeId ); // 递归处理子文件夹 @@ -4522,7 +4670,8 @@ public class TsFilesServiceImpl extends ServiceImpl impl newPrefix, child.getId(), processedChild.getId(), // 使用新记录的ID作为父ID - type + type, + nodeId ); } } @@ -4532,7 +4681,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 处理单个子项记录 */ private TsFiles processChildRecord(TsFiles child, String newParentId, String newPrefix, - String oldPrefix, String type, LoginUser user, Timestamp now) { + String oldPrefix, String type, LoginUser user, Timestamp now,String nodeId) { if ("0".equals(type)) { // 覆盖模式 TsFiles existing = tsFilesMapper.selectOne( new QueryWrapper() @@ -4540,23 +4689,24 @@ public class TsFilesServiceImpl extends ServiceImpl impl .eq("file_name", child.getFileName()) ); if (existing != null) { - updateExisting(existing, child, now, user); + updateExisting(existing, child, now, user,nodeId); return existing; } else { - return insertNewChild(child, newParentId, buildNewWorkPath(child, oldPrefix, newPrefix), - user, now, null); + return insertNewChild(child, newParentId, newPrefix, + user, now, null, nodeId); } } else { // 重命名模式 return insertNewChild(child, newParentId, newPrefix, - user, now, child.getFileName()); + user, now, child.getFileName(), nodeId); } } /** * 更新现有记录(覆盖模式) */ - private void updateExisting(TsFiles existing, TsFiles source, Timestamp time, LoginUser user) { + private void updateExisting(TsFiles existing, TsFiles source, Timestamp time, LoginUser user,String nodeId) { existing.setFileSize(source.getFileSize()); + existing.setNodeId(nodeId); existing.setDescription(source.getDescription()); existing.setUpdateTime(time); existing.setUploader(user.getUsername()); @@ -4567,9 +4717,9 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 插入新子项记录 */ private TsFiles insertNewChild(TsFiles source, String parentId, String newWorkPath, - LoginUser user, Timestamp time, String customName) { + LoginUser user, Timestamp time, String customName,String nodeId) { TsFiles newChild = new TsFiles(); - newChild.setNodeId(source.getNodeId()); + newChild.setNodeId(nodeId); newChild.setTaskId(source.getTaskId()); newChild.setIsFile(source.getIsFile()); newChild.setParentId(parentId); diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java index edf398c..e672bf3 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java @@ -117,32 +117,39 @@ public class TsNodesServiceImpl extends ServiceImpl impl // 查找所有根节点(parentId为"00"的节点) List> rootNodes = findRootNodes(allNodes, taskId); - // 如果未找到根节点,返回空列表 - if (rootNodes.isEmpty()) { - return new ArrayList<>(); - } - // 根节点的基本路径:/项目名称/ String basePath = "/" + tsTask.getTaskName() + "/"; // 存储最终结果 List> result = new ArrayList<>(); + Map rootNodeData = new HashMap<>(); + rootNodeData.put("nodeName", "根节点"); + rootNodeData.put("path", "/"+tsTask.getTaskName()+"/"); + rootNodeData.put("nodeId", tsTask.getId()); + rootNodeData.put("nodeOrder", "0"); + rootNodeData.put("taskId", tsTask.getId()); + rootNodeData.put("parentId", "00"); + result.add(rootNodeData); // 如果 nodeName 为空,返回所有根节点的完整树形结构 if (StringUtils.isEmpty(nodeName)) { + if (!rootNodes.isEmpty()) { for (Map rootNode : rootNodes) { rootNode.put("path", basePath); result.addAll(buildFullTree(rootNode, allNodes)); } + } return result; } // 否则,返回从根节点到目标节点的树形结构 - for (Map rootNode : rootNodes) { - rootNode.put("path", basePath); - List> tree = buildTreeToTargetNode(rootNode, allNodes, nodeName); - if (!tree.isEmpty()) { - result.addAll(tree); + if (!rootNodes.isEmpty()) { + for (Map rootNode : rootNodes) { + rootNode.put("path", basePath); + List> tree = buildTreeToTargetNode(rootNode, allNodes, nodeName); + if (!tree.isEmpty()) { + result.addAll(tree); + } } } @@ -174,7 +181,7 @@ public class TsNodesServiceImpl extends ServiceImpl impl queryWrapper.eq("task_id", taskId); } // 按节点顺序升序排序 - queryWrapper.orderByAsc("node_order"); + queryWrapper.orderByAsc("node_name"); // 查询所有符合条件的节点 return tsNodesMapper.selectMaps(queryWrapper); @@ -853,23 +860,21 @@ public class TsNodesServiceImpl extends ServiceImpl impl } else { //todo 如果是文件 首先判断表中有没有 如果没有 就新增 到节点名称为根节点的 节点下面 - //查询节点表中 有没有根节点的节点 如果有就直接使用 如果没有就新增 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(TsNodes::getTaskId, taskId); - queryWrapper.eq(TsNodes::getParentId, TOP_LEVEL_PARENT_NODE); - queryWrapper.eq(TsNodes::getNodeName, "根节点"); - TsNodes nodeData = tsNodesMapper.selectOne(queryWrapper); - if (nodeData == null) { - //新增一个根节点 - TsNodes node = savetsNodes(taskId, TOP_LEVEL_PARENT_NODE, "根节点"); - + //先通过名称 + 节点 + 任务 + 路径 查询 如果有就跳过 没有就继续新增 + LambdaQueryWrapper queryWrapperFiles = new LambdaQueryWrapper<>(); + queryWrapperFiles.eq(TsFiles::getNodeId, taskId); + queryWrapperFiles.eq(TsFiles::getTaskId, taskId); + queryWrapperFiles.eq(TsFiles::getWorkPath, item.getPath()); + queryWrapperFiles.eq(TsFiles::getFileName, item.getName()); + TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapperFiles); + if (tsFiles == null) { String finalPath = item.getPath().replace(item.getName(), ""); //保存文件信息 TsFiles tsFiles1 = new TsFiles(); //任务 tsFiles1.setTaskId(taskId); //节点 - tsFiles1.setNodeId(node.getNodeId()); + tsFiles1.setNodeId(taskId); //文件 文件夹 区分 tsFiles1.setIsFile("FILE"); //上级ID @@ -886,43 +891,81 @@ public class TsNodesServiceImpl extends ServiceImpl impl String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数 tsFiles1.setFileSize(fileSizeFormatted); tsFilesMapper.insert(tsFiles1); - } else { - //先通过名称 + 节点 + 任务 + 路径 查询 如果有就跳过 没有就继续新增 - LambdaQueryWrapper queryWrapperFiles = new LambdaQueryWrapper<>(); - queryWrapperFiles.eq(TsFiles::getNodeId, nodeData.getNodeId()); - queryWrapperFiles.eq(TsFiles::getTaskId, taskId); - queryWrapperFiles.eq(TsFiles::getWorkPath, item.getPath()); - queryWrapperFiles.eq(TsFiles::getFileName, item.getName()); - TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapperFiles); - if (tsFiles == null) { - String finalPath = item.getPath().replace(item.getName(), ""); - //保存文件信息 - TsFiles tsFiles1 = new TsFiles(); - //任务 - tsFiles1.setTaskId(taskId); - //节点 - tsFiles1.setNodeId(nodeData.getNodeId()); - //文件 文件夹 区分 - tsFiles1.setIsFile("FILE"); - //上级ID - tsFiles1.setParentId("00"); - //文件名称 - tsFiles1.setFileName(item.getName()); - //工作空间路径 - tsFiles1.setWorkPath(ensurePathFormat(finalPath)); - tsFiles1.setUploadTime(currentTime); - tsFiles1.setUploader(loginuser.getUsername()); - long bytes = item.getSize(); - // 转换为 KB 并保留两位小数 - double fileSizeInKB = bytes / (1024.0); - String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数 - tsFiles1.setFileSize(fileSizeFormatted); - tsFilesMapper.insert(tsFiles1); - } else { - continue; - } - + }else { + continue; } + + +// //查询节点表中 有没有根节点的节点 如果有就直接使用 如果没有就新增 +// LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); +// queryWrapper.eq(TsNodes::getTaskId, taskId); +// queryWrapper.eq(TsNodes::getParentId, TOP_LEVEL_PARENT_NODE); +// queryWrapper.eq(TsNodes::getNodeName, "根节点"); +// TsNodes nodeData = tsNodesMapper.selectOne(queryWrapper); +// if (nodeData == null) { +// //新增一个根节点 +// TsNodes node = savetsNodes(taskId, TOP_LEVEL_PARENT_NODE, "根节点"); +// +// String finalPath = item.getPath().replace(item.getName(), ""); +// //保存文件信息 +// TsFiles tsFiles1 = new TsFiles(); +// //任务 +// tsFiles1.setTaskId(taskId); +// //节点 +// tsFiles1.setNodeId(node.getNodeId()); +// //文件 文件夹 区分 +// tsFiles1.setIsFile("FILE"); +// //上级ID +// tsFiles1.setParentId("00"); +// //文件名称 +// tsFiles1.setFileName(item.getName()); +// //工作空间路径 +// tsFiles1.setWorkPath(ensurePathFormat(finalPath)); +// tsFiles1.setUploadTime(currentTime); +// tsFiles1.setUploader(loginuser.getUsername()); +// long bytes = item.getSize(); +// // 转换为 KB 并保留两位小数 +// double fileSizeInKB = bytes / (1024.0); +// String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数 +// tsFiles1.setFileSize(fileSizeFormatted); +// tsFilesMapper.insert(tsFiles1); +// } else { +// //先通过名称 + 节点 + 任务 + 路径 查询 如果有就跳过 没有就继续新增 +// LambdaQueryWrapper queryWrapperFiles = new LambdaQueryWrapper<>(); +// queryWrapperFiles.eq(TsFiles::getNodeId, nodeData.getNodeId()); +// queryWrapperFiles.eq(TsFiles::getTaskId, taskId); +// queryWrapperFiles.eq(TsFiles::getWorkPath, item.getPath()); +// queryWrapperFiles.eq(TsFiles::getFileName, item.getName()); +// TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapperFiles); +// if (tsFiles == null) { +// String finalPath = item.getPath().replace(item.getName(), ""); +// //保存文件信息 +// TsFiles tsFiles1 = new TsFiles(); +// //任务 +// tsFiles1.setTaskId(taskId); +// //节点 +// tsFiles1.setNodeId(nodeData.getNodeId()); +// //文件 文件夹 区分 +// tsFiles1.setIsFile("FILE"); +// //上级ID +// tsFiles1.setParentId("00"); +// //文件名称 +// tsFiles1.setFileName(item.getName()); +// //工作空间路径 +// tsFiles1.setWorkPath(ensurePathFormat(finalPath)); +// tsFiles1.setUploadTime(currentTime); +// tsFiles1.setUploader(loginuser.getUsername()); +// long bytes = item.getSize(); +// // 转换为 KB 并保留两位小数 +// double fileSizeInKB = bytes / (1024.0); +// String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数 +// tsFiles1.setFileSize(fileSizeFormatted); +// tsFilesMapper.insert(tsFiles1); +// } else { +// continue; +// } +// +// } } } } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java index 180c89a..2a2a128 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java @@ -7,6 +7,8 @@ import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.yfd.platform.config.ResponseResult; import com.yfd.platform.modules.experimentalData.domain.TsFiles; import com.yfd.platform.modules.experimentalData.domain.TsNodes; @@ -18,6 +20,7 @@ import com.yfd.platform.modules.experimentalData.service.ITsFilesService; import com.yfd.platform.modules.experimentalData.service.ITsNodesService; import com.yfd.platform.modules.experimentalData.service.ITsTaskService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yfd.platform.modules.specialDocument.domain.Project; import com.yfd.platform.modules.storage.context.StorageSourceContext; import com.yfd.platform.modules.storage.mapper.StorageSourceMapper; import com.yfd.platform.modules.storage.model.entity.StorageSource; @@ -35,16 +38,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.IOException; import java.sql.*; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; import javax.annotation.Resource; import javax.sql.DataSource; import java.time.LocalDateTime; +import java.util.stream.Collectors; /** *

@@ -107,7 +110,7 @@ public class TsTaskServiceImpl extends ServiceImpl impleme * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 ***********************************/ @Override - public Page getTsTaskPage(String taskName, String startDate, String endDate, String taskPlace, String taskPerson, String taskCode, String taskType, String carrierName, String deviceCode, String testDescribe, String sensorDescribe, Page page) { + public Page getTsTaskPage(String taskName, String startDate, String endDate, String taskPlace, String taskPerson, String taskCode, String taskType, String carrierName, String deviceCode, String testDescribe, String sensorDescribe, Page page,List> attributeContent) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); //如果任务名称 taskName 不为空 @@ -161,6 +164,48 @@ public class TsTaskServiceImpl extends ServiceImpl impleme queryWrapper.ge(TsTask::getTaskStartdate, parseStartDate).lt(TsTask::getTaskEnddate, parseEndDate); } queryWrapper.orderByDesc(TsTask::getTaskStartdate); + + + // 处理属性过滤条件 - MySQL 5.7+ 兼容版本 + if (attributeContent != null && !attributeContent.isEmpty()) { + for (Map attr : attributeContent) { + for (Map.Entry entry : attr.entrySet()) { + String code = entry.getKey(); + String value = entry.getValue(); + + if (StringUtils.isEmpty(value)) { + // 检查属性存在 + queryWrapper.apply( + "EXISTS (SELECT 1 FROM JSON_TABLE(task_props, '$[*]' " + + "COLUMNS (code VARCHAR(50) PATH '$.code') AS jt " + + "WHERE jt.code = {0})", + code + ); + } else { + // 转义特殊字符 + String safeValue = value.replace("'", "''") + .replace("%", "\\%") + .replace("_", "\\_"); + + // 使用 JSON_EXTRACT 实现兼容查询 + queryWrapper.apply( + "EXISTS (SELECT 1 FROM (" + + " SELECT " + + " JSON_UNQUOTE(JSON_EXTRACT(t.obj, '$.code')) AS code, " + + " JSON_UNQUOTE(JSON_EXTRACT(t.obj, '$.data')) AS data " + + " FROM (" + + " SELECT JSON_EXTRACT(task_props, CONCAT('$[', idx.idx, ']')) AS obj " + + " FROM (SELECT 0 AS idx UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) idx" + + " WHERE idx.idx < JSON_LENGTH(task_props)" + + " ) t" + + ") jt " + + "WHERE jt.code = {0} AND jt.data LIKE CONCAT('%', {1}, '%'))", + code, value + ); + } + } + } + } //分页查询 Page tsTaskPage = tsTaskMapper.selectPage(page, queryWrapper); return tsTaskPage; @@ -173,12 +218,25 @@ public class TsTaskServiceImpl extends ServiceImpl impleme * 返回值说明: com.yfd.platform.config.ResponseResult 返回新增成功或者失败 ***********************************/ @Override - public Boolean addSdproject(TsTask tsTask) { + public Boolean addtsTask(TsTask tsTask) throws IOException { //todo 新增实验任务的时候创建一个本地的文件夹 //生成任务编号 String taskCode = generateNextTsTaskCode(); tsTask.setTaskCode(taskCode); + //处理属性 + String frontEndJson = tsTask.getTaskProps(); + List tsTasksList = tsTaskMapper.selectList(new LambdaQueryWrapper<>()); + if (tsTasksList.size() > 0) { + for (TsTask tsTaskData : tsTasksList) { + String dbJson = tsTaskData.getTaskProps(); + String syncData = syncData(frontEndJson, dbJson); + tsTaskData.setTaskProps(syncData); + tsTaskMapper.updateById(tsTaskData); + } + } + + //生成任务名称 任务开始时间_结束时间_地点_载机名称_设备代号_编号 String taskName = buildTaskName(tsTask); tsTask.setTaskName(taskName); @@ -222,6 +280,67 @@ public class TsTaskServiceImpl extends ServiceImpl impleme } } + public static String syncData(String frontEndJson, String dbJson) throws IOException { + // 1. 如果 frontEndJson 为空,则返回一个空的 dbJson + if (frontEndJson == null || frontEndJson.trim().isEmpty()) { + return "[]"; // 返回空的 JSON 数组 + } + + // 2. 解析前端传递的 JSON 字符串为 List>,如果为空,直接返回空的 dbJson + ObjectMapper objectMapper = new ObjectMapper(); + List> frontEndData = objectMapper.readValue(frontEndJson, List.class); + + // 3. 如果前端有数据,且 dbJson 为空,直接使用前端数据并将 data 设置为空 + if (frontEndData != null && !frontEndData.isEmpty() && (dbJson == null || dbJson.trim().isEmpty())) { + List> result = new ArrayList<>(); + for (Map item : frontEndData) { + Map newItem = new HashMap<>(); + newItem.put("code", item.get("code")); + newItem.put("name", item.get("name")); + newItem.put("data", ""); // 数据为空 + result.add(newItem); + } + return objectMapper.writeValueAsString(result); // 返回填充后的结果 + } + + // 4. 如果 dbJson 不为空,解析 dbJson + List> dbData = objectMapper.readValue(dbJson, List.class); + + // 5. 根据前端数据创建一个Map,以便快速查找前端的项 + Map> frontEndMap = frontEndData.stream() + .collect(Collectors.toMap(item -> (String) item.get("name"), item -> item)); + + // 6. 遍历数据库中的数据,进行相应的增、删、改 + List> result = new ArrayList<>(); + + // 7. 处理数据库中的项:先将前端数据对应的项保留,新增的项加上空的数据 + for (Map dbItem : dbData) { + String name = dbItem.get("name"); + if (frontEndMap.containsKey(name)) { + // 如果前端有该项,则保留数据库中的项,保持其原有的id + // 只有当前端的 data 不为空时才更新,避免改变数据库中原有的 data + String frontEndDataValue = frontEndMap.get(name).get("data"); +// if (frontEndDataValue != null && !frontEndDataValue.trim().isEmpty()) { +// //dbItem.put("data", frontEndDataValue); // 只在前端有值时才更新 +// } + result.add(dbItem); + frontEndMap.remove(name); // 从前端map中移除已处理的项 + } + } + + // 8. 处理前端数据中没有在数据库中出现的项:新增这些项,data为空 + for (Map.Entry> entry : frontEndMap.entrySet()) { + Map newItem = new HashMap<>(); + newItem.put("code", entry.getValue().get("code")); // 保持前端传来的id + newItem.put("name", entry.getValue().get("name")); + newItem.put("data", ""); // 如果数据库中没有该项,则data为空 + result.add(newItem); + } + + // 9. 将结果转换为 JSON 字符串并返回 + return objectMapper.writeValueAsString(result); + } + // 动态创建任务文件表 private void createTaskFileTable(String taskCode) { @@ -326,17 +445,63 @@ public class TsTaskServiceImpl extends ServiceImpl impleme * 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败 ***********************************/ @Override - public boolean updatetsTask(TsTask tsTask) { + public boolean updatetsTask(TsTask tsTask) throws IOException { + Boolean value = false; - //生成任务名称 任务开始时间_结束时间_地点_载机名称_设备代号_编号 - String taskName = buildTaskName(tsTask); - tsTask.setTaskName(taskName); - int valueUpdate = tsTaskMapper.updateById(tsTask); - if (valueUpdate == 1) { - return true; - } else { - return false; + //处理属性 + String frontEndJson = tsTask.getTaskProps(); + List tsTasksList = tsTaskMapper.selectList(new LambdaQueryWrapper<>()); + if (tsTasksList.size() > 0) { + for (TsTask tsTaskData : tsTasksList) { + String dbJson = tsTaskData.getTaskProps(); + String syncData = syncData(frontEndJson, dbJson); + tsTaskData.setTaskProps(syncData); + tsTaskMapper.updateById(tsTaskData); + } } + + //修改的时候判断本地存储空间是不是发生了变化 如果是的话 需要重新创建本地文件 + TsTask TsTaskOld = tsTaskMapper.selectById(tsTask.getId()); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + + + if (!TsTaskOld.getLocalStorageId().equals(tsTask.getLocalStorageId())) { + String path = "/"; + //新增节点的时候 创建文件夹 + NewFolderRequest newFolderRequest = new NewFolderRequest(); + newFolderRequest.setName(tsTask.getTaskName());//新建的文件夹名称,示例值(/a/b/c) + newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) + newFolderRequest.setPath(path);//请求路径,示例值(/) + newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio) + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); + boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); + if (flag) { + String taskName = buildTaskName(tsTask); + tsTask.setTaskName(taskName); + int valueUpdate = tsTaskMapper.updateById(tsTask); + if (valueUpdate == 1) { + value = true; + } else { + value = false; + } + value = true; + } else { + LOGGER.error("节点新增成功,但是本地专项文件夹创建失败"); + value = false; + } + } else { + + String taskName = buildTaskName(tsTask); + tsTask.setTaskName(taskName); + int valueUpdate = tsTaskMapper.updateById(tsTask); + if (valueUpdate == 1) { + value = true; + } else { + value = false; + } + + } + return value; } /********************************** @@ -381,7 +546,7 @@ public class TsTaskServiceImpl extends ServiceImpl impleme // value = false; // } - StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); // 删除 local 中的文件夹 项目文件夹 List deleteItemList = new ArrayList<>(); BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem(); @@ -492,8 +657,8 @@ public class TsTaskServiceImpl extends ServiceImpl impleme LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.orderByDesc(TsTask::getTaskStartdate); List tsTasks = tsTaskMapper.selectList(queryWrapper); - for (TsTask tsTask : tsTasks){ - StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + for (TsTask tsTask : tsTasks) { + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); tsTask.setKey(storageSource.getKey()); } return tsTasks; @@ -531,7 +696,7 @@ public class TsTaskServiceImpl extends ServiceImpl impleme } // 辅助方法:获取存储配置 - private StorageSource getStorageConfig( Integer id) { + private StorageSource getStorageConfig(Integer id) { return storageSourceMapper.selectOne(new LambdaQueryWrapper().eq(StorageSource::getId, id) ); } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/NodesController.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/NodesController.java index aa58390..6ca89b9 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/NodesController.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/NodesController.java @@ -3,15 +3,16 @@ package com.yfd.platform.modules.specialDocument.controller; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONArray; + import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.yfd.platform.annotation.Log; import com.yfd.platform.component.TaskStatusHolder; -import com.yfd.platform.component.WebSocketServer; + import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.modules.experimentalData.domain.TsNodes; +import com.yfd.platform.modules.specialDocument.domain.Files; import com.yfd.platform.modules.specialDocument.domain.Nodes; +import com.yfd.platform.modules.specialDocument.service.IFilesService; import com.yfd.platform.modules.specialDocument.service.INodesService; import com.yfd.platform.system.domain.LoginUser; import io.swagger.annotations.ApiOperation; @@ -22,8 +23,8 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; -import java.io.IOException; -import java.util.Arrays; + + import java.util.List; import java.util.Map; @@ -43,6 +44,10 @@ public class NodesController { @Resource private INodesService nodesService; + + @Resource + private IFilesService filesService; + @Autowired private TaskStatusHolder taskStatusHolder; @@ -185,7 +190,7 @@ public class NodesController { jsonObject1.putOpt("scanstatus", "1"); jsonObject1.putOpt("scanname", "扫描"); } - }else { + } else { jsonObject1.putOpt("scanstatus", "1"); jsonObject1.putOpt("scanname", "扫描"); } @@ -203,12 +208,12 @@ public class NodesController { jsonObject1.putOpt("uploadstatus", "1"); jsonObject1.putOpt("uploadname", "上传"); } - }else { + } else { jsonObject1.putOpt("uploadstatus", "1"); jsonObject1.putOpt("uploadname", "上传"); } //如果都为空 - if (StrUtil.isEmpty(scanValue)&& StrUtil.isEmpty(uploadValue)) { + if (StrUtil.isEmpty(scanValue) && StrUtil.isEmpty(uploadValue)) { jsonObject1.putOpt("scanstatus", "1"); jsonObject1.putOpt("scanname", "扫描"); jsonObject1.putOpt("uploadstatus", "1"); @@ -280,4 +285,34 @@ public class NodesController { } } + /********************************** + * 用途说明: 查询可不可以初始化专项文档扫描 + * 参数说明 projectId 所属项目ID + * 返回值说明: com.yfd.platform.config.ResponseResult + ***********************************/ + @Log(module = "查询可不可以修改项目", value = "查询可不可以修改项目!") + @PostMapping("/selectNodesById") + @ApiOperation("查询可不可以修改项目") + public ResponseResult selectNodesById(String projectId) { + if (StrUtil.isBlank(projectId)) { + return ResponseResult.error("参数为空"); + } + List nodesList = nodesService.list(new QueryWrapper().eq("project_id", projectId)); + //如果节点不为空 就不能初始化了 如果大于0是false 代表不能修改 + if (nodesList.size() > 0) { + return ResponseResult.successData(false); + } else { + //如果节点为空 就判断文件表ew Qu + List filesList = filesService.list(new QueryWrapper().eq("project_id", projectId)); + if (filesList.size() > 0) { + return ResponseResult.successData(false); + + } else { + return ResponseResult.successData(true); + + } + } + } + + } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/ProjectController.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/ProjectController.java index 905da3c..5a39554 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/ProjectController.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/ProjectController.java @@ -3,6 +3,8 @@ package com.yfd.platform.modules.specialDocument.controller; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -10,11 +12,16 @@ import com.yfd.platform.annotation.Log; import com.yfd.platform.config.ResponseResult; import com.yfd.platform.modules.specialDocument.domain.Project; import com.yfd.platform.modules.specialDocument.service.IProjectService; +import com.yfd.platform.utils.StringUtils; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -48,12 +55,41 @@ public class ProjectController { @GetMapping("/page") @ApiOperation("分页查询专项文档管理项目管理") @PreAuthorize("@el.check('select:project')") - public ResponseResult getSdProjectPage(String description, String projectType, String projectName, Page page) { - //分页查询 - Page sdProjectPage = projectService.getSdProjectPage(description, projectType, projectName, page); + public ResponseResult getSdProjectPage(String description, String projectType, String projectName, Page page, String attributeContentJson) { + // 双重解码处理 + if (attributeContentJson != null) { + try { + // 第二次解码:%5B → [ + attributeContentJson = URLDecoder.decode(attributeContentJson, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + return ResponseResult.error("参数解码错误"); + } + } + // 将JSON字符串转换为List> + List> attributeContent = null; + if (StringUtils.isNotEmpty(attributeContentJson)) { + try { + // 使用 TypeReference 指定精确类型 + attributeContent = JSON.parseObject( + attributeContentJson, + new TypeReference>>() { + } + ); + // 遍历并移除空值字段 + if (attributeContent != null) { + for (Map item : attributeContent) { + // 遍历 Map,移除值为空的键值对 + item.entrySet().removeIf(entry -> entry.getValue() == null || entry.getValue().isEmpty()); + } + } + } catch (Exception e) { + return ResponseResult.error("属性参数格式错误"); + } + } + // 分页查询 + Page sdProjectPage = projectService.getSdProjectPage(description, projectType, projectName, page, attributeContent); return ResponseResult.successData(sdProjectPage); } - /*********************************** * 用途说明:新增专项文档管理-项目管理 * 参数说明 @@ -65,7 +101,7 @@ public class ProjectController { @ApiOperation("新增专项文档管理项目管理") @ResponseBody @PreAuthorize("@el.check('add:project')") - public ResponseResult addSdproject(@RequestBody Project project) { + public ResponseResult addSdproject(@RequestBody Project project) throws IOException{ //对象不能为空 if (ObjUtil.isEmpty(project)) { return ResponseResult.error("参数为空"); @@ -89,7 +125,7 @@ public class ProjectController { @PostMapping("/updateSdproject") @ApiOperation("修改专项文档管理项目管理") @PreAuthorize("@el.check('update:project')") - public ResponseResult updateSdproject(@RequestBody Project project) { + public ResponseResult updateSdproject(@RequestBody Project project) throws IOException { //对象不能为空 if (ObjUtil.isEmpty(project) && StrUtil.isBlank(project.getId())) { return ResponseResult.error("参数为空"); @@ -166,4 +202,6 @@ public class ProjectController { } + + } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/ProjectMapper.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/ProjectMapper.java index b2609e4..d2c1fea 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/ProjectMapper.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/ProjectMapper.java @@ -1,8 +1,14 @@ package com.yfd.platform.modules.specialDocument.mapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.modules.specialDocument.domain.Project; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; +import java.util.Map; /** *

@@ -18,4 +24,5 @@ public interface ProjectMapper extends BaseMapper { static int createFileTable(@Param("tableName") String tableName) { return 0; } + } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IProjectService.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IProjectService.java index 9cd3512..a1969d1 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IProjectService.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IProjectService.java @@ -4,7 +4,9 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.modules.specialDocument.domain.Project; import com.baomidou.mybatisplus.extension.service.IService; +import java.io.IOException; import java.util.List; +import java.util.Map; /** *

@@ -25,7 +27,7 @@ public interface IProjectService extends IService { * pageNum 当前页 * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 ***********************************/ - Page getSdProjectPage(String description, String projectType, String projectName, Page page); + Page getSdProjectPage(String description, String projectType, String projectName, Page page,List> attributeContent); /*********************************** * 用途说明:新增专项文档管理-项目管理 @@ -33,7 +35,7 @@ public interface IProjectService extends IService { * Project 项目管理 * 返回值说明: com.yfd.platform.config.ResponseResult 返回新增成功或者失败 ***********************************/ - Boolean addSdproject(Project project); + Boolean addSdproject(Project project) throws IOException; /********************************** * 用途说明: 修改专项文档管理-项目管理 @@ -41,7 +43,7 @@ public interface IProjectService extends IService { * Project 项目管理 * 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败 ***********************************/ - boolean updateSdproject(Project project); + boolean updateSdproject(Project project) throws IOException; boolean deleteProjectByIds(List dataset); diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/FilesServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/FilesServiceImpl.java index 64d80b6..c230695 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/FilesServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/FilesServiceImpl.java @@ -182,7 +182,7 @@ public class FilesServiceImpl extends ServiceImpl implements } queryWrapperfiles.eq(Files::getProjectId, projectId);//所属项目ID queryWrapperfiles.eq(Files::getNodeId, nodeId);//节点ID - queryWrapperfiles.orderByDesc(Files::getFileName);//时间 + queryWrapperfiles.orderByAsc(Files::getFileName);//时间 //分页查询 Page filesPage = filesMapper.selectPage(page, queryWrapperfiles); //处理文件内容 diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/NodesServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/NodesServiceImpl.java index 1f60759..76806a5 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/NodesServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/NodesServiceImpl.java @@ -133,24 +133,37 @@ public class NodesServiceImpl extends ServiceImpl implements List> allNodes = getAllNodes(projectId); // 查找所有根节点(parentId为"00"的节点) List> rootNodes = findRootNodes(allNodes, projectId); - // 如果未找到根节点,返回空列表 - if (rootNodes.isEmpty()) { - return new ArrayList<>(); - } + // 根节点的基本路径:/项目名称/ String basePath = "/" + project.getProjectName() + "/"; // 存储最终结果 List> result = new ArrayList<>(); + Map rootNodeData = new HashMap<>(); + rootNodeData.put("creator", "admin"); + rootNodeData.put("id", project.getId()); + rootNodeData.put("nodeName", "根节点"); + rootNodeData.put("nodeOrder", 1); + rootNodeData.put("nodeType", "01"); + rootNodeData.put("parentId", "00"); + rootNodeData.put("path", "/"+project.getProjectName()+"/"); + rootNodeData.put("projectId", project.getId()); + result.add(rootNodeData); + // 如果 nodeName 为空,返回所有根节点的完整树形结构 if (StringUtils.isEmpty(nodeName)) { - for (Map rootNode : rootNodes) { - rootNode.put("path", basePath); - result.addAll(buildFullTree(rootNode, allNodes)); + // 如果未找到根节点,返回空列表 + if (!rootNodes.isEmpty()) { + for (Map rootNode : rootNodes) { + rootNode.put("path", basePath); + result.addAll(buildFullTree(rootNode, allNodes)); + } } + return result; } // 否则,返回从根节点到目标节点的树形结构 + if (!rootNodes.isEmpty()) { for (Map rootNode : rootNodes) { rootNode.put("path", basePath); List> tree = buildTreeToTargetNode(rootNode, allNodes, nodeName); @@ -158,6 +171,7 @@ public class NodesServiceImpl extends ServiceImpl implements result.addAll(tree); } } + } // 返回结果 return result; } @@ -294,7 +308,7 @@ public class NodesServiceImpl extends ServiceImpl implements queryWrapper.eq("project_id", projectId); } // 按节点顺序升序排序 - queryWrapper.orderByAsc("node_order"); + queryWrapper.orderByAsc("node_name"); // 查询所有符合条件的节点 return nodesMapper.selectMaps(queryWrapper); } @@ -613,11 +627,13 @@ public class NodesServiceImpl extends ServiceImpl implements // deleteWrapper.eq("project_id", nodes.getProjectId()); // filesMapper.delete(deleteWrapper); // } - //递归删除节点 - nodesMapper.deleteNodesRecursively(id); + //递归删除文件 filesMapper.deleteByNodeId(id); + //递归删除节点 + nodesMapper.deleteNodesRecursively(id); + // 删除 sdlocal 中的文件夹 List deleteItemList = new ArrayList<>(); BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem(); @@ -853,7 +869,12 @@ public class NodesServiceImpl extends ServiceImpl implements Files files = new Files(); files.setId(IdUtil.fastSimpleUUID()); files.setProjectId(id); - files.setNodeId("00"); + if (absolutePath.equals(ensurePathFormat(finalPath))) { + files.setNodeId(id); + }else { + files.setNodeId("00"); + } + files.setFileName(file.getName()); files.setFilePath(ensurePathFormat(finalPath)); diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/ProjectServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/ProjectServiceImpl.java index f1f9043..c3aef2d 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/ProjectServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/ProjectServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.databind.ObjectMapper; import com.yfd.platform.modules.specialDocument.domain.Nodes; import com.yfd.platform.modules.specialDocument.domain.Project; import com.yfd.platform.modules.specialDocument.mapper.ProjectMapper; @@ -27,11 +28,12 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import javax.sql.DataSource; +import java.io.IOException; import java.sql.*; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; /** *

@@ -79,37 +81,60 @@ public class ProjectServiceImpl extends ServiceImpl impl * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 ***********************************/ @Override - public Page getSdProjectPage(String description, String projectType, String projectName, Page page) { + public Page getSdProjectPage(String description, String projectType, String projectName, Page page,List> attributeContent) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - //如果项目描述 description 不为空 - if (StringUtils.isNotEmpty(description)) { + + // 基础条件处理 + if (StringUtils.isNotEmpty(description)) queryWrapper.like(Project::getDescription, description); - } - //如果项目类型 projectType 不为空 - if (StringUtils.isNotEmpty(projectType)) { + if (StringUtils.isNotEmpty(projectType)) queryWrapper.like(Project::getProjectType, projectType); -// //查询字典表获取项目类型对应数据字典 -// QueryWrapper queryWrapperSysDictionary = new QueryWrapper<>(); -// queryWrapperSysDictionary.eq("parentcode", "zxxmlx"); -// queryWrapperSysDictionary.eq("itemcode", projectType); -// queryWrapperSysDictionary.orderByAsc("orderno"); -// SysDictionaryItems sysDictionaryItems = sysDictionaryItemsMapper.selectOne(queryWrapperSysDictionary); -// if(sysDictionaryItems != null){ -// queryWrapper.like(Project::getProjectType, sysDictionaryItems.getDictName()); -// }else { -// queryWrapper.like(Project::getProjectType, projectType); -// } - } - //如果项目名称 projectName 不为空 - if (StringUtils.isNotEmpty(projectName)) { + if (StringUtils.isNotEmpty(projectName)) queryWrapper.like(Project::getProjectName, projectName); - } - //根据创建时间排序 queryWrapper.orderByDesc(Project::getProjectTime); - //分页查询 - Page sdProjectPage = projectMapper.selectPage(page, queryWrapper); - return sdProjectPage; + // 处理属性过滤条件 - MySQL 5.7+ 兼容版本 + if (attributeContent != null && !attributeContent.isEmpty()) { + for (Map attr : attributeContent) { + for (Map.Entry entry : attr.entrySet()) { + String code = entry.getKey(); + String value = entry.getValue(); + + if (StringUtils.isEmpty(value)) { + // 检查属性存在 + queryWrapper.apply( + "EXISTS (SELECT 1 FROM JSON_TABLE(project_props, '$[*]' " + + "COLUMNS (code VARCHAR(50) PATH '$.code') AS jt " + + "WHERE jt.code = {0})", + code + ); + } else { + // 转义特殊字符 + String safeValue = value.replace("'", "''") + .replace("%", "\\%") + .replace("_", "\\_"); + + // 使用 JSON_EXTRACT 实现兼容查询 + queryWrapper.apply( + "EXISTS (SELECT 1 FROM (" + + " SELECT " + + " JSON_UNQUOTE(JSON_EXTRACT(t.obj, '$.code')) AS code, " + + " JSON_UNQUOTE(JSON_EXTRACT(t.obj, '$.data')) AS data " + + " FROM (" + + " SELECT JSON_EXTRACT(project_props, CONCAT('$[', idx.idx, ']')) AS obj " + + " FROM (SELECT 0 AS idx UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) idx" + + " WHERE idx.idx < JSON_LENGTH(project_props)" + + " ) t" + + ") jt " + + "WHERE jt.code = {0} AND jt.data LIKE CONCAT('%', {1}, '%'))", + code, value + ); + } + } + } + } + return projectMapper.selectPage(page, queryWrapper); + } /*********************************** @@ -119,12 +144,24 @@ public class ProjectServiceImpl extends ServiceImpl impl * 返回值说明: com.yfd.platform.config.ResponseResult 返回新增成功或者失败 ***********************************/ @Override - public Boolean addSdproject(Project project) { + public Boolean addSdproject(Project project) throws IOException { //创建项目的时候要创建一个本地的文件夹 路径的话去找专项的存储路径 //生成项目编号 String projectCode = generateNextProjectCode(); project.setProjectCode(projectCode); + String frontEndJson = project.getProjectProps(); + List projectList = projectMapper.selectList(new LambdaQueryWrapper<>()); + if (projectList.size()>0){ + for (Project projectData : projectList) { + String dbJson = projectData.getProjectProps(); + String syncData = syncData(frontEndJson, dbJson); + projectData.setProjectProps(syncData); + projectMapper.updateById(projectData); + } + } + + // 设置当前时间 LocalDateTime now = LocalDateTime.now(); // 转换为 Timestamp @@ -270,25 +307,119 @@ public class ProjectServiceImpl extends ServiceImpl impl * 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败 ***********************************/ @Override - public boolean updateSdproject(Project project) { - //查询字典表获取项目类型对应数据字典 -// QueryWrapper queryWrapperSysDictionary = new QueryWrapper<>(); -// queryWrapperSysDictionary.eq("parentcode", "zxxmlx"); -// queryWrapperSysDictionary.eq("itemcode", project.getProjectType()); -// queryWrapperSysDictionary.orderByAsc("orderno"); -// SysDictionaryItems sysDictionaryItems = sysDictionaryItemsMapper.selectOne(queryWrapperSysDictionary); -// if(sysDictionaryItems != null){ -// project.setProjectType(sysDictionaryItems.getDictName()); -// } + public boolean updateSdproject(Project project) throws IOException { + Boolean value = true; if (project.getProjectTime() == null || project.getProjectTime().equals("")) { project.setProjectTime(null); } - int valueUpdate = projectMapper.updateById(project); - if (valueUpdate == 1) { - return true; - } else { - return false; + String frontEndJson = project.getProjectProps(); + List projectList = projectMapper.selectList(new LambdaQueryWrapper<>()); + if (projectList.size()>0){ + for (Project projectData : projectList) { + String dbJson = projectData.getProjectProps(); + String syncData = syncData(frontEndJson, dbJson); + projectData.setProjectProps(syncData); + projectMapper.updateById(projectData); + } } + + + + //修改的时候判断本地存储空间是不是发生了变化 如果是的话 需要重新创建本地文件 + Project projectOld = projectMapper.selectById(project.getId()); + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); + if (!projectOld.getLocalStorageId().equals(project.getLocalStorageId())){ + String path = "/"; + //新增节点的时候 创建文件夹 + NewFolderRequest newFolderRequest = new NewFolderRequest(); + newFolderRequest.setName(project.getProjectName());//新建的文件夹名称,示例值(/a/b/c) + newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) + newFolderRequest.setPath(path);//请求路径,示例值(/) + newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio) + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); + boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); + if (flag) { + int valueUpdate = projectMapper.updateById(project); + if (valueUpdate == 1) { + value = true; + } else { + value = false; + } + value = true; + } else { + LOGGER.error("节点新增成功,但是本地专项文件夹创建失败"); + value = false; + } + }else { + int valueUpdate = projectMapper.updateById(project); + if (valueUpdate == 1) { + value = true; + } else { + value = false; + } + } + return value; + } + + public static String syncData(String frontEndJson, String dbJson) throws IOException { + // 1. 如果 frontEndJson 为空,则返回一个空的 dbJson + if (frontEndJson == null || frontEndJson.trim().isEmpty()) { + return "[]"; // 返回空的 JSON 数组 + } + + // 2. 解析前端传递的 JSON 字符串为 List>,如果为空,直接返回空的 dbJson + ObjectMapper objectMapper = new ObjectMapper(); + List> frontEndData = objectMapper.readValue(frontEndJson, List.class); + + // 3. 如果前端有数据,且 dbJson 为空,直接使用前端数据并将 data 设置为空 + if (frontEndData != null && !frontEndData.isEmpty() && (dbJson == null || dbJson.trim().isEmpty())) { + List> result = new ArrayList<>(); + for (Map item : frontEndData) { + Map newItem = new HashMap<>(); + newItem.put("code", item.get("code")); + newItem.put("name", item.get("name")); + newItem.put("data", ""); // 数据为空 + result.add(newItem); + } + return objectMapper.writeValueAsString(result); // 返回填充后的结果 + } + + // 4. 如果 dbJson 不为空,解析 dbJson + List> dbData = objectMapper.readValue(dbJson, List.class); + + // 5. 根据前端数据创建一个Map,以便快速查找前端的项 + Map> frontEndMap = frontEndData.stream() + .collect(Collectors.toMap(item -> (String) item.get("name"), item -> item)); + + // 6. 遍历数据库中的数据,进行相应的增、删、改 + List> result = new ArrayList<>(); + + // 7. 处理数据库中的项:先将前端数据对应的项保留,新增的项加上空的数据 + for (Map dbItem : dbData) { + String name = dbItem.get("name"); + if (frontEndMap.containsKey(name)) { + // 如果前端有该项,则保留数据库中的项,保持其原有的id + // 只有当前端的 data 不为空时才更新,避免改变数据库中原有的 data + String frontEndDataValue = frontEndMap.get(name).get("data"); +// if (frontEndDataValue != null && !frontEndDataValue.trim().isEmpty()) { +// //dbItem.put("data", frontEndDataValue); // 只在前端有值时才更新 +// } + result.add(dbItem); + frontEndMap.remove(name); // 从前端map中移除已处理的项 + } + } + + // 8. 处理前端数据中没有在数据库中出现的项:新增这些项,data为空 + for (Map.Entry> entry : frontEndMap.entrySet()) { + Map newItem = new HashMap<>(); + newItem.put("code", entry.getValue().get("code")); // 保持前端传来的id + newItem.put("name", entry.getValue().get("name")); + newItem.put("data", ""); // 如果数据库中没有该项,则data为空 + result.add(newItem); + } + + // 9. 将结果转换为 JSON 字符串并返回 + return objectMapper.writeValueAsString(result); } /********************************** diff --git a/java/src/main/java/com/yfd/platform/modules/storage/convert/impl/StorageSourceConvertImpl.java b/java/src/main/java/com/yfd/platform/modules/storage/convert/impl/StorageSourceConvertImpl.java index 768cda9..88beeb8 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/convert/impl/StorageSourceConvertImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/convert/impl/StorageSourceConvertImpl.java @@ -17,10 +17,15 @@ import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig; import com.yfd.platform.modules.storage.model.result.StorageSourceAdminResult; import com.yfd.platform.modules.storage.model.result.StorageSourceConfigResult; import com.yfd.platform.modules.storage.model.result.StorageSourceResult; +import com.yfd.platform.utils.StringUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.File; +import java.nio.file.FileStore; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; @@ -135,8 +140,10 @@ public class StorageSourceConvertImpl implements StorageSourceConvert { String value = storageSourceConfigMapper.selectOne(queryWrapperData).getValue(); storageSource.setValueData(value); - //空间使用率 - storageSource.setSpaceOccupancyRatio(calculateLocalStorageUsage(value)); + if(StringUtils.isNotBlank(value)){ + //空间使用率 + storageSource.setSpaceOccupancyRatio(calculateLocalStorageUsage(value)); + } }else { LambdaQueryWrapper queryWrapper1 = new LambdaQueryWrapper<>(); @@ -151,7 +158,18 @@ public class StorageSourceConvertImpl implements StorageSourceConvert { } } storageSource.setStoreContent(String.valueOf(result)); - storageSource.setValueData(null); + //存储路径 + LambdaQueryWrapper queryWrapperData = new LambdaQueryWrapper<>(); + queryWrapperData.eq(StorageSourceConfig::getStorageId, storageSource.getId()); + queryWrapperData.eq(StorageSourceConfig::getName, "filePath"); + String value = storageSourceConfigMapper.selectOne(queryWrapperData).getValue(); + storageSource.setValueData(value); + if(StringUtils.isNotBlank(value)){ + //空间使用率 + storageSource.setSpaceOccupancyRatio(calculateLocalStorageUsage(value)); + } + + } } @@ -180,22 +198,48 @@ public class StorageSourceConvertImpl implements StorageSourceConvert { // 计算本地路径的空间使用率 public static String calculateLocalStorageUsage(String path) { - File file = new File(path); - if (!file.exists()) { - throw new IllegalArgumentException("路径不存在: " + path); + + try { + Path target = Paths.get(path); + + // 处理符号链接(获取实际挂载点) + if (Files.isSymbolicLink(target)) { + target = Files.readSymbolicLink(target); + } + + // 获取文件存储信息 + FileStore store = Files.getFileStore(target); + + long totalSpace = store.getTotalSpace(); + long usableSpace = store.getUsableSpace(); + + if (totalSpace <= 0) { + return "0%"; // 特殊文件系统处理 + } + + double usagePercentage = (double) (totalSpace - usableSpace) / totalSpace * 100; + DecimalFormat df = new DecimalFormat("#.##"); + return df.format(usagePercentage) + "%"; + + } catch (Exception e) { + throw new IllegalArgumentException("无法获取磁盘空间: " + e.getMessage()); } - - // 获取磁盘空间信息 - long totalSpace = file.getTotalSpace(); - long freeSpace = file.getFreeSpace(); - // 计算使用率 - long usedSpace = totalSpace - freeSpace; - double usagePercentage = (double) usedSpace / totalSpace * 100; - - // 格式化输出 - DecimalFormat df = new DecimalFormat("#.##"); - - return df.format(usagePercentage) + "%"; +// File file = new File(path); +// if (!file.exists()) { +// throw new IllegalArgumentException("路径不存在: " + path); +// } +// +// // 获取磁盘空间信息 +// long totalSpace = file.getTotalSpace(); +// long freeSpace = file.getFreeSpace(); +// // 计算使用率 +// long usedSpace = totalSpace - freeSpace; +// double usagePercentage = (double) usedSpace / totalSpace * 100; +// +// // 格式化输出 +// DecimalFormat df = new DecimalFormat("#.##"); +// +// return df.format(usagePercentage) + "%"; } diff --git a/java/src/main/java/com/yfd/platform/modules/storage/service/StorageSourceService.java b/java/src/main/java/com/yfd/platform/modules/storage/service/StorageSourceService.java index d82210f..5caf573 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/service/StorageSourceService.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/service/StorageSourceService.java @@ -3,6 +3,7 @@ package com.yfd.platform.modules.storage.service; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.exception.BadRequestException; @@ -10,6 +11,10 @@ import com.yfd.platform.exception.StorageSourceException; import com.yfd.platform.exception.file.InvalidStorageSourceException; import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest; import com.yfd.platform.modules.config.model.request.UpdateStorageSortRequest; +import com.yfd.platform.modules.experimentalData.domain.TsTask; +import com.yfd.platform.modules.experimentalData.mapper.TsTaskMapper; +import com.yfd.platform.modules.specialDocument.domain.Project; +import com.yfd.platform.modules.specialDocument.mapper.ProjectMapper; import com.yfd.platform.modules.storage.context.StorageSourceContext; import com.yfd.platform.modules.storage.convert.StorageSourceConvert; import com.yfd.platform.modules.storage.mapper.StorageSourceMapper; @@ -55,6 +60,13 @@ public class StorageSourceService { @Resource private StorageSourceConvert storageSourceConvert; + //专项项目表Mapper + @Resource + private ProjectMapper projectMapper; + + //试验任务Mapper + @Resource + private TsTaskMapper tsTaskMapper; /** * 获取所有存储源列表 @@ -244,6 +256,37 @@ public class StorageSourceService { public StorageSource deleteById(Integer id) { log.info("删除 id 为 {} 的存储源", id); StorageSource storageSource = findById(id); + String type = storageSource.getType().getKey(); + + if ("local".equals(type)) { + //获取关联的存储内容 先获取专项文档 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(Project::getLocalStorageId, storageSource.getId()); + List projects = projectMapper.selectList(queryWrapper); + if (projects.size()>0){ + throw new BadRequestException("存在存储内容不能删除"); + } + + LambdaQueryWrapper queryWrapper1 = new LambdaQueryWrapper<>(); + queryWrapper1.eq(TsTask::getLocalStorageId, storageSource.getId()); + List tsTasks = tsTaskMapper.selectList(queryWrapper1); + if (tsTasks.size()>0){ + throw new BadRequestException("存在存储内容不能删除"); + } + + + }else { + LambdaQueryWrapper queryWrapper1 = new LambdaQueryWrapper<>(); + queryWrapper1.eq(TsTask::getBackupStorageId, storageSource.getId()); + List tsTasks = tsTaskMapper.selectList(queryWrapper1); + if (tsTasks.size()>0){ + throw new BadRequestException("存在存储内容不能删除"); + } + } + + + + if (storageSource == null) { String msg = StrUtil.format("删除存储源时检测到 id 为 {} 的存储源不存在", id); @@ -316,7 +359,7 @@ public class StorageSourceService { saveStorageSourceRequest.getKey(), saveStorageSourceRequest.getType().getDescription()); StorageSource storageSourceData = storageSourceMapper.findByStorageKey(saveStorageSourceRequest.getKey()); - if (storageSourceData != null ){ + if (storageSourceData != null && saveStorageSourceRequest.getId() == null ){ throw new BadRequestException("填充存储源别名已存在"); } @@ -338,6 +381,7 @@ public class StorageSourceService { storageSourceConfigService.toStorageSourceConfigList(storageId, dbSaveResult.getType(), saveStorageSourceRequest.getStorageSourceAllParam()); + storageSourceConfigService.saveBatch(storageId, storageSourceConfigList); log.info("保存存储源参数成功,尝试根据参数初始化存储源, id: {}, name: {}, config size: {}", dbSaveResult.getId(), dbSaveResult.getName(), storageSourceConfigList.size());