2025-09-26 13:46:54 +08:00
|
|
|
|
package com.yj.earth.business.controller;
|
|
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.io.FileUtil;
|
|
|
|
|
|
import cn.hutool.core.lang.UUID;
|
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
|
import com.yj.earth.annotation.CheckAuth;
|
|
|
|
|
|
import com.yj.earth.business.domain.ModelLibrary;
|
|
|
|
|
|
import com.yj.earth.business.domain.ModelType;
|
|
|
|
|
|
import com.yj.earth.business.service.FileInfoService;
|
|
|
|
|
|
import com.yj.earth.business.service.ModelLibraryService;
|
|
|
|
|
|
import com.yj.earth.common.util.ApiResponse;
|
2025-09-29 13:56:36 +08:00
|
|
|
|
import com.yj.earth.common.util.FileCommonUtil;
|
2025-09-26 13:46:54 +08:00
|
|
|
|
import com.yj.earth.common.util.SQLiteUtil;
|
|
|
|
|
|
import com.yj.earth.dto.militaryLibrary.DragMilitaryTypeDto;
|
|
|
|
|
|
import com.yj.earth.dto.modelLibrary.AddModelTypeDto;
|
|
|
|
|
|
import com.yj.earth.dto.modelLibrary.CreateModelLibraryDto;
|
|
|
|
|
|
import com.yj.earth.dto.modelLibrary.DragModelTypeDto;
|
|
|
|
|
|
import com.yj.earth.dto.modelLibrary.UpdateModelTypeNameDto;
|
2025-09-29 13:56:36 +08:00
|
|
|
|
import com.yj.earth.vo.ModelDataVo;
|
2025-09-26 13:46:54 +08:00
|
|
|
|
import com.yj.earth.vo.ModelTypeVo;
|
|
|
|
|
|
import com.yj.earth.vo.ModelVo;
|
|
|
|
|
|
import io.swagger.v3.oas.annotations.Operation;
|
|
|
|
|
|
import io.swagger.v3.oas.annotations.Parameter;
|
|
|
|
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
2025-09-28 15:10:29 +08:00
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
2025-09-29 13:56:36 +08:00
|
|
|
|
import org.springframework.http.HttpHeaders;
|
|
|
|
|
|
import org.springframework.http.HttpStatus;
|
|
|
|
|
|
import org.springframework.http.MediaType;
|
|
|
|
|
|
import org.springframework.http.ResponseEntity;
|
2025-09-26 13:46:54 +08:00
|
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
|
import java.io.IOException;
|
2025-09-29 13:56:36 +08:00
|
|
|
|
import java.net.URLEncoder;
|
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
2025-09-26 13:46:54 +08:00
|
|
|
|
import java.sql.SQLException;
|
|
|
|
|
|
import java.time.LocalDateTime;
|
2025-09-29 13:56:36 +08:00
|
|
|
|
import java.util.*;
|
2025-09-26 13:46:54 +08:00
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
2025-09-30 10:14:40 +08:00
|
|
|
|
@Tag(name = "模型数据管理")
|
2025-09-26 13:46:54 +08:00
|
|
|
|
@CheckAuth
|
|
|
|
|
|
@RestController
|
|
|
|
|
|
@RequestMapping("/modelLibrary")
|
|
|
|
|
|
public class ModelLibraryController {
|
|
|
|
|
|
@Resource
|
|
|
|
|
|
private ModelLibraryService modelLibraryService;
|
|
|
|
|
|
@Resource
|
|
|
|
|
|
private FileInfoService fileInfoService;
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "创建模型库")
|
|
|
|
|
|
@PostMapping("/createModelLibrary")
|
|
|
|
|
|
public ApiResponse createModelLibrary(@RequestBody CreateModelLibraryDto createModelLibraryDto) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 参数校验
|
|
|
|
|
|
String folderPath = createModelLibraryDto.getPath();
|
|
|
|
|
|
String modelName = createModelLibraryDto.getName();
|
2025-09-29 14:00:20 +08:00
|
|
|
|
// 处理路径、组合为完整模型库文件路径
|
2025-09-26 13:46:54 +08:00
|
|
|
|
File parentDir = new File(folderPath);
|
2025-09-29 14:00:20 +08:00
|
|
|
|
File modelFile = new File(parentDir, modelName);
|
2025-09-26 13:46:54 +08:00
|
|
|
|
String modelPath = modelFile.getAbsolutePath().replace("\\", "/");
|
|
|
|
|
|
// 检查父目录是否存在、不存在则创建
|
|
|
|
|
|
if (!parentDir.exists()) {
|
|
|
|
|
|
boolean mkdirsSuccess = parentDir.mkdirs();
|
|
|
|
|
|
if (!mkdirsSuccess) {
|
|
|
|
|
|
return ApiResponse.failure("创建父目录失败:" + folderPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 检查模型库文件是否已存在
|
|
|
|
|
|
if (modelFile.exists()) {
|
|
|
|
|
|
if (modelFile.isDirectory()) {
|
|
|
|
|
|
return ApiResponse.failure("同名目录已存在、无法创建文件:" + modelPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
return ApiResponse.failure("模型库文件已存在:" + modelPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 创建模型库文件(
|
|
|
|
|
|
boolean createSuccess = modelFile.createNewFile();
|
|
|
|
|
|
if (!createSuccess) {
|
|
|
|
|
|
return ApiResponse.failure("创建模型库文件失败:" + modelPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 添加模型库信息
|
|
|
|
|
|
addModelLibrary(modelPath);
|
|
|
|
|
|
SQLiteUtil.initializationModel(modelPath);
|
|
|
|
|
|
return ApiResponse.success(null);
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
return ApiResponse.failure("创建模型库失败:" + e.getMessage());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "导入模型库")
|
|
|
|
|
|
@PostMapping("/importModelLibrary")
|
|
|
|
|
|
public ApiResponse importModelLibrary(@RequestParam("modelPath") @Parameter(description = "模型库路径") String modelPath) {
|
|
|
|
|
|
addModelLibrary(modelPath);
|
|
|
|
|
|
return ApiResponse.success(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "添加模型类型")
|
|
|
|
|
|
@PostMapping("/addModelType")
|
|
|
|
|
|
public ApiResponse addModelType(@RequestBody AddModelTypeDto addModelTypeDto) throws SQLException, IllegalAccessException, InstantiationException {
|
|
|
|
|
|
String modelPath = getModelLibrary();
|
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
|
return ApiResponse.failure("请先创建或导入模型库");
|
|
|
|
|
|
}
|
|
|
|
|
|
// 检查父级是否存在
|
|
|
|
|
|
String parentId = addModelTypeDto.getParentId();
|
|
|
|
|
|
if (parentId != null) {
|
|
|
|
|
|
String sql = "SELECT * FROM model_type WHERE id = ?";
|
|
|
|
|
|
List<Object> params = new ArrayList<>();
|
|
|
|
|
|
params.add(parentId);
|
|
|
|
|
|
ModelType modelType = SQLiteUtil.queryForObject(modelPath, sql, params, ModelType.class);
|
|
|
|
|
|
if (modelType == null) {
|
|
|
|
|
|
return ApiResponse.failure("父级模型类型不存在");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
String sql = "INSERT INTO model_type " +
|
|
|
|
|
|
"(id, name, parent_id, tree_index, created_at) " +
|
|
|
|
|
|
"VALUES (?, ?, ?, ?, ?)";
|
|
|
|
|
|
List<Object> params = new ArrayList<>();
|
|
|
|
|
|
params.add(UUID.fastUUID().toString(true));
|
|
|
|
|
|
params.add(addModelTypeDto.getName());
|
|
|
|
|
|
params.add(addModelTypeDto.getParentId());
|
|
|
|
|
|
params.add(0);
|
|
|
|
|
|
params.add(LocalDateTime.now());
|
|
|
|
|
|
SQLiteUtil.executeUpdate(modelPath, sql, params);
|
|
|
|
|
|
return ApiResponse.success(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "修改模型类型名称")
|
|
|
|
|
|
@PostMapping("/updateModelTypeName")
|
|
|
|
|
|
public ApiResponse updateModelTypeName(@RequestBody UpdateModelTypeNameDto updateModelTypeNameDto) throws SQLException {
|
|
|
|
|
|
String modelPath = getModelLibrary();
|
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
|
return ApiResponse.failure("请先创建或导入模型库");
|
|
|
|
|
|
}
|
|
|
|
|
|
String sql = "UPDATE model_type SET name = ? WHERE id = ?";
|
|
|
|
|
|
List<Object> params = new ArrayList<>();
|
|
|
|
|
|
params.add(updateModelTypeNameDto.getName());
|
|
|
|
|
|
params.add(updateModelTypeNameDto.getId());
|
|
|
|
|
|
SQLiteUtil.executeUpdate(modelPath, sql, params);
|
|
|
|
|
|
return ApiResponse.success(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "删除模型类型")
|
|
|
|
|
|
@PostMapping("/deleteModelType")
|
|
|
|
|
|
public ApiResponse deleteModelType(@Parameter(description = "模型类型ID") @RequestParam("modelTypeId") String modelTypeId) throws SQLException {
|
|
|
|
|
|
String modelPath = getModelLibrary();
|
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
|
return ApiResponse.failure("请先创建或导入模型库");
|
|
|
|
|
|
}
|
|
|
|
|
|
String sql = "DELETE FROM model_type WHERE id = ?";
|
|
|
|
|
|
List<Object> params = new ArrayList<>();
|
|
|
|
|
|
params.add(modelTypeId);
|
|
|
|
|
|
SQLiteUtil.executeUpdate(modelPath, sql, params);
|
|
|
|
|
|
return ApiResponse.success(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "模型类型列表")
|
|
|
|
|
|
@GetMapping("/modelTypeList")
|
|
|
|
|
|
public ApiResponse modelTypeTree() throws SQLException, IllegalAccessException, InstantiationException {
|
2025-09-28 15:10:29 +08:00
|
|
|
|
return ApiResponse.success(modelTypeList());
|
2025-09-26 13:46:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "添加模型文件")
|
|
|
|
|
|
@PostMapping("/addModelFile")
|
|
|
|
|
|
public ApiResponse addModelFile(@RequestParam("files") MultipartFile[] files, @Parameter(description = "模型类型ID") @RequestParam("modelTypeId") String modelTypeId) throws IOException, SQLException {
|
|
|
|
|
|
// 获取最新的模型库路径
|
|
|
|
|
|
String modelPath = getModelLibrary();
|
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
|
return ApiResponse.failure("请先创建或导入模型库");
|
|
|
|
|
|
}
|
|
|
|
|
|
// 循环处理每个上传的文件
|
|
|
|
|
|
for (MultipartFile file : files) {
|
|
|
|
|
|
// 跳过空文件
|
|
|
|
|
|
if (file.isEmpty()) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 获取文件信息
|
|
|
|
|
|
String fileName = file.getOriginalFilename();
|
|
|
|
|
|
if (fileName == null) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
String fileSuffix = FileUtil.extName(fileName);
|
|
|
|
|
|
String fileNameWithoutSuffix = FileUtil.mainName(fileName);
|
|
|
|
|
|
|
|
|
|
|
|
// 构建插入SQL
|
|
|
|
|
|
String sql = "INSERT INTO model " +
|
2025-09-29 13:56:36 +08:00
|
|
|
|
"(id, model_type_id, model_name, model_type, model_data, created_at) " +
|
2025-09-26 13:46:54 +08:00
|
|
|
|
"VALUES (?, ?, ?, ?, ?, ?)";
|
|
|
|
|
|
|
|
|
|
|
|
List<Object> params = new ArrayList<>();
|
2025-09-29 13:56:36 +08:00
|
|
|
|
String modelId = UUID.fastUUID().toString(true);
|
|
|
|
|
|
params.add(modelId);
|
2025-09-26 13:46:54 +08:00
|
|
|
|
params.add(modelTypeId);
|
|
|
|
|
|
params.add(fileNameWithoutSuffix);
|
|
|
|
|
|
params.add(fileSuffix);
|
2025-09-29 13:56:36 +08:00
|
|
|
|
params.add(file.getBytes());
|
2025-09-26 13:46:54 +08:00
|
|
|
|
params.add(LocalDateTime.now());
|
|
|
|
|
|
|
|
|
|
|
|
// 执行插入操作
|
|
|
|
|
|
SQLiteUtil.executeUpdate(modelPath, sql, params);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return ApiResponse.success(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 13:56:36 +08:00
|
|
|
|
@Operation(summary = "获取模型数据")
|
|
|
|
|
|
@GetMapping("/data/{type}/{modelId}/{fileSuffix}")
|
|
|
|
|
|
public ResponseEntity<byte[]> modelData(
|
|
|
|
|
|
@Parameter(description = "数据类型") @PathVariable("type") String type,
|
|
|
|
|
|
@Parameter(description = "模型ID") @PathVariable("modelId") String modelId,
|
|
|
|
|
|
@Parameter(description = "模型类型") @PathVariable(value = "fileSuffix") String fileSuffix) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 获取最新的模型库
|
|
|
|
|
|
String modelPath = getModelLibrary();
|
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
|
return ResponseEntity.notFound().build();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
List<Object> params = new ArrayList<>();
|
|
|
|
|
|
params.add(modelId);
|
|
|
|
|
|
String sql = null;
|
|
|
|
|
|
if (type.equals("model")) {
|
|
|
|
|
|
sql = "SELECT model_name, model_data FROM model WHERE id = ?";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
sql = "SELECT model_name, poster_data FROM model WHERE id = ?";
|
|
|
|
|
|
}
|
|
|
|
|
|
// 查询模型数据
|
|
|
|
|
|
ModelDataVo modelDataVo = SQLiteUtil.queryForObject(
|
|
|
|
|
|
modelPath,
|
|
|
|
|
|
sql,
|
|
|
|
|
|
params,
|
|
|
|
|
|
ModelDataVo.class
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if (modelDataVo == null) {
|
|
|
|
|
|
return ResponseEntity.notFound().build();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建原始文件名(使用从数据库查询的名称更合理)
|
|
|
|
|
|
String originalFileName = modelDataVo.getModelName() + "." + fileSuffix;
|
|
|
|
|
|
|
|
|
|
|
|
// 对文件名进行URL编码处理、解决非ASCII字符问题
|
|
|
|
|
|
String encodedFileName = URLEncoder.encode(originalFileName, StandardCharsets.UTF_8.name());
|
|
|
|
|
|
|
|
|
|
|
|
// 根据图片后缀获取对应的MediaType
|
|
|
|
|
|
MediaType contentType = FileCommonUtil.getImageMediaType(fileSuffix);
|
|
|
|
|
|
|
|
|
|
|
|
// 设置响应头、使用 inline 确保可以预览
|
|
|
|
|
|
if (type.equals("model")) {
|
|
|
|
|
|
return ResponseEntity.ok()
|
|
|
|
|
|
.contentType(contentType)
|
|
|
|
|
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
|
|
|
|
|
"inline; filename=\"" + encodedFileName + "\"")
|
|
|
|
|
|
.body(modelDataVo.getModelData());
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return ResponseEntity.ok()
|
|
|
|
|
|
.contentType(contentType)
|
|
|
|
|
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
|
|
|
|
|
"inline; filename=\"" + encodedFileName + "\"")
|
|
|
|
|
|
.body(modelDataVo.getPosterData());
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (SQLException e) {
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-09-26 13:46:54 +08:00
|
|
|
|
@Operation(summary = "根据模型类型查看模型列表")
|
|
|
|
|
|
@PostMapping("/modelList")
|
|
|
|
|
|
public ApiResponse modelList(@Parameter(description = "模型类型ID") @RequestParam("modelTypeId") String modelTypeId) throws SQLException, IllegalAccessException, InstantiationException {
|
|
|
|
|
|
// 获取最新的模型库
|
|
|
|
|
|
String modelPath = getModelLibrary();
|
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
|
return ApiResponse.failure("请先创建或导入模型库");
|
|
|
|
|
|
}
|
2025-09-29 13:56:36 +08:00
|
|
|
|
|
|
|
|
|
|
// 获取分类ID及其所有子分类ID的列表
|
|
|
|
|
|
List<String> typeIdList = getModelTypeIdsWithChildren(modelTypeId);
|
|
|
|
|
|
if (typeIdList.isEmpty()) {
|
|
|
|
|
|
return ApiResponse.success(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String idsWithQuotes = typeIdList.stream()
|
|
|
|
|
|
.map(id -> "'" + id + "'")
|
|
|
|
|
|
.collect(Collectors.joining(","));
|
|
|
|
|
|
|
|
|
|
|
|
// 多表联查、查询所有指定分类及其子分类下的模型
|
2025-09-26 13:46:54 +08:00
|
|
|
|
String sql = """
|
|
|
|
|
|
SELECT
|
|
|
|
|
|
model.id,
|
|
|
|
|
|
model.model_type_id as modelTypeId,
|
|
|
|
|
|
model.model_name as modelName,
|
|
|
|
|
|
model.model_type as modelType,
|
|
|
|
|
|
model.poster_type as posterType,
|
|
|
|
|
|
model.created_at as createdAt,
|
|
|
|
|
|
model.updated_at as updatedAt,
|
2025-09-29 13:56:36 +08:00
|
|
|
|
model_type.name as modelTypeName
|
|
|
|
|
|
FROM model
|
|
|
|
|
|
JOIN model_type ON model.model_type_id = model_type.id
|
|
|
|
|
|
WHERE model.model_type_id IN (?)
|
|
|
|
|
|
""".replace("?", idsWithQuotes);
|
|
|
|
|
|
|
|
|
|
|
|
// 使用所有分类ID作为查询参数
|
2025-09-26 13:46:54 +08:00
|
|
|
|
List<Object> params = new ArrayList<>();
|
2025-09-29 13:56:36 +08:00
|
|
|
|
List<ModelVo> modelVos = SQLiteUtil.queryForList(modelPath, sql, null, ModelVo.class);
|
|
|
|
|
|
// 循环遍历数据
|
|
|
|
|
|
for (ModelVo modelVo : modelVos) {
|
|
|
|
|
|
if (modelVo.getModelType() != null) {
|
2025-09-29 17:34:21 +08:00
|
|
|
|
String processedModelType = trimDot(modelVo.getModelType());
|
|
|
|
|
|
modelVo.setModelDataUrl("/modelLibrary/data/model/" + modelVo.getId() + "/" + processedModelType);
|
|
|
|
|
|
modelVo.setModelType(processedModelType);
|
2025-09-29 13:56:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (modelVo.getPosterType() != null) {
|
2025-09-29 17:34:21 +08:00
|
|
|
|
String processedPosterType = trimDot(modelVo.getPosterType());
|
|
|
|
|
|
modelVo.setPosterDataUrl("/modelLibrary/data/poster/" + modelVo.getId() + "/" + processedPosterType);
|
|
|
|
|
|
modelVo.setPosterType(processedPosterType);
|
2025-09-29 13:56:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-29 17:34:21 +08:00
|
|
|
|
|
2025-09-26 13:46:54 +08:00
|
|
|
|
return ApiResponse.success(modelVos);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "更新模型信息")
|
|
|
|
|
|
@PostMapping("/uploadModelInfo")
|
2025-09-29 13:56:36 +08:00
|
|
|
|
public ApiResponse uploadModelInfo(@Parameter(description = "模型封面文件") @RequestParam(value = "file", required = false) MultipartFile file,
|
|
|
|
|
|
@Parameter(description = "模型ID") @RequestParam("modelId") String modelId,
|
|
|
|
|
|
@Parameter(description = "模型名称") @RequestParam(value = "modelName", required = false) String modelName) throws IOException, SQLException {
|
2025-09-26 13:46:54 +08:00
|
|
|
|
|
|
|
|
|
|
// 获取最新的模型库路径
|
|
|
|
|
|
String modelPath = getModelLibrary();
|
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
|
return ApiResponse.failure("请先创建或导入模型库");
|
|
|
|
|
|
}
|
|
|
|
|
|
// 动态构建SQL更新语句和参数
|
|
|
|
|
|
StringBuilder sql = new StringBuilder("UPDATE model SET updated_at = ? ");
|
|
|
|
|
|
List<Object> params = new ArrayList<>();
|
|
|
|
|
|
// 始终更新时间
|
|
|
|
|
|
params.add(LocalDateTime.now());
|
|
|
|
|
|
// 处理封面文件
|
|
|
|
|
|
if (file != null && !file.isEmpty()) {
|
|
|
|
|
|
String fileSuffix = FileUtil.extName(file.getOriginalFilename());
|
2025-09-29 13:56:36 +08:00
|
|
|
|
sql.append(", poster_type = ?, poster_data = ? ");
|
2025-09-26 13:46:54 +08:00
|
|
|
|
params.add(fileSuffix);
|
2025-09-29 13:56:36 +08:00
|
|
|
|
params.add(file.getBytes());
|
2025-09-26 13:46:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理模型名称
|
|
|
|
|
|
if (StringUtils.hasText(modelName)) {
|
|
|
|
|
|
sql.append(", model_name = ? ");
|
|
|
|
|
|
params.add(modelName);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 拼接WHERE条件
|
|
|
|
|
|
sql.append("WHERE id = ?");
|
|
|
|
|
|
params.add(modelId);
|
|
|
|
|
|
// 执行更新
|
|
|
|
|
|
SQLiteUtil.executeUpdate(modelPath, sql.toString(), params);
|
|
|
|
|
|
return ApiResponse.success(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "删除模型")
|
|
|
|
|
|
@PostMapping("/deleteModel")
|
|
|
|
|
|
public ApiResponse deleteModel(@Parameter(description = "模型ID") @RequestParam("modelId") String modelId) throws SQLException {
|
|
|
|
|
|
String modelPath = getModelLibrary();
|
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
|
return ApiResponse.failure("请先创建或导入模型库");
|
|
|
|
|
|
}
|
|
|
|
|
|
String sql = "DELETE FROM model WHERE id = ?";
|
|
|
|
|
|
List<Object> params = new ArrayList<>();
|
|
|
|
|
|
params.add(modelId);
|
|
|
|
|
|
SQLiteUtil.executeUpdate(modelPath, sql, params);
|
|
|
|
|
|
return ApiResponse.success(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 15:10:29 +08:00
|
|
|
|
@Operation(summary = "拖动层级")
|
|
|
|
|
|
@PostMapping("/dragModelType")
|
|
|
|
|
|
public ApiResponse dragModelType(@RequestBody List<DragModelTypeDto> dragModelTypeDtoList) throws SQLException, IllegalAccessException, InstantiationException {
|
|
|
|
|
|
String modelPath = getModelLibrary();
|
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
|
return ApiResponse.failure("请先创建或导入模型库");
|
|
|
|
|
|
}
|
|
|
|
|
|
// 遍历数据列表
|
|
|
|
|
|
for (DragModelTypeDto dragModelTypeDto : dragModelTypeDtoList) {
|
|
|
|
|
|
String id = dragModelTypeDto.getId();
|
|
|
|
|
|
String parentId = dragModelTypeDto.getParentId();
|
|
|
|
|
|
String treeIndex = dragModelTypeDto.getTreeIndex();
|
|
|
|
|
|
List<Object> params = new ArrayList<>();
|
|
|
|
|
|
params.add(parentId);
|
|
|
|
|
|
params.add(treeIndex);
|
|
|
|
|
|
params.add(id);
|
|
|
|
|
|
SQLiteUtil.executeUpdate(modelPath, "UPDATE model_type SET parent_id = ?, tree_index = ? WHERE id = ?", params);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 返回树列表
|
|
|
|
|
|
return ApiResponse.success(modelTypeList());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private List<ModelTypeVo> modelTypeList() throws SQLException, IllegalAccessException, InstantiationException {
|
|
|
|
|
|
String modelPath = getModelLibrary();
|
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
String sql = """
|
|
|
|
|
|
SELECT id, name, parent_id as parentId,
|
|
|
|
|
|
tree_index as treeIndex, created_at as createdAt,
|
|
|
|
|
|
updated_at as updatedAt FROM model_type ORDER BY tree_index ASC
|
|
|
|
|
|
""";
|
2025-09-29 13:56:36 +08:00
|
|
|
|
// 查询所有模型的类型
|
2025-09-28 15:10:29 +08:00
|
|
|
|
List<ModelType> modelTypes = SQLiteUtil.queryForList(modelPath, sql, null, ModelType.class);
|
|
|
|
|
|
// 转换为树形结构
|
|
|
|
|
|
return buildModelTypeTree(modelTypes);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-26 13:46:54 +08:00
|
|
|
|
private List<ModelTypeVo> buildModelTypeTree(List<ModelType> modelTypes) {
|
|
|
|
|
|
List<ModelTypeVo> treeNodes = modelTypes.stream()
|
|
|
|
|
|
.map(modelType -> new ModelTypeVo(modelType))
|
|
|
|
|
|
.collect(Collectors.toList());
|
2025-09-29 13:56:36 +08:00
|
|
|
|
|
2025-09-26 13:46:54 +08:00
|
|
|
|
// 构建节点ID到节点的映射
|
|
|
|
|
|
Map<String, ModelTypeVo> nodeMap = treeNodes.stream()
|
|
|
|
|
|
.collect(Collectors.toMap(ModelTypeVo::getId, node -> node));
|
2025-09-29 13:56:36 +08:00
|
|
|
|
|
2025-09-26 13:46:54 +08:00
|
|
|
|
// 根节点列表
|
|
|
|
|
|
List<ModelTypeVo> rootNodes = new ArrayList<>();
|
2025-09-29 13:56:36 +08:00
|
|
|
|
|
2025-09-26 13:46:54 +08:00
|
|
|
|
// 为每个节点添加子节点
|
|
|
|
|
|
for (ModelTypeVo node : treeNodes) {
|
|
|
|
|
|
String parentId = node.getParentId();
|
|
|
|
|
|
if (parentId == null || parentId.isEmpty()) {
|
|
|
|
|
|
// 没有父节点的是根节点
|
|
|
|
|
|
rootNodes.add(node);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 找到父节点并添加为子节点
|
|
|
|
|
|
ModelTypeVo parentNode = nodeMap.get(parentId);
|
|
|
|
|
|
if (parentNode != null) {
|
|
|
|
|
|
parentNode.getChildren().add(node);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-29 13:56:36 +08:00
|
|
|
|
|
|
|
|
|
|
// 排序根节点
|
|
|
|
|
|
rootNodes.sort(Comparator.comparingInt(ModelTypeVo::getTreeIndex));
|
|
|
|
|
|
|
|
|
|
|
|
// 递归排序所有子节点
|
|
|
|
|
|
sortChildren(rootNodes);
|
|
|
|
|
|
|
2025-09-26 13:46:54 +08:00
|
|
|
|
return rootNodes;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 13:56:36 +08:00
|
|
|
|
// 递归排序所有子节点
|
|
|
|
|
|
private void sortChildren(List<ModelTypeVo> nodes) {
|
|
|
|
|
|
if (nodes == null || nodes.isEmpty()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 排序当前层级节点
|
|
|
|
|
|
nodes.sort(Comparator.comparingInt(ModelTypeVo::getTreeIndex));
|
|
|
|
|
|
// 递归排序下一层级
|
|
|
|
|
|
for (ModelTypeVo node : nodes) {
|
|
|
|
|
|
sortChildren(node.getChildren());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-26 13:46:54 +08:00
|
|
|
|
private String getModelLibrary() {
|
|
|
|
|
|
// 获取启用的模型库
|
|
|
|
|
|
LambdaQueryWrapper<ModelLibrary> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
|
queryWrapper.eq(ModelLibrary::getIsEnable, 1);
|
|
|
|
|
|
ModelLibrary modelLibrary = modelLibraryService.getOne(queryWrapper);
|
|
|
|
|
|
if (modelLibrary == null) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
return modelLibrary.getPath();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void addModelLibrary(String modelPath) {
|
|
|
|
|
|
// 查询系统所有的模型库
|
|
|
|
|
|
List<ModelLibrary> modelLibraries = modelLibraryService.list();
|
|
|
|
|
|
// 遍历并更新状态
|
|
|
|
|
|
for (ModelLibrary modelLibrary : modelLibraries) {
|
|
|
|
|
|
// 设置启用状态为0
|
|
|
|
|
|
modelLibrary.setIsEnable(0);
|
|
|
|
|
|
modelLibraryService.updateById(modelLibrary);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查相同路径的模型库是否已存在
|
|
|
|
|
|
LambdaQueryWrapper<ModelLibrary> pathWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
|
pathWrapper.eq(ModelLibrary::getPath, modelPath);
|
|
|
|
|
|
ModelLibrary existingModel = modelLibraryService.getOne(pathWrapper);
|
|
|
|
|
|
// 若存在相同路径的模型库、不做处理、仅仅更新状态为显示
|
|
|
|
|
|
if (existingModel != null) {
|
|
|
|
|
|
existingModel.setIsEnable(1);
|
|
|
|
|
|
modelLibraryService.updateById(existingModel);
|
|
|
|
|
|
return;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 新增模型库
|
|
|
|
|
|
ModelLibrary newModel = new ModelLibrary();
|
|
|
|
|
|
File file = FileUtil.file(modelPath);
|
|
|
|
|
|
newModel.setId(UUID.fastUUID().toString(true));
|
|
|
|
|
|
newModel.setPath(modelPath);
|
|
|
|
|
|
newModel.setName(FileUtil.extName(file));
|
|
|
|
|
|
newModel.setIsEnable(1);
|
|
|
|
|
|
modelLibraryService.save(newModel);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-29 13:56:36 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 根据模型分类ID、查询该分类ID及其所有子分类ID的列表(递归包含所有层级子分类)
|
|
|
|
|
|
*/
|
|
|
|
|
|
private List<String> getModelTypeIdsWithChildren(String modelTypeId) throws SQLException, IllegalAccessException, InstantiationException {
|
|
|
|
|
|
// 结果列表初始化
|
|
|
|
|
|
List<String> typeIdList = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
|
|
// 校验入参:分类ID不能为空
|
|
|
|
|
|
if (StringUtils.isEmpty(modelTypeId)) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前启用的模型库路径
|
|
|
|
|
|
String modelPath = getModelLibrary();
|
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 校验目标分类ID是否存在(避免无效ID导致递归无结果)
|
|
|
|
|
|
if (!isModelTypeExist(modelPath, modelTypeId)) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 递归查询: 收集当前分类及所有子分类ID
|
|
|
|
|
|
recursiveGetChildIds(modelPath, modelTypeId, typeIdList);
|
|
|
|
|
|
|
|
|
|
|
|
return typeIdList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 递归查询子分类ID、并将结果存入列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void recursiveGetChildIds(String modelPath, String currentTypeId, List<String> resultList) throws SQLException, IllegalAccessException, InstantiationException {
|
|
|
|
|
|
// 先将当前分类ID加入结果列表(确保包含自身)
|
|
|
|
|
|
resultList.add(currentTypeId);
|
|
|
|
|
|
|
|
|
|
|
|
// 查询当前分类的「直接子分类」(按 tree_index 排序、保持树形结构原有顺序)
|
|
|
|
|
|
String childSql = "SELECT id FROM model_type WHERE parent_id = ? ORDER BY tree_index ASC";
|
|
|
|
|
|
List<Object> childParams = new ArrayList<>();
|
|
|
|
|
|
childParams.add(currentTypeId);
|
|
|
|
|
|
List<ModelType> childModelTypes = SQLiteUtil.queryForList(
|
|
|
|
|
|
modelPath, childSql, childParams, ModelType.class
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 若存在子分类、递归查询每个子分类的子分类
|
|
|
|
|
|
if (childModelTypes != null && !childModelTypes.isEmpty()) {
|
|
|
|
|
|
for (ModelType childType : childModelTypes) {
|
|
|
|
|
|
recursiveGetChildIds(modelPath, childType.getId(), resultList);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 校验模型分类ID是否存在于模型库中
|
|
|
|
|
|
*/
|
|
|
|
|
|
private boolean isModelTypeExist(String modelPath, String typeId)
|
|
|
|
|
|
throws SQLException, IllegalAccessException, InstantiationException {
|
|
|
|
|
|
String checkSql = "SELECT id FROM model_type WHERE id = ?";
|
|
|
|
|
|
List<Object> checkParams = new ArrayList<>();
|
|
|
|
|
|
checkParams.add(typeId);
|
|
|
|
|
|
List<ModelType> existTypes = SQLiteUtil.queryForList(modelPath, checkSql, checkParams, ModelType.class);
|
|
|
|
|
|
// 若查询结果非空、说明分类存在
|
|
|
|
|
|
return existTypes != null && !existTypes.isEmpty();
|
|
|
|
|
|
}
|
2025-09-29 17:34:21 +08:00
|
|
|
|
|
|
|
|
|
|
private String trimDot(String str) {
|
|
|
|
|
|
if (str == null) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
return str.startsWith(".") ? str.substring(1) : str;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-26 13:46:54 +08:00
|
|
|
|
}
|