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.IconLibrary; import com.yj.earth.business.domain.IconType; import com.yj.earth.business.service.FileInfoService; import com.yj.earth.business.service.IconLibraryService; import com.yj.earth.common.util.ApiResponse; import com.yj.earth.common.util.SQLiteUtil; import com.yj.earth.dto.iconLibrary.AddIconTypeDto; import com.yj.earth.dto.iconLibrary.CreateIconLibraryDto; import com.yj.earth.dto.iconLibrary.DragIconTypeDto; import com.yj.earth.dto.iconLibrary.UpdateIconTypeNameDto; import com.yj.earth.vo.IconTypeVo; import com.yj.earth.vo.IconVo; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; 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; import java.sql.SQLException; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Tag(name = "图标库管理") @CheckAuth @RestController @RequestMapping("/iconLibrary") public class IconLibraryController { @Resource private IconLibraryService iconLibraryService; @Resource private FileInfoService fileInfoService; @Operation(summary = "创建图标库") @PostMapping("/createIconLibrary") public ApiResponse createIconLibrary(@RequestBody CreateIconLibraryDto createIconLibraryDto) { try { // 参数校验与路径处理 String folderPath = createIconLibraryDto.getPath(); String iconName = createIconLibraryDto.getName(); File parentDir = new File(folderPath); File iconFile = new File(parentDir, iconName); String iconPath = iconFile.getAbsolutePath().replace("\\", "/"); // 检查父目录(不存在则创建) if (!parentDir.exists()) { boolean mkdirsSuccess = parentDir.mkdirs(); if (!mkdirsSuccess) { return ApiResponse.failure("创建图标库父目录失败:" + folderPath); } } // 检查图标库文件是否已存在 if (iconFile.exists()) { if (iconFile.isDirectory()) { return ApiResponse.failure("同名目录已存在、无法创建图标库文件:" + iconPath); } return ApiResponse.failure("图标库文件已存在:" + iconPath); } // 创建图标库文件 boolean createSuccess = iconFile.createNewFile(); if (!createSuccess) { return ApiResponse.failure("创建图标库文件失败:" + iconPath); } // 新增图标库记录并初始化SQLite表结构 addIconLibrary(iconPath); SQLiteUtil.initializationIcon(iconPath); return ApiResponse.success(null); } catch (Exception e) { return ApiResponse.failure("创建图标库失败:" + e.getMessage()); } } @Operation(summary = "导入图标库") @PostMapping("/importIconLibrary") public ApiResponse importIconLibrary(@RequestParam("iconPath") @Parameter(description = "图标库路径") String iconPath) { addIconLibrary(iconPath); return ApiResponse.success(null); } @Operation(summary = "添加图标类型") @PostMapping("/addIconType") public ApiResponse addIconType(@RequestBody AddIconTypeDto addIconTypeDto) throws SQLException, IllegalAccessException, InstantiationException { String iconPath = getIconLibrary(); if (iconPath == null) { return ApiResponse.failure("请先创建或导入图标库"); } // 检查父级图标类型是否存在 String parentId = addIconTypeDto.getParentId(); if (parentId != null) { String sql = "SELECT * FROM icon_type WHERE id = ?"; List params = new ArrayList<>(); params.add(parentId); IconType iconType = SQLiteUtil.queryForObject(iconPath, sql, params, IconType.class); if (iconType == null) { return ApiResponse.failure("父级图标类型不存在"); } } // 插入图标类型 String sql = "INSERT INTO icon_type " + "(id, name, parent_id, tree_index, created_at) " + "VALUES (?, ?, ?, ?, ?)"; List params = new ArrayList<>(); params.add(UUID.fastUUID().toString(true)); params.add(addIconTypeDto.getName()); params.add(addIconTypeDto.getParentId()); params.add(0); params.add(LocalDateTime.now()); SQLiteUtil.executeUpdate(iconPath, sql, params); return ApiResponse.success(null); } @Operation(summary = "删除图标类型") @PostMapping("/deleteIconType") public ApiResponse deleteIconType(@Parameter(description = "图标类型ID") @RequestParam("iconTypeId") String iconTypeId) throws SQLException { String iconPath = getIconLibrary(); if (iconPath == null) { return ApiResponse.failure("请先创建或导入图标库"); } // 删除图标类型 String sql = "DELETE FROM icon_type WHERE id = ?"; List params = new ArrayList<>(); params.add(iconTypeId); SQLiteUtil.executeUpdate(iconPath, sql, params); return ApiResponse.success(null); } @Operation(summary = "修改图标类型名称") @PostMapping("/updateIconTypeName") public ApiResponse updateIconTypeName(@RequestBody UpdateIconTypeNameDto updateIconTypeNameDto) throws SQLException { String iconPath = getIconLibrary(); if (iconPath == null) { return ApiResponse.failure("请先创建或导入图标库"); } // 更新图标类型名称 String sql = "UPDATE icon_type SET name = ? WHERE id = ?"; List params = new ArrayList<>(); params.add(updateIconTypeNameDto.getName()); params.add(updateIconTypeNameDto.getId()); SQLiteUtil.executeUpdate(iconPath, sql, params); return ApiResponse.success(null); } @Operation(summary = "图标类型列表") @GetMapping("/iconTypeTree") public ApiResponse iconTypeTree() throws SQLException, IllegalAccessException, InstantiationException { String iconPath = getIconLibrary(); if (iconPath == null) { return ApiResponse.failure("请先创建或导入图标库"); } // 查询所有图标类型 String sql = """ 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 iconTypes = SQLiteUtil.queryForList(iconPath, sql, null, IconType.class); // 构建树形结构 List treeList = buildIconTypeTree(iconTypes); return ApiResponse.success(treeList); } @Operation(summary = "拖动图标类型树") @PostMapping("/dragIconType") public ApiResponse dragIconType(@RequestBody DragIconTypeDto dragIconTypeDto) throws SQLException { String iconPath = getIconLibrary(); if (iconPath == null) { return ApiResponse.failure("请先创建或导入图标库"); } // 动态构建更新SQL List updateFields = new ArrayList<>(); List params = new ArrayList<>(); if (dragIconTypeDto.getParentId() != null) { updateFields.add("parent_id = ?"); params.add(dragIconTypeDto.getParentId()); } if (dragIconTypeDto.getTreeIndex() != null) { updateFields.add("tree_index = ?"); params.add(dragIconTypeDto.getTreeIndex()); } String sql = "UPDATE icon_type SET " + String.join(", ", updateFields) + " WHERE id = ?"; params.add(dragIconTypeDto.getId()); SQLiteUtil.executeUpdate(iconPath, sql, params); return ApiResponse.success(null); } @Operation(summary = "添加图标文件") @PostMapping("/addIconFile") public ApiResponse addIconFile(@RequestParam("files") MultipartFile[] files, @Parameter(description = "图标类型ID") @RequestParam("iconTypeId") String iconTypeId) throws IOException, SQLException { String iconPath = getIconLibrary(); if (iconPath == 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); // 上传文件并获取访问URL String url = fileInfoService.uploadWithPreview(file); // 插入图标记录 String sql = "INSERT INTO icon " + "(id, icon_type_id, icon_name, icon_type, data, created_at) " + "VALUES (?, ?, ?, ?, ?, ?)"; List params = new ArrayList<>(); params.add(UUID.fastUUID().toString(true)); params.add(iconTypeId); params.add(fileNameWithoutSuffix); params.add(fileSuffix); params.add(url); params.add(LocalDateTime.now()); SQLiteUtil.executeUpdate(iconPath, sql, params); } return ApiResponse.success(null); } @Operation(summary = "根据图标类型查看图标列表") @PostMapping("/iconList") public ApiResponse iconList(@Parameter(description = "图标类型ID") @RequestParam("iconTypeId") String iconTypeId) throws SQLException, IllegalAccessException, InstantiationException { String iconPath = getIconLibrary(); if (iconPath == null) { return ApiResponse.failure("请先创建或导入图标库"); } // 多表联查图标数据 String sql = """ SELECT icon.id, icon.icon_type_id as iconTypeId, icon.icon_name as iconName, icon.icon_type as iconType, icon.data, icon.view, icon.created_at as createdAt, icon.updated_at as updatedAt, icon_type.name as iconTypeName FROM icon JOIN icon_type ON icon.icon_type_id = icon_type.id WHERE icon.icon_type_id = ? """; List params = new ArrayList<>(); params.add(iconTypeId); List iconVos = SQLiteUtil.queryForList(iconPath, sql, params, IconVo.class); return ApiResponse.success(iconVos); } @Operation(summary = "更新图标信息") @PostMapping("/updateIconInfo") public ApiResponse updateIconInfo(@Parameter(description = "图标ID") @RequestParam("iconId") String iconId, @Parameter(description = "图标名称") @RequestParam(value = "iconName", required = false) String iconName) throws SQLException { String iconPath = getIconLibrary(); if (iconPath == null) { return ApiResponse.failure("请先创建或导入图标库"); } // 无更新字段直接返回成功 if (!StringUtils.hasText(iconName)) { return ApiResponse.success(null); } // 更新图标名称 String sql = "UPDATE icon SET updated_at = ?, icon_name = ? WHERE id = ?"; List params = new ArrayList<>(); params.add(LocalDateTime.now()); params.add(iconName); params.add(iconId); SQLiteUtil.executeUpdate(iconPath, sql, params); return ApiResponse.success(null); } @Operation(summary = "删除图标") @PostMapping("/deleteIcon") public ApiResponse deleteIcon(@Parameter(description = "图标ID") @RequestParam("iconId") String iconId) throws SQLException { String iconPath = getIconLibrary(); if (iconPath == null) { return ApiResponse.failure("请先创建或导入图标库"); } // 删除图标 String sql = "DELETE FROM icon WHERE id = ?"; List params = new ArrayList<>(); params.add(iconId); SQLiteUtil.executeUpdate(iconPath, sql, params); return ApiResponse.success(null); } /** * 构建图标类型树形结构 * * @param iconTypes 图标类型列表 * @return 树形结构列表 */ private List buildIconTypeTree(List iconTypes) { // 转换为VO列表 List treeNodes = iconTypes.stream() .map(IconTypeVo::new) .collect(Collectors.toList()); // 构建ID到VO的映射(便于快速查找父节点) Map nodeMap = treeNodes.stream() .collect(Collectors.toMap(IconTypeVo::getId, node -> node)); // 组装树形结构 List rootNodes = new ArrayList<>(); for (IconTypeVo node : treeNodes) { String parentId = node.getParentId(); if (parentId == null || parentId.isEmpty()) { // 无父节点 → 根节点 rootNodes.add(node); } else { // 有父节点 → 加入父节点的子列表 IconTypeVo parentNode = nodeMap.get(parentId); if (parentNode != null) { parentNode.getChildren().add(node); } } } return rootNodes; } /** * 获取当前启用的图标库路径 * * @return 图标库路径(null表示无启用的图标库) */ private String getIconLibrary() { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(IconLibrary::getIsEnable, 1); IconLibrary iconLibrary = iconLibraryService.getOne(queryWrapper); return iconLibrary == null ? null : iconLibrary.getPath(); } private void addIconLibrary(String iconPath) { // 查询所有图标库并置为禁用 List iconLibraries = iconLibraryService.list(); for (IconLibrary iconLibrary : iconLibraries) { iconLibrary.setIsEnable(0); iconLibraryService.updateById(iconLibrary); } // 检查路径是否已存在(存在则启用、不存在则新增) LambdaQueryWrapper pathWrapper = new LambdaQueryWrapper<>(); pathWrapper.eq(IconLibrary::getPath, iconPath); IconLibrary existingIconLib = iconLibraryService.getOne(pathWrapper); if (existingIconLib != null) { existingIconLib.setIsEnable(1); iconLibraryService.updateById(existingIconLib); } else { // 新增图标库记录 IconLibrary newIconLib = new IconLibrary(); File iconFile = FileUtil.file(iconPath); newIconLib.setId(UUID.fastUUID().toString(true)); newIconLib.setPath(iconPath); newIconLib.setName(FileUtil.extName(iconFile)); newIconLib.setIsEnable(1); iconLibraryService.save(newIconLib); } } }