全部
This commit is contained in:
@ -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");
|
||||
|
||||
@ -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<String, Object> response = new HashMap<>();
|
||||
List<CsvField> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ public class DeviceController {
|
||||
List<Device> deviceList = devicePage.getRecords();
|
||||
|
||||
if (CollectionUtils.isEmpty(deviceList)) {
|
||||
// 如果没有数据,直接返回空分页
|
||||
// 如果没有数据、直接返回空分页
|
||||
return ApiResponse.success(devicePage);
|
||||
}
|
||||
|
||||
@ -105,15 +105,15 @@ public class DeviceController {
|
||||
// 异步并发检测所有 IP 的在线状态
|
||||
Map<String, Boolean> 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);
|
||||
}
|
||||
});
|
||||
|
||||
@ -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<IconTypeVo> treeList = iconTypeList();
|
||||
public ApiResponse iconTypeTree(@Parameter(description = "图标名称") @RequestParam(value = "iconName", required = false) String iconName) throws SQLException, IllegalAccessException, InstantiationException {
|
||||
List<IconTypeVo> 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<String> typeIdList = getIconTypeIdsWithChildren(typeId);
|
||||
List<String> 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<IconVo> 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<IconTypeVo> treeList = iconTypeList();
|
||||
List<IconTypeVo> treeList = iconTypeList(null);
|
||||
return ApiResponse.success(treeList);
|
||||
}
|
||||
|
||||
@ -381,7 +391,10 @@ public class IconLibraryController {
|
||||
LambdaQueryWrapper<IconLibrary> 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<IconTypeVo> iconTypeList() throws SQLException, IllegalAccessException, InstantiationException {
|
||||
/**
|
||||
* 查询图标分类树形结构
|
||||
*/
|
||||
private List<IconTypeVo> 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<IconType> 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<IconType> iconTypes = SQLiteUtil.queryForList(
|
||||
iconPath,
|
||||
sqlBuilder.toString(),
|
||||
null,
|
||||
IconType.class
|
||||
);
|
||||
|
||||
// 将扁平的分类列表转换为树形结构
|
||||
return buildIconTypeTree(iconTypes);
|
||||
}
|
||||
|
||||
private List<IconTypeVo> buildIconTypeTree(List<IconType> typeList) {
|
||||
|
||||
@ -204,8 +204,8 @@ public class MilitaryLibraryController {
|
||||
|
||||
@Operation(summary = "军标类型树形列表")
|
||||
@GetMapping("/militaryTypeTree")
|
||||
public ApiResponse militaryTypeTree() throws SQLException, IllegalAccessException, InstantiationException {
|
||||
List<MilitaryTypeVo> treeList = militaryTypeList();
|
||||
public ApiResponse militaryTypeTree(@Parameter(description = "军标名称") @RequestParam(value = "militaryName", required = false) String militaryName) throws SQLException, IllegalAccessException, InstantiationException {
|
||||
List<MilitaryTypeVo> 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<byte[]> 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<String> typeIdList = getMilitaryTypeIdsWithChildren(typeId);
|
||||
List<String> 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<MilitaryVo> 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<MilitaryTypeVo> treeList = militaryTypeList();
|
||||
List<MilitaryTypeVo> treeList = militaryTypeList(null);
|
||||
return ApiResponse.success(treeList);
|
||||
}
|
||||
|
||||
@ -415,7 +429,10 @@ public class MilitaryLibraryController {
|
||||
LambdaQueryWrapper<MilitaryLibrary> 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<MilitaryTypeVo> militaryTypeList() throws SQLException, IllegalAccessException, InstantiationException {
|
||||
/**
|
||||
* 查询军标分类树形结构
|
||||
*/
|
||||
private List<MilitaryTypeVo> 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<MilitaryType> 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<MilitaryType> militaryTypes = SQLiteUtil.queryForList(
|
||||
militaryPath,
|
||||
sqlBuilder.toString(),
|
||||
null,
|
||||
MilitaryType.class
|
||||
);
|
||||
|
||||
// 将扁平的分类列表转换为树形结构
|
||||
return buildMilitaryTypeTree(militaryTypes);
|
||||
}
|
||||
|
||||
private List<MilitaryTypeVo> buildMilitaryTypeTree(List<MilitaryType> typeList) {
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -88,24 +88,19 @@ public class RoleController {
|
||||
if (status != null) {
|
||||
queryWrapper.eq(Role::getStatus, status);
|
||||
}
|
||||
|
||||
// 统计当前条件下每个角色名称的数量
|
||||
List<Role> allMatchedRoles = roleService.list(queryWrapper);
|
||||
Map<String, Long> roleNameCountMap = allMatchedRoles.stream()
|
||||
.collect(Collectors.groupingBy(Role::getRoleName, Collectors.counting()));
|
||||
|
||||
// 分页查询
|
||||
Page<Role> rolePage = roleService.page(new Page<>(pageNum, pageSize), queryWrapper);
|
||||
|
||||
// 转换为 Page<RoleVo>
|
||||
Page<RoleVo> roleVoPage = (Page<RoleVo>) rolePage.convert(role -> {
|
||||
LambdaQueryWrapper<User> 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);
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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<TsSource>()
|
||||
.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<TsPlan> queryWrapper = new LambdaQueryWrapper<>();
|
||||
@ -86,87 +134,66 @@ public class TsPlanController {
|
||||
queryWrapper.like(TsPlan::getName, name);
|
||||
}
|
||||
|
||||
// 用户名查询
|
||||
if (StringUtils.isNotBlank(username)) {
|
||||
LambdaQueryWrapper<User> userQueryWrapper = new LambdaQueryWrapper<>();
|
||||
userQueryWrapper.like(User::getUsername, username);
|
||||
List<User> userList = userService.list(userQueryWrapper);
|
||||
|
||||
// 判断列表是否为空
|
||||
if (userList.isEmpty()) {
|
||||
// 无匹配用户、直接返回空分页结果
|
||||
Page<TsPlan> emptyPage = new Page<>(pageNum, pageSize);
|
||||
emptyPage.setTotal(0);
|
||||
emptyPage.setRecords(Collections.emptyList());
|
||||
return ApiResponse.success(emptyPage);
|
||||
}
|
||||
|
||||
// 提取用户 ID 列表(确保类型匹配)
|
||||
List<String> userIdList = userList.stream()
|
||||
.map(User::getId)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
|
||||
// 若 ID 列表为空,也返回空结果
|
||||
if (userIdList.isEmpty()) {
|
||||
Page<TsPlan> 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<User>()
|
||||
.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<TsPlan> page = tsPlanService.page(new Page<>(pageNum, pageSize), queryWrapper);
|
||||
|
||||
// 优化用户名查询
|
||||
// 关联查询用户信息并封装结果
|
||||
if (!page.getRecords().isEmpty()) {
|
||||
// 提取所有创建人 ID
|
||||
List<String> creatorIds = page.getRecords().stream()
|
||||
.map(TsPlan::getCreatedBy)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 批量查询用户
|
||||
if (!creatorIds.isEmpty()) {
|
||||
List<User> creators = userService.listByIds(creatorIds);
|
||||
// 构建 ID -> 昵称映射
|
||||
Map<String, String> 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<TsPlan> createEmptyPage(Integer pageNum, Integer pageSize) {
|
||||
Page<TsPlan> emptyPage = new Page<>(pageNum, pageSize);
|
||||
emptyPage.setTotal(0);
|
||||
emptyPage.setRecords(Collections.emptyList());
|
||||
return emptyPage;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<BatchUpdateShowStatusDto> batchUpdateShowStatusDtoList) {
|
||||
for (BatchUpdateShowStatusDto batchUpdateShowStatusDto : batchUpdateShowStatusDtoList) {
|
||||
LambdaQueryWrapper<TsSource> 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) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -21,6 +21,8 @@ public interface SourceService extends IService<Source> {
|
||||
|
||||
String fetchCltDetail(String sourceId);
|
||||
|
||||
String fetchJsonDetail(String sourceId);
|
||||
|
||||
String fetchMbtilesDetail(String sourceId);
|
||||
|
||||
String fetchPakDetail(String sourceId);
|
||||
|
||||
@ -61,6 +61,7 @@ public class SourceServiceImpl extends ServiceImpl<SourceMapper, Source> 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<SourceMapper, Source> 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<SourceMapper, Source> impleme
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
// 创建用于计算总数的查询条件(始终排除directory类型)
|
||||
// 创建用于计算总数的查询条件
|
||||
LambdaQueryWrapper<Source> countQueryWrapper = new LambdaQueryWrapper<>();
|
||||
countQueryWrapper.ne(Source::getSourceType, "directory");
|
||||
|
||||
// 构建资源查询条件
|
||||
LambdaQueryWrapper<Source> sourceQueryWrapper = new LambdaQueryWrapper<>();
|
||||
// 排序字段
|
||||
sourceQueryWrapper.orderByDesc(Source::getUpdatedAt);
|
||||
|
||||
// 公共查询条件
|
||||
if (sourceType != null) {
|
||||
@ -263,7 +275,6 @@ public class SourceServiceImpl extends ServiceImpl<SourceMapper, Source> impleme
|
||||
// 不分页: 获取全部数据(包含所有类型)和总数(排除directory)
|
||||
List<Source> sourceList = sourceService.list(sourceQueryWrapper);
|
||||
long total = sourceService.count(countQueryWrapper);
|
||||
|
||||
resultMap.put("list", sourceList);
|
||||
resultMap.put("total", total);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -9,6 +9,8 @@ import java.util.List;
|
||||
@SourceType("roam")
|
||||
public class Roam {
|
||||
private String name;
|
||||
private String defaultTime;
|
||||
private String totalTime;
|
||||
private List<Point> points;
|
||||
private String repeat;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user