From 9c52bb1c73f59a564300f022dd010292c7c8e473 Mon Sep 17 00:00:00 2001 From: tangwei Date: Fri, 8 May 2026 17:08:25 +0800 Subject: [PATCH 01/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/SmsVerifyCodeController.java | 38 +++--- .../src/main/resources/application-server.yml | 109 +++++++++++++++--- 2 files changed, 110 insertions(+), 37 deletions(-) diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java b/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java index 279f5d6..dad479d 100644 --- a/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java +++ b/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java @@ -204,7 +204,7 @@ public class SmsVerifyCodeController { selectedBasinCodes.addAll(Arrays.asList(hbrvcdCode.split(","))); } - Set addedStationCodes = new HashSet<>(); +// Set addedStationCodes = new HashSet<>(); for (String basinCode : selectedBasinCodes) { if (StringUtils.isEmpty(basinCode)) { @@ -241,7 +241,7 @@ public class SmsVerifyCodeController { scope.setStatus(1); scope.setPermissionType("READ"); sysUserDataScopeService.addDataScope(scope); - addedStationCodes.add(basinCode); +// addedStationCodes.add(basinCode); } else { Set stationsInBasinAndSelected = allStationCodesInBasin.stream() .filter(selectedStationCodes::contains) @@ -255,27 +255,27 @@ public class SmsVerifyCodeController { scope.setStatus(1); scope.setPermissionType("READ"); sysUserDataScopeService.addDataScope(scope); - addedStationCodes.add(stationCd); +// addedStationCodes.add(stationCd); } } } - Set standaloneStations = selectedStationCodes.stream() - .filter(code -> !addedStationCodes.contains(code)) - .collect(Collectors.toSet()); - - for (String stationCd : standaloneStations) { - if (StringUtils.isEmpty(stationCd)) { - continue; - } - SysUserDataScope scope = new SysUserDataScope(); - scope.setUserId(userId); - scope.setOrgType("STATION"); - scope.setOrgId(stationCd); - scope.setStatus(1); - scope.setPermissionType("READ"); - sysUserDataScopeService.addDataScope(scope); - } +// Set standaloneStations = selectedStationCodes.stream() +// .filter(code -> !addedStationCodes.contains(code)) +// .collect(Collectors.toSet()); +// +// for (String stationCd : standaloneStations) { +// if (StringUtils.isEmpty(stationCd)) { +// continue; +// } +// SysUserDataScope scope = new SysUserDataScope(); +// scope.setUserId(userId); +// scope.setOrgType("STATION"); +// scope.setOrgId(stationCd); +// scope.setStatus(1); +// scope.setPermissionType("READ"); +// sysUserDataScopeService.addDataScope(scope); +// } SysUser user = new SysUser(); user.setId(userId); userService.updateUserRoles( user,"c13481a486c9ee559cf305284df4d207"); diff --git a/backend/src/main/resources/application-server.yml b/backend/src/main/resources/application-server.yml index b4e0057..b03a5b5 100644 --- a/backend/src/main/resources/application-server.yml +++ b/backend/src/main/resources/application-server.yml @@ -1,5 +1,5 @@ server: - port: 8090 + port: 8093 spring: #应用名称 @@ -9,44 +9,117 @@ spring: type: com.alibaba.druid.pool.DruidDataSource druid: master: - driverClassName: com.mysql.cj.jdbc.Driver - url: "${DB_MASTER_URL:jdbc:mysql://43.138.168.68:3306/frameworkdb2025?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true}" - username: "${DB_MASTER_USERNAME:root}" - password: "${DB_MASTER_PASSWORD:}" + driverClassName: oracle.jdbc.OracleDriver + url: "${DB_MASTER_URL:jdbc:oracle:thin:@172.16.21.134:1521/SDLYZ}" + username: "${DB_MASTER_USERNAME:QGC_REFA}" + password: "${DB_MASTER_PASSWORD:Y4M4K1oCkL8U}" + slave: + driverClassName: oracle.jdbc.OracleDriver + url: "${DB_SLAVE_URL:jdbc:oracle:thin:@172.16.21.134:1521/SDLYZ}" + username: "${DB_SLAVE_USERNAME:QGC_REFA}" + password: "${DB_SLAVE_PASSWORD:Y4M4K1oCkL8U}" + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 mvc: pathmatch: matching-strategy: ant_path_matcher servlet: multipart: - max-file-size: 30MB - max-request-size: 100MB + max-file-size: 300MB + max-request-size: 500MB logging: file: - name: logs/projectname.log - + name: logs/platform-dev.log level: - com.genersoft.iot: debug - com.genersoft.iot.vmp.storager.dao: info - com.genersoft.iot.vmp.gb28181: info + root: info + com.yfd.platform: info +# com.yfd.platform.*.mapper: trace # 在线文档: swagger-ui(生产环境建议关闭) swagger-ui: - enabled: false + enabled: true -file-space: #项目文档空间 - files: D:\demoproject\files\ #单独上传的文件附件 - useravatar: D:\demoproject\useravatar\ #用户头像 - system: D:\demoproject\system\ #系统文档根目录,用于头像等静态资源 +mybatis-plus: + # mapper-locations: classpath*:**/mapper/*Mapper.xml,classpath*:**/mapping/*Mapper.xml + global-config: + banner: false + db-config: + id-type: ASSIGN_ID + insert-strategy: not_null + update-strategy: not_null + select-strategy: not_empty + table-underline: true + logic-delete-value: 1 + logic-not-delete-value: 0 + logic-delete-field: isDeleted + configuration: + map-underscore-to-camel-case: true + cache-enabled: false + log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl +# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + + +# 登录相关配置 +login: + # 登录缓存 + cache-enable: true + # 是否限制单用户登录 + single-login: false + # 验证码 + login-code: + # 验证码类型配置 查看 LoginProperties 类 + code-type: arithmetic # 启动自动数据库初始化(仅 dev/server): app: + # ZIP导入临时目录配置 + zip-import: + temp-dir: ${ZIP_IMPORT_TEMP_DIR:/qgc-platform/tmp/zip_import_temp} init: - enabled: true + enabled: false schema: classpath:db-init/sql/min-schema.sql # data 文件可选;为避免复杂 dump 解析问题,先不导入 # data: marker-table: sys_user marker-version: v1.0.0 + # 登录图形验证码有效时间/分钟 + expiration: 2 + # 验证码高度 + width: 111 + # 验证码宽度 + heigth: 36 + # 内容长度 + length: 2 + # 字体名称,为空则使用默认字体 + font-name: + # 字体大小 + font-size: 25 +# IP 本地解析 +ip: + local-parsing: true + + +file-space: #项目文档空间 + files: /qgc-platform/files/ #单独上传的文件附件 + system: /qgc-platform/system/ #单独上传的文件 + +task: + pool: + # 核心线程池大小 + core-pool-size: 10 + # 最大线程数 + max-pool-size: 30 + # 活跃时间 + keep-alive-seconds: 60 + # 队列容量 + queue-capacity: 50 + +attachment: + token: ${ATTACHMENT_TOKEN:qgcBkod25ngBa4wu8BtfCPYsJ7lQGVDoexH} + upload-url: ${ATTACHMENT_UPLOAD_URL:http://172.16.31.185:18200/upload} + video-url: ${ATTACHMENT_VIDEO_URL:http://172.16.31.185:18200/upload} + delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/delete} \ No newline at end of file From 76821ca7866145959357d1a599293bbfbc6ad441 Mon Sep 17 00:00:00 2001 From: tangwei Date: Sat, 9 May 2026 08:29:58 +0800 Subject: [PATCH 02/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FishDraftDataController.java | 11 ++- .../yfd/platform/data/utils/ZipFileUtil.java | 97 +++++++++++++++++-- 2 files changed, 96 insertions(+), 12 deletions(-) diff --git a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java index 1e1a0d5..318650e 100644 --- a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java +++ b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java @@ -3,7 +3,9 @@ package com.yfd.platform.data.controller; import java.io.File; import java.io.FileInputStream; import java.io.OutputStream; +import java.net.URLDecoder; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -495,6 +497,9 @@ public class FishDraftDataController { @GetMapping("/previewFile") @Operation(summary = "预览临时文件内容") public void previewFile(@RequestParam String taskId, @RequestParam String filename, @RequestParam String type, HttpServletRequest request, HttpServletResponse response) { + // 解码 URL 编码的 filename(处理中文文件名) + String decodedFilename = URLDecoder.decode(filename, StandardCharsets.UTF_8); + log.debug("原始文件名: {}, 解码后: {}", filename, decodedFilename); ImportTask importTask = importTaskService.getById(taskId); String resultJson = importTask.getResultJson(); @@ -502,9 +507,9 @@ public class FishDraftDataController { String dir = "1".equals(type) ? "images" : "videos"; if (resultJson != null && !resultJson.isEmpty()) { try { - FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class); - String tempDir = importResult.getTempDir(); - filePath = tempDir + File.separator + dir + File.separator + filename; +// FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class); + String tempDir = importTask.getTempDir(); + filePath = tempDir + File.separator + dir + File.separator + decodedFilename; } catch (Exception e) { e.printStackTrace(); // ignore parse error diff --git a/backend/src/main/java/com/yfd/platform/data/utils/ZipFileUtil.java b/backend/src/main/java/com/yfd/platform/data/utils/ZipFileUtil.java index 662fb4b..d183bca 100644 --- a/backend/src/main/java/com/yfd/platform/data/utils/ZipFileUtil.java +++ b/backend/src/main/java/com/yfd/platform/data/utils/ZipFileUtil.java @@ -1,5 +1,7 @@ package com.yfd.platform.data.utils; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -364,22 +366,99 @@ public class ZipFileUtil { } private static String saveFileToDir(InputStream is, File tempDir, String subFolder, String fileName) throws IOException { + // 使用 Hutool 构建文件路径 + String safeFileName = sanitizeFileName(fileName); File folder = new File(tempDir, subFolder); - if (!folder.exists()) { - folder.mkdirs(); + + // 使用 Hutool 创建目录(会自动创建父目录) + FileUtil.mkdir(folder); + + log.info("保存文件: fileName{} -> safeFileName{}->subFolder{}", fileName, safeFileName,subFolder); + // 构建完整文件路径 + File file = new File(folder, safeFileName); + + // 安全检查:防止目录穿越 + String canonicalPath = file.getCanonicalPath(); + String canonicalDir = folder.getCanonicalPath(); + if (!canonicalPath.startsWith(canonicalDir)) { + throw new IOException("非法的文件路径: " + fileName); } - File file = new File(folder, fileName); - try (FileOutputStream fos = new FileOutputStream(file)) { - byte[] buffer = new byte[4096]; - int len; - while ((len = is.read(buffer)) > 0) { - fos.write(buffer, 0, len); - } + // 使用 Hutool 从流复制到文件 + try { + FileUtil.writeFromStream(is, file); + log.debug("保存文件: {} -> {}, 大小: {} bytes", fileName, safeFileName, file.length()); + } catch (Exception e) { + throw new IOException("保存文件失败: " + fileName, e); } + return file.getAbsolutePath(); } + + /** + * 清理和标准化文件名,确保在 Linux 上正确显示中文 + */ + private static String sanitizeFileName(String fileName) { + if (StrUtil.isBlank(fileName)) { + return "unnamed_" + System.currentTimeMillis(); + } + + // 使用 Hutool 去除首尾空格 + String sanitized = StrUtil.trim(fileName); + + // 替换非法字符(Linux/Windows 都不允许的字符) + sanitized = sanitized.replaceAll("[\\\\/:*?\"<>|]", "_"); + + // 去除连续的下划线 + sanitized = sanitized.replaceAll("_+", "_"); + + // 如果文件名过长,截断(Linux 文件名最大 255 字节) + byte[] bytes = sanitized.getBytes(StandardCharsets.UTF_8); + if (bytes.length > 200) { + String extension = ""; + int dotIndex = sanitized.lastIndexOf('.'); + if (dotIndex > 0 && dotIndex < sanitized.length() - 1) { + extension = sanitized.substring(dotIndex); + sanitized = sanitized.substring(0, dotIndex); + } + + // 重新计算长度 + bytes = sanitized.getBytes(StandardCharsets.UTF_8); + int maxNameLength = 200 - extension.getBytes(StandardCharsets.UTF_8).length; + + if (bytes.length > maxNameLength) { + // 安全截断,避免切断多字节字符 + sanitized = StrUtil.subPre(sanitized, maxNameLength); + } + sanitized = sanitized + extension; + } + + // 确保文件名不为空 + if (StrUtil.isBlank(sanitized) || ".".equals(sanitized)) { + return "file_" + System.currentTimeMillis(); + } + + return sanitized; + } + +// private static String saveFileToDir(InputStream is, File tempDir, String subFolder, String fileName) throws IOException { +// File folder = new File(tempDir, subFolder); +// if (!folder.exists()) { +// folder.mkdirs(); +// } +// +// File file = new File(folder, fileName); +// try (FileOutputStream fos = new FileOutputStream(file)) { +// byte[] buffer = new byte[4096]; +// int len; +// while ((len = is.read(buffer)) > 0) { +// fos.write(buffer, 0, len); +// } +// } +// return file.getAbsolutePath(); +// } + private static boolean isImageFile(String fileName) { return fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || fileName.endsWith(".png") || fileName.endsWith(".gif") || From 8c20e76cd0e77b4cc943dd248f20ab6e6a37a1b0 Mon Sep 17 00:00:00 2001 From: tangwei Date: Sat, 9 May 2026 13:26:26 +0800 Subject: [PATCH 03/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/data/domain/FishDraftData.java | 12 ++ .../service/impl/FishImportServiceImpl.java | 69 ++++++++-- .../service/impl/SdEngInfoBHServiceImpl.java | 118 ++++++++++++++++-- .../impl/SysOrganizationServiceImpl.java | 29 +++-- .../java/com/yfd/platform/utils/FileUtil.java | 36 ++++++ 5 files changed, 234 insertions(+), 30 deletions(-) diff --git a/backend/src/main/java/com/yfd/platform/data/domain/FishDraftData.java b/backend/src/main/java/com/yfd/platform/data/domain/FishDraftData.java index 4273248..d452318 100644 --- a/backend/src/main/java/com/yfd/platform/data/domain/FishDraftData.java +++ b/backend/src/main/java/com/yfd/platform/data/domain/FishDraftData.java @@ -65,11 +65,23 @@ public class FishDraftData implements Serializable { */ private Date strdt; + /** + * 开始日期 + */ + @TableField(exist = false) + private String strdtStr; + /** * 结束日期 */ private Date enddt; + /** + * 结束日期 + */ + @TableField(exist = false) + private String enddtStr; + /** * 游向(上行/下行/上行折返/下行折返) */ 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 0228d07..afe954c 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 @@ -413,12 +413,19 @@ public class FishImportServiceImpl implements IFishImportService { case "strdt": if (!StringUtils.hasText(cellValue)) { importRow.getWarnings().add(fieldName); + data.setStrdtStr(cellValue); } else { Date strdt = parseDate(cellValue); if (strdt == null) { importRow.getWarnings().add(fieldName); + data.setStrdt(null); + data.setStrdtStr(cellValue); + }else{ + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String dateString = sdf.format(strdt); + data.setStrdtStr(dateString); + data.setStrdt(strdt); } - data.setStrdt(strdt); } break; case "enddt": @@ -452,6 +459,13 @@ public class FishImportServiceImpl implements IFishImportService { objectObjectHashMap.put("value", fileName); importRow.getVdpthList().add(objectObjectHashMap); vdpthList.add(fileName); + } else if (com.yfd.platform.utils.FileUtil.isVideoFileName(fileName)) { + Map objectObjectHashMap = new HashMap<>(); + objectObjectHashMap.put("name", fileName); + objectObjectHashMap.put("value", fileName); + importRow.getVdpthList().add(objectObjectHashMap); + vdpthList.add(fileName); + importRow.getVdpthsWarnings().add(fileName); } } @@ -474,6 +488,13 @@ public class FishImportServiceImpl implements IFishImportService { objectObjectHashMap.put("value", fileName); importRow.getPicpthList().add(objectObjectHashMap); picpthList.add(fileName); + } else if (!com.yfd.platform.utils.FileUtil.isImageFileName(fileName)) { + Map objectObjectHashMap = new HashMap<>(); + objectObjectHashMap.put("name", fileName); + objectObjectHashMap.put("value", fileName); + importRow.getPicpthList().add(objectObjectHashMap); + picpthList.add(fileName); + importRow.getPicpthsWarnings().add(fileName); } } @@ -529,6 +550,8 @@ public class FishImportServiceImpl implements IFishImportService { return importRow; } + + private void validateStationFpssRelation(FishDraftData data, FishImportResult.FishImportRow importRow) { loadStationAndBaseCache(); if (StringUtils.hasText(data.getHbrvcd()) && StringUtils.hasText(data.getRstcd())) { @@ -1119,28 +1142,54 @@ public class FishImportServiceImpl implements IFishImportService { return true; } + /** + * 解析日期字符串,支持多种格式 + * @param dateStr 日期字符串 + * @return 解析后的 Date 对象,如果解析失败返回 null + */ private Date parseDate(String dateStr) { if (!StringUtils.hasText(dateStr)) { return null; } + + // 去除首尾空格 + dateStr = dateStr.trim(); + + // 支持的日期格式列表(按常用程度排序) String[] patterns = { - "yyyy-MM-dd HH:mm:ss", - "yyyy-MM-dd", - "yyyy/MM/dd", - "yyyy.MM.dd", - "yyyyMMdd" + "yyyy-MM-dd HH:mm:ss", // 2024-01-15 14:30:00 + "yyyy-MM-dd", // 2024-01-15 + "yyyy/MM/dd HH:mm:ss", // 2024/01/15 14:30:00 + "yyyy/MM/dd", // 2024/01/15 + "yyyy.MM.dd HH:mm:ss", // 2024.01.15 14:30:00 + "yyyy.MM.dd", // 2024.01.15 + "yyyyMMdd HHmmss", // 20240115 143000 + "yyyyMMdd", // 20240115 + "yyyy年MM月dd日", // 2024年01月15日 + "yyyy年MM月dd日HH时mm分ss秒" // 2024年01月15日14时30分00秒 }; + for (String pattern : patterns) { try { SimpleDateFormat sdf = new SimpleDateFormat(pattern); - sdf.setLenient(false); - return sdf.parse(dateStr); - } catch (ParseException ignored) { + sdf.setLenient(false); // 严格模式,不允许非法日期 + Date parsedDate = sdf.parse(dateStr); + + // 验证解析后的日期是否合理(例如年份不能是 0001) + Calendar cal = Calendar.getInstance(); + cal.setTime(parsedDate); + int year = cal.get(Calendar.YEAR); + if (year >= 1900 && year <= 2100) { + return parsedDate; + } + } catch (ParseException e) { + // 尝试下一个格式 } } + + log.debug("无法解析日期: '{}'", dateStr); return null; } - private Integer parseInteger(String value) { if (!StringUtils.hasText(value)) { return null; diff --git a/backend/src/main/java/com/yfd/platform/env/service/impl/SdEngInfoBHServiceImpl.java b/backend/src/main/java/com/yfd/platform/env/service/impl/SdEngInfoBHServiceImpl.java index 9d68ba5..55d8d4b 100644 --- a/backend/src/main/java/com/yfd/platform/env/service/impl/SdEngInfoBHServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/env/service/impl/SdEngInfoBHServiceImpl.java @@ -69,11 +69,110 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl selectForDropdown(SdEngInfoBHRequest sdEngInfoBHRequest) { - String baseId = sdEngInfoBHRequest.getBaseId(); - String hbrvcd = sdEngInfoBHRequest.getHbrvcd(); - String ennm = sdEngInfoBHRequest.getEnnm(); - List rvcds = sdEngInfoBHRequest.getRvcds(); - List hbrvcds = sdEngInfoBHRequest.getHbrvcds(); + String userId = SecurityUtils.getUserId(); + String currentUsername = SecurityUtils.getCurrentUsername(); + + // 管理员直接查询 + if ("admin".equals(currentUsername)) { + return queryEngInfoList(sdEngInfoBHRequest, null, null); + } + + // 获取用户权限范围 + List sysUserDataScopes = sysUserDataScopeMapper.selectList( + new LambdaQueryWrapper() + .eq(SysUserDataScope::getUserId, userId) + .select(SysUserDataScope::getOrgId, SysUserDataScope::getOrgType) + ); + + if (sysUserDataScopes == null || sysUserDataScopes.isEmpty()) { + return new ArrayList<>(); + } + + // 分类权限类型 + Set stationCodes = new HashSet<>(); + Set basinCodes = new HashSet<>(); + + for (SysUserDataScope scope : sysUserDataScopes) { + String orgType = scope.getOrgType(); + String orgId = scope.getOrgId(); + + if ("STATION".equals(orgType)) { + stationCodes.add(orgId); + } else if ("HBRVCD".equals(orgType)) { + basinCodes.add(orgId); + } + } + + // 如果有具体站点权限且数量较少,直接使用 IN + if (!stationCodes.isEmpty() && stationCodes.size() <= 100) { + return queryEngInfoList(sdEngInfoBHRequest, stationCodes, null); + } + + // 如果只有流域权限或站点数量过多,使用流域过滤 + if (!basinCodes.isEmpty()) { + return queryEngInfoList(sdEngInfoBHRequest, null, basinCodes); + } + + // 站点数量过多但没有流域信息,分批查询 + if (!stationCodes.isEmpty()) { + return queryEngInfoByBatches(sdEngInfoBHRequest, stationCodes); + } + + return new ArrayList<>(); + } + + /** + * 查询工程信息列表 + */ + private List queryEngInfoList(SdEngInfoBHRequest request, + Set stationCodes, + Set basinCodes) { + LambdaQueryWrapper wrapper = buildQueryWrapper(request); + + // 添加权限过滤 + if (stationCodes != null && !stationCodes.isEmpty()) { + wrapper.in(SdEngInfoBH::getStcd, stationCodes); + } else if (basinCodes != null && !basinCodes.isEmpty()) { + wrapper.in(SdEngInfoBH::getHbrvcd, basinCodes); + } + + return this.list(wrapper); + } + + /** + * 分批查询(当站点数量过多时) + */ + private List queryEngInfoByBatches(SdEngInfoBHRequest request, Set stationCodes) { + List result = new ArrayList<>(); + int batchSize = 100; // 每批最多 100 个站点 + + List stationList = new ArrayList<>(stationCodes); + for (int i = 0; i < stationList.size(); i += batchSize) { + int end = Math.min(i + batchSize, stationList.size()); + List batch = stationList.subList(i, end); + + LambdaQueryWrapper wrapper = buildQueryWrapper(request); + wrapper.in(SdEngInfoBH::getStcd, batch); + + List batchResult = this.list(wrapper); + if (batchResult != null && !batchResult.isEmpty()) { + result.addAll(batchResult); + } + } + + return result; + } + + /** + * 构建查询条件 + */ + private LambdaQueryWrapper buildQueryWrapper(SdEngInfoBHRequest request) { + String baseId = request.getBaseId(); + String hbrvcd = request.getHbrvcd(); + String ennm = request.getEnnm(); + List rvcds = request.getRvcds(); + List hbrvcds = request.getHbrvcds(); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(StringUtils.hasText(baseId), SdEngInfoBH::getBaseId, baseId) .eq(StringUtils.hasText(hbrvcd), SdEngInfoBH::getHbrvcd, hbrvcd) @@ -83,14 +182,7 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl authorizedStations = getUserAuthorizedStationCodes(); - if (authorizedStations != null && !authorizedStations.isEmpty()) { - wrapper.in(SdEngInfoBH::getStcd, authorizedStations); - } else if (!"admin".equals(SecurityUtils.getCurrentUsername())){ - return new ArrayList<>(); - } - - return this.list(wrapper); + return wrapper; } @Override diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java index 4bc9925..a4665df 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java @@ -14,6 +14,7 @@ import com.yfd.platform.system.mapper.SysRoleMapper; import com.yfd.platform.system.service.ISysOrganizationService; import com.yfd.platform.system.service.IUserService; import com.yfd.platform.utils.ObjectConverterUtil; +import com.yfd.platform.utils.SecurityUtils; import org.springframework.stereotype.Service; import jakarta.annotation.Resource; @@ -79,7 +80,7 @@ public class SysOrganizationServiceImpl extends ServiceImpl stringList = Arrays.asList(split); Set set = new HashSet<>(); - if (stringList.size() > 0) { + if (!stringList.isEmpty()) { List list = sysOrganizationMapper.selectList(new LambdaQueryWrapper().in(SysOrganization::getId, stringList)); list.forEach(l -> set.add(l.getParentid())); @@ -243,20 +244,34 @@ public class SysOrganizationServiceImpl extends ServiceImpl> getOrgScopeTree(String roleId) { - LambdaQueryWrapper queryWrapper = - new LambdaQueryWrapper<>(); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if(!"admin".equals(SecurityUtils.getCurrentUsername())){ + String userId = SecurityUtils.getUserId(); + List roles = sysRoleMapper.getRoleByUserId(userId); + List ids = new ArrayList<>(); + for (SysRole role : roles) { + String orgscope = role.getOrgscope(); + if(StrUtil.isNotBlank(orgscope)){ + ids.addAll(Arrays.asList(orgscope.split(","))); + } + } + if(ids.isEmpty()){ + return new ArrayList<>(); + } + queryWrapper.in(SysOrganization::getId, ids); + } queryWrapper.eq(SysOrganization::getIsvaild, '1'); queryWrapper.orderByAsc(SysOrganization::getOrgcode); - List> listMaps = this.listMaps(queryWrapper); + List> mapList = this.listMaps(queryWrapper); + List> listMaps = ObjectConverterUtil.convertMapFieldsToEntityFormat(SysOrganization.class, mapList); // 获取当前角色 SysRole sysRole = sysRoleMapper.selectById(roleId); String orgscope = sysRole.getOrgscope(); List ids = new ArrayList<>(); if (StrUtil.isNotBlank(orgscope)) { - String[] split = orgscope.split(","); - ids = Arrays.asList(split); + ids.addAll(Arrays.asList(orgscope.split(","))); } - for (Map map : listMaps) { String id = (String) map.get("id"); if (ids.contains(id)) { diff --git a/backend/src/main/java/com/yfd/platform/utils/FileUtil.java b/backend/src/main/java/com/yfd/platform/utils/FileUtil.java index 6940aee..3261a3d 100644 --- a/backend/src/main/java/com/yfd/platform/utils/FileUtil.java +++ b/backend/src/main/java/com/yfd/platform/utils/FileUtil.java @@ -391,6 +391,42 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { fis.close(); } + /** + * 判断文件名是否为图片类型 + */ + public static boolean isImageFileName(String fileName) { + if (fileName == null || fileName.isEmpty()) { + return false; + } + + String lowerName = fileName.toLowerCase(); + return lowerName.endsWith(".jpg") + || lowerName.endsWith(".jpeg") + || lowerName.endsWith(".png") + || lowerName.endsWith(".gif") + || lowerName.endsWith(".bmp") + || lowerName.endsWith(".webp") + || lowerName.endsWith(".svg"); + } + + /** + * 判断文件名是否为视频类型 + */ + public static boolean isVideoFileName(String fileName) { + if (fileName == null || fileName.isEmpty()) { + return false; + } + + String lowerName = fileName.toLowerCase(); + return lowerName.endsWith(".mp4") + || lowerName.endsWith(".avi") + || lowerName.endsWith(".mov") + || lowerName.endsWith(".wmv") + || lowerName.endsWith(".flv") + || lowerName.endsWith(".mkv"); + } + + public static String getMd5(File file) { return getMd5(getByte(file)); } From 8038df7dcf932488dabf20959b0065fa7cf120a9 Mon Sep 17 00:00:00 2001 From: tangwei Date: Sat, 9 May 2026 15:06:37 +0800 Subject: [PATCH 04/22] =?UTF-8?q?fix:=20=E4=BD=BF=E7=94=A8=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/FishImportServiceImpl.java | 205 +++++++++--------- 1 file changed, 102 insertions(+), 103 deletions(-) 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 afe954c..2ee0827 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 @@ -176,38 +176,14 @@ public class FishImportServiceImpl implements IFishImportService { Map columnIndexMap = new HashMap<>(EXCEL_COLUMN_INDEX_MAPPING); - int totalRows = sheet.getLastRowNum(); - for (int i = 1; i <= totalRows; i++) { - Row row = sheet.getRow(i); - if (row == null || isRowEmpty(row)) { - continue; - } - - FishImportResult.FishImportRow importRow = parseRow(result, row, columnIndexMap, i, uploadUserId); - result.setTotalCount(result.getTotalCount() + 1); - if (importRow.getData() != null && importRow.getWarnings().isEmpty()) { - result.addSuccessRow(importRow); - result.setSuccessCount(result.getSuccessCount() + 1); - } else { - result.addFailedRow(importRow); - result.setFailedCount(result.getFailedCount() + 1); - } - } - result.setSummary(String.format("共解析%d条数据,失败%d条", - result.getSuccessCount(), result.getFailedCount())); - - return result; - } - - private FishImportResult.FishImportRow parseRow(FishImportResult result, Row row, Map columnIndexMap, int rowIndex, String userId) { - FishImportResult.FishImportRow importRow = new FishImportResult.FishImportRow(rowIndex); - FishDraftData data = new FishDraftData(); - data.setId(UUID.randomUUID().toString()); Set allowedHbrvcdSet = new HashSet<>(); Set directStcdSet = new HashSet<>(); - Set directBHSet = new HashSet<>(); - if (userId != null) { - List permissions = userDataScopeMapper.selectValidPermissions(userId); + + List sdFpssList=new ArrayList<>(); + List allowedHbrvcdList = new ArrayList<>(); + List directStcdList = new ArrayList<>(); + if (uploadUserId != null) { + List permissions = userDataScopeMapper.selectValidPermissions(uploadUserId); if (permissions != null && !permissions.isEmpty()) { for (SysUserDataScope permission : permissions) { String orgType = permission.getOrgType(); @@ -226,7 +202,6 @@ public class FishImportServiceImpl implements IFishImportService { } } -// Set allStcdSet = new HashSet<>(); if (!allowedHbrvcdSet.isEmpty() || !directStcdSet.isEmpty()) { if (!allowedHbrvcdSet.isEmpty()) { @@ -250,14 +225,52 @@ public class FishImportServiceImpl implements IFishImportService { } } } + + if(!allowedHbrvcdSet.isEmpty()){ + List sdHbrvDics = sdHbrvDicMapper.selectList(new LambdaQueryWrapper().in(SdHbrvDic::getHbrvcd, allowedHbrvcdSet).select(SdHbrvDic::getHbrvcd, SdHbrvDic::getHbrvnm)); + allowedHbrvcdList.addAll(sdHbrvDics); + } + if (!directStcdSet.isEmpty()) { - List sdFpssBHS = fpssBHMapper.selectList(new LambdaQueryWrapper().in(SdFpssBH::getRstcd, directStcdSet).select(SdFpssBH::getStcd)); - for (SdFpssBH sdFpssBH : sdFpssBHS) { - if (sdFpssBH.getStcd() != null) { - directBHSet.add(sdFpssBH.getStcd()); - } + List sdFpssBHS = fpssBHMapper.selectList(new LambdaQueryWrapper().in(SdFpssBH::getRstcd, directStcdSet).select(SdFpssBH::getStcd, SdFpssBH::getStnm)); + //设施 + sdFpssList.addAll(sdFpssBHS.stream().filter(sdFpssBH -> sdFpssBH.getStcd() != null).toList()); + + //电站 + directStcdList.addAll(engInfoBHMapper.selectList(new LambdaQueryWrapper().in(SdEngInfoBH::getStcd, directStcdSet).select(SdEngInfoBH::getStcd, SdEngInfoBH::getEnnm))); + + } + + int totalRows = sheet.getLastRowNum(); + for (int i = 1; i <= totalRows; i++) { + Row row = sheet.getRow(i); + if (row == null || isRowEmpty(row)) { + continue; + } + + FishImportResult.FishImportRow importRow = parseRow(result, row, columnIndexMap, i, uploadUserId,allowedHbrvcdList,directStcdList,sdFpssList); + result.setTotalCount(result.getTotalCount() + 1); + if (importRow.getData() != null && importRow.getWarnings().isEmpty()) { + result.addSuccessRow(importRow); + result.setSuccessCount(result.getSuccessCount() + 1); + } else { + result.addFailedRow(importRow); + result.setFailedCount(result.getFailedCount() + 1); } } + result.setSummary(String.format("共解析%d条数据,失败%d条", + result.getSuccessCount(), result.getFailedCount())); + + return result; + } + + private FishImportResult.FishImportRow parseRow(FishImportResult result, Row row, Map columnIndexMap, int rowIndex, String userId,List allowedHbrvcdList,List directStcdList,List sdFpssList) { + + + FishImportResult.FishImportRow importRow = new FishImportResult.FishImportRow(rowIndex); + FishDraftData data = new FishDraftData(); + data.setId(UUID.randomUUID().toString()); + for (Map.Entry entry : columnIndexMap.entrySet()) { Integer columnIndex = entry.getKey(); String fieldName = entry.getValue(); @@ -271,20 +284,14 @@ public class FishImportServiceImpl implements IFishImportService { data.setEnnm(cellValue.trim()); data.setRstcd(cellValue); } else { - String stcd = resolveStationCode(cellValue.trim()); - if (stcd == null) { + String stcd = directStcdList.stream().filter(sdEngInfoBH -> sdEngInfoBH.getEnnm().equals(cellValue.trim())).map(SdEngInfoBH::getStcd).findFirst().get(); + if (StrUtil.isBlank(stcd)) { importRow.getWarnings().add("rstcd"); data.setEnnm(cellValue.trim()); + data.setRstcd(cellValue.trim()); } else { - if (directStcdSet.contains(stcd)) { - data.setEnnm(cellValue.trim()); - data.setRstcd(stcd); - } else { - importRow.getWarnings().add("rstcd"); - data.setEnnm(cellValue.trim()); - data.setRstcd(cellValue); - } - + data.setEnnm(cellValue.trim()); + data.setRstcd(stcd); } } break; @@ -322,33 +329,17 @@ public class FishImportServiceImpl implements IFishImportService { data.setHbrvcd(cellValue); data.setHbrvnm(cellValue); } else { - String hbrvcdCode = resolveHbrvcdCode(cellValue.trim()); - if (hbrvcdCode == null) { + String hbrvcdCode = allowedHbrvcdList.stream().filter(sdHbrvDic -> sdHbrvDic.getHbrvnm().equals(cellValue.trim())).map(SdHbrvDic::getHbrvcd).findFirst().get(); + if (StrUtil.isBlank(hbrvcdCode)) { importRow.getWarnings().add("hbrvcd"); data.setHbrvcd(cellValue.trim()); data.setHbrvnm(cellValue.trim()); } else { - if (allowedHbrvcdSet.contains(hbrvcdCode)) { - data.setHbrvcd(hbrvcdCode); - data.setHbrvnm(cellValue.trim()); - } else { - importRow.getWarnings().add("hbrvcd"); - data.setHbrvcd(cellValue.trim()); - data.setHbrvnm(cellValue.trim()); - } - + data.setHbrvcd(hbrvcdCode); + data.setHbrvnm(cellValue.trim()); } } -// if (StringUtils.hasText(cellValue)) { -// String rvcd = resolveHbrvcdCode(cellValue.trim()); -// if (rvcd == null) { -// importRow.getWarnings().add(fieldName); -// data.setRvcd(cellValue); -// } else { -// data.setHbrvcd(rvcd); -// data.setHbrvcd(rvcd); -// } -// } +// break; case "tm": if (!StringUtils.hasText(cellValue)) { @@ -519,21 +510,14 @@ public class FishImportServiceImpl implements IFishImportService { importRow.getWarnings().add("stcd"); data.setStcd(cellValue); } else { - String stcd = resolveFpssCode(cellValue.trim()); - if (stcd == null) { + String stcd = sdFpssList.stream().filter(sdFpssBH -> sdFpssBH.getStnm().equals(cellValue.trim())).map(SdFpssBH::getStcd).findFirst().get(); + if (StrUtil.isBlank(stcd)) { importRow.getWarnings().add("stcd"); data.setStcd(cellValue.trim()); data.setStnm(cellValue.trim()); } else { - if (directBHSet.contains(stcd)) { - data.setStnm(cellValue.trim()); - data.setStcd(stcd); - } else { - importRow.getWarnings().add("stcd"); - data.setStcd(cellValue.trim()); - data.setStnm(cellValue.trim()); - } - + data.setStnm(cellValue.trim()); + data.setStcd(stcd); } } break; @@ -541,7 +525,8 @@ public class FishImportServiceImpl implements IFishImportService { break; } } catch (Exception e) { - e.printStackTrace(); + log.error("字段[" + fieldName + "]解析异常: " + e.getMessage()); +// e.printStackTrace(); // importRow.getWarnings().add("字段[" + fieldName + "]解析异常: " + e.getMessage()); } } @@ -553,33 +538,47 @@ public class FishImportServiceImpl implements IFishImportService { private void validateStationFpssRelation(FishDraftData data, FishImportResult.FishImportRow importRow) { - loadStationAndBaseCache(); - if (StringUtils.hasText(data.getHbrvcd()) && StringUtils.hasText(data.getRstcd())) { - if (!validateStationBelongsToBase(data.getRstcd(), data.getHbrvcd())) { - if (!importRow.getWarnings().contains("hbrvcd")) { - importRow.getWarnings().add("hbrvcd"); - } - if (!importRow.getWarnings().contains("rstcd")) { - importRow.getWarnings().add("rstcd"); - } - if (!importRow.getWarnings().contains("stcd")) { - importRow.getWarnings().add("stcd"); - } + if (importRow.getWarnings().contains("hbrvcd")) { + if (!importRow.getWarnings().contains("rstcd")) { + importRow.getWarnings().add("rstcd"); + } + if (!importRow.getWarnings().contains("stcd")) { + importRow.getWarnings().add("stcd"); } } - if (StringUtils.hasText(data.getRstcd()) && StringUtils.hasText(data.getStcd())) { - if (!validateFpssBelongsToStation(data.getStcd(), data.getRstcd())) { - if (!importRow.getWarnings().contains("hbrvcd")) { - importRow.getWarnings().add("hbrvcd"); - } - if (!importRow.getWarnings().contains("stcd")) { - importRow.getWarnings().add("stcd"); - } - if (!importRow.getWarnings().contains("rstcd")) { - importRow.getWarnings().add("rstcd"); - } + if (importRow.getWarnings().contains("rstcd")) { + if (!importRow.getWarnings().contains("stcd")) { + importRow.getWarnings().add("stcd"); } } + + // loadStationAndBaseCache(); +// if (StringUtils.hasText(data.getHbrvcd()) && StringUtils.hasText(data.getRstcd())) { +// if (!validateStationBelongsToBase(data.getRstcd(), data.getHbrvcd())) { +// if (!importRow.getWarnings().contains("hbrvcd")) { +// importRow.getWarnings().add("hbrvcd"); +// } +// if (!importRow.getWarnings().contains("rstcd")) { +// importRow.getWarnings().add("rstcd"); +// } +// if (!importRow.getWarnings().contains("stcd")) { +// importRow.getWarnings().add("stcd"); +// } +// } +// } +// if (StringUtils.hasText(data.getRstcd()) && StringUtils.hasText(data.getStcd())) { +// if (!validateFpssBelongsToStation(data.getStcd(), data.getRstcd())) { +// if (!importRow.getWarnings().contains("hbrvcd")) { +// importRow.getWarnings().add("hbrvcd"); +// } +// if (!importRow.getWarnings().contains("stcd")) { +// importRow.getWarnings().add("stcd"); +// } +// if (!importRow.getWarnings().contains("rstcd")) { +// importRow.getWarnings().add("rstcd"); +// } +// } +// } } private void loadStationAndBaseCache() { From ae34d9300159bc59ec9e0912a4c96a113f4226fc Mon Sep 17 00:00:00 2001 From: tangwei Date: Sat, 9 May 2026 15:17:24 +0800 Subject: [PATCH 05/22] =?UTF-8?q?fix:=20=E5=A2=9E=E5=8A=A0=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E6=89=B9=E9=87=8F=E5=8F=91=E9=80=81=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E7=A0=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/SmsVerifyCodeController.java | 18 ++++++++++++++++++ .../system/domain/SmsVerifyCodeRequest.java | 6 ++++++ .../system/service/ISmsVerifyCodeService.java | 4 ++++ .../service/impl/SmsVerifyCodeServiceImpl.java | 13 +++++++++++++ 4 files changed, 41 insertions(+) diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java b/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java index dad479d..ea12096 100644 --- a/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java +++ b/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java @@ -124,6 +124,24 @@ public class SmsVerifyCodeController { } + /** + * 发送验证码 + */ + @PostMapping("/batchSendContent") + @Operation(summary = "发送验证码") + public ResponseResult batchSendContent(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { + + List phoneList = smsVerifyCodeRequest.getPhoneList(); + if(phoneList==null){ + return ResponseResult.error("手机号不能为空"); + } + + smsVerifyCodeService.batchSendContent(phoneList, smsVerifyCodeRequest.getContent()); + return ResponseResult.success(); + } + + + /** * 注册用户 */ diff --git a/backend/src/main/java/com/yfd/platform/system/domain/SmsVerifyCodeRequest.java b/backend/src/main/java/com/yfd/platform/system/domain/SmsVerifyCodeRequest.java index 70c3cb9..7a7bc9c 100644 --- a/backend/src/main/java/com/yfd/platform/system/domain/SmsVerifyCodeRequest.java +++ b/backend/src/main/java/com/yfd/platform/system/domain/SmsVerifyCodeRequest.java @@ -3,6 +3,8 @@ package com.yfd.platform.system.domain; import lombok.Data; +import java.util.List; + @Data public class SmsVerifyCodeRequest { @@ -61,5 +63,9 @@ public class SmsVerifyCodeRequest { */ private String stationCode; + private List phoneList; + + private String content; + } diff --git a/backend/src/main/java/com/yfd/platform/system/service/ISmsVerifyCodeService.java b/backend/src/main/java/com/yfd/platform/system/service/ISmsVerifyCodeService.java index 95b3765..a674a47 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/ISmsVerifyCodeService.java +++ b/backend/src/main/java/com/yfd/platform/system/service/ISmsVerifyCodeService.java @@ -3,6 +3,8 @@ package com.yfd.platform.system.service; import com.baomidou.mybatisplus.extension.service.IService; import com.yfd.platform.system.domain.SmsVerifyCode; +import java.util.List; + /** *

* 短信验证码表 服务类 @@ -46,4 +48,6 @@ public interface ISmsVerifyCodeService extends IService { * @return 是否发送成功 */ boolean sendAuditNotify(String phone, String auditStatus, String reason); + + void batchSendContent(List phoneList, String content); } \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SmsVerifyCodeServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SmsVerifyCodeServiceImpl.java index 6f25515..4a070ab 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SmsVerifyCodeServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/SmsVerifyCodeServiceImpl.java @@ -11,6 +11,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Date; +import java.util.List; import java.util.Random; /** @@ -120,4 +121,16 @@ public class SmsVerifyCodeServiceImpl extends ServiceImpl phoneList, String content) { + for (String phone : phoneList) { + try { + smsSender.send(phone, content); + } catch (Exception e) { + log.debug("批量发送短信失败"+phone); + } + } + + } } \ No newline at end of file From 098cd094eea9838a528d727cdaec6e3a2f467a12 Mon Sep 17 00:00:00 2001 From: tangwei Date: Sat, 9 May 2026 17:05:23 +0800 Subject: [PATCH 06/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FishDraftDataController.java | 41 ++++++ .../service/impl/FishImportServiceImpl.java | 6 +- .../service/impl/ImportTaskServiceImpl.java | 7 +- .../service/impl/SdEngInfoBHServiceImpl.java | 123 +++--------------- .../env/service/impl/SdFpssBHServiceImpl.java | 42 ++++-- .../service/impl/SdHbrvDicServiceImpl.java | 24 ++-- 6 files changed, 108 insertions(+), 135 deletions(-) diff --git a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java index 318650e..6415ee3 100644 --- a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java +++ b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java @@ -15,6 +15,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.fasterxml.jackson.databind.ObjectMapper; @@ -35,6 +36,8 @@ import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.transaction.annotation.Transactional; @@ -71,6 +74,9 @@ public class FishDraftDataController { @Resource private AttachmentUploadService attachmentUploadService; + @Autowired + private ThreadPoolTaskExecutor taskExecutor; + @PostMapping("/page") @Operation(summary = "分页查询过鱼数据(关联电站和设施)") public ResponseResult queryPageList(@RequestBody DataSourceRequest dataSourceRequest) { @@ -232,6 +238,41 @@ public class FishDraftDataController { @Operation(summary = "批量删除草稿(软删除)") public ResponseResult batchRemoveDraft(@RequestBody List ids) { boolean result = fishDraftDataService.batchRemoveDraft(ids); + if(result){ + List list = fishDraftDataService.list(new LambdaQueryWrapper().in(FishDraftData::getId, ids).select(FishDraftData::getPicpth, FishDraftData::getVdpth, FishDraftData::getId)); + // 异步删除附件 + CompletableFuture.runAsync(() -> { + for (FishDraftData fishDraftData : list) { + String picpth = fishDraftData.getPicpth(); + String vdpth = fishDraftData.getVdpth(); + + try { + if (StrUtil.isNotBlank(picpth)) { + // 假设 picpth 是分号或逗号分隔的文件ID/路径 + List split = StrUtil.split(picpth, StrUtil.C_COMMA); + for (String fileId : split) { + if (StrUtil.isNotBlank(fileId)) { + attachmentUploadService.deleteFile(fileId.trim()); + } + } + } + if (StrUtil.isNotBlank(vdpth)) { + List split = StrUtil.split(vdpth, StrUtil.C_COMMA); + for (String fileId : split) { + if (StrUtil.isNotBlank(fileId)) { + attachmentUploadService.deleteFile(fileId.trim()); + } + } + } + } catch (Exception e) { + log.error("异步删除附件失败, dataId: {}", fishDraftData.getId(), e); + } + } + }, taskExecutor).exceptionally(ex -> { + log.error("异步删除任务执行异常", ex); + return null; + }); + } return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败"); } 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 2ee0827..0cfe76f 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 @@ -284,7 +284,7 @@ public class FishImportServiceImpl implements IFishImportService { data.setEnnm(cellValue.trim()); data.setRstcd(cellValue); } else { - String stcd = directStcdList.stream().filter(sdEngInfoBH -> sdEngInfoBH.getEnnm().equals(cellValue.trim())).map(SdEngInfoBH::getStcd).findFirst().get(); + String stcd = directStcdList.stream().filter(sdEngInfoBH -> sdEngInfoBH.getEnnm().equals(cellValue.trim())).map(SdEngInfoBH::getStcd).findFirst().orElse( null); if (StrUtil.isBlank(stcd)) { importRow.getWarnings().add("rstcd"); data.setEnnm(cellValue.trim()); @@ -329,7 +329,7 @@ public class FishImportServiceImpl implements IFishImportService { data.setHbrvcd(cellValue); data.setHbrvnm(cellValue); } else { - String hbrvcdCode = allowedHbrvcdList.stream().filter(sdHbrvDic -> sdHbrvDic.getHbrvnm().equals(cellValue.trim())).map(SdHbrvDic::getHbrvcd).findFirst().get(); + String hbrvcdCode = allowedHbrvcdList.stream().filter(sdHbrvDic -> sdHbrvDic.getHbrvnm().equals(cellValue.trim())).map(SdHbrvDic::getHbrvcd).findFirst().orElse( null); if (StrUtil.isBlank(hbrvcdCode)) { importRow.getWarnings().add("hbrvcd"); data.setHbrvcd(cellValue.trim()); @@ -510,7 +510,7 @@ public class FishImportServiceImpl implements IFishImportService { importRow.getWarnings().add("stcd"); data.setStcd(cellValue); } else { - String stcd = sdFpssList.stream().filter(sdFpssBH -> sdFpssBH.getStnm().equals(cellValue.trim())).map(SdFpssBH::getStcd).findFirst().get(); + String stcd = sdFpssList.stream().filter(sdFpssBH -> sdFpssBH.getStnm().equals(cellValue.trim())).map(SdFpssBH::getStcd).findFirst().orElse( null); if (StrUtil.isBlank(stcd)) { importRow.getWarnings().add("stcd"); data.setStcd(cellValue.trim()); diff --git a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java index c8cb5f6..1ffcd3b 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java @@ -164,7 +164,7 @@ public class ImportTaskServiceImpl extends ServiceImpl().eq(ImportTask::getId, taskId).select(ImportTask::getId,ImportTask::getStatus, ImportTask::getTempDir)); if (importTask == null) { return false; } @@ -176,9 +176,10 @@ public class ImportTaskServiceImpl extends ServiceImpl selectForDropdown(SdEngInfoBHRequest sdEngInfoBHRequest) { - String userId = SecurityUtils.getUserId(); - String currentUsername = SecurityUtils.getCurrentUsername(); - - // 管理员直接查询 - if ("admin".equals(currentUsername)) { - return queryEngInfoList(sdEngInfoBHRequest, null, null); - } - - // 获取用户权限范围 - List sysUserDataScopes = sysUserDataScopeMapper.selectList( - new LambdaQueryWrapper() - .eq(SysUserDataScope::getUserId, userId) - .select(SysUserDataScope::getOrgId, SysUserDataScope::getOrgType) - ); - - if (sysUserDataScopes == null || sysUserDataScopes.isEmpty()) { - return new ArrayList<>(); - } - - // 分类权限类型 - Set stationCodes = new HashSet<>(); - Set basinCodes = new HashSet<>(); - - for (SysUserDataScope scope : sysUserDataScopes) { - String orgType = scope.getOrgType(); - String orgId = scope.getOrgId(); - - if ("STATION".equals(orgType)) { - stationCodes.add(orgId); - } else if ("HBRVCD".equals(orgType)) { - basinCodes.add(orgId); - } - } - - // 如果有具体站点权限且数量较少,直接使用 IN - if (!stationCodes.isEmpty() && stationCodes.size() <= 100) { - return queryEngInfoList(sdEngInfoBHRequest, stationCodes, null); - } - - // 如果只有流域权限或站点数量过多,使用流域过滤 - if (!basinCodes.isEmpty()) { - return queryEngInfoList(sdEngInfoBHRequest, null, basinCodes); - } - - // 站点数量过多但没有流域信息,分批查询 - if (!stationCodes.isEmpty()) { - return queryEngInfoByBatches(sdEngInfoBHRequest, stationCodes); - } - - return new ArrayList<>(); - } - - /** - * 查询工程信息列表 - */ - private List queryEngInfoList(SdEngInfoBHRequest request, - Set stationCodes, - Set basinCodes) { - LambdaQueryWrapper wrapper = buildQueryWrapper(request); - - // 添加权限过滤 - if (stationCodes != null && !stationCodes.isEmpty()) { - wrapper.in(SdEngInfoBH::getStcd, stationCodes); - } else if (basinCodes != null && !basinCodes.isEmpty()) { - wrapper.in(SdEngInfoBH::getHbrvcd, basinCodes); - } - - return this.list(wrapper); - } - - /** - * 分批查询(当站点数量过多时) - */ - private List queryEngInfoByBatches(SdEngInfoBHRequest request, Set stationCodes) { - List result = new ArrayList<>(); - int batchSize = 100; // 每批最多 100 个站点 - - List stationList = new ArrayList<>(stationCodes); - for (int i = 0; i < stationList.size(); i += batchSize) { - int end = Math.min(i + batchSize, stationList.size()); - List batch = stationList.subList(i, end); - - LambdaQueryWrapper wrapper = buildQueryWrapper(request); - wrapper.in(SdEngInfoBH::getStcd, batch); - - List batchResult = this.list(wrapper); - if (batchResult != null && !batchResult.isEmpty()) { - result.addAll(batchResult); - } - } - - return result; - } - - /** - * 构建查询条件 - */ - private LambdaQueryWrapper buildQueryWrapper(SdEngInfoBHRequest request) { - String baseId = request.getBaseId(); - String hbrvcd = request.getHbrvcd(); - String ennm = request.getEnnm(); - List rvcds = request.getRvcds(); - List hbrvcds = request.getHbrvcds(); - + String baseId = sdEngInfoBHRequest.getBaseId(); + String hbrvcd = sdEngInfoBHRequest.getHbrvcd(); + String ennm = sdEngInfoBHRequest.getEnnm(); + List rvcds = sdEngInfoBHRequest.getRvcds(); + List hbrvcds = sdEngInfoBHRequest.getHbrvcds(); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(StringUtils.hasText(baseId), SdEngInfoBH::getBaseId, baseId) .eq(StringUtils.hasText(hbrvcd), SdEngInfoBH::getHbrvcd, hbrvcd) @@ -182,9 +83,19 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl authorizedStations = getUserAuthorizedStationCodes(); + if (authorizedStations != null && !authorizedStations.isEmpty()) { + List list = this.list(wrapper); + return list.stream() + .filter(item -> authorizedStations.contains(item.getStcd())) + .collect(Collectors.toList()); + }else{ + return new ArrayList<>(); + } } - @Override public Set getUserAuthorizedStationCodes() { String userId = SecurityUtils.getUserId(); diff --git a/backend/src/main/java/com/yfd/platform/env/service/impl/SdFpssBHServiceImpl.java b/backend/src/main/java/com/yfd/platform/env/service/impl/SdFpssBHServiceImpl.java index 036578e..d620898 100644 --- a/backend/src/main/java/com/yfd/platform/env/service/impl/SdFpssBHServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/env/service/impl/SdFpssBHServiceImpl.java @@ -67,28 +67,42 @@ public class SdFpssBHServiceImpl extends ServiceImpl i @Override public List selectForDropdown(String rstcd, String stnm, String baseId) { + // 管理员直接查询,无需权限过滤 + if ("admin".equals(SecurityUtils.getCurrentUsername())) { + return queryFpssList(rstcd, stnm, baseId); + } + + // 获取用户有权限的工程编码 Set authorizedStations = getUserAuthorizedStationCodes(); - List result; - - if (StringUtils.hasText(baseId)) { - result = baseMapper.selectForDropdownWithBaseId(rstcd, stnm, baseId); - } else { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(StringUtils.hasText(rstcd), SdFpssBH::getRstcd, rstcd) - .like(StringUtils.hasText(stnm), SdFpssBH::getStnm, stnm) - .orderByDesc(SdFpssBH::getOrderIndex); - result = list(wrapper); - } - if (authorizedStations.isEmpty()&&"admin".equals(SecurityUtils.getCurrentUsername())) { - return result; + // 无权限直接返回空列表 + if (authorizedStations == null || authorizedStations.isEmpty()) { + return new ArrayList<>(); } + // 查询数据 + List result = queryFpssList(rstcd, stnm, baseId); + + // 权限过滤 return result.stream() - .filter(fpss -> authorizedStations.contains(fpss.getRstcd())) + .filter(fpss -> fpss.getRstcd() != null && authorizedStations.contains(fpss.getRstcd())) .collect(Collectors.toList()); } + /** + * 查询过鱼设施列表(公共方法) + */ + private List queryFpssList(String rstcd, String stnm, String baseId) { + if (StringUtils.hasText(baseId)) { + return baseMapper.selectForDropdownWithBaseId(rstcd, stnm, baseId); + } else { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(StringUtils.hasText(rstcd), SdFpssBH::getRstcd, rstcd) + .like(StringUtils.hasText(stnm), SdFpssBH::getStnm, stnm) + .orderByDesc(SdFpssBH::getOrderIndex); + return list(wrapper); + } + } @Override public Set getUserAuthorizedStationCodes() { String userId = SecurityUtils.getUserId(); diff --git a/backend/src/main/java/com/yfd/platform/env/service/impl/SdHbrvDicServiceImpl.java b/backend/src/main/java/com/yfd/platform/env/service/impl/SdHbrvDicServiceImpl.java index da19175..90ea0e9 100644 --- a/backend/src/main/java/com/yfd/platform/env/service/impl/SdHbrvDicServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/env/service/impl/SdHbrvDicServiceImpl.java @@ -92,8 +92,16 @@ public class SdHbrvDicServiceImpl extends ServiceImpl selectForDropdown(String hbrvnm, String baseid) { - Set authorizedStations = getUserAuthorizedStationCodes(); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.like(hbrvnm != null && !hbrvnm.isEmpty(), SdHbrvDic::getHbrvnm, hbrvnm) + .eq(baseid != null && !baseid.isEmpty(), SdHbrvDic::getBaseid, baseid) + .eq(SdHbrvDic::getEnabled, 1) + .orderByAsc(SdHbrvDic::getOrderIndex); + if("admin".equals(SecurityUtils.getCurrentUsername())){ + return this.list(wrapper); + } + Set authorizedStations = getUserAuthorizedStationCodes(); if (authorizedStations != null && !authorizedStations.isEmpty()) { List engInfos = engInfoBHMapper.selectList( new LambdaQueryWrapper() @@ -104,21 +112,19 @@ public class SdHbrvDicServiceImpl extends ServiceImpl id != null && !id.isEmpty()) .distinct() - .collect(Collectors.toList()); + .toList(); if (!hbrvcds.isEmpty()) { - wrapper.in(SdHbrvDic::getHbrvcd, hbrvcds); + List list = this.list(wrapper); + return list.stream() + .filter(hbrvDic -> hbrvcds.contains(hbrvDic.getHbrvcd())) + .collect(Collectors.toList()); } else { return new ArrayList<>(); } - }else if (!"admin".equals(SecurityUtils.getCurrentUsername())){ + }else { return new ArrayList<>(); } - wrapper.like(hbrvnm != null && !hbrvnm.isEmpty(), SdHbrvDic::getHbrvnm, hbrvnm) - .eq(baseid != null && !baseid.isEmpty(), SdHbrvDic::getBaseid, baseid) - .eq(SdHbrvDic::getEnabled, 1) - .orderByAsc(SdHbrvDic::getOrderIndex); - return this.list(wrapper); } @Override From 3371905b4aeebc872b969af0b98c4d3adb6b4699 Mon Sep 17 00:00:00 2001 From: tangwei Date: Sat, 9 May 2026 19:10:54 +0800 Subject: [PATCH 07/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ApprovalMainController.java | 8 + .../controller/FishDraftDataController.java | 45 ++++ .../service/impl/FishImportServiceImpl.java | 213 +++++++++++++++--- .../service/impl/ImportTaskServiceImpl.java | 13 +- .../platform/system/mapper/SysRoleMapper.java | 6 + .../system/service/impl/UserServiceImpl.java | 4 + .../resources/mapper/system/SysRoleMapper.xml | 10 + 7 files changed, 261 insertions(+), 38 deletions(-) diff --git a/backend/src/main/java/com/yfd/platform/data/controller/ApprovalMainController.java b/backend/src/main/java/com/yfd/platform/data/controller/ApprovalMainController.java index 53d927d..c0db986 100644 --- a/backend/src/main/java/com/yfd/platform/data/controller/ApprovalMainController.java +++ b/backend/src/main/java/com/yfd/platform/data/controller/ApprovalMainController.java @@ -13,6 +13,7 @@ import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.*; import java.util.Date; +import java.util.List; /** *

@@ -116,4 +117,11 @@ public class ApprovalMainController { boolean result = approvalMainService.removeById(id); return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败"); } + + @PostMapping("/batchDelete") + @Operation(summary = "删除审批") + public ResponseResult delete(@RequestBody List ids) { + boolean result = approvalMainService.removeBatchByIds(ids); + return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败"); + } } \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java index 6415ee3..abfb880 100644 --- a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java +++ b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java @@ -234,6 +234,51 @@ public class FishDraftDataController { return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败"); } + + +// @PostMapping("/approvalIdRemoveDraft") +// @Operation(summary = "根据批次号批量删除草稿(软删除)") +// public ResponseResult approvalIdRemoveDraft(@RequestBody BatchApproveRequest request) { +// List draft = fishDraftDataService.list(new LambdaQueryWrapper().eq(FishDraftData::getDeletedFlag, 0).in(FishDraftData::getApprovalId, request.getApprovalIds()).eq(FishDraftData::getStatus, "REJECTED").select(FishDraftData::getId)); +// List ids = draft.stream().map(FishDraftData::getId).toList(); +// boolean result = fishDraftDataService.batchRemoveDraft(ids); +// if(result){ +// List list = fishDraftDataService.list(new LambdaQueryWrapper().in(FishDraftData::getId, ids).select(FishDraftData::getPicpth, FishDraftData::getVdpth, FishDraftData::getId)); +// // 异步删除附件 +// CompletableFuture.runAsync(() -> { +// for (FishDraftData fishDraftData : list) { +// String picpth = fishDraftData.getPicpth(); +// String vdpth = fishDraftData.getVdpth(); +// +// try { +// if (StrUtil.isNotBlank(picpth)) { +// // 假设 picpth 是分号或逗号分隔的文件ID/路径 +// List split = StrUtil.split(picpth, StrUtil.C_COMMA); +// for (String fileId : split) { +// if (StrUtil.isNotBlank(fileId)) { +// attachmentUploadService.deleteFile(fileId.trim()); +// } +// } +// } +// if (StrUtil.isNotBlank(vdpth)) { +// List split = StrUtil.split(vdpth, StrUtil.C_COMMA); +// for (String fileId : split) { +// if (StrUtil.isNotBlank(fileId)) { +// attachmentUploadService.deleteFile(fileId.trim()); +// } +// } +// } +// } catch (Exception e) { +// log.error("异步删除附件失败, dataId: {}", fishDraftData.getId(), e); +// } +// } +// }, taskExecutor).exceptionally(ex -> { +// log.error("异步删除任务执行异常", ex); +// return null; +// }); +// } +// return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败"); +// } @PostMapping("/batchRemoveDraft") @Operation(summary = "批量删除草稿(软删除)") public ResponseResult batchRemoveDraft(@RequestBody List ids) { 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 0cfe76f..17f5f5d 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 cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; import com.yfd.platform.data.domain.FishDraftData; import com.yfd.platform.data.domain.FishImportRequest; import com.yfd.platform.data.domain.FishImportResult; @@ -19,6 +20,7 @@ import com.yfd.platform.system.service.ISysDictionaryService; import com.yfd.platform.utils.SecurityUtils; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.apache.poi.EncryptedDocumentException; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.security.core.context.SecurityContext; @@ -33,6 +35,7 @@ import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.text.ParseException; +import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.CompletableFuture; @@ -370,7 +373,10 @@ public class FishImportServiceImpl implements IFishImportService { } break; case "fsz": - data.setFsz(cellValue.trim()); + if (StringUtils.hasText(cellValue)) { + String parsedFsz = parseFishSizeRange(cellValue.trim()); + data.setFsz(parsedFsz); + } break; case "fcnt": if (!StringUtils.hasText(cellValue)) { @@ -403,14 +409,14 @@ public class FishImportServiceImpl implements IFishImportService { break; case "strdt": if (!StringUtils.hasText(cellValue)) { - importRow.getWarnings().add(fieldName); + importRow.getWarnings().add("strdtStr"); data.setStrdtStr(cellValue); } else { Date strdt = parseDate(cellValue); if (strdt == null) { - importRow.getWarnings().add(fieldName); + importRow.getWarnings().add("strdtStr"); data.setStrdt(null); - data.setStrdtStr(cellValue); + data.setStrdtStr(cellValue.replaceAll("T", " ")); }else{ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateString = sdf.format(strdt); @@ -443,6 +449,9 @@ public class FishImportServiceImpl implements IFishImportService { Map videoFiles = result.getVideoFiles(); for (String fileName : vdpth.split(";")) { + if(StrUtil.isBlank(fileName)){ + continue; + } for (String entryName : videoFiles.keySet()) { if (entryName.equals(fileName) || entryName.endsWith("/" + fileName) || entryName.endsWith("\\" + fileName)) { Map objectObjectHashMap = new HashMap<>(); @@ -450,7 +459,7 @@ public class FishImportServiceImpl implements IFishImportService { objectObjectHashMap.put("value", fileName); importRow.getVdpthList().add(objectObjectHashMap); vdpthList.add(fileName); - } else if (com.yfd.platform.utils.FileUtil.isVideoFileName(fileName)) { + } else if (!com.yfd.platform.utils.FileUtil.isVideoFileName(fileName)) { Map objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("name", fileName); objectObjectHashMap.put("value", fileName); @@ -472,6 +481,9 @@ public class FishImportServiceImpl implements IFishImportService { Map imageFiles = result.getImageFiles(); for (String fileName : picpth.split(";")) { + if(StrUtil.isBlank(fileName)){ + continue; + } for (String entryName : imageFiles.keySet()) { if (entryName.equals(fileName) || entryName.endsWith("/" + fileName) || entryName.endsWith("\\" + fileName)) { Map objectObjectHashMap = new HashMap<>(); @@ -536,6 +548,67 @@ public class FishImportServiceImpl implements IFishImportService { } + /** + * 解析鱼类体长范围 + * 从混乱的字符串中提取所有数字(支持小数),返回 "最小值~最大值" 格式 + * 例如: "123123&234.dey76fd78" -> 提取出 123123, 234., 76, 78 -> "76~123123" + * + * @param input 原始字符串 + * @return 格式化后的范围字符串,如果没有有效数字则返回原字符串 + */ + private String parseFishSizeRange(String input) { + if (!StringUtils.hasText(input)) { + return input; + } + + // 使用正则表达式提取所有数字(包括整数和小数) + // 解释: \d+ 匹配一个或多个数字, (\.\d+)? 匹配可选的小数部分 + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\d+(?:\\.\\d+)?"); + java.util.regex.Matcher matcher = pattern.matcher(input); + + List numbers = new ArrayList<>(); + while (matcher.find()) { + try { + String numStr = matcher.group(); + // 排除单独的点或无效格式 + if (numStr != null && !numStr.isEmpty()) { + numbers.add(Double.parseDouble(numStr)); + } + } catch (NumberFormatException e) { + // 忽略无法解析的数字 + } + } + + // 如果没有提取到任何数字,返回原字符串或空 + if (numbers.isEmpty()) { + log.warn("鱼类体长字段未提取到有效数字: {}", input); + return input; + } + + // 找出最小值和最大值 + double min = numbers.stream().mapToDouble(Double::doubleValue).min().getAsDouble(); + double max = numbers.stream().mapToDouble(Double::doubleValue).max().getAsDouble(); + + // 格式化结果:如果是整数则不显示小数点,否则保留原有精度 + String minStr = formatNumber(min); + String maxStr = formatNumber(max); + + return minStr + "~" + maxStr; + } + + /** + * 格式化数字:如果是整数则去掉 .0,否则保留小数 + */ + private String formatNumber(double value) { + if (value == Math.floor(value) && !Double.isInfinite(value)) { + return String.valueOf((long) value); + } else { + // 去除末尾多余的 0,例如 12.50 -> 12.5 + return String.valueOf(value).replaceAll("\\.?0+$", ""); + } + } + + private void validateStationFpssRelation(FishDraftData data, FishImportResult.FishImportRow importRow) { if (importRow.getWarnings().contains("hbrvcd")) { @@ -1141,54 +1214,103 @@ public class FishImportServiceImpl implements IFishImportService { return true; } - /** - * 解析日期字符串,支持多种格式 - * @param dateStr 日期字符串 - * @return 解析后的 Date 对象,如果解析失败返回 null - */ - private Date parseDate(String dateStr) { + + private static Date parseDate(String dateStr) { if (!StringUtils.hasText(dateStr)) { return null; } - - // 去除首尾空格 dateStr = dateStr.trim(); // 支持的日期格式列表(按常用程度排序) String[] patterns = { "yyyy-MM-dd HH:mm:ss", // 2024-01-15 14:30:00 - "yyyy-MM-dd", // 2024-01-15 + "yyyy-MM-dd'T'HH:mm:ss", // ⭐ 新增:支持 2024-01-15T14:30:00 (ISO格式) + "yyyy-MM-dd HH:mm", // 2024-01-15 14:30 + "yyyy-MM-dd'T'HH:mm", // ⭐ 确保这一行存在且正确:支持 2024-01-15T14:30 + "yyyy-MM-dd", // 2024-01-15 "yyyy/MM/dd HH:mm:ss", // 2024/01/15 14:30:00 - "yyyy/MM/dd", // 2024/01/15 + "yyyy/MM/dd HH:mm", // 2024/01/15 14:30 + "yyyy/MM/dd", // 2024/01/15 (标准双位) + "yyyy/M/d HH:mm:ss", // 支持 2024/1/1 14:30:00 + "yyyy/M/d HH:mm", // 支持 2024/1/1 14:30 + "yyyy/M/d", // 支持 2024/1/1 (单位数) "yyyy.MM.dd HH:mm:ss", // 2024.01.15 14:30:00 - "yyyy.MM.dd", // 2024.01.15 + "yyyy.MM.dd", // 2024.01.15 + "yyyy.M.d", // 支持 2024.1.1 "yyyyMMdd HHmmss", // 20240115 143000 - "yyyyMMdd", // 20240115 + "yyyyMMdd", // 20240115 "yyyy年MM月dd日", // 2024年01月15日 + "yyyy年M月d日", // 支持 2024年1月1日 "yyyy年MM月dd日HH时mm分ss秒" // 2024年01月15日14时30分00秒 }; for (String pattern : patterns) { try { SimpleDateFormat sdf = new SimpleDateFormat(pattern); - sdf.setLenient(false); // 严格模式,不允许非法日期 - Date parsedDate = sdf.parse(dateStr); - - // 验证解析后的日期是否合理(例如年份不能是 0001) - Calendar cal = Calendar.getInstance(); - cal.setTime(parsedDate); - int year = cal.get(Calendar.YEAR); - if (year >= 1900 && year <= 2100) { - return parsedDate; + sdf.setLenient(false); + ParsePosition pos = new ParsePosition(0); + Date parsedDate = sdf.parse(dateStr, pos); + if (parsedDate != null && pos.getIndex() == dateStr.length()) { + // 整个字符串都被成功解析 + Calendar cal = Calendar.getInstance(); + cal.setTime(parsedDate); + int year = cal.get(Calendar.YEAR); + if (year >= 1900 && year <= 2100) { + return parsedDate; + } } - } catch (ParseException e) { - // 尝试下一个格式 + } catch (Exception e) { + // ignore } } - log.debug("无法解析日期: '{}'", dateStr); return null; } + + +// private Date parseDate(String dateStr) { +// if (!StringUtils.hasText(dateStr)) { +// return null; +// } +// +// // 去除首尾空格 +// dateStr = dateStr.trim(); +// +// // 支持的日期格式列表(按常用程度排序) +// String[] patterns = { +// "yyyy-MM-dd HH:mm:ss", // 2024-01-15 14:30:00 +// "yyyy-MM-dd", // 2024-01-15 +// "yyyy/MM/dd HH:mm:ss", // 2024/01/15 14:30:00 +// "yyyy/MM/dd", // 2024/01/15 +// "yyyy.MM.dd HH:mm:ss", // 2024.01.15 14:30:00 +// "yyyy.MM.dd", // 2024.01.15 +// "yyyyMMdd HHmmss", // 20240115 143000 +// "yyyyMMdd", // 20240115 +// "yyyy年MM月dd日", // 2024年01月15日 +// "yyyy年MM月dd日HH时mm分ss秒" // 2024年01月15日14时30分00秒 +// }; +// +// for (String pattern : patterns) { +// try { +// SimpleDateFormat sdf = new SimpleDateFormat(pattern); +// sdf.setLenient(false); // 严格模式,不允许非法日期 +// Date parsedDate = sdf.parse(dateStr); +// +// // 验证解析后的日期是否合理(例如年份不能是 0001) +// Calendar cal = Calendar.getInstance(); +// cal.setTime(parsedDate); +// int year = cal.get(Calendar.YEAR); +// if (year >= 1900 && year <= 2100) { +// return parsedDate; +// } +// } catch (ParseException e) { +// // 尝试下一个格式 +// } +// } +// +// log.debug("无法解析日期: '{}'", dateStr); +// return null; +// } private Integer parseInteger(String value) { if (!StringUtils.hasText(value)) { return null; @@ -1295,9 +1417,40 @@ public class FishImportServiceImpl implements IFishImportService { result.setTempDir(zipContent.tempDir); result.setImageFiles(zipContent.images); result.setVideoFiles(zipContent.videos); - try (Workbook workbook = new XSSFWorkbook(new FileInputStream(zipContent.excelFilePath))) { + Workbook workbook = null; + // 1. 验证文件是否存在且有效 + File excelFile = new File(zipContent.excelFilePath); + if (!excelFile.exists() || excelFile.length() == 0) { + log.error("Excel文件不存在或为空: {}", zipContent.excelFilePath); + throw new RuntimeException("Excel文件不存在或已损坏"); + } + + try (InputStream fis = new FileInputStream(excelFile)) { + // 2. 使用 WorkbookFactory 自动识别 .xls 和 .xlsx 格式 + // 这样可以避免因为格式不匹配导致的 NotOfficeXmlFileException + workbook = WorkbookFactory.create(fis); + Sheet sheet = workbook.getSheetAt(0); result = parseSheet(sheet, result, uploadUserId); + + } catch (EncryptedDocumentException e) { + log.error("Excel文件已加密,无法解析: {}", excelFile.getName(), e); + throw new RuntimeException("Excel文件已设置密码,请移除密码后重新上传"); + } catch (InvalidFormatException e) { + log.error("Excel文件格式无效: {}", excelFile.getName(), e); + throw new RuntimeException("Excel文件格式无效或已损坏"); + } catch (IOException e) { + log.error("读取Excel文件IO异常: {}", excelFile.getName(), e); + throw new RuntimeException("读取Excel文件失败"); + } finally { + // 3. 确保 Workbook 被正确关闭,释放资源 + if (workbook != null) { + try { + workbook.close(); + } catch (IOException e) { + log.warn("关闭Workbook失败", e); + } + } } result.setExcelFileName(zipContent.excelFileName); result.setExcelFilePath(zipContent.excelFilePath); diff --git a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java index 1ffcd3b..c576f07 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java @@ -3,6 +3,7 @@ package com.yfd.platform.data.service.impl; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fasterxml.jackson.databind.ObjectMapper; @@ -133,14 +134,10 @@ public class ImportTaskServiceImpl extends ServiceImpl() + .eq(ImportTask::getId, id) + .set(ImportTask::getStatus, "CONFIRMED") + .set(ImportTask::getUpdatedAt, new Date())); // 如果没有配置自动填充,建议保留此行 } @Override diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java index 09201a1..4852da3 100644 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java +++ b/backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java @@ -63,6 +63,12 @@ public interface SysRoleMapper extends BaseMapper { ***********************************/ List getRoleByUserId(String id); + + /** + * 批量获取用户角色 + */ + List getRolesByUserIds(@Param("userIds") List userIds); + /********************************** * 用途说明: 根据角色ID删除菜单与角色关联信息 * 参数说明 id 角色id diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java index e2bc0c9..112e8c0 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java @@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yfd.platform.config.ResponseResult; +import com.yfd.platform.data.mapper.SysUserDataScopeMapper; import com.yfd.platform.system.domain.LoginUser; import com.yfd.platform.system.domain.SysRole; import com.yfd.platform.system.domain.SysUser; @@ -61,6 +62,9 @@ public class UserServiceImpl extends ServiceImpl impleme @Resource private FileSpaceProperties fileSpaceProperties; + @Resource + private SysUserDataScopeMapper sysUserDataScopeMapper; + /********************************** * 用途说明:获取当前用户账号及名称 * 参数说明 diff --git a/backend/src/main/resources/mapper/system/SysRoleMapper.xml b/backend/src/main/resources/mapper/system/SysRoleMapper.xml index c2c0d97..9d3f206 100644 --- a/backend/src/main/resources/mapper/system/SysRoleMapper.xml +++ b/backend/src/main/resources/mapper/system/SysRoleMapper.xml @@ -133,6 +133,16 @@ ORDER BY r."LEVEL" ASC, lastmodifydate ASC + + delete from sys_role_users where userid !=(select u.id from sys_user u where u.account="admin") and roleid=#{roleid} and userid=#{urserid} From 80277fecd6763006d082bcfd3dae3cdac580aea8 Mon Sep 17 00:00:00 2001 From: tangwei Date: Mon, 11 May 2026 08:17:21 +0800 Subject: [PATCH 08/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/domain/SysUserDataScope.java | 6 ++++ .../data/mapper/SysUserDataScopeMapper.java | 9 ++++++ .../service/impl/FishImportServiceImpl.java | 2 +- .../mapper/data/SysUserDataScopeMapper.xml | 31 +++++++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/com/yfd/platform/data/domain/SysUserDataScope.java b/backend/src/main/java/com/yfd/platform/data/domain/SysUserDataScope.java index b3513dd..beca8a9 100644 --- a/backend/src/main/java/com/yfd/platform/data/domain/SysUserDataScope.java +++ b/backend/src/main/java/com/yfd/platform/data/domain/SysUserDataScope.java @@ -49,6 +49,12 @@ public class SysUserDataScope implements Serializable { */ private String orgId; + /** + * 资源名称(根据orgType关联查询得出) + */ + @TableField(exist = false) + private String orgName; + /** * 上级资源编码(可选,用于层级追溯) */ diff --git a/backend/src/main/java/com/yfd/platform/data/mapper/SysUserDataScopeMapper.java b/backend/src/main/java/com/yfd/platform/data/mapper/SysUserDataScopeMapper.java index 8a592c2..3557ce2 100644 --- a/backend/src/main/java/com/yfd/platform/data/mapper/SysUserDataScopeMapper.java +++ b/backend/src/main/java/com/yfd/platform/data/mapper/SysUserDataScopeMapper.java @@ -43,4 +43,13 @@ public interface SysUserDataScopeMapper extends BaseMapper { * 查询有效权限(状态=1且在有效期内的) */ List selectValidPermissions(@Param("userId") String userId); + + /** + * 根据用户ID查询权限列表(含关联资源名称) + * orgType=STATION时关联SD_ENGINFO_B_H获取ennm(工程名称) + * orgType=HBRVCD时关联SD_HBRV_DIC获取hbrvnm(基地流域名称) + * orgType=BASE时关联SD_HYDROBASE获取basename(基地名称) + * orgType=RVCD时关联SD_RVCD_DIC获取rvnm(流域名称) + */ + List selectValidPermissionsWithName(@Param("userId") String userId); } 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 17f5f5d..a7e79b2 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 @@ -1509,7 +1509,7 @@ public class FishImportServiceImpl implements IFishImportService { String vdpth = data.getVdpth(); String picpth = data.getPicpth(); - if(StrUtil.isBlank(vdpth)||StrUtil.isBlank(picpth)){ + if(StrUtil.isBlank(vdpth) && StrUtil.isBlank(picpth)){ log.error("数据不完整, 忽略处理"); return; } diff --git a/backend/src/main/resources/mapper/data/SysUserDataScopeMapper.xml b/backend/src/main/resources/mapper/data/SysUserDataScopeMapper.xml index 1fb8aa6..76194ae 100644 --- a/backend/src/main/resources/mapper/data/SysUserDataScopeMapper.xml +++ b/backend/src/main/resources/mapper/data/SysUserDataScopeMapper.xml @@ -72,4 +72,35 @@ ORDER BY CREATED_AT DESC + + From 33cea1fd1ec681f0df4a9373e709cc90ffd616ce Mon Sep 17 00:00:00 2001 From: tangwei Date: Mon, 11 May 2026 10:39:50 +0800 Subject: [PATCH 09/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E7=AC=AC?= =?UTF-8?q?=E4=B8=80=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FishDraftDataController.java | 91 ++----- .../yfd/platform/data/domain/ImportTask.java | 29 +- .../platform/data/domain/ImportTaskRow.java | 104 +++++++ .../data/mapper/ImportTaskMapper.java | 5 +- .../data/mapper/ImportTaskRowMapper.java | 21 ++ .../data/service/IImportTaskService.java | 21 +- .../service/impl/ImportTaskServiceImpl.java | 256 ++++++++++++++++-- .../mapper/data/ImportTaskRowMapper.xml | 64 +++++ 8 files changed, 504 insertions(+), 87 deletions(-) create mode 100644 backend/src/main/java/com/yfd/platform/data/domain/ImportTaskRow.java create mode 100644 backend/src/main/java/com/yfd/platform/data/mapper/ImportTaskRowMapper.java create mode 100644 backend/src/main/resources/mapper/data/ImportTaskRowMapper.xml diff --git a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java index abfb880..7bc2ff6 100644 --- a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java +++ b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java @@ -145,18 +145,12 @@ public class FishDraftDataController { public ResponseResult saveDraft(@RequestBody FishImportRowRequest request) { String taskId = request.getTaskId(); ImportTask importTask = importTaskService.getById(taskId); - String resultJson = importTask.getResultJson(); - FishImportResult importResult = null; + FishImportResult importResult = importTaskService.buildImportResult(taskId); Map imageFiles = null; Map videoFiles = null; - if (resultJson != null && !resultJson.isEmpty()) { - try { - importResult = objectMapper.readValue(resultJson, FishImportResult.class); - imageFiles = importResult.getImageFiles(); - videoFiles = importResult.getVideoFiles(); - } catch (Exception e) { - e.printStackTrace(); - } + if (importResult != null) { + imageFiles = importResult.getImageFiles(); + videoFiles = importResult.getVideoFiles(); } if (importResult == null || importResult.getRows() == null) { @@ -188,11 +182,10 @@ public class FishDraftDataController { if (importTask == null) { return ResponseResult.error("导入任务不存在"); } - String resultJson = importTask.getResultJson(); + FishImportResult importResult = importTaskService.buildImportResult(taskId); List fishDraftDataList = batchSaveDraftRequest.getFishDraftDataList(); - if (resultJson != null && !resultJson.isEmpty()) { + if (importResult != null) { try { - FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class); ZipFileUtil.ZipContent content = new ZipFileUtil.ZipContent(); content.images = importResult.getImageFiles(); content.videos = importResult.getVideoFiles(); @@ -211,7 +204,6 @@ public class FishDraftDataController { }); } catch (Exception e) { e.printStackTrace(); - // ignore parse error } } @@ -494,8 +486,8 @@ public class FishDraftDataController { importTaskService.updateStatus(taskId, status, result.getTempDir(), null); importTaskService.updateProgress(taskId, result.getTotalCount(), result.getSuccessCount(), result.getFailedCount()); - String resultJson = objectMapper.writeValueAsString(result); - importTaskService.saveResultJson(taskId, resultJson); +// String resultJson = objectMapper.writeValueAsString(result); + importTaskService.saveResultJson(taskId, result); log.info("异步解析完成, taskId: {}, 状态: {}", taskId, status); } catch (Exception e) { log.error("异步解析ZIP失败, taskId: {}", taskId, e); @@ -533,13 +525,11 @@ public class FishDraftDataController { return ResponseResult.error("任务不存在"); } - String resultJson = task.getResultJson(); - if (resultJson == null || resultJson.isEmpty()) { + FishImportResult importResult = importTaskService.buildImportResult(taskId); + if (importResult == null) { return ResponseResult.error("任务结果为空"); } - FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class); - Map previewData = new HashMap<>(); previewData.put("tempDir", importResult.getTempDir()); previewData.put("excelFileName", importResult.getExcelFileName()); @@ -583,23 +573,14 @@ public class FishDraftDataController { @GetMapping("/previewFile") @Operation(summary = "预览临时文件内容") public void previewFile(@RequestParam String taskId, @RequestParam String filename, @RequestParam String type, HttpServletRequest request, HttpServletResponse response) { - // 解码 URL 编码的 filename(处理中文文件名) String decodedFilename = URLDecoder.decode(filename, StandardCharsets.UTF_8); log.debug("原始文件名: {}, 解码后: {}", filename, decodedFilename); ImportTask importTask = importTaskService.getById(taskId); - String resultJson = importTask.getResultJson(); String filePath = null; String dir = "1".equals(type) ? "images" : "videos"; - if (resultJson != null && !resultJson.isEmpty()) { - try { -// FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class); - String tempDir = importTask.getTempDir(); - filePath = tempDir + File.separator + dir + File.separator + decodedFilename; - } catch (Exception e) { - e.printStackTrace(); - // ignore parse error - } + if (importTask != null && importTask.getTempDir() != null) { + filePath = importTask.getTempDir() + File.separator + dir + File.separator + decodedFilename; } if (filePath == null) { writeErrorResponse(response, "文件路径不能为空"); @@ -659,13 +640,12 @@ public class FishDraftDataController { return ResponseResult.error("任务不存在"); } - String resultJson = importTask.getResultJson(); - if (resultJson == null || resultJson.isEmpty()) { + FishImportResult importResult = importTaskService.buildImportResult(taskId); + if (importResult == null) { return ResponseResult.error("任务结果为空"); } try { - FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class); boolean found = false; for (FishImportResult.FishImportRow row : importResult.getRows()) { @@ -723,8 +703,7 @@ public class FishDraftDataController { return ResponseResult.error("未找到对应的数据行"); } - String updatedJson = objectMapper.writeValueAsString(importResult); - importTaskService.saveResultJson(taskId, updatedJson); + importTaskService.saveResultJson(taskId, importResult); return ResponseResult.success("删除成功"); @@ -814,7 +793,6 @@ public class FishDraftDataController { result.put("currentTask", null); return ResponseResult.successData(result); } - String statusText = getStatusText(currentTask.getStatus()); boolean canImport = isTaskComplete(currentTask.getStatus()); @@ -843,7 +821,8 @@ public class FishDraftDataController { } private boolean isTaskComplete(String status) { - return "CONFIRMED".equals(status) || "FAILED".equals(status) || "CANCELLED".equals(status); + return "CONFIRMED".equals(status) || "CANCELLED".equals(status); +// return "CONFIRMED".equals(status) || "FAILED".equals(status) || "CANCELLED".equals(status); } @GetMapping("/getLastImportResult") @@ -859,15 +838,7 @@ public class FishDraftDataController { )); } - FishImportResult importResult = null; - if (lastTask.getResultJson() != null && !lastTask.getResultJson().isEmpty()) { - try { - importResult = objectMapper.readValue(lastTask.getResultJson(), FishImportResult.class); - } catch (Exception e) { - e.printStackTrace(); - // ignore parse error - } - } + FishImportResult importResult = importTaskService.buildImportResult(lastTask.getId()); int totalCount = lastTask.getTotalCount() != null ? lastTask.getTotalCount() : 0; int successCount = lastTask.getSuccessCount() != null ? lastTask.getSuccessCount() : 0; @@ -962,13 +933,11 @@ public class FishDraftDataController { return ResponseResult.error("任务不存在"); } - String resultJson = task.getResultJson(); - if (resultJson == null || resultJson.isEmpty()) { + FishImportResult importResult = importTaskService.buildImportResult(taskId); + if (importResult == null) { return ResponseResult.error("任务结果为空"); } - FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class); - FishImportResult.FishImportRow targetRow = null; int targetIndex = -1; for (int i = 0; i < importResult.getRows().size(); i++) { @@ -1016,8 +985,8 @@ public class FishDraftDataController { importResult.setSuccessCount(successCount); importResult.setFailedCount(failedCount); - String updatedJson = objectMapper.writeValueAsString(importResult); - importTaskService.saveResultJson(taskId, updatedJson); +// String updatedJson = objectMapper.writeValueAsString(importResult); + importTaskService.saveResultJson(taskId, importResult); Map map = new HashMap<>(); map.put("success", true); @@ -1052,13 +1021,11 @@ public class FishDraftDataController { return ResponseResult.error("任务不存在"); } - String resultJson = task.getResultJson(); - if (resultJson == null || resultJson.isEmpty()) { + FishImportResult importResult = importTaskService.buildImportResult(taskId); + if (importResult == null) { return ResponseResult.error("任务结果为空"); } - FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class); - FishImportResult.FishImportRow targetRow = null; int targetIndex = -1; for (int i = 0; i < importResult.getRows().size(); i++) { @@ -1074,8 +1041,8 @@ public class FishDraftDataController { return ResponseResult.error("未找到对应的数据行"); } importResult.getRows().remove(targetIndex); - String updatedJson = objectMapper.writeValueAsString(importResult); - importTaskService.saveResultJson(taskId, updatedJson); +// String updatedJson = objectMapper.writeValueAsString(importResult); + importTaskService.saveResultJson(taskId, importResult); return ResponseResult.success(); } catch (Exception e) { @@ -1213,13 +1180,11 @@ public class FishDraftDataController { return ResponseResult.error("任务不存在"); } - String resultJson = task.getResultJson(); - if (resultJson == null || resultJson.isEmpty()) { + FishImportResult importResult = importTaskService.buildImportResult(taskId); + if (importResult == null) { return ResponseResult.error("任务结果为空"); } - FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class); - FishImportResult.FishImportRow matchedRow = findMatchingRow(importResult, data.getId()); FishImportResult.FishImportRow resultRow = new FishImportResult.FishImportRow(); diff --git a/backend/src/main/java/com/yfd/platform/data/domain/ImportTask.java b/backend/src/main/java/com/yfd/platform/data/domain/ImportTask.java index 53b6311..2893160 100644 --- a/backend/src/main/java/com/yfd/platform/data/domain/ImportTask.java +++ b/backend/src/main/java/com/yfd/platform/data/domain/ImportTask.java @@ -96,9 +96,34 @@ public class ImportTask implements Serializable { private Date expireTime; /** - * 导入结果JSON(存储校验后的数据) + * 解析结果摘要 */ - private String resultJson; + private String summary; + + /** + * 结果代码(0成功 1失败) + */ + private String code; + + /** + * 结果消息 + */ + private String message; + + /** + * 未识别字段(逗号分隔) + */ + private String unrecognizedFields; + + /** + * 图片文件映射JSON + */ + private String imageFilesJson; + + /** + * 视频文件映射JSON + */ + private String videoFilesJson; /** * 创建时间 diff --git a/backend/src/main/java/com/yfd/platform/data/domain/ImportTaskRow.java b/backend/src/main/java/com/yfd/platform/data/domain/ImportTaskRow.java new file mode 100644 index 0000000..a43098a --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/data/domain/ImportTaskRow.java @@ -0,0 +1,104 @@ +package com.yfd.platform.data.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * 导入任务行数据表(DATA_JSON 拆为独立字段,彻底消除 CLOB) + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("IMPORT_TASK_ROW") +public class ImportTaskRow implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_UUID) + private String id; + + private String taskId; + + private Integer rowIndex; + + private String status; + + // ========== FishDraftData 字段(原 DATA_JSON) ========== + + private String dataId; + + private String stcd; + + private String stnm; + + private String rstcd; + + private String ennm; + + private String hbrvcd; + + private String hbrvnm; + + private String rvcd; + + private String baseId; + + private String baseName; + + private Date strdt; + + private String strdtStr; + + private Date enddt; + + private String ftp; + + private String ftpName; + + private Integer isfs; + + private String direction; + + private Integer fcnt; + + private String fsz; + + private String fwet; + + private BigDecimal wt; + + private String picpth; + + private String vdpth; + + private Date tm; + + private String sourceType; + + private Integer mouth; + + private Integer yr; + + // ========== 校验相关 ========== + + private String warnings; + + private String unrecognizedFields; + + private String vdpthListJson; + + private String picpthListJson; + + private String vdpthWarnings; + + private String picpthWarnings; + + @TableField(fill = FieldFill.INSERT) + private Date createdAt; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/data/mapper/ImportTaskMapper.java b/backend/src/main/java/com/yfd/platform/data/mapper/ImportTaskMapper.java index 0937aab..a7d4edd 100644 --- a/backend/src/main/java/com/yfd/platform/data/mapper/ImportTaskMapper.java +++ b/backend/src/main/java/com/yfd/platform/data/mapper/ImportTaskMapper.java @@ -40,11 +40,10 @@ public interface ImportTaskMapper extends BaseMapper { @Select("SELECT * FROM (" + "SELECT ID, IMPORT_NO, BIZ_TYPE, FILE_NAME, FILE_SIZE, FILE_PATH, TEMP_DIR, " + - "TOTAL_COUNT, SUCCESS_COUNT, FAIL_COUNT, STATUS, ERROR_MSG, " + - "UPLOAD_USER_ID, UPLOAD_TIME, EXPIRE_TIME, CREATED_AT, UPDATED_AT " + + "TOTAL_COUNT, SUCCESS_COUNT, FAIL_COUNT, STATUS, ERROR_MSG " + "FROM IMPORT_TASK " + "WHERE UPLOAD_USER_ID = #{uploadUserId} " + - "AND STATUS IN ('UPLOADED', 'PARSING', 'VALIDATED') " + + "AND STATUS IN ('UPLOADED', 'PARSING', 'VALIDATED','FAILED') " + "ORDER BY CREATED_AT DESC" + ") WHERE ROWNUM = 1") List selectByUserIdAndStatuses(@Param("uploadUserId") String uploadUserId); diff --git a/backend/src/main/java/com/yfd/platform/data/mapper/ImportTaskRowMapper.java b/backend/src/main/java/com/yfd/platform/data/mapper/ImportTaskRowMapper.java new file mode 100644 index 0000000..a1e56db --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/data/mapper/ImportTaskRowMapper.java @@ -0,0 +1,21 @@ +package com.yfd.platform.data.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yfd.platform.data.domain.ImportTaskRow; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 导入任务行数据表 Mapper 接口 + *

+ */ +public interface ImportTaskRowMapper extends BaseMapper { + + List selectByTaskId(@Param("taskId") String taskId); + + List selectByTaskIdAndStatus(@Param("taskId") String taskId, @Param("status") String status); + + int deleteByTaskId(@Param("taskId") String taskId); +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/data/service/IImportTaskService.java b/backend/src/main/java/com/yfd/platform/data/service/IImportTaskService.java index 9726983..d0ca0b7 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/IImportTaskService.java +++ b/backend/src/main/java/com/yfd/platform/data/service/IImportTaskService.java @@ -2,7 +2,9 @@ package com.yfd.platform.data.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; +import com.yfd.platform.data.domain.FishImportResult; import com.yfd.platform.data.domain.ImportTask; +import com.yfd.platform.data.domain.ImportTaskRow; import java.util.List; @@ -79,12 +81,27 @@ public interface IImportTaskService extends IService { ImportTask getCurrentTaskByUserId(String uploadUserId); /** - * 保存导入结果JSON + * 保存导入结果(同时写入 IMPORT_TASK 汇总字段和 IMPORT_TASK_ROW 行数据) */ - boolean saveResultJson(String taskId, String resultJson); + boolean saveResultJson(String taskId, FishImportResult result); /** * 获取用户最后一次导入结果(用于断点续传或查看历史) */ ImportTask getLastImportResult(String uploadUserId); + + /** + * 根据任务ID查询行数据列表 + */ + List getRowsByTaskId(String taskId); + + /** + * 根据任务ID和状态查询行数据列表 + */ + List getRowsByTaskIdAndStatus(String taskId, String status); + + /** + * 根据任务ID重建 FishImportResult 对象(从行表组装) + */ + FishImportResult buildImportResult(String taskId); } \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java index c576f07..e03544f 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java @@ -6,33 +6,42 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.yfd.platform.data.domain.FishDraftData; import com.yfd.platform.data.domain.FishImportResult; import com.yfd.platform.data.domain.ImportTask; +import com.yfd.platform.data.domain.ImportTaskRow; import com.yfd.platform.data.mapper.ImportTaskMapper; +import com.yfd.platform.data.mapper.ImportTaskRowMapper; import com.yfd.platform.data.service.AttachmentUploadService; import com.yfd.platform.data.service.IImportTaskService; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; -import java.util.Date; -import java.util.List; +import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; /** *

* 导入任务表 服务实现类 *

*/ +@Slf4j @Service public class ImportTaskServiceImpl extends ServiceImpl implements IImportTaskService { @Resource private ImportTaskMapper importTaskMapper; + @Resource + private ImportTaskRowMapper importTaskRowMapper; + @Resource private ObjectMapper objectMapper; @Resource @@ -148,6 +157,9 @@ public class ImportTaskServiceImpl extends ServiceImpl ids = expiredTasks.stream().map(ImportTask::getId).toList(); + for (String id : ids) { + importTaskRowMapper.deleteByTaskId(id); + } return this.removeByIds(ids); } @@ -166,29 +178,26 @@ public class ImportTaskServiceImpl extends ServiceImpl rows = new ArrayList<>(); + for (FishImportResult.FishImportRow row : importResult.getRows()) { + ImportTaskRow taskRow = new ImportTaskRow(); + taskRow.setTaskId(taskId); + taskRow.setRowIndex(row.getRowIndex()); + taskRow.setStatus(row.getStatus()); + + FishDraftData data = row.getData(); + if (data != null) { + taskRow.setDataId(data.getId()); + taskRow.setStcd(data.getStcd()); + taskRow.setStnm(data.getStnm()); + taskRow.setRstcd(data.getRstcd()); + taskRow.setEnnm(data.getEnnm()); + taskRow.setHbrvcd(data.getHbrvcd()); + taskRow.setHbrvnm(data.getHbrvnm()); + taskRow.setRvcd(data.getRvcd()); + taskRow.setBaseId(data.getBaseId()); + taskRow.setBaseName(data.getBaseName()); + taskRow.setStrdt(data.getStrdt()); + taskRow.setStrdtStr(data.getStrdtStr()); + taskRow.setEnddt(data.getEnddt()); + taskRow.setFtp(data.getFtp()); + taskRow.setFtpName(data.getFtpName()); + taskRow.setIsfs(data.getIsfs()); + taskRow.setDirection(data.getDirection()); + taskRow.setFcnt(data.getFcnt()); + taskRow.setFsz(data.getFsz()); + taskRow.setFwet(data.getFwet()); + taskRow.setWt(data.getWt()); + taskRow.setPicpth(data.getPicpth()); + taskRow.setVdpth(data.getVdpth()); + taskRow.setTm(data.getTm()); + taskRow.setSourceType(data.getSourceType()); + taskRow.setMouth(data.getMouth()); + taskRow.setYr(data.getYr()); + } + if (row.getWarnings() != null && !row.getWarnings().isEmpty()) { + taskRow.setWarnings(String.join(",", row.getWarnings())); + } + if (row.getUnrecognizedFields() != null && !row.getUnrecognizedFields().isEmpty()) { + taskRow.setUnrecognizedFields(String.join(",", row.getUnrecognizedFields())); + } + if (row.getVdpthList() != null && !row.getVdpthList().isEmpty()) { + taskRow.setVdpthListJson(objectMapper.writeValueAsString(row.getVdpthList())); + } + if (row.getPicpthList() != null && !row.getPicpthList().isEmpty()) { + taskRow.setPicpthListJson(objectMapper.writeValueAsString(row.getPicpthList())); + } + if (row.getVdpthsWarnings() != null && !row.getVdpthsWarnings().isEmpty()) { + taskRow.setVdpthWarnings(String.join(",", row.getVdpthsWarnings())); + } + if (row.getPicpthsWarnings() != null && !row.getPicpthsWarnings().isEmpty()) { + taskRow.setPicpthWarnings(String.join(",", row.getPicpthsWarnings())); + } + taskRow.setCreatedAt(new Date()); + rows.add(taskRow); + } + importTaskRowMapper.insert(rows); + } + } catch (Exception e) { + log.error("保存导入结果行数据失败, taskId: {}", taskId, e); + importTask.setErrorMsg("保存行数据失败: " + e.getMessage()); + this.updateById(importTask); + return false; + } + + return true; } @Override @@ -219,4 +317,128 @@ public class ImportTaskServiceImpl extends ServiceImpl getRowsByTaskId(String taskId) { + return importTaskRowMapper.selectByTaskId(taskId); + } + + @Override + public List getRowsByTaskIdAndStatus(String taskId, String status) { + return importTaskRowMapper.selectByTaskIdAndStatus(taskId, status); + } + + @Override + public FishImportResult buildImportResult(String taskId) { + ImportTask importTask = this.getById(taskId); + if (importTask == null) { + return null; + } + + FishImportResult result = new FishImportResult(); + result.setTaskId(taskId); + result.setTempDir(importTask.getTempDir()); + result.setSummary(importTask.getSummary()); + result.setCode(importTask.getCode()); + result.setMessage(importTask.getMessage()); + result.setTotalCount(importTask.getTotalCount() != null ? importTask.getTotalCount() : 0); + result.setSuccessCount(importTask.getSuccessCount() != null ? importTask.getSuccessCount() : 0); + result.setFailedCount(importTask.getFailCount() != null ? importTask.getFailCount() : 0); + + if (importTask.getUnrecognizedFields() != null && !importTask.getUnrecognizedFields().isEmpty()) { + result.setUnrecognizedFields(Arrays.asList(importTask.getUnrecognizedFields().split(","))); + } + + try { + if (importTask.getImageFilesJson() != null && !importTask.getImageFilesJson().isEmpty()) { + Map imageFiles = objectMapper.readValue( + importTask.getImageFilesJson(), new TypeReference>() {}); + result.setImageFiles(imageFiles); + } + if (importTask.getVideoFilesJson() != null && !importTask.getVideoFilesJson().isEmpty()) { + Map videoFiles = objectMapper.readValue( + importTask.getVideoFilesJson(), new TypeReference>() {}); + result.setVideoFiles(videoFiles); + } + } catch (Exception e) { + log.error("解析文件映射JSON失败, taskId: {}", taskId, e); + } + + List rows = importTaskRowMapper.selectByTaskId(taskId); + if (rows != null && !rows.isEmpty()) { + for (ImportTaskRow row : rows) { + FishImportResult.FishImportRow importRow = new FishImportResult.FishImportRow(row.getRowIndex()); + importRow.setStatus(row.getStatus()); + + FishDraftData data = new FishDraftData(); + data.setId(row.getDataId()); + data.setStcd(row.getStcd()); + data.setStnm(row.getStnm()); + data.setRstcd(row.getRstcd()); + data.setEnnm(row.getEnnm()); + data.setHbrvcd(row.getHbrvcd()); + data.setHbrvnm(row.getHbrvnm()); + data.setRvcd(row.getRvcd()); + data.setBaseId(row.getBaseId()); + data.setBaseName(row.getBaseName()); + data.setStrdt(row.getStrdt()); + data.setStrdtStr(row.getStrdtStr()); + data.setEnddt(row.getEnddt()); + data.setFtp(row.getFtp()); + data.setFtpName(row.getFtpName()); + data.setIsfs(row.getIsfs()); + data.setDirection(row.getDirection()); + data.setFcnt(row.getFcnt()); + data.setFsz(row.getFsz()); + data.setFwet(row.getFwet()); + data.setWt(row.getWt()); + data.setPicpth(row.getPicpth()); + data.setVdpth(row.getVdpth()); + data.setTm(row.getTm()); + data.setSourceType(row.getSourceType()); + data.setMouth(row.getMouth()); + data.setYr(row.getYr()); + importRow.setData(data); + + if (row.getWarnings() != null && !row.getWarnings().isEmpty()) { + importRow.setWarnings(Arrays.asList(row.getWarnings().split(","))); + } + if (row.getUnrecognizedFields() != null && !row.getUnrecognizedFields().isEmpty()) { + importRow.setUnrecognizedFields(Arrays.asList(row.getUnrecognizedFields().split(","))); + } + if (row.getVdpthListJson() != null && !row.getVdpthListJson().isEmpty()) { + try { + List> vdpthList = objectMapper.readValue( + row.getVdpthListJson(), new TypeReference>>() {}); + importRow.setVdpthList(vdpthList); + } catch (Exception e) { + log.error("解析视频列表JSON失败, rowId: {}", row.getId(), e); + } + } + if (row.getPicpthListJson() != null && !row.getPicpthListJson().isEmpty()) { + try { + List> picpthList = objectMapper.readValue( + row.getPicpthListJson(), new TypeReference>>() {}); + importRow.setPicpthList(picpthList); + } catch (Exception e) { + log.error("解析图片列表JSON失败, rowId: {}", row.getId(), e); + } + } + if (row.getVdpthWarnings() != null && !row.getVdpthWarnings().isEmpty()) { + importRow.setVdpthsWarnings(Arrays.asList(row.getVdpthWarnings().split(","))); + } + if (row.getPicpthWarnings() != null && !row.getPicpthWarnings().isEmpty()) { + importRow.setPicpthsWarnings(Arrays.asList(row.getPicpthWarnings().split(","))); + } + + if ("SUCCESS".equals(row.getStatus())) { + result.addSuccessRow(importRow); + } else { + result.addFailedRow(importRow); + } + } + } + + return result; + } } \ No newline at end of file diff --git a/backend/src/main/resources/mapper/data/ImportTaskRowMapper.xml b/backend/src/main/resources/mapper/data/ImportTaskRowMapper.xml new file mode 100644 index 0000000..2de26c3 --- /dev/null +++ b/backend/src/main/resources/mapper/data/ImportTaskRowMapper.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM IMPORT_TASK_ROW WHERE TASK_ID = #{taskId} + + + \ No newline at end of file From aa7f4ac0a0c66317ec07fc15735fa4c53e936b09 Mon Sep 17 00:00:00 2001 From: tangwei Date: Mon, 11 May 2026 13:09:38 +0800 Subject: [PATCH 10/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96json=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E6=95=B0=E6=8D=AE=E6=94=B9=E6=88=90=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E8=A1=A8=E5=AD=98=E5=82=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FishDraftDataController.java | 10 ++-- .../platform/data/domain/FishDraftData.java | 8 +++ .../data/domain/FishImportResult.java | 2 - .../yfd/platform/data/domain/ImportTask.java | 18 +++---- .../data/service/IFishImportService.java | 7 +-- .../service/impl/FishImportServiceImpl.java | 29 +++++++++- .../service/impl/ImportTaskServiceImpl.java | 53 ++++++++----------- 7 files changed, 74 insertions(+), 53 deletions(-) diff --git a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java index 7bc2ff6..3133027 100644 --- a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java +++ b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java @@ -146,12 +146,6 @@ public class FishDraftDataController { String taskId = request.getTaskId(); ImportTask importTask = importTaskService.getById(taskId); FishImportResult importResult = importTaskService.buildImportResult(taskId); - Map imageFiles = null; - Map videoFiles = null; - if (importResult != null) { - imageFiles = importResult.getImageFiles(); - videoFiles = importResult.getVideoFiles(); - } if (importResult == null || importResult.getRows() == null) { return ResponseResult.error("导入数据不存在"); @@ -166,10 +160,12 @@ public class FishDraftDataController { data.setDeletedFlag(0); data.setLockFlag(0); data.setTm(date); + data.setVdpthList(row.getVdpthList()); + data.setPicpthList(row.getPicpthList()); fishDraftDataList.add(data); } boolean result = fishDraftDataService.saveBatch(fishDraftDataList); - fishImportService.processAttachmentsAsync(fishDraftDataList, imageFiles, videoFiles,importTask.getTempDir()); + fishImportService.processAttachmentsAsync(fishDraftDataList,importTask.getTempDir()); importTaskService.markSuccess(taskId); return result ? ResponseResult.success("保存成功") : ResponseResult.error("保存失败"); } diff --git a/backend/src/main/java/com/yfd/platform/data/domain/FishDraftData.java b/backend/src/main/java/com/yfd/platform/data/domain/FishDraftData.java index d452318..da33082 100644 --- a/backend/src/main/java/com/yfd/platform/data/domain/FishDraftData.java +++ b/backend/src/main/java/com/yfd/platform/data/domain/FishDraftData.java @@ -8,6 +8,8 @@ import lombok.EqualsAndHashCode; import java.io.Serializable; import java.math.BigDecimal; import java.util.Date; +import java.util.List; +import java.util.Map; /** *

@@ -266,4 +268,10 @@ public class FishDraftData implements Serializable { @TableField(exist = false) private String ftpName; + @TableField(exist = false) + private List> vdpthList; + + @TableField(exist = false) + private List> picpthList; + } \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/data/domain/FishImportResult.java b/backend/src/main/java/com/yfd/platform/data/domain/FishImportResult.java index 99eed19..64641db 100644 --- a/backend/src/main/java/com/yfd/platform/data/domain/FishImportResult.java +++ b/backend/src/main/java/com/yfd/platform/data/domain/FishImportResult.java @@ -21,8 +21,6 @@ public class FishImportResult { private List unrecognizedFields; private Map imageFiles; private Map videoFiles; -// public Map images; -// public Map videos; private String tempDir; private String excelFileName; private String excelFilePath; diff --git a/backend/src/main/java/com/yfd/platform/data/domain/ImportTask.java b/backend/src/main/java/com/yfd/platform/data/domain/ImportTask.java index 2893160..a132556 100644 --- a/backend/src/main/java/com/yfd/platform/data/domain/ImportTask.java +++ b/backend/src/main/java/com/yfd/platform/data/domain/ImportTask.java @@ -115,15 +115,15 @@ public class ImportTask implements Serializable { */ private String unrecognizedFields; - /** - * 图片文件映射JSON - */ - private String imageFilesJson; - - /** - * 视频文件映射JSON - */ - private String videoFilesJson; +// /** +// * 图片文件映射JSON +// */ +// private String imageFilesJson; +// +// /** +// * 视频文件映射JSON +// */ +// private String videoFilesJson; /** * 创建时间 diff --git a/backend/src/main/java/com/yfd/platform/data/service/IFishImportService.java b/backend/src/main/java/com/yfd/platform/data/service/IFishImportService.java index c78bdc5..4862f01 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/IFishImportService.java +++ b/backend/src/main/java/com/yfd/platform/data/service/IFishImportService.java @@ -1,5 +1,6 @@ package com.yfd.platform.data.service; +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.utils.ZipFileUtil; @@ -7,6 +8,8 @@ import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.InputStream; +import java.util.List; +import java.util.Map; /** *

@@ -52,8 +55,6 @@ public interface IFishImportService { void processAttachments(FishImportResult result, ZipFileUtil.ZipContent zipContent); - void processAttachmentsAsync(java.util.List dataList, - java.util.Map imageFiles, - java.util.Map videoFiles, + void processAttachmentsAsync(List dataList, String tempDir); } \ 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 a7e79b2..4dbb068 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 @@ -1494,8 +1494,6 @@ public class FishImportServiceImpl implements IFishImportService { @Override public void processAttachmentsAsync(List dataList, - Map imageFiles, - Map videoFiles, String tempDir) { if (dataList == null || dataList.isEmpty()) { return; @@ -1513,6 +1511,12 @@ public class FishImportServiceImpl implements IFishImportService { log.error("数据不完整, 忽略处理"); return; } + List> vdpthList = data.getVdpthList(); + List> picpthList = data.getPicpthList(); + + Map videoFiles = buildFileMap(vdpthList, tempDir, "videos"); + Map imageFiles = buildFileMap(picpthList, tempDir, "images"); + if (StringUtils.hasText(vdpth) && videoFiles != null && !videoFiles.isEmpty()) { String uploadedVdpth = uploadVideoFilesAsync(vdpth, videoFiles); if (uploadedVdpth != null) { @@ -1554,6 +1558,27 @@ public class FishImportServiceImpl implements IFishImportService { }); } + + private Map buildFileMap(List> fileList, String tempDir, String subDir) { + if (fileList == null || fileList.isEmpty()) { + return null; + } + + Map fileMap = new HashMap<>(); + String baseDir = tempDir + File.separator + subDir + File.separator; + + for (Map item : fileList) { + String name = item.get("name"); + String value = item.get("value"); + if (name != null && value != null) { + fileMap.put(name, baseDir + value); + } + } + + return fileMap.isEmpty() ? null : fileMap; + } + + private String uploadVideoFilesAsync(String videoNames, Map videoMap) { String[] fileNames = videoNames.split(";"); List attachmentIds = new ArrayList<>(); diff --git a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java index e03544f..2fdfadb 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java @@ -186,19 +186,25 @@ public class ImportTaskServiceImpl extends ServiceImpl { + try { + FileUtil.del(temp); + log.info("异步删除临时目录成功: {}", temp); + } catch (Exception e) { + log.error("异步删除临时目录失败: {}", temp, e); + } + }); + } + + return result; } @Override @@ -230,12 +236,12 @@ public class ImportTaskServiceImpl extends ServiceImpl imageFiles = objectMapper.readValue( - importTask.getImageFilesJson(), new TypeReference>() {}); - result.setImageFiles(imageFiles); - } - if (importTask.getVideoFilesJson() != null && !importTask.getVideoFilesJson().isEmpty()) { - Map videoFiles = objectMapper.readValue( - importTask.getVideoFilesJson(), new TypeReference>() {}); - result.setVideoFiles(videoFiles); - } - } catch (Exception e) { - log.error("解析文件映射JSON失败, taskId: {}", taskId, e); - } List rows = importTaskRowMapper.selectByTaskId(taskId); if (rows != null && !rows.isEmpty()) { @@ -409,7 +401,8 @@ public class ImportTaskServiceImpl extends ServiceImpl> vdpthList = objectMapper.readValue( - row.getVdpthListJson(), new TypeReference>>() {}); + row.getVdpthListJson(), new TypeReference<>() { + }); importRow.setVdpthList(vdpthList); } catch (Exception e) { log.error("解析视频列表JSON失败, rowId: {}", row.getId(), e); From 125ff31f7fffcd6ad1060df7e4eb753d1fad197e Mon Sep 17 00:00:00 2001 From: tangwei Date: Mon, 11 May 2026 14:18:21 +0800 Subject: [PATCH 11/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E8=BF=9E=E6=8E=A5=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/ImportTaskServiceImpl.java | 25 +++++++++++++++ .../src/main/resources/application-devtw.yml | 32 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java index 2fdfadb..7b6e8e9 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java @@ -430,6 +430,31 @@ public class ImportTaskServiceImpl extends ServiceImpl imageFiles = new LinkedHashMap<>(); + Map videoFiles = new LinkedHashMap<>(); + for (FishImportResult.FishImportRow row : result.getRows()) { + if (row.getPicpthList() != null) { + for (Map pic : row.getPicpthList()) { + String name = pic.get("name"); + String path = pic.get("path"); + if (name != null && path != null) { + imageFiles.putIfAbsent(name, path); + } + } + } + if (row.getVdpthList() != null) { + for (Map vid : row.getVdpthList()) { + String name = vid.get("name"); + String path = vid.get("path"); + if (name != null && path != null) { + videoFiles.putIfAbsent(name, path); + } + } + } + } + result.setImageFiles(imageFiles); + result.setVideoFiles(videoFiles); } return result; diff --git a/backend/src/main/resources/application-devtw.yml b/backend/src/main/resources/application-devtw.yml index 64b040c..8b71822 100644 --- a/backend/src/main/resources/application-devtw.yml +++ b/backend/src/main/resources/application-devtw.yml @@ -13,11 +13,43 @@ spring: url: "${DB_MASTER_URL:jdbc:oracle:thin:@172.16.21.134:1521/SDLYZ}" username: "${DB_MASTER_USERNAME:QGC_REFA}" password: "${DB_MASTER_PASSWORD:Y4M4K1oCkL8U}" + initial-size: 5 + min-idle: 5 + max-active: 20 + max-wait: 60000 + keep-alive-between-time-millis: 120000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 300000 + validation-query: SELECT 1 FROM DUAL + test-while-idle: true + test-on-borrow: false + test-on-return: false + keep-alive: true + remove-abandoned: true + remove-abandoned-timeout: 1800 + log-abandoned: true + connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=30000 slave: driverClassName: oracle.jdbc.OracleDriver url: "${DB_SLAVE_URL:jdbc:oracle:thin:@172.16.21.134:1521/SDLYZ}" username: "${DB_SLAVE_USERNAME:QGC_REFA}" password: "${DB_SLAVE_PASSWORD:Y4M4K1oCkL8U}" + initial-size: 5 + min-idle: 5 + max-active: 20 + max-wait: 60000 + min-evictable-idle-time-millis: 300000 + validation-query: SELECT 1 FROM DUAL + test-while-idle: true + test-on-borrow: false + test-on-return: false + keep-alive: true + keep-alive-between-time-millis: 120000 + time-between-eviction-runs-millis: 60000 + remove-abandoned: true + remove-abandoned-timeout: 1800 + log-abandoned: true + connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=30000 jackson: date-format: yyyy-MM-dd HH:mm:ss From d4250a304abc17d6eae45995cf0477ce8ae0169d Mon Sep 17 00:00:00 2001 From: tangwei Date: Mon, 11 May 2026 16:46:41 +0800 Subject: [PATCH 12/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E6=9D=83?= =?UTF-8?q?=E9=99=90=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/mapper/SysUserDataScopeMapper.java | 5 + .../yfd/platform/system/domain/SysUser.java | 6 + .../platform/system/mapper/SysRoleMapper.java | 4 +- .../impl/SysOrganizationServiceImpl.java | 126 +++++++++++------ .../system/service/impl/UserServiceImpl.java | 129 ++++++++++++++++-- .../mapper/data/SysUserDataScopeMapper.xml | 32 +++++ .../resources/mapper/system/SysRoleMapper.xml | 21 +++ 7 files changed, 269 insertions(+), 54 deletions(-) diff --git a/backend/src/main/java/com/yfd/platform/data/mapper/SysUserDataScopeMapper.java b/backend/src/main/java/com/yfd/platform/data/mapper/SysUserDataScopeMapper.java index 3557ce2..e1e10f1 100644 --- a/backend/src/main/java/com/yfd/platform/data/mapper/SysUserDataScopeMapper.java +++ b/backend/src/main/java/com/yfd/platform/data/mapper/SysUserDataScopeMapper.java @@ -52,4 +52,9 @@ public interface SysUserDataScopeMapper extends BaseMapper { * orgType=RVCD时关联SD_RVCD_DIC获取rvnm(流域名称) */ List selectValidPermissionsWithName(@Param("userId") String userId); + + /** + * 批量根据用户ID查询权限列表(含关联资源名称) + */ + List selectValidPermissionsWithNameByUserIds(@Param("userIds") List userIds); } diff --git a/backend/src/main/java/com/yfd/platform/system/domain/SysUser.java b/backend/src/main/java/com/yfd/platform/system/domain/SysUser.java index e37f595..b23df27 100644 --- a/backend/src/main/java/com/yfd/platform/system/domain/SysUser.java +++ b/backend/src/main/java/com/yfd/platform/system/domain/SysUser.java @@ -163,4 +163,10 @@ public class SysUser implements Serializable { @TableField(exist = false) List roles; + + @TableField(exist = false) + private String basinNames; + + @TableField(exist = false) + private String stationNames; } diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java index 4852da3..ea37488 100644 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java +++ b/backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java @@ -65,9 +65,9 @@ public interface SysRoleMapper extends BaseMapper { /** - * 批量获取用户角色 + * 批量获取用户角色(含userId映射) */ - List getRolesByUserIds(@Param("userIds") List userIds); + List> getUserRolesByUserIds(@Param("userIds") List userIds); /********************************** * 用途说明: 根据角色ID删除菜单与角色关联信息 diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java index a4665df..bb956d3 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java @@ -57,21 +57,13 @@ public class SysOrganizationServiceImpl extends ServiceImpl> getOrgTree(String parentid, String params) { - List orgList = new ArrayList<>(); - QueryWrapper queryWrapper = new QueryWrapper<>(); - //根据父级id查询 - queryWrapper.eq("parentid", parentid); - if (StrUtil.isNotEmpty(params)) { - queryWrapper.like("orgname", params); // 根据 部门名称 - } SysUser userInfo = userService.getUserInfo(); + + // 构建权限过滤条件 + Set allowedOrgIds = new HashSet<>(); if (userInfo.getUsertype() != 0) { - List roleByUserId = - sysRoleMapper.getRoleByUserId(userInfo.getId()); - List ids = new ArrayList<>(); - // 循环当前角色 + List roleByUserId = sysRoleMapper.getRoleByUserId(userInfo.getId()); for (SysRole sysRole : roleByUserId) { - // 获取角色的组织Id String orgscope = sysRole.getOrgscope(); if (StrUtil.isBlank(orgscope)) { continue; @@ -79,21 +71,33 @@ public class SysOrganizationServiceImpl extends ServiceImpl stringList = Arrays.asList(split); - Set set = new HashSet<>(); if (!stringList.isEmpty()) { - List list = - sysOrganizationMapper.selectList(new LambdaQueryWrapper().in(SysOrganization::getId, stringList)); - list.forEach(l -> set.add(l.getParentid())); + allowedOrgIds.addAll(stringList); + // 查询这些组织的父级ID + List list = sysOrganizationMapper.selectList( + new LambdaQueryWrapper().in(SysOrganization::getId, stringList)); + for (SysOrganization org : list) { + if (org.getParentid() != null) { + allowedOrgIds.add(org.getParentid()); + } + } } - ids.addAll(stringList); - ids.addAll(set); } - queryWrapper.in("id", ids); } - orgList = this.list(queryWrapper.orderByAsc("orgcode")); - // 将实体对象转换为 Map,确保字段名与实体类一致 - // 将实体对象转换为 Map,确保字段名与实体类一致 - List> listMap = orgList.stream().map(org -> { + + // 查询所有组织数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (!allowedOrgIds.isEmpty()) { + queryWrapper.in("id", allowedOrgIds); + } + if (StrUtil.isNotEmpty(params)) { + queryWrapper.like("orgname", params); + } + + List allOrgList = this.list(queryWrapper.orderByAsc("orgcode")); + + // 将所有组织数据转换为Map结构 + List> allOrgMaps = allOrgList.stream().map(org -> { Map map = new HashMap<>(); map.put("id", org.getId()); map.put("orgtype", org.getOrgtype()); @@ -110,12 +114,39 @@ public class SysOrganizationServiceImpl extends ServiceImpl map : listMap) { - List> childList = child(map.get( - "id").toString());//查询下一子集 - map.put("childList", childList); //添加新列 子集 + + // 构建父子关系映射 + Map>> parentToChildrenMap = new HashMap<>(); + for (Map orgMap : allOrgMaps) { + String parentId = (String) orgMap.get("parentid"); + parentToChildrenMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(orgMap); + } + + // 过滤出指定父级ID的组织作为根节点 + List> rootOrgs = parentToChildrenMap.getOrDefault(parentid, new ArrayList<>()); + + // 构建完整的树形结构 + buildTreeStructure(rootOrgs, parentToChildrenMap); + + return rootOrgs; + } + + + /** + * 构建树形结构 + * @param orgList 当前层级的组织列表 + * @param parentToChildrenMap 父子关系映射 + */ + private void buildTreeStructure(List> orgList, + Map>> parentToChildrenMap) { + for (Map orgMap : orgList) { + String orgId = (String) orgMap.get("id"); + List> children = parentToChildrenMap.getOrDefault(orgId, new ArrayList<>()); + if (!children.isEmpty()) { + buildTreeStructure(children, parentToChildrenMap); // 递归构建子树 + } + orgMap.put("childList", children); } - return listMap; } /*********************************** @@ -203,35 +234,42 @@ public class SysOrganizationServiceImpl extends ServiceImpl getOrganizationById(String id, String orgName) { - - LambdaQueryWrapper queryWrapper = - new LambdaQueryWrapper<>(); SysUser userInfo = userService.getUserInfo(); + + // 收集所有允许的组织ID + Set allowedOrgIds = new HashSet<>(); if (userInfo.getUsertype() != 0) { - List roleByUserId = - sysRoleMapper.getRoleByUserId(userInfo.getId()); - List ids = new ArrayList<>(); - // 循环当前角色 + List roleByUserId = sysRoleMapper.getRoleByUserId(userInfo.getId()); for (SysRole sysRole : roleByUserId) { - // 获取角色的组织Id String orgscope = sysRole.getOrgscope(); if (StrUtil.isBlank(orgscope)) { continue; } - // 拆分组织Id + // 拆分组织Id并添加到集合中(自动去重) String[] split = orgscope.split(","); - List stringList = Arrays.asList(split); - ids.addAll(stringList); + for (String orgId : split) { + if (StrUtil.isNotBlank(orgId)) { + allowedOrgIds.add(orgId.trim()); + } + } } - if (ObjectUtil.isNotEmpty(ids)) { - queryWrapper.in(SysOrganization::getId, ids); - } - } + + // 构建查询条件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysOrganization::getParentid, id); + if (StrUtil.isNotBlank(orgName)) { queryWrapper.like(SysOrganization::getOrgname, orgName); } - queryWrapper.eq(SysOrganization::getParentid, id).orderByDesc(SysOrganization::getOrgcode); + + // 如果有权限限制,添加IN条件 + if (!allowedOrgIds.isEmpty()) { + queryWrapper.in(SysOrganization::getId, allowedOrgIds); + } + + queryWrapper.orderByDesc(SysOrganization::getOrgcode); + return this.list(queryWrapper); } diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java index 112e8c0..87558dd 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java @@ -10,7 +10,12 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yfd.platform.config.ResponseResult; +import com.yfd.platform.data.domain.SysUserDataScope; import com.yfd.platform.data.mapper.SysUserDataScopeMapper; +import com.yfd.platform.env.domain.SdEngInfoBH; +import com.yfd.platform.env.domain.SdHbrvDic; +import com.yfd.platform.env.mapper.SdEngInfoBHMapper; +import com.yfd.platform.env.mapper.SdHbrvDicMapper; import com.yfd.platform.system.domain.LoginUser; import com.yfd.platform.system.domain.SysRole; import com.yfd.platform.system.domain.SysUser; @@ -56,6 +61,12 @@ public class UserServiceImpl extends ServiceImpl impleme @Resource private PasswordEncoder passwordEncoder; + + @Resource + private SdHbrvDicMapper sdHbrvDicMapper; + + @Resource + private SdEngInfoBHMapper sdEngInfoBHMapper; /** * 文件空间配置 */ @@ -636,10 +647,10 @@ public class UserServiceImpl extends ServiceImpl impleme } @Override - public Page queryPendingAuditUsers(Page page,String name,String regStatus) { + public Page queryPendingAuditUsers(Page page, String name, String regStatus) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(SysUser::getRegStatus, "PENDING","APPROVED","REJECTED"); - queryWrapper.eq(ObjectUtil.isNotEmpty(regStatus),SysUser::getRegStatus, regStatus); + queryWrapper.in(SysUser::getRegStatus, "PENDING", "APPROVED", "REJECTED"); + queryWrapper.eq(ObjectUtil.isNotEmpty(regStatus), SysUser::getRegStatus, regStatus); queryWrapper.and(StrUtil.isNotBlank(name), wrapper -> wrapper.like(SysUser::getNickname, name) .or() @@ -647,11 +658,113 @@ public class UserServiceImpl extends ServiceImpl impleme ); queryWrapper.orderByDesc(SysUser::getRegTime); Page mapPage = this.page(page, queryWrapper); - mapPage.getRecords().forEach(record -> { - String id = record.getId(); - List sysRoles = sysRoleMapper.getRoleByUserId(id); - record.setRoles(sysRoles); - }); + + List records = mapPage.getRecords(); + if (records == null || records.isEmpty()) { + return mapPage; + } + + List userIds = records.stream() + .map(SysUser::getId) + .collect(Collectors.toList()); + + Map> userRoleMap = new HashMap<>(); + List> userRoles = sysRoleMapper.getUserRolesByUserIds(userIds); + if (userRoles != null) { + for (Map row : userRoles) { + String userId = (String) row.get("userId"); + SysRole role = new SysRole(); + role.setId((String) row.get("id")); + role.setRolecode((String) row.get("rolecode")); + role.setRolename((String) row.get("rolename")); + role.setLevel((String) row.get("level")); + role.setDescription((String) row.get("description")); + role.setIsvaild((String) row.get("isvaild")); + role.setOrgscope((String) row.get("orgscope")); + role.setOptscope((String) row.get("optscope")); + role.setBusscope((String) row.get("busscope")); + userRoleMap.computeIfAbsent(userId, k -> new ArrayList<>()).add(role); + } + } + + Map> userScopeMap = new HashMap<>(); + List allScopes = sysUserDataScopeMapper.selectValidPermissionsWithNameByUserIds(userIds); + if (allScopes != null) { + for (SysUserDataScope scope : allScopes) { + userScopeMap.computeIfAbsent(scope.getUserId(), k -> new ArrayList<>()).add(scope); + } + } + List allHbrvDicts = sdHbrvDicMapper.selectList(null); + Map basinCodeToNameMap = new HashMap<>(); + if (allHbrvDicts != null) { + for (SdHbrvDic hbrv : allHbrvDicts) { + if (hbrv.getHbrvcd() != null && hbrv.getHbrvnm() != null) { + basinCodeToNameMap.put(hbrv.getHbrvcd(), hbrv.getHbrvnm()); + } + } + } + + List allStations = sdEngInfoBHMapper.selectList(null); + Map> basinToStationsMap = new HashMap<>(); + Map stationCodeToNameMap = new HashMap<>(); + + if (allStations != null) { + for (SdEngInfoBH station : allStations) { + if (station.getStcd() != null && station.getEnnm() != null) { + stationCodeToNameMap.put(station.getStcd(), station.getEnnm()); + } + if (station.getHbrvcd() != null) { + basinToStationsMap.computeIfAbsent(station.getHbrvcd(), k -> new ArrayList<>()).add(station); + } + } + } + + for (SysUser record : records) { + String userId = record.getId(); + + List roles = userRoleMap.getOrDefault(userId, Collections.emptyList()); + record.setRoles(roles); + + List scopes = userScopeMap.getOrDefault(userId, Collections.emptyList()); + Set basinNameSet = new LinkedHashSet<>(); + Set stationNameSet = new LinkedHashSet<>(); + + for (SysUserDataScope scope : scopes) { + String orgType = scope.getOrgType(); + String orgId = scope.getOrgId(); + String orgName = scope.getOrgName(); + + if ("HBRVCD".equals(orgType)) { + if (orgName != null) { + basinNameSet.add(orgName); + } + if (orgId != null) { + List stations = basinToStationsMap.get(orgId); + if (stations != null) { + for (SdEngInfoBH station : stations) { + if (station.getEnnm() != null) { + stationNameSet.add(station.getEnnm()); + } + } + } + } + } else if ("STATION".equals(orgType)) { + if (orgName != null) { + stationNameSet.add(orgName); + } + if (orgId != null) { + String stationName = stationCodeToNameMap.get(orgId); + if (stationName != null) { + stationNameSet.add(stationName); + } + } + } + } + + record.setBasinNames(basinNameSet.isEmpty() ? null : String.join(",", basinNameSet)); + record.setStationNames(stationNameSet.isEmpty() ? null : String.join(",", stationNameSet)); + } + return mapPage; } diff --git a/backend/src/main/resources/mapper/data/SysUserDataScopeMapper.xml b/backend/src/main/resources/mapper/data/SysUserDataScopeMapper.xml index 76194ae..572746d 100644 --- a/backend/src/main/resources/mapper/data/SysUserDataScopeMapper.xml +++ b/backend/src/main/resources/mapper/data/SysUserDataScopeMapper.xml @@ -103,4 +103,36 @@ ORDER BY s.CREATED_AT DESC + + diff --git a/backend/src/main/resources/mapper/system/SysRoleMapper.xml b/backend/src/main/resources/mapper/system/SysRoleMapper.xml index 9d3f206..8ebae21 100644 --- a/backend/src/main/resources/mapper/system/SysRoleMapper.xml +++ b/backend/src/main/resources/mapper/system/SysRoleMapper.xml @@ -143,6 +143,27 @@ #{id} + + delete from sys_role_users where userid !=(select u.id from sys_user u where u.account="admin") and roleid=#{roleid} and userid=#{urserid} From 148fffe2d092d2f176d9cf9411c09c0df6fe1197 Mon Sep 17 00:00:00 2001 From: tangwei Date: Mon, 11 May 2026 17:27:59 +0800 Subject: [PATCH 13/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=AE=A1=E6=A0=B8=E5=88=86=E9=A1=B5=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../env/mapper/SdEngInfoBHMapper.java | 4 ++ .../system/service/impl/UserServiceImpl.java | 57 ++++----------- .../src/main/resources/application-devtw.yml | 69 ++++++++++++++++--- .../mapper/env/SdEngInfoBHMapper.xml | 17 +++++ 4 files changed, 96 insertions(+), 51 deletions(-) diff --git a/backend/src/main/java/com/yfd/platform/env/mapper/SdEngInfoBHMapper.java b/backend/src/main/java/com/yfd/platform/env/mapper/SdEngInfoBHMapper.java index 0c6b51c..45b9e69 100644 --- a/backend/src/main/java/com/yfd/platform/env/mapper/SdEngInfoBHMapper.java +++ b/backend/src/main/java/com/yfd/platform/env/mapper/SdEngInfoBHMapper.java @@ -2,6 +2,7 @@ package com.yfd.platform.env.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.yfd.platform.env.domain.SdEngInfoBH; +import com.yfd.platform.env.domain.StationBasinInfo; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -37,4 +38,7 @@ public interface SdEngInfoBHMapper extends BaseMapper { * 根据基地流域编码列表批量查询电站 */ List selectByHbrvcdList(@Param("hbrvcdList") List hbrvcdList); + + + List selectStationBasinInfo(); } diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java index 87558dd..31aa4ea 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java @@ -14,6 +14,7 @@ import com.yfd.platform.data.domain.SysUserDataScope; import com.yfd.platform.data.mapper.SysUserDataScopeMapper; import com.yfd.platform.env.domain.SdEngInfoBH; import com.yfd.platform.env.domain.SdHbrvDic; +import com.yfd.platform.env.domain.StationBasinInfo; import com.yfd.platform.env.mapper.SdEngInfoBHMapper; import com.yfd.platform.env.mapper.SdHbrvDicMapper; import com.yfd.platform.system.domain.LoginUser; @@ -239,7 +240,6 @@ public class UserServiceImpl extends ServiceImpl impleme * 返回值说明: 是否更新成功 ************************************/ // ... existing code ... - @Override @Transactional(rollbackFor = Exception.class) public Map updateById(SysUser sysUser, String roleids) { @@ -324,7 +324,8 @@ public class UserServiceImpl extends ServiceImpl impleme /** * 处理用户角色分配(增量更新) - * @param userId 用户 ID + * + * @param userId 用户 ID * @param roleIds 角色 ID 字符串(逗号分隔) */ private void handleUserRoles(String userId, String roleIds) { @@ -445,9 +446,9 @@ public class UserServiceImpl extends ServiceImpl impleme //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id String level = sysUserMapper.getMaxLevel(id); //判断是否获取级别 - if ("admin".equals(SecurityUtils.getCurrentUsername())||StrUtil.isNotEmpty(level)) { + if ("admin".equals(SecurityUtils.getCurrentUsername()) || StrUtil.isNotEmpty(level)) { //判断当前用户级别 管理员及以上权限 - if ("admin".equals(SecurityUtils.getCurrentUsername())||Integer.parseInt(level) <= 2) { + if ("admin".equals(SecurityUtils.getCurrentUsername()) || Integer.parseInt(level) <= 2) { SysUser sysUser = sysUserMapper.selectById(id); UpdateWrapper updateWrapper = new UpdateWrapper<>(); String password = PasswordGenerator.generateRandomPassword(sysUser.getUsername()); @@ -480,7 +481,7 @@ public class UserServiceImpl extends ServiceImpl impleme //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id String level = sysUserMapper.getMaxLevel(id); //判断当前用户级别 管理员及以上权限 - if ("admin".equals(SecurityUtils.getCurrentUsername())||Integer.parseInt(level) <= 2) { + if ("admin".equals(SecurityUtils.getCurrentUsername()) || Integer.parseInt(level) <= 2) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); //根据id修改用户状态,最近修改人,最近修改时间 updateWrapper.eq("id", id).set("status", status).set( @@ -562,8 +563,8 @@ public class UserServiceImpl extends ServiceImpl impleme @Override public Page queryUsers(String orgid, - String username, - Page page) { + String username, + Page page) { Page mapPage = sysUserMapper.queryUsers(orgid, username, page); mapPage.getRecords().forEach(record -> { @@ -694,31 +695,7 @@ public class UserServiceImpl extends ServiceImpl impleme userScopeMap.computeIfAbsent(scope.getUserId(), k -> new ArrayList<>()).add(scope); } } - List allHbrvDicts = sdHbrvDicMapper.selectList(null); - Map basinCodeToNameMap = new HashMap<>(); - if (allHbrvDicts != null) { - for (SdHbrvDic hbrv : allHbrvDicts) { - if (hbrv.getHbrvcd() != null && hbrv.getHbrvnm() != null) { - basinCodeToNameMap.put(hbrv.getHbrvcd(), hbrv.getHbrvnm()); - } - } - } - - List allStations = sdEngInfoBHMapper.selectList(null); - Map> basinToStationsMap = new HashMap<>(); - Map stationCodeToNameMap = new HashMap<>(); - - if (allStations != null) { - for (SdEngInfoBH station : allStations) { - if (station.getStcd() != null && station.getEnnm() != null) { - stationCodeToNameMap.put(station.getStcd(), station.getEnnm()); - } - if (station.getHbrvcd() != null) { - basinToStationsMap.computeIfAbsent(station.getHbrvcd(), k -> new ArrayList<>()).add(station); - } - } - } - + List stationBasinInfos = sdEngInfoBHMapper.selectStationBasinInfo(); for (SysUser record : records) { String userId = record.getId(); @@ -739,13 +716,9 @@ public class UserServiceImpl extends ServiceImpl impleme basinNameSet.add(orgName); } if (orgId != null) { - List stations = basinToStationsMap.get(orgId); - if (stations != null) { - for (SdEngInfoBH station : stations) { - if (station.getEnnm() != null) { - stationNameSet.add(station.getEnnm()); - } - } + if (stationBasinInfos != null) { + List stcdList = stationBasinInfos.stream().filter(info -> info.getHbrvcd().equals(orgId)).map(StationBasinInfo::getEnnm).toList(); + stationNameSet.addAll(stcdList); } } } else if ("STATION".equals(orgType)) { @@ -753,9 +726,9 @@ public class UserServiceImpl extends ServiceImpl impleme stationNameSet.add(orgName); } if (orgId != null) { - String stationName = stationCodeToNameMap.get(orgId); - if (stationName != null) { - stationNameSet.add(stationName); + if (stationBasinInfos != null) { + String hbrbcd = stationBasinInfos.stream().filter(info -> info.getStcd().equals(orgId)).map(StationBasinInfo::getHbrvnm).findFirst().orElse(null); + basinNameSet.add(hbrbcd); } } } diff --git a/backend/src/main/resources/application-devtw.yml b/backend/src/main/resources/application-devtw.yml index 8b71822..5e9570a 100644 --- a/backend/src/main/resources/application-devtw.yml +++ b/backend/src/main/resources/application-devtw.yml @@ -16,11 +16,15 @@ spring: initial-size: 5 min-idle: 5 max-active: 20 - max-wait: 60000 + max-wait: 30000 + async-init: true keep-alive-between-time-millis: 120000 time-between-eviction-runs-millis: 60000 - min-evictable-idle-time-millis: 300000 + min-evictable-idle-time-millis: 180000 + max-evictable-idle-time-millis: 300000 + phy-timeout-millis: 25200000 validation-query: SELECT 1 FROM DUAL + validation-query-timeout: 3 test-while-idle: true test-on-borrow: false test-on-return: false @@ -28,7 +32,12 @@ spring: remove-abandoned: true remove-abandoned-timeout: 1800 log-abandoned: true - connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=30000 + break-after-acquire-failure: true + time-between-connect-error-millis: 300000 + pool-prepared-statements: true + max-open-prepared-statements: 100 + max-pool-prepared-statement-per-connection-size: 100 + connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000 slave: driverClassName: oracle.jdbc.OracleDriver url: "${DB_SLAVE_URL:jdbc:oracle:thin:@172.16.21.134:1521/SDLYZ}" @@ -37,19 +46,61 @@ spring: initial-size: 5 min-idle: 5 max-active: 20 - max-wait: 60000 - min-evictable-idle-time-millis: 300000 + max-wait: 30000 + async-init: true + keep-alive-between-time-millis: 120000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 180000 + max-evictable-idle-time-millis: 300000 + phy-timeout-millis: 25200000 validation-query: SELECT 1 FROM DUAL + validation-query-timeout: 3 test-while-idle: true test-on-borrow: false test-on-return: false keep-alive: true - keep-alive-between-time-millis: 120000 - time-between-eviction-runs-millis: 60000 remove-abandoned: true remove-abandoned-timeout: 1800 log-abandoned: true - connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=30000 + break-after-acquire-failure: true + time-between-connect-error-millis: 300000 + pool-prepared-statements: true + max-open-prepared-statements: 100 + max-pool-prepared-statement-per-connection-size: 100 + connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000 + filter: + stat: + enabled: true + log-slow-sql: true + slow-sql-millis: 3000 + merge-sql: true + slf4j: + enabled: true + wall: + enabled: true + log-violation: true + throw-exception: true + config: + select-where-alway-true-check: true + select-having-alway-true-check: true + delete-where-alway-true-check: true + update-where-alay-true-check: true + update-where-alway-true-check: true + update-where-none-check: true + multi-statement-allow: false + web-stat-filter: + enabled: true + url-pattern: /* + exclusions: '*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*' + session-stat-enable: true + principal-session-name: admin + profile-enable: true + stat-view-servlet: + enabled: true + url-pattern: /druid/* + login-username: admin + login-password: admin + reset-enable: false jackson: date-format: yyyy-MM-dd HH:mm:ss @@ -154,6 +205,6 @@ attachment: token: ${ATTACHMENT_TOKEN:qgcBkod25ngBa4wu8BtfCPYsJ7lQGVDoexH} upload-url: ${ATTACHMENT_UPLOAD_URL:http://172.16.31.185:18200/upload} video-url: ${ATTACHMENT_VIDEO_URL:http://172.16.31.185:18200/upload} - delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/delete} + delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/FileDelete} # upload-url: ${ATTACHMENT_UPLOAD_URL:https://211.99.26.225:12125/upload} # video-url: ${ATTACHMENT_VIDEO_URL:https://211.99.26.225:12125/upload} \ 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 bee8c09..a01627c 100644 --- a/backend/src/main/resources/mapper/env/SdEngInfoBHMapper.xml +++ b/backend/src/main/resources/mapper/env/SdEngInfoBHMapper.xml @@ -231,6 +231,23 @@ + + + + + + + + + + SELECT * FROM ( + SELECT t.*, ROWNUM rn FROM ( + + ) t + WHERE ROWNUM <= #{endRow} + ) WHERE rn > #{startRow} + + + + + \ No newline at end of file From 85434d4d336101eca1d698c444f7f825d130bb5e Mon Sep 17 00:00:00 2001 From: tangwei Date: Wed, 13 May 2026 15:54:04 +0800 Subject: [PATCH 18/22] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E5=88=B0?= =?UTF-8?q?=E6=95=B0=E7=BB=9F=E8=AE=A1=E6=8E=A5=E5=8F=A3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/config/ProdApiPrefixFilter.java | 44 --- .../data/domain/vo/FishStatisticsVO.java | 4 + .../data/mapper/FishStatisticsMapper.java | 8 +- .../impl/FishStatisticsServiceImpl.java | 12 +- .../src/main/resources/application-devtw.yml | 6 + .../src/main/resources/application-prod.yml | 4 +- .../mapper/data/FishStatisticsMapper.xml | 254 +++++++++++------- 7 files changed, 177 insertions(+), 155 deletions(-) delete mode 100644 backend/src/main/java/com/yfd/platform/config/ProdApiPrefixFilter.java diff --git a/backend/src/main/java/com/yfd/platform/config/ProdApiPrefixFilter.java b/backend/src/main/java/com/yfd/platform/config/ProdApiPrefixFilter.java deleted file mode 100644 index 4c1680a..0000000 --- a/backend/src/main/java/com/yfd/platform/config/ProdApiPrefixFilter.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.yfd.platform.config; - -import jakarta.servlet.Filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.RequestDispatcher; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.annotation.WebFilter; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * 将以 /prod-api/ 开头的请求转发到去掉前缀的真实后端接口路径。 - * 例如:/prod-api/user/code -> /user/code - * 这样可以兼容前端生产环境仍使用 /prod-api 作为网关前缀的情况。 - */ -@WebFilter(urlPatterns = "/prod-api/*", filterName = "prodApiPrefixFilter") -public class ProdApiPrefixFilter implements Filter { - - private static final String PREFIX = "/prod-api"; - - @Override - public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - if (!(req instanceof HttpServletRequest) || !(res instanceof HttpServletResponse)) { - chain.doFilter(req, res); - return; - } - - HttpServletRequest request = (HttpServletRequest) req; - String uri = request.getRequestURI(); - - // 仅拦截 /prod-api/* 的接口请求并进行内部 forward - if (uri.startsWith(PREFIX + "/")) { - String forwardUri = uri.substring(PREFIX.length()); - RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUri); - dispatcher.forward(req, res); - return; - } - - chain.doFilter(req, res); - } -} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/data/domain/vo/FishStatisticsVO.java b/backend/src/main/java/com/yfd/platform/data/domain/vo/FishStatisticsVO.java index 4459c9a..17d4572 100644 --- a/backend/src/main/java/com/yfd/platform/data/domain/vo/FishStatisticsVO.java +++ b/backend/src/main/java/com/yfd/platform/data/domain/vo/FishStatisticsVO.java @@ -22,6 +22,10 @@ public class FishStatisticsVO implements Serializable { private String stationNames; + private String basinCode; + + private String stationCode; + private String reportMonth; private Date minStrdt; diff --git a/backend/src/main/java/com/yfd/platform/data/mapper/FishStatisticsMapper.java b/backend/src/main/java/com/yfd/platform/data/mapper/FishStatisticsMapper.java index aeae61e..47a44ec 100644 --- a/backend/src/main/java/com/yfd/platform/data/mapper/FishStatisticsMapper.java +++ b/backend/src/main/java/com/yfd/platform/data/mapper/FishStatisticsMapper.java @@ -7,11 +7,11 @@ import java.util.List; public interface FishStatisticsMapper { - List queryStatistics(@Param("basinNames") List basinNames, - @Param("stationNames") List stationNames, + List queryStatistics(@Param("basinCode") String basinCode, + @Param("stationCode") String stationCode, @Param("startRow") int startRow, @Param("endRow") int endRow); - int countStatistics(@Param("basinNames") List basinNames, - @Param("stationNames") List stationNames); + int countStatistics(@Param("basinCode") String basinCode, + @Param("stationCode") String stationCode); } \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/data/service/impl/FishStatisticsServiceImpl.java b/backend/src/main/java/com/yfd/platform/data/service/impl/FishStatisticsServiceImpl.java index 7778c5f..2b43bbe 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/impl/FishStatisticsServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/data/service/impl/FishStatisticsServiceImpl.java @@ -28,11 +28,11 @@ public class FishStatisticsServiceImpl implements IFishStatisticsService { public Page queryPage(DataSourceRequest dataSourceRequest) { DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest(); - String basinNamesStr = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "basinNames"); - String stationNamesStr = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stationNames"); + String basinNamesStr = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "basinCode"); + String stationNamesStr = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stationCode"); - List basinNames = parseFilterList(basinNamesStr); - List stationNames = parseFilterList(stationNamesStr); +// List basinNames = parseFilterList(basinNamesStr); +// List stationNames = parseFilterList(stationNamesStr); int take = dataSourceRequest.getTake(); int skip = dataSourceRequest.getSkip(); @@ -44,9 +44,9 @@ public class FishStatisticsServiceImpl implements IFishStatisticsService { int endRow = skip + take; List records = fishStatisticsMapper.queryStatistics( - basinNames, stationNames, startRow, endRow); + basinNamesStr, stationNamesStr, startRow, endRow); - int total = fishStatisticsMapper.countStatistics(basinNames, stationNames); + int total = fishStatisticsMapper.countStatistics(basinNamesStr, basinNamesStr); Page page = new Page<>(); page.setRecords(records); diff --git a/backend/src/main/resources/application-devtw.yml b/backend/src/main/resources/application-devtw.yml index 5e9570a..5f7dcb3 100644 --- a/backend/src/main/resources/application-devtw.yml +++ b/backend/src/main/resources/application-devtw.yml @@ -1,5 +1,8 @@ server: port: 8093 + tomcat: + connection-timeout: 300000 + max-swallow-size: 500MB spring: #应用名称 @@ -112,6 +115,9 @@ spring: multipart: max-file-size: 300MB max-request-size: 500MB + file-size-threshold: 1KB + location: /tmp/upload + resolve-lazily: true logging: file: diff --git a/backend/src/main/resources/application-prod.yml b/backend/src/main/resources/application-prod.yml index 15a029b..9c441c1 100644 --- a/backend/src/main/resources/application-prod.yml +++ b/backend/src/main/resources/application-prod.yml @@ -1,8 +1,8 @@ server: port: 8093 tomcat: - max-http-form-post-size: 500MB # Tomcat 表单体大小限制 - connection-timeout: 120000 # 连接超时(毫秒),大文件上传需要更长 + connection-timeout: 300000 + max-swallow-size: 500MB spring: #应用名称 application: diff --git a/backend/src/main/resources/mapper/data/FishStatisticsMapper.xml b/backend/src/main/resources/mapper/data/FishStatisticsMapper.xml index 1709c26..1680c7b 100644 --- a/backend/src/main/resources/mapper/data/FishStatisticsMapper.xml +++ b/backend/src/main/resources/mapper/data/FishStatisticsMapper.xml @@ -10,6 +10,8 @@ + + @@ -17,117 +19,171 @@ - WITH user_scope_detail AS ( - SELECT DISTINCT - su.ID AS USER_ID, - h.HBRVNM AS BASIN_NAME, - e.ENNM AS STATION_NAME - FROM QGC_REFA.SYS_USER su - JOIN QGC_REFA.SYS_USER_DATA_SCOPE sud - ON su.ID = sud.USER_ID - AND sud.STATUS = 1 - AND sud.ORG_TYPE = 'HBRVCD' - JOIN QGC_REFA.SD_HBRV_DIC h - ON sud.ORG_ID = h.HBRVCD - AND h.ENABLED = 1 - AND h.IS_DELETED = 0 - JOIN QGC_REFA.SD_ENGINFO_B_H e - ON e.HBRVCD = h.HBRVCD - AND e.USFL = 1 - WHERE su.STATUS = 1 - AND su.REG_STATUS IN ('PENDING', 'APPROVED', 'REJECTED') + WITH + user_scope_detail AS ( + SELECT DISTINCT + su.ID AS USER_ID, + e.STCD AS STATION_CODE, + h.HBRVCD AS BASIN_CODE, + h.HBRVNM AS BASIN_NAME, + e.ENNM AS STATION_NAME + FROM QGC_REFA.SYS_USER su + JOIN QGC_REFA.SYS_USER_DATA_SCOPE sud + ON su.ID = sud.USER_ID + AND sud.STATUS = 1 + AND sud.ORG_TYPE = 'HBRVCD' + JOIN QGC_REFA.SD_HBRV_DIC h + ON sud.ORG_ID = h.HBRVCD + AND h.ENABLED = 1 + AND h.IS_DELETED = 0 + JOIN QGC_REFA.SD_ENGINFO_B_H e + ON e.HBRVCD = h.HBRVCD + AND e.USFL = 1 + WHERE su.STATUS = 1 + AND su.REG_STATUS IN ('PENDING', 'APPROVED', 'REJECTED') - UNION + UNION - SELECT DISTINCT - su.ID AS USER_ID, - h.HBRVNM AS BASIN_NAME, - e.ENNM AS STATION_NAME - FROM QGC_REFA.SYS_USER su - JOIN QGC_REFA.SYS_USER_DATA_SCOPE sud - ON su.ID = sud.USER_ID - AND sud.STATUS = 1 - AND sud.ORG_TYPE = 'STATION' - JOIN QGC_REFA.SD_ENGINFO_B_H e - ON sud.ORG_ID = e.STCD - AND e.USFL = 1 - JOIN QGC_REFA.SD_HBRV_DIC h - ON e.HBRVCD = h.HBRVCD - AND h.ENABLED = 1 - AND h.IS_DELETED = 0 - WHERE su.STATUS = 1 - AND su.REG_STATUS IN ('PENDING', 'APPROVED', 'REJECTED') + SELECT DISTINCT + su.ID AS USER_ID, + e.STCD AS STATION_CODE, + h.HBRVCD AS BASIN_CODE, + h.HBRVNM AS BASIN_NAME, + e.ENNM AS STATION_NAME + FROM QGC_REFA.SYS_USER su + JOIN QGC_REFA.SYS_USER_DATA_SCOPE sud + ON su.ID = sud.USER_ID + AND sud.STATUS = 1 + AND sud.ORG_TYPE = 'STATION' + JOIN QGC_REFA.SD_ENGINFO_B_H e + ON sud.ORG_ID = e.STCD + AND e.USFL = 1 + JOIN QGC_REFA.SD_HBRV_DIC h + ON e.HBRVCD = h.HBRVCD + AND h.ENABLED = 1 + AND h.IS_DELETED = 0 + WHERE su.STATUS = 1 + AND su.REG_STATUS IN ('PENDING', 'APPROVED', 'REJECTED') ), - user_scope AS ( - SELECT - USER_ID, - RTRIM( - XMLAGG(XMLELEMENT(E, BASIN_NAME || ',') ORDER BY BASIN_NAME) - .EXTRACT('//text()').GETCLOBVAL(), - ',' - ) AS BASIN_NAMES, - RTRIM( - XMLAGG(XMLELEMENT(E, STATION_NAME || ',') ORDER BY STATION_NAME) - .EXTRACT('//text()').GETCLOBVAL(), - ',' - ) AS STATION_NAMES - FROM user_scope_detail - GROUP BY USER_ID + + filtered_users AS ( + SELECT DISTINCT USER_ID + FROM user_scope_detail + + + AND BASIN_CODE = #{basinCode} + + + AND STATION_CODE = #{stationCode} + + ), - fish_monthly AS ( - SELECT - CREATED_BY, - TO_CHAR(STRDT, 'YYYY-MM') AS REPORT_MONTH, - MIN(STRDT) AS MIN_STRDT, - MAX(STRDT) AS MAX_ENDDT, - SUM(FCNT) AS TOTAL_FCNT - FROM QGC_REFA.FISH_DRAFT_DATA - WHERE DELETED_FLAG = 0 AND STATUS IN ('PENDING','APPROVED') - GROUP BY CREATED_BY, TO_CHAR(STRDT, 'YYYY-MM') - ) + + distinct_basins AS ( + SELECT DISTINCT USER_ID,BASIN_CODE, BASIN_NAME + FROM user_scope_detail + WHERE USER_ID IN (SELECT USER_ID FROM filtered_users) + ), + + distinct_stations AS ( + SELECT DISTINCT USER_ID, STATION_CODE, STATION_NAME + FROM user_scope_detail + WHERE USER_ID IN (SELECT USER_ID FROM filtered_users) + ), + + basin_agg AS ( SELECT - us.USER_ID, - su.REAL_NAME, - su.PHONE, - su.NICKNAME || '/' || su.PHONE AS CONTACT, - us.BASIN_NAMES, - us.STATION_NAMES, - fm.REPORT_MONTH, - fm.MIN_STRDT, - fm.MAX_ENDDT, - fm.TOTAL_FCNT - FROM user_scope us + USER_ID, + RTRIM( + XMLAGG(XMLELEMENT(E, BASIN_NAME || ',') ORDER BY BASIN_NAME) + .EXTRACT('//text()').GETCLOBVAL(), + ',' + ) AS BASIN_NAMES, + MIN(BASIN_CODE) AS MIN_BASIN_CODE -- 辅助排序字段(VARCHAR2) + FROM distinct_basins + GROUP BY USER_ID + ), + + station_agg AS ( + SELECT + USER_ID, + RTRIM( + XMLAGG(XMLELEMENT(E, STATION_NAME || ',') ORDER BY STATION_NAME) + .EXTRACT('//text()').GETCLOBVAL(), + ',' + ) AS STATION_NAMES, + MIN(STATION_CODE) AS MIN_STATION_CODE -- 辅助排序字段(VARCHAR2) + FROM distinct_stations + GROUP BY USER_ID + ), + + fish_monthly AS ( + SELECT + CREATED_BY, + TO_CHAR(STRDT, 'YYYY-MM') AS REPORT_MONTH, + MIN(STRDT) AS MIN_STRDT, + MAX(STRDT) AS MAX_ENDDT, + SUM(FCNT) AS TOTAL_FCNT + FROM QGC_REFA.FISH_DRAFT_DATA + WHERE DELETED_FLAG = 0 + AND STATUS IN ('PENDING','APPROVED') + GROUP BY CREATED_BY, TO_CHAR(STRDT, 'YYYY-MM') + ), + + all_users AS ( + SELECT USER_ID FROM filtered_users + ) + + SELECT + u.USER_ID, + su.REAL_NAME, + su.PHONE, + su.NICKNAME || '/' || su.PHONE AS CONTACT, + ba.MIN_BASIN_CODE, + sa.MIN_STATION_CODE, + ba.BASIN_NAMES, + sa.STATION_NAMES, + fm.REPORT_MONTH, + fm.MIN_STRDT, + fm.MAX_ENDDT, + fm.TOTAL_FCNT + FROM all_users u JOIN QGC_REFA.SYS_USER su - ON us.USER_ID = su.ID + ON u.USER_ID = su.ID + LEFT JOIN basin_agg ba + ON u.USER_ID = ba.USER_ID + LEFT JOIN station_agg sa + ON u.USER_ID = sa.USER_ID LEFT JOIN fish_monthly fm - ON us.USER_ID = fm.CREATED_BY - WHERE 1 = 1 - - AND ( - - INSTR(us.BASIN_NAMES, #{name}) > 0 - - ) - - - AND ( - - INSTR(us.STATION_NAMES, #{name}) > 0 - - ) - - ORDER BY fm.REPORT_MONTH, us.USER_ID + ON u.USER_ID = fm.CREATED_BY + + + + + + + + + + + + + + + + -