From 74bee3e232f0970e6d0995ddb08d19064543722f Mon Sep 17 00:00:00 2001 From: ZZX9599 <536509593@qq.com> Date: Fri, 28 Nov 2025 15:35:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=A8=E9=83=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yj/earth/auth/AuthGenerator.java | 2 +- .../business/controller/CsvController.java | 23 ++- .../business/controller/DeviceController.java | 8 +- .../controller/IconLibraryController.java | 117 +++++++++------ .../controller/MilitaryLibraryController.java | 113 ++++++++++----- .../controller/ModelLibraryController.java | 16 +-- .../business/controller/RoleController.java | 13 +- .../business/controller/SystemController.java | 2 +- .../controller/TsEventController.java | 1 + .../business/controller/TsPlanController.java | 135 +++++++++++------- .../controller/TsSourceController.java | 14 ++ .../com/yj/earth/business/domain/Source.java | 2 +- .../earth/business/service/SourceService.java | 2 + .../service/impl/SourceServiceImpl.java | 15 +- .../com/yj/earth/common/util/SQLiteUtil.java | 4 +- .../dto/tsPlan/BatchUpdateShowStatusDto.java | 14 ++ src/main/java/com/yj/earth/params/Path.java | 16 +++ src/main/java/com/yj/earth/params/Roam.java | 2 + 18 files changed, 330 insertions(+), 169 deletions(-) create mode 100644 src/main/java/com/yj/earth/dto/tsPlan/BatchUpdateShowStatusDto.java diff --git a/src/main/java/com/yj/earth/auth/AuthGenerator.java b/src/main/java/com/yj/earth/auth/AuthGenerator.java index 8182c5f..1269ba7 100644 --- a/src/main/java/com/yj/earth/auth/AuthGenerator.java +++ b/src/main/java/com/yj/earth/auth/AuthGenerator.java @@ -77,7 +77,7 @@ public class AuthGenerator { public static void main(String[] args) { try { // 生成加密的授权字符串 - String authContent = generateAuth("标准版", 1000, 365, "3A446222D1FE537F6C9EEF5C2AB3F957"); + String authContent = generateAuth("标准版", 1000, 365, "8B1FB12E9F8E80109724989E0B25773B"); // 定义授权文件路径(当前目录下的 yjearth.YJ) Path licPath = Paths.get("yjearth.YJ"); diff --git a/src/main/java/com/yj/earth/business/controller/CsvController.java b/src/main/java/com/yj/earth/business/controller/CsvController.java index 82e4017..e4ced50 100644 --- a/src/main/java/com/yj/earth/business/controller/CsvController.java +++ b/src/main/java/com/yj/earth/business/controller/CsvController.java @@ -19,37 +19,46 @@ import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; @Tag(name = "CSV文件解析") @RestController @RequestMapping("/csv") public class CsvController { + + @GetMapping("/parseCsv") @Operation(summary = "解析CSV文件") public ApiResponse parseCsv(@Parameter(description = "文件路径") @RequestParam String filePath) { - Map response = new HashMap<>(); List fieldList = new ArrayList<>(); - try { File file = new File(filePath); + // 验证文件是否存在 + if (!file.exists()) { + return ApiResponse.failure("文件不存在"); + } + try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), "GBK"); CSVParser parser = new CSVParser(reader, CSVFormat.DEFAULT)) { - // 遍历所有行(CSVRecord即一行数据) + // 遍历所有行、跳过第一行(下标为0) for (CSVRecord record : parser) { + // 跳过表头行(第一行) + if (record.getRecordNumber() == 1) { + continue; + } // 确保每行至少有3列(A、B、C列) if (record.size() >= 3) { String label = record.get(1).trim(); String key = record.get(2).trim(); - fieldList.add(new CsvField(key, label)); + if (!key.isEmpty() && !label.isEmpty()) { + fieldList.add(new CsvField(key, label)); + } } } } return ApiResponse.success(fieldList); } catch (Exception e) { - return ApiResponse.failure(e.getMessage()); + return ApiResponse.failure("解析失败:" + e.getMessage()); } } } diff --git a/src/main/java/com/yj/earth/business/controller/DeviceController.java b/src/main/java/com/yj/earth/business/controller/DeviceController.java index 1bf86a7..035fc61 100644 --- a/src/main/java/com/yj/earth/business/controller/DeviceController.java +++ b/src/main/java/com/yj/earth/business/controller/DeviceController.java @@ -91,7 +91,7 @@ public class DeviceController { List deviceList = devicePage.getRecords(); if (CollectionUtils.isEmpty(deviceList)) { - // 如果没有数据,直接返回空分页 + // 如果没有数据、直接返回空分页 return ApiResponse.success(devicePage); } @@ -105,15 +105,15 @@ public class DeviceController { // 异步并发检测所有 IP 的在线状态 Map reachabilityMap = NetUtils.checkReachabilityAsync(ipAddresses); - // 更新设备状态:遍历设备列表,根据 IP 设置 status 字段 + // 更新设备状态:遍历设备列表、根据 IP 设置 status 字段 deviceList.forEach(device -> { String ip = device.getIp(); if (ip != null) { Boolean isOnline = reachabilityMap.get(ip); - // 根据 Ping 结果设置 status: 1 为在线,0 为离线 + // 根据 Ping 结果设置 status: 1 为在线、0 为离线 device.setStatus(isOnline != null && isOnline ? 1 : 0); } else { - // 如果 IP 地址为空,直接设置为离线 + // 如果 IP 地址为空、直接设置为离线 device.setStatus(0); } }); diff --git a/src/main/java/com/yj/earth/business/controller/IconLibraryController.java b/src/main/java/com/yj/earth/business/controller/IconLibraryController.java index 1d487c1..d6f9a93 100644 --- a/src/main/java/com/yj/earth/business/controller/IconLibraryController.java +++ b/src/main/java/com/yj/earth/business/controller/IconLibraryController.java @@ -36,10 +36,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.sql.SQLException; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; @Tag(name = "图标数据管理") @@ -194,8 +191,8 @@ public class IconLibraryController { @Operation(summary = "图标类型树形列表") @GetMapping("/iconTypeTree") - public ApiResponse iconTypeTree() throws SQLException, IllegalAccessException, InstantiationException { - List treeList = iconTypeList(); + public ApiResponse iconTypeTree(@Parameter(description = "图标名称") @RequestParam(value = "iconName", required = false) String iconName) throws SQLException, IllegalAccessException, InstantiationException { + List treeList = iconTypeList(iconName); return ApiResponse.success(treeList); } @@ -267,48 +264,61 @@ public class IconLibraryController { } } - @Operation(summary = "根据类型查询图标列表") + @Operation(summary = "根据类型和名称模糊查询图标列表") @PostMapping("/iconList") - public ApiResponse getIconList(@RequestParam("iconTypeId") @Parameter(description = "图标类型ID") String typeId) throws SQLException, IllegalAccessException, InstantiationException { + public ApiResponse getIconList( + @RequestParam("iconTypeId") @Parameter(description = "图标类型ID") String iconTypeId, + @Parameter(description = "图标名称模糊查询") @RequestParam(value = "name", required = false) String name) + throws SQLException, IllegalAccessException, InstantiationException { String iconPath = getIconLibrary(); if (iconPath == null) { return ApiResponse.failure("请先创建或导入图标库"); } // 获取当前类型及所有子类型ID(递归) - List typeIdList = getIconTypeIdsWithChildren(typeId); + List typeIdList = getIconTypeIdsWithChildren(iconTypeId); if (typeIdList == null || typeIdList.isEmpty()) { return ApiResponse.success(new ArrayList<>()); } - // 构建IN条件(处理SQL注入风险) + // 构建IN条件 String idsWithQuotes = typeIdList.stream() .map(id -> "'" + id + "'") .collect(Collectors.joining(",")); - // 多表联查 - String querySql = """ - SELECT - i.id, - i.icon_type_id as iconTypeId, - i.icon_name as iconName, - i.icon_type as iconType, - i.created_at as createdAt, - i.updated_at as updatedAt, - t.name as iconTypeName - FROM icon i - JOIN icon_type t ON i.icon_type_id = t.id - WHERE i.icon_type_id IN (%s) - ORDER BY i.created_at DESC - """.replace("%s", idsWithQuotes); + // 构建SQL语句 + StringBuilder sql = new StringBuilder(""" + SELECT + i.id, + i.icon_type_id as iconTypeId, + i.icon_name as iconName, + i.icon_type as iconType, + i.created_at as createdAt, + i.updated_at as updatedAt, + t.name as iconTypeName + FROM icon i + JOIN icon_type t ON i.icon_type_id = t.id + WHERE i.icon_type_id IN (%s) + """.formatted(idsWithQuotes)); - // 查询并转换为VO + // 如果传入了名称、则增加模糊查询条件 + if (name != null && !name.trim().isEmpty()) { + // 直接拼接SQL、注意SQL注入风险 + sql.append(" AND i.icon_name LIKE '%" + name.trim() + "%'"); + } + + // 统一添加排序条件 + sql.append(" ORDER BY i.created_at DESC"); + + // 执行查询 List iconVoList = SQLiteUtil.queryForList( - iconPath, querySql, null, IconVo.class + iconPath, sql.toString(), null, IconVo.class ); + for (IconVo vo : iconVoList) { vo.setIconDataUrl("/iconLibrary/data/icon/" + vo.getId() + "/" + vo.getIconType()); } + return ApiResponse.success(iconVoList); } @@ -373,7 +383,7 @@ public class IconLibraryController { } // 返回更新后的树形列表 - List treeList = iconTypeList(); + List treeList = iconTypeList(null); return ApiResponse.success(treeList); } @@ -381,7 +391,10 @@ public class IconLibraryController { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(IconLibrary::getIsEnable, 1); IconLibrary library = iconLibraryService.getOne(queryWrapper); - return library == null ? null : library.getPath(); + if(library == null){ + throw new RuntimeException("请先创建或导入图标库"); + } + return library.getPath(); } private void addIconLibrary(String iconPath) { @@ -411,24 +424,44 @@ public class IconLibraryController { } } - private List iconTypeList() throws SQLException, IllegalAccessException, InstantiationException { + /** + * 查询图标分类树形结构 + */ + private List iconTypeList(String iconName) throws SQLException, IllegalAccessException, InstantiationException { String iconPath = getIconLibrary(); if (iconPath == null) { - return new ArrayList<>(); + return null; } - String querySql = """ - SELECT - id, name, parent_id as parentId, - tree_index as treeIndex, created_at as createdAt, - updated_at as updatedAt - FROM icon_type - ORDER BY tree_index ASC - """; - List typeList = SQLiteUtil.queryForList(iconPath, querySql, null, IconType.class); + // 构建基础SQL语句 + StringBuilder sqlBuilder = new StringBuilder(""" + SELECT DISTINCT icon_type.id, icon_type.name, icon_type.parent_id, + icon_type.tree_index, icon_type.created_at, + icon_type.updated_at + FROM icon_type + """); - // 构建树形结构 - return buildIconTypeTree(typeList); + // 如果传入了图标名称、则拼接 JOIN 和 WHERE 条件 + if (iconName != null && !iconName.trim().isEmpty()) { + String trimmedName = iconName.trim(); + // 直接拼接SQL + sqlBuilder.append(" INNER JOIN icon ON icon_type.id = icon.icon_type_id"); + sqlBuilder.append(" WHERE icon.icon_name LIKE '%" + trimmedName + "%'"); + } + + // 为所有查询都加上统一的排序条件 + sqlBuilder.append(" ORDER BY icon_type.tree_index ASC"); + + // 执行查询、获取符合条件的图标分类列表 + List iconTypes = SQLiteUtil.queryForList( + iconPath, + sqlBuilder.toString(), + null, + IconType.class + ); + + // 将扁平的分类列表转换为树形结构 + return buildIconTypeTree(iconTypes); } private List buildIconTypeTree(List typeList) { diff --git a/src/main/java/com/yj/earth/business/controller/MilitaryLibraryController.java b/src/main/java/com/yj/earth/business/controller/MilitaryLibraryController.java index 77cec6e..b65b313 100644 --- a/src/main/java/com/yj/earth/business/controller/MilitaryLibraryController.java +++ b/src/main/java/com/yj/earth/business/controller/MilitaryLibraryController.java @@ -204,8 +204,8 @@ public class MilitaryLibraryController { @Operation(summary = "军标类型树形列表") @GetMapping("/militaryTypeTree") - public ApiResponse militaryTypeTree() throws SQLException, IllegalAccessException, InstantiationException { - List treeList = militaryTypeList(); + public ApiResponse militaryTypeTree(@Parameter(description = "军标名称") @RequestParam(value = "militaryName", required = false) String militaryName) throws SQLException, IllegalAccessException, InstantiationException { + List treeList = militaryTypeList(militaryName); return ApiResponse.success(treeList); } @@ -241,6 +241,7 @@ public class MilitaryLibraryController { return ApiResponse.success(null); } + @Operation(summary = "获取军标文件数据") @GetMapping("/data/military/{militaryId}/{fileSuffix}") public ResponseEntity getMilitaryData(@PathVariable("militaryId") @Parameter(description = "军标ID") String militaryId, @PathVariable("fileSuffix") @Parameter(description = "军标文件后缀") String fileSuffix) { @@ -275,48 +276,61 @@ public class MilitaryLibraryController { } } - @Operation(summary = "根据类型查询军标列表") + @Operation(summary = "根据类型和名称模糊查询军标列表") @PostMapping("/militaryList") - public ApiResponse getMilitaryList(@RequestParam("militaryTypeId") @Parameter(description = "军标类型ID") String typeId) throws SQLException, IllegalAccessException, InstantiationException { + public ApiResponse getMilitaryList( + @RequestParam("militaryTypeId") @Parameter(description = "军标类型ID") String militaryTypeId, + @Parameter(description = "军标名称模糊查询") @RequestParam(value = "name", required = false) String name) + throws SQLException, IllegalAccessException, InstantiationException { String militaryPath = getMilitaryLibrary(); if (militaryPath == null) { return ApiResponse.failure("请先创建或导入军标库"); } // 获取当前类型及所有子类型ID(递归) - List typeIdList = getMilitaryTypeIdsWithChildren(typeId); + List typeIdList = getMilitaryTypeIdsWithChildren(militaryTypeId); if (typeIdList == null || typeIdList.isEmpty()) { return ApiResponse.success(new ArrayList<>()); } - // 构建IN条件(处理SQL注入风险) + // 构建IN条件 String idsWithQuotes = typeIdList.stream() .map(id -> "'" + id + "'") .collect(Collectors.joining(",")); - // 多表联查 - String querySql = """ - SELECT - m.id, - m.military_type_id as militaryTypeId, - m.military_name as militaryName, - m.military_type as militaryType, - m.created_at as createdAt, - m.updated_at as updatedAt, - t.name as militaryTypeName - FROM military m - JOIN military_type t ON m.military_type_id = t.id - WHERE m.military_type_id IN (%s) - ORDER BY m.created_at DESC - """.replace("%s", idsWithQuotes); + // 构建SQL语句 + StringBuilder sql = new StringBuilder(""" + SELECT + m.id, + m.military_type_id as militaryTypeId, + m.military_name as militaryName, + m.military_type as militaryType, + m.created_at as createdAt, + m.updated_at as updatedAt, + t.name as militaryTypeName + FROM military m + JOIN military_type t ON m.military_type_id = t.id + WHERE m.military_type_id IN (%s) + """.formatted(idsWithQuotes)); - // 查询并转换为VO + // 如果传入了名称、则增加模糊查询条件 + if (name != null && !name.trim().isEmpty()) { + // 直接拼接SQL、注意SQL注入风险 + sql.append(" AND m.military_name LIKE '%" + name.trim() + "%'"); + } + + // 统一添加排序条件 + sql.append(" ORDER BY m.created_at DESC"); + + // 执行查询 List militaryVoList = SQLiteUtil.queryForList( - militaryPath, querySql, null, MilitaryVo.class + militaryPath, sql.toString(), null, MilitaryVo.class ); + for (MilitaryVo vo : militaryVoList) { vo.setMilitaryDataUrl("/militaryLibrary/data/military/" + vo.getId() + "/" + vo.getMilitaryType()); } + return ApiResponse.success(militaryVoList); } @@ -407,7 +421,7 @@ public class MilitaryLibraryController { } // 返回更新后的树形列表 - List treeList = militaryTypeList(); + List treeList = militaryTypeList(null); return ApiResponse.success(treeList); } @@ -415,7 +429,10 @@ public class MilitaryLibraryController { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(MilitaryLibrary::getIsEnable, 1); // 1=启用、0=未启用 MilitaryLibrary library = militaryLibraryService.getOne(queryWrapper); - return library == null ? null : library.getPath(); + if (library == null) { + throw new RuntimeException("请先创建或导入军标库"); + } + return library.getPath(); } private void addMilitaryLibrary(String militaryPath) { @@ -445,24 +462,44 @@ public class MilitaryLibraryController { } } - private List militaryTypeList() throws SQLException, IllegalAccessException, InstantiationException { + /** + * 查询军标分类树形结构 + */ + private List militaryTypeList(String militaryName) throws SQLException, IllegalAccessException, InstantiationException { String militaryPath = getMilitaryLibrary(); if (militaryPath == null) { - return new ArrayList<>(); + return null; } - String querySql = """ - SELECT - id, name, parent_id as parentId, - tree_index as treeIndex, created_at as createdAt, - updated_at as updatedAt - FROM military_type - ORDER BY tree_index ASC - """; - List typeList = SQLiteUtil.queryForList(militaryPath, querySql, null, MilitaryType.class); + // 构建基础SQL语句 + StringBuilder sqlBuilder = new StringBuilder(""" + SELECT DISTINCT military_type.id, military_type.name, military_type.parent_id, + military_type.tree_index, military_type.created_at, + military_type.updated_at + FROM military_type + """); - // 构建树形结构 - return buildMilitaryTypeTree(typeList); + // 如果传入了军标名称、则拼接 JOIN 和 WHERE 条件 + if (militaryName != null && !militaryName.trim().isEmpty()) { + String trimmedName = militaryName.trim(); + // 直接拼接SQL + sqlBuilder.append(" INNER JOIN military ON military_type.id = military.military_type_id"); + sqlBuilder.append(" WHERE military.military_name LIKE '%" + trimmedName + "%'"); + } + + // 为所有查询都加上统一的排序条件 + sqlBuilder.append(" ORDER BY military_type.tree_index ASC"); + + // 执行查询、获取符合条件的军标分类列表 + List militaryTypes = SQLiteUtil.queryForList( + militaryPath, + sqlBuilder.toString(), + null, + MilitaryType.class + ); + + // 将扁平的分类列表转换为树形结构 + return buildMilitaryTypeTree(militaryTypes); } private List buildMilitaryTypeTree(List typeList) { diff --git a/src/main/java/com/yj/earth/business/controller/ModelLibraryController.java b/src/main/java/com/yj/earth/business/controller/ModelLibraryController.java index 0f9066f..f2d67fc 100644 --- a/src/main/java/com/yj/earth/business/controller/ModelLibraryController.java +++ b/src/main/java/com/yj/earth/business/controller/ModelLibraryController.java @@ -174,7 +174,7 @@ public class ModelLibraryController { @Operation(summary = "模型类型列表") @GetMapping("/modelTypeList") - public ApiResponse modelTypeTree(@Parameter(description = "模型名称") @RequestParam(value = "modelName",required = false) String modelName) throws SQLException, IllegalAccessException, InstantiationException { + public ApiResponse modelTypeTree(@Parameter(description = "模型名称") @RequestParam(value = "modelName", required = false) String modelName) throws SQLException, IllegalAccessException, InstantiationException { return ApiResponse.success(modelTypeList(modelName)); } @@ -463,16 +463,16 @@ public class ModelLibraryController { // 构建基础SQL语句 StringBuilder sqlBuilder = new StringBuilder(""" - SELECT DISTINCT model_type.id, model_type.name, model_type.parent_id, - model_type.tree_index, model_type.created_at, - model_type.updated_at - FROM model_type - """); + SELECT DISTINCT model_type.id, model_type.name, model_type.parent_id, + model_type.tree_index, model_type.created_at, + model_type.updated_at + FROM model_type + """); // 如果传入了模型名称、则拼接 JOIN 和 WHERE 条件 if (modelName != null && !modelName.trim().isEmpty()) { String trimmedName = modelName.trim(); - // 直接拼接SQL、不做任何转义(存在SQL注入风险) + // 直接拼接SQL sqlBuilder.append(" INNER JOIN model ON model_type.id = model.model_type_id"); sqlBuilder.append(" WHERE model.model_name LIKE '%" + trimmedName + "%'"); } @@ -547,7 +547,7 @@ public class ModelLibraryController { queryWrapper.eq(ModelLibrary::getIsEnable, 1); ModelLibrary modelLibrary = modelLibraryService.getOne(queryWrapper); if (modelLibrary == null) { - return null; + throw new RuntimeException("请先创建或导入模型库"); } return modelLibrary.getPath(); } diff --git a/src/main/java/com/yj/earth/business/controller/RoleController.java b/src/main/java/com/yj/earth/business/controller/RoleController.java index 05b9fb3..8ea88d5 100644 --- a/src/main/java/com/yj/earth/business/controller/RoleController.java +++ b/src/main/java/com/yj/earth/business/controller/RoleController.java @@ -88,24 +88,19 @@ public class RoleController { if (status != null) { queryWrapper.eq(Role::getStatus, status); } - - // 统计当前条件下每个角色名称的数量 - List allMatchedRoles = roleService.list(queryWrapper); - Map roleNameCountMap = allMatchedRoles.stream() - .collect(Collectors.groupingBy(Role::getRoleName, Collectors.counting())); - // 分页查询 Page rolePage = roleService.page(new Page<>(pageNum, pageSize), queryWrapper); - // 转换为 Page Page roleVoPage = (Page) rolePage.convert(role -> { + LambdaQueryWrapper userQueryWrapper = new LambdaQueryWrapper<>(); + userQueryWrapper.eq(User::getRoleId, role.getId()); + Long userCount = userService.count(userQueryWrapper); RoleVo roleVo = new RoleVo(); BeanUtils.copyProperties(role, roleVo); // 设置数量 - roleVo.setCount(roleNameCountMap.getOrDefault(role.getRoleName(), 0L).intValue()); + roleVo.setCount(Math.toIntExact(userCount)); return roleVo; }); - return ApiResponse.success(roleVoPage); } diff --git a/src/main/java/com/yj/earth/business/controller/SystemController.java b/src/main/java/com/yj/earth/business/controller/SystemController.java index 23a1561..c822be8 100644 --- a/src/main/java/com/yj/earth/business/controller/SystemController.java +++ b/src/main/java/com/yj/earth/business/controller/SystemController.java @@ -177,7 +177,7 @@ public class SystemController { source.setSourceType(resultSet.getString("source_type")); source.setSourcePath(resultSet.getString("source_path")); - // 关键修改: 读取原始parent_id、而非覆盖为新父节点ID + // 读取原始parent_id、而非覆盖为新父节点ID source.setParentId(resultSet.getString("parent_id")); Integer treeIndex = resultSet.getObject("tree_index") != null diff --git a/src/main/java/com/yj/earth/business/controller/TsEventController.java b/src/main/java/com/yj/earth/business/controller/TsEventController.java index 59270b8..9645f1b 100644 --- a/src/main/java/com/yj/earth/business/controller/TsEventController.java +++ b/src/main/java/com/yj/earth/business/controller/TsEventController.java @@ -50,6 +50,7 @@ public class TsEventController { public ApiResponse update(@RequestBody UpdateTsEventDto updateTsEventDto) { TsEvent tsEvent = new TsEvent(); BeanUtils.copyProperties(updateTsEventDto, tsEvent); + tsEventService.updateById(tsEvent); return ApiResponse.success(null); } diff --git a/src/main/java/com/yj/earth/business/controller/TsPlanController.java b/src/main/java/com/yj/earth/business/controller/TsPlanController.java index 6a20a3e..f178909 100644 --- a/src/main/java/com/yj/earth/business/controller/TsPlanController.java +++ b/src/main/java/com/yj/earth/business/controller/TsPlanController.java @@ -4,9 +4,12 @@ import cn.dev33.satoken.stp.StpUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yj.earth.business.domain.Source; import com.yj.earth.business.domain.TsPlan; +import com.yj.earth.business.domain.TsSource; import com.yj.earth.business.domain.User; import com.yj.earth.business.service.TsPlanService; +import com.yj.earth.business.service.TsSourceService; import com.yj.earth.business.service.UserService; import com.yj.earth.common.util.ApiResponse; import com.yj.earth.dto.tsPlan.AddTsPlanDto; @@ -21,6 +24,7 @@ import javax.annotation.Resource; import java.time.DateTimeException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.Collections; import java.util.List; import java.util.Map; @@ -36,6 +40,8 @@ public class TsPlanController { private TsPlanService tsPlanService; @Resource private UserService userService; + @Resource + private TsSourceService tsSourceService; @PostMapping("/add") @Operation(summary = "添加方案") @@ -45,9 +51,51 @@ public class TsPlanController { // 获取当前登录用户ID tsPlan.setCreatedBy(StpUtil.getLoginIdAsString()); tsPlanService.save(tsPlan); + // 获取最新得到的方案ID + String tsPlanId = tsPlan.getId(); + // 添加方案之后、新增默认资源 + createSourceIfNotExists("倾斜模型", "directory", null, 0, 1, tsPlanId); + createSourceIfNotExists("人工模型", "directory", null, 0, 1, tsPlanId); + createSourceIfNotExists("卫星底图", "directory", null, 0, 1, tsPlanId); + createSourceIfNotExists("地形", "directory", null, 0, 1, tsPlanId); + // 创建"在线图源"目录及其子资源 + TsSource onlineSource = createSourceIfNotExists("在线图源", "directory", null, 0, 1, tsPlanId); + if (onlineSource != null) { + String onlineSourceId = onlineSource.getId(); + createSourceIfNotExists("卫星图", "arcgisWximagery", onlineSourceId, 0, 1, tsPlanId); + createSourceIfNotExists("暗黑地图", "arcgisBlueImagery", onlineSourceId, 0, 1, tsPlanId); + createSourceIfNotExists("路网图", "gdlwImagery", onlineSourceId, 0, 1, tsPlanId); + createSourceIfNotExists("矢量图", "gdslImagery", onlineSourceId, 0, 1, tsPlanId); + } return ApiResponse.success(null); } + private TsSource createSourceIfNotExists(String sourceName, String sourceType, String parentId, int treeIndex, int isShow, String tsPlanId) { + // 检查资源是否已存在(通过名称和父ID组合判断唯一性) + TsSource existingSource = tsSourceService.getOne(new LambdaQueryWrapper() + .eq(TsSource::getSourceName, sourceName) + .eq(parentId != null, TsSource::getParentId, parentId) + .isNull(parentId == null, TsSource::getParentId)); + if (existingSource != null) { + return existingSource; + } + // 不存在则创建新资源 + try { + TsSource newSource = new TsSource(); + newSource.setId(cn.hutool.core.lang.UUID.fastUUID().toString(true)); + newSource.setPlanId(tsPlanId); + newSource.setSourceName(sourceName); + newSource.setSourceType(sourceType); + newSource.setParentId(parentId); + newSource.setTreeIndex(treeIndex); + newSource.setIsShow(isShow); + tsSourceService.save(newSource); + return newSource; + } catch (Exception e) { + return null; + } + } + @Operation(summary = "删除方案") @PostMapping("/delete") public ApiResponse delete(@Parameter(description = "态势方案ID") @RequestParam(required = true) String id) { @@ -73,10 +121,10 @@ public class TsPlanController { @Operation(summary = "查询所有方案") @PostMapping("/list") - public ApiResponse list(@Parameter(description = "分页数量") @RequestParam Integer pageNum, - @Parameter(description = "分页大小") @RequestParam Integer pageSize, + public ApiResponse list(@Parameter(description = "分页数量") @RequestParam(defaultValue = "1") Integer pageNum, + @Parameter(description = "分页大小") @RequestParam(defaultValue = "10") Integer pageSize, @Parameter(description = "方案名称") @RequestParam(required = false) String name, - @Parameter(description = "用户名称") @RequestParam(required = false) String username, + @Parameter(description = "创建人昵称") @RequestParam(required = false) String nickname, @Parameter(description = "开始时间") @RequestParam(required = false) String startTime, @Parameter(description = "结束时间") @RequestParam(required = false) String endTime) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); @@ -86,87 +134,66 @@ public class TsPlanController { queryWrapper.like(TsPlan::getName, name); } - // 用户名查询 - if (StringUtils.isNotBlank(username)) { - LambdaQueryWrapper userQueryWrapper = new LambdaQueryWrapper<>(); - userQueryWrapper.like(User::getUsername, username); - List userList = userService.list(userQueryWrapper); - - // 判断列表是否为空 - if (userList.isEmpty()) { - // 无匹配用户、直接返回空分页结果 - Page emptyPage = new Page<>(pageNum, pageSize); - emptyPage.setTotal(0); - emptyPage.setRecords(Collections.emptyList()); - return ApiResponse.success(emptyPage); - } - - // 提取用户 ID 列表(确保类型匹配) - List userIdList = userList.stream() - .map(User::getId) - .filter(Objects::nonNull) - .toList(); - - // 若 ID 列表为空,也返回空结果 - if (userIdList.isEmpty()) { - Page emptyPage = new Page<>(pageNum, pageSize); - emptyPage.setTotal(0); - emptyPage.setRecords(Collections.emptyList()); - return ApiResponse.success(emptyPage); - } - - queryWrapper.in(TsPlan::getCreatedBy, userIdList); + // 创建人昵称模糊查询 + if (StringUtils.isNotBlank(nickname)) { + queryWrapper.in(TsPlan::getCreatedBy, + new LambdaQueryWrapper() + .select(User::getId) + .like(User::getNickname, nickname) + ); } - // 时间条件优化 + // 时间范围查询 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - if (StringUtils.isNotBlank(startTime)) { - try { + try { + if (StringUtils.isNotBlank(startTime)) { LocalDateTime start = LocalDateTime.parse(startTime, formatter); queryWrapper.ge(TsPlan::getCreatedAt, start); - } catch (DateTimeException e) { - return ApiResponse.failure("开始时间格式错误,需为 yyyy-MM-dd HH:mm:ss"); } - } - if (StringUtils.isNotBlank(endTime)) { - try { + if (StringUtils.isNotBlank(endTime)) { LocalDateTime end = LocalDateTime.parse(endTime, formatter); queryWrapper.le(TsPlan::getCreatedAt, end); - } catch (DateTimeException e) { - return ApiResponse.failure("结束时间格式错误,需为 yyyy-MM-dd HH:mm:ss"); } + } catch (DateTimeParseException e) { + return ApiResponse.failure("时间格式错误、需为 yyyy-MM-dd HH:mm:ss"); } - // 分页查询方案 + // 执行分页查询 Page page = tsPlanService.page(new Page<>(pageNum, pageSize), queryWrapper); - // 优化用户名查询 + // 关联查询用户信息并封装结果 if (!page.getRecords().isEmpty()) { - // 提取所有创建人 ID List creatorIds = page.getRecords().stream() .map(TsPlan::getCreatedBy) .filter(Objects::nonNull) .distinct() - .toList(); + .collect(Collectors.toList()); - // 批量查询用户 if (!creatorIds.isEmpty()) { List creators = userService.listByIds(creatorIds); - // 构建 ID -> 昵称映射 Map creatorNicknameMap = creators.stream() .collect(Collectors.toMap( User::getId, - User::getNickname, - (k1, k2) -> k1)); + user -> user.getNickname() != null ? user.getNickname() : "未知昵称", + (k1, k2) -> k1 + )); - // 填充昵称 page.getRecords().forEach(plan -> { - String nickname = creatorNicknameMap.getOrDefault(plan.getCreatedBy(), "未知用户"); - plan.setCreatedBy(nickname); + plan.setCreatedBy(creatorNicknameMap.getOrDefault(plan.getCreatedBy(), "未知用户")); }); } } return ApiResponse.success(page); } + + /** + * 抽取创建空分页结果的方法 + */ + private Page createEmptyPage(Integer pageNum, Integer pageSize) { + Page emptyPage = new Page<>(pageNum, pageSize); + emptyPage.setTotal(0); + emptyPage.setRecords(Collections.emptyList()); + return emptyPage; + } } diff --git a/src/main/java/com/yj/earth/business/controller/TsSourceController.java b/src/main/java/com/yj/earth/business/controller/TsSourceController.java index 0a5021a..84c2056 100644 --- a/src/main/java/com/yj/earth/business/controller/TsSourceController.java +++ b/src/main/java/com/yj/earth/business/controller/TsSourceController.java @@ -7,6 +7,7 @@ import com.yj.earth.business.service.TsSourceService; import com.yj.earth.common.util.ApiResponse; import com.yj.earth.common.util.JsonUtil; import com.yj.earth.common.util.MapUtil; +import com.yj.earth.dto.tsPlan.BatchUpdateShowStatusDto; import com.yj.earth.dto.tsSource.AddTsModelSourceDto; import com.yj.earth.dto.tsSource.AddTsSourceDto; import com.yj.earth.dto.tsSource.UpdateTsSourceDto; @@ -54,6 +55,19 @@ public class TsSourceController { return ApiResponse.success(null); } + @Operation(summary = "批量修改资源显示状态") + @PostMapping("/batchUpdateShowStatus") + public ApiResponse batchUpdateShowStatus(@RequestBody List batchUpdateShowStatusDtoList) { + for (BatchUpdateShowStatusDto batchUpdateShowStatusDto : batchUpdateShowStatusDtoList) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + TsSource tsSource = new TsSource(); + tsSource.setId(batchUpdateShowStatusDto.getId()); + tsSource.setIsShow(batchUpdateShowStatusDto.getShow()); + tsSourceService.updateById(tsSource); + } + return ApiResponse.success(null); + } + @Operation(summary = "查询某个方案下的态势资源") @PostMapping("/query") public ApiResponse query(@Parameter(description = "态势方案ID") @RequestParam(required = true) String id) { diff --git a/src/main/java/com/yj/earth/business/domain/Source.java b/src/main/java/com/yj/earth/business/domain/Source.java index 9f0a73b..e808bad 100644 --- a/src/main/java/com/yj/earth/business/domain/Source.java +++ b/src/main/java/com/yj/earth/business/domain/Source.java @@ -51,6 +51,6 @@ public class Source implements Serializable { private LocalDateTime createdAt; @Schema(description = "更新时间") - @TableField(fill = FieldFill.UPDATE) + @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt; } diff --git a/src/main/java/com/yj/earth/business/service/SourceService.java b/src/main/java/com/yj/earth/business/service/SourceService.java index 2ccb58a..f84bb6b 100644 --- a/src/main/java/com/yj/earth/business/service/SourceService.java +++ b/src/main/java/com/yj/earth/business/service/SourceService.java @@ -21,6 +21,8 @@ public interface SourceService extends IService { String fetchCltDetail(String sourceId); + String fetchJsonDetail(String sourceId); + String fetchMbtilesDetail(String sourceId); String fetchPakDetail(String sourceId); diff --git a/src/main/java/com/yj/earth/business/service/impl/SourceServiceImpl.java b/src/main/java/com/yj/earth/business/service/impl/SourceServiceImpl.java index bad0a69..48dd85e 100644 --- a/src/main/java/com/yj/earth/business/service/impl/SourceServiceImpl.java +++ b/src/main/java/com/yj/earth/business/service/impl/SourceServiceImpl.java @@ -61,6 +61,7 @@ public class SourceServiceImpl extends ServiceImpl impleme detailFetchers.put("clt", this::fetchCltDetail); detailFetchers.put("mbtiles", this::fetchMbtilesDetail); detailFetchers.put("pak", this::fetchPakDetail); + detailFetchers.put("json", this::fetchJsonDetail); } /** @@ -156,6 +157,15 @@ public class SourceServiceImpl extends ServiceImpl impleme return HttpUtil.doGet(url); } + /** + * 获取 JSON 类型资源详情 + */ + @Override + public String fetchJsonDetail(String sourceId) { + String url = buildSdkUrl("/data/clt/json/detail/" + sourceId); + return HttpUtil.doGet(url); + } + /** * 获取 MBTiles 类型资源详情 */ @@ -199,12 +209,14 @@ public class SourceServiceImpl extends ServiceImpl impleme return resultMap; } - // 创建用于计算总数的查询条件(始终排除directory类型) + // 创建用于计算总数的查询条件 LambdaQueryWrapper countQueryWrapper = new LambdaQueryWrapper<>(); countQueryWrapper.ne(Source::getSourceType, "directory"); // 构建资源查询条件 LambdaQueryWrapper sourceQueryWrapper = new LambdaQueryWrapper<>(); + // 排序字段 + sourceQueryWrapper.orderByDesc(Source::getUpdatedAt); // 公共查询条件 if (sourceType != null) { @@ -263,7 +275,6 @@ public class SourceServiceImpl extends ServiceImpl impleme // 不分页: 获取全部数据(包含所有类型)和总数(排除directory) List sourceList = sourceService.list(sourceQueryWrapper); long total = sourceService.count(countQueryWrapper); - resultMap.put("list", sourceList); resultMap.put("total", total); } diff --git a/src/main/java/com/yj/earth/common/util/SQLiteUtil.java b/src/main/java/com/yj/earth/common/util/SQLiteUtil.java index 0ecb347..3026a98 100644 --- a/src/main/java/com/yj/earth/common/util/SQLiteUtil.java +++ b/src/main/java/com/yj/earth/common/util/SQLiteUtil.java @@ -121,7 +121,7 @@ public class SQLiteUtil { try { dataSource.close(); } catch (SQLException e) { - System.err.println("关闭SQLite数据源失败: " + e.getMessage()); + System.err.println("关闭SQLite: " + e.getMessage()); } } // 清理缓存(避免内存泄漏) @@ -199,7 +199,7 @@ public class SQLiteUtil { } catch (SQLException e) { // 异常时关闭当前数据源(避免后续请求使用异常连接) closeDataSource(dbFilePath); - throw new SQLException("执行查询失败(SQL: " + sql + ")", e); + throw new SQLException("请检查文件是否存在"); } return resultList; diff --git a/src/main/java/com/yj/earth/dto/tsPlan/BatchUpdateShowStatusDto.java b/src/main/java/com/yj/earth/dto/tsPlan/BatchUpdateShowStatusDto.java new file mode 100644 index 0000000..b289ac9 --- /dev/null +++ b/src/main/java/com/yj/earth/dto/tsPlan/BatchUpdateShowStatusDto.java @@ -0,0 +1,14 @@ +package com.yj.earth.dto.tsPlan; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Data +public class BatchUpdateShowStatusDto { + @Schema(description = "资源ID列表") + private String id; + @Schema(description = "显示状态") + private Integer show; +} diff --git a/src/main/java/com/yj/earth/params/Path.java b/src/main/java/com/yj/earth/params/Path.java index a7e3f24..e15bf37 100644 --- a/src/main/java/com/yj/earth/params/Path.java +++ b/src/main/java/com/yj/earth/params/Path.java @@ -54,6 +54,22 @@ public class Path { @Data public static class CustomView { + private AttackArrow.CustomView.Orientation orientation; + private AttackArrow.CustomView.RelativePosition relativePosition; + + @Data + public static class Orientation { + private double heading; + private double pitch; + private double roll; + } + + @Data + public static class RelativePosition { + private double lng; + private double lat; + private double alt; + } } @Data diff --git a/src/main/java/com/yj/earth/params/Roam.java b/src/main/java/com/yj/earth/params/Roam.java index 38ecbdb..9571149 100644 --- a/src/main/java/com/yj/earth/params/Roam.java +++ b/src/main/java/com/yj/earth/params/Roam.java @@ -9,6 +9,8 @@ import java.util.List; @SourceType("roam") public class Roam { private String name; + private String defaultTime; + private String totalTime; private List points; private String repeat;