@ -6,19 +6,24 @@ 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.FileCommonUtil ;
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.IconDataVo ;
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.http.HttpHeaders ;
import org.springframework.http.HttpStatus ;
import org.springframework.http.MediaType ;
import org.springframework.http.ResponseEntity ;
import org.springframework.util.StringUtils ;
import org.springframework.web.bind.annotation.* ;
import org.springframework.web.multipart.MultipartFile ;
@ -26,9 +31,12 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource ;
import java.io.File ;
import java.io.IOException ;
import java.net.URLEncoder ;
import java.nio.charset.StandardCharsets ;
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.stream.Collectors ;
@ -38,47 +46,52 @@ import java.util.stream.Collectors;
@RestController
@RequestMapping ( " /iconLibrary " )
public class IconLibraryController {
@Resource
private IconLibraryService iconLibraryService ;
@Resource
private FileInfoService fileInfoService ;
@Operation ( summary = " 创建图标库 " )
@PostMapping ( " /createIconLibrary " )
public ApiResponse createIconLibrary ( @RequestBody CreateIconLibraryDto createIconLibrary Dto ) {
public ApiResponse createIconLibrary ( @RequestBody CreateIconLibraryDto createDto ) {
try {
// 参数校验与路径处理
String folderPath = createIconLibrary Dto . getPath ( ) ;
String icon Name = createIconLibrary Dto . getName ( ) ;
String folderPath = createDto . getPath ( ) ;
String library Name = createDto . getName ( ) ;
if ( ! StringUtils . hasText ( folderPath ) | | ! StringUtils . hasText ( libraryName ) ) {
return ApiResponse . failure ( " 路径和名称不能为空 " ) ;
}
// 构建完整图标库文件路径( SQLite文件)
File parentDir = new File ( folderPath ) ;
File iconFile = new File ( parentDir , icon Name) ;
File iconFile = new File ( parentDir , library Name) ;
String iconPath = iconFile . getAbsolutePath ( ) . replace ( " \\ " , " / " ) ;
// 检查 父目录( 不存在则创建)
// 父目录不存在则创建
if ( ! parentDir . exists ( ) ) {
boolean mkdirsSuccess = parentDir . mkdirs ( ) ;
if ( ! mkdirsSuccess ) {
return ApiResponse . failure ( " 创建图标库 父目录失败: " + folderPath ) ;
return ApiResponse . failure ( " 创建父目录失败: " + folderPath ) ;
}
}
// 检查 图标库文件是否已存在
// 校验 图标库文件是否已存在
if ( iconFile . exists ( ) ) {
if ( iconFile . isDirectory ( ) ) {
return ApiResponse . failure ( " 同名目录已存在、 无法创建图标库 文件: " + iconPath ) ;
return ApiResponse . failure ( " 同名目录已存在, 无法创建文件: " + iconPath ) ;
}
return ApiResponse . failure ( " 图标库文件已存在: " + iconPath ) ;
}
// 创建图标库 文件
boolean createSuccess = iconFile . createNewFile ( ) ;
if ( ! createSuccess ) {
// 创建SQLite 文件
boolean createFile Success = iconFile . createNewFile ( ) ;
if ( ! createFile Success ) {
return ApiResponse . failure ( " 创建图标库文件失败: " + iconPath ) ;
}
// 新增图标库记录并初始化SQLite 表结构
addIconLibrary ( iconPath ) ;
// 初始化图标库 表结构
SQLiteUtil . initializationIcon ( iconPath ) ;
// 添加图标库配置到数据库
addIconLibrary ( iconPath ) ;
return ApiResponse . success ( null ) ;
} catch ( Exception e ) {
return ApiResponse . failure ( " 创建图标库失败: " + e . getMessage ( ) ) ;
@ -87,311 +100,441 @@ public class IconLibraryController {
@Operation ( summary = " 导入图标库 " )
@PostMapping ( " /importIconLibrary " )
public ApiResponse importIconLibrary ( @RequestParam ( " iconPath " ) @Parameter ( description = " 图标库路径 " ) String iconPath ) {
addIconLibrary ( iconPath ) ;
return ApiResponse . success ( null ) ;
public ApiResponse importIconLibrary (
@RequestParam ( " iconPath " ) @Parameter ( description = " 图标库SQLite文件路径 " ) String iconPath ) {
try {
// 校验路径是否存在
File iconFile = new File ( iconPath ) ;
if ( ! iconFile . exists ( ) | | ! iconFile . isFile ( ) ) {
return ApiResponse . failure ( " 图标库文件不存在: " + iconPath ) ;
}
// 添加到配置表并启用
addIconLibrary ( iconPath ) ;
return ApiResponse . success ( null ) ;
} catch ( Exception e ) {
return ApiResponse . failure ( " 导入图标库失败: " + e . getMessage ( ) ) ;
}
}
@Operation ( summary = " 添加图标类型 " )
@PostMapping ( " /addIconType " )
public ApiResponse addIconType ( @RequestBody AddIconTypeDto addIconType Dto ) throws SQLException , IllegalAccessException , InstantiationException {
public ApiResponse addIconType ( @RequestBody AddIconTypeDto addDto ) throws SQLException , IllegalAccessException , InstantiationException {
// 获取当前启用的图标库路径
String iconPath = getIconLibrary ( ) ;
if ( iconPath = = null ) {
return ApiResponse . failure ( " 请先创建或导入图标库 " ) ;
}
// 检查父级图标类型是否存在
String parentId = addIconType Dto . getParentId ( ) ;
if ( parentId ! = null ) {
String s ql = " SELECT * FROM icon_type WHERE id = ? " ;
List < Object > params = new ArrayList < > ( ) ;
params . add ( parentId ) ;
IconType icon Type = SQLiteUtil . queryForObject ( iconPath , sql , params , IconType . class ) ;
if ( iconType = = null ) {
return ApiResponse . failure ( " 父级图标类型不存在 " ) ;
// 校验父级类型(若有)
String parentId = addDto . getParentId ( ) ;
if ( StringUtils . hasText ( parentId ) ) {
String checkParentS ql = " SELECT id FROM icon_type WHERE id = ? " ;
List < Object > parentPar ams = new ArrayList < > ( ) ;
parentPar ams . add ( parentId ) ;
IconType parent Type = SQLiteUtil . queryForObject (
iconPath , checkParentSql , parentParams , IconType . class
) ;
if ( parentType = = null ) {
return ApiResponse . failure ( " 父级图标类型不存在: " + parentId ) ;
}
}
// 插入图标类型
String s ql = " INSERT INTO icon_type " +
String insertS ql = " INSERT INTO icon_type " +
" (id, name, parent_id, tree_index, created_at) " +
" VALUES (?, ?, ?, ?, ?) " ;
List < Object > params = new ArrayList < > ( ) ;
params . add ( UUID . fastUUID ( ) . toString ( true ) ) ;
params . add ( addIconType Dto . getName ( ) ) ;
params . add ( addIconTypeDto . getP arentId( ) );
params . add ( addDto . getName ( ) ) ;
params . add ( p arentId) ;
params . add ( 0 ) ;
params . add ( LocalDateTime . now ( ) ) ;
SQLiteUtil . executeUpdate ( iconPath , s ql, 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 < Object > params = new ArrayList < > ( ) ;
params . add ( iconTypeId ) ;
SQLiteUtil . executeUpdate ( iconPath , sql , params ) ;
params . add ( LocalDateTime . now ( ) . toString ( ) );
SQLiteUtil . executeUpdate ( iconPath , insertS ql, 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 < Object > 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 < IconType > iconTypes = SQLiteUtil . queryForList ( iconPath , sql , null , IconType . class ) ;
// 构建树形结构
List < IconTypeVo > 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 < String > updateFields = new ArrayList < > ( ) ;
List < Object > 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 < Object > 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 < Object > params = new ArrayList < > ( ) ;
params . add ( iconTypeId ) ;
List < IconVo > 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 )
public ApiResponse updateIconTypeName ( @RequestBody UpdateIconTypeNameDto updateDto )
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 = ? " ;
// 执行更新
String updateSql = " UPDATE icon_type SET name = ?, updated_at = ? WHERE id = ? " ;
List < Object > params = new ArrayList < > ( ) ;
params . add ( LocalDateTime . now ( ) ) ;
params . add ( iconName ) ;
params . add ( iconId ) ;
SQLiteUtil . executeUpdate ( iconPath , s ql, params ) ;
params . add ( updateDto . getName ( ) ) ;
params . add ( LocalDateTime . now ( ) . toString ( ) ) ;
params . add ( updateDto . getId ( ) ) ;
SQLiteUtil . executeUpdate ( iconPath , updateS ql, params ) ;
return ApiResponse . success ( null ) ;
}
@Operation ( summary = " 删除图标 " )
@PostMapping ( " /deleteIcon " )
public ApiResponse deleteIcon (@Parameter ( description = " 图标ID " ) @RequestParam ( " iconId " ) String iconId ) throws SQLException {
@Operation ( summary = " 删除图标类型 " )
@PostMapping ( " /deleteIconType " )
public ApiResponse deleteIconType (
@RequestParam ( " iconTypeId " ) @Parameter ( description = " 图标类型ID " ) String typeId )
throws SQLException {
String iconPath = getIconLibrary ( ) ;
if ( iconPath = = null ) {
return ApiResponse . failure ( " 请先创建或导入图标库 " ) ;
}
// 删除图标
String s ql = " DELETE FROM icon WHERE id = ? " ;
// 执行 删除
String deleteS ql = " DELETE FROM icon_type WHERE id = ? " ;
List < Object > params = new ArrayList < > ( ) ;
params . add ( icon Id) ;
SQLiteUtil . executeUpdate ( iconPath , sql , params ) ;
params . add ( type Id) ;
SQLiteUtil . executeUpdate ( iconPath , deleteSql , params ) ;
return ApiResponse . success ( null ) ;
}
/**
* 构建图标类型树形结构
*
* @param iconTypes 图标类型列表
* @ return 树形结构列表
*/
private List < IconTypeVo > buildIconTypeTree ( List < IconType > iconTypes ) {
// 转换为VO列表
List < IconTypeVo > treeNodes = iconTypes . stream ( )
. map ( IconTypeVo : : new )
. collect ( Collectors . toList ( ) ) ;
// 构建ID到VO的映射( 便于快速查找父节点)
Map < String , IconTypeVo > nodeMap = treeNodes . stream ( )
. collect ( Collectors . toMap ( IconTypeVo : : getId , node - > node ) ) ;
// 组装树形结构
List < IconTypeVo > 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 ;
@Operation ( summary = " 图标类型树形列表 " )
@GetMapping ( " /iconTypeTree " )
public ApiResponse iconTypeTree ( ) throws SQLException , IllegalAccessException , InstantiationException {
List < IconTypeVo > treeList = iconTypeList ( ) ;
return ApiResponse . success ( treeList ) ;
}
@Operation ( summary = " 添加图标文件 " )
@PostMapping ( " /addIconFile " )
public ApiResponse addIconFile ( @RequestParam ( " files " ) MultipartFile [ ] files , @RequestParam ( " iconTypeId " ) @Parameter ( description = " 图标类型ID " ) String typeId ) throws IOException , SQLException , IllegalAccessException , InstantiationException {
// 获取当前启用的图标库
String iconPath = getIconLibrary ( ) ;
if ( iconPath = = null ) {
return ApiResponse . failure ( " 请先创建或导入图标库 " ) ;
}
// 校验类型是否存在
if ( ! is IconTypeExist ( iconPath , typeId ) ) {
return ApiResponse . failure ( " 图标类型不存在: " + typeId ) ;
}
// 循环处理每个文件
for ( MultipartFile file : files ) {
if ( file . isEmpty ( ) ) {
continue ; // 跳过空文件
}
// 解析文件名与后缀
String originalFileName = file . getOriginalFilename ( ) ;
if ( originalFileName = = null ) {
continue ;
}
String fileSuffix = FileUtil . extName ( originalFileName ) ;
String fileNameWithoutSuffix = FileUtil . mainName ( originalFileName ) ;
// 插入图标数据
String insertSql = " INSERT INTO icon " +
" (id, icon_type_id, icon_name, icon_type, icon_data, created_at) " +
" VALUES (?, ?, ?, ?, ?, ?) " ;
List < Object > params = new ArrayList < > ( ) ;
params . add ( UUID . fastUUID ( ) . toString ( true ) ) ;
params . add ( typeId ) ;
params . add ( fileNameWithoutSuffix ) ;
params . add ( fileSuffix ) ;
params . add ( file . getBytes ( ) ) ;
params . add ( LocalDateTime . now ( ) . toString ( ) ) ;
SQLiteUtil . executeUpdate ( iconPath , insertSql , params ) ;
}
return ApiResponse . success ( null ) ;
}
@Operation ( summary = " 获取图标文件数据 " )
@GetMapping ( " /data/icon/{iconId}/{fileSuffix} " )
public ResponseEntity < byte [ ] > getIconData ( @PathVariable ( " iconId " ) @Parameter ( description = " 图标ID " ) String iconId , @PathVariable ( " fileSuffix " ) @Parameter ( description = " 图标文件后缀 " ) String fileSuffix ) {
try {
String iconPath = getIconLibrary ( ) ;
if ( iconPath = = null ) {
return ResponseEntity . notFound ( ) . build ( ) ;
}
// 查询图标二进制数据
String querySql = " SELECT icon_name, icon_data FROM icon WHERE id = ? " ;
List < Object > params = new ArrayList < > ( ) ;
params . add ( iconId ) ;
IconDataVo dataVo = SQLiteUtil . queryForObject (
iconPath , querySql , params , IconDataVo . class
) ;
if ( dataVo = = null | | dataVo . getIconData ( ) = = null ) {
return ResponseEntity . notFound ( ) . build ( ) ;
}
// 构建响应头【支持中文文件名+预览】
String originalFileName = dataVo . getIconName ( ) + " . " + fileSuffix ;
String encodedFileName = URLEncoder . encode ( originalFileName , StandardCharsets . UTF_8 . name ( ) ) ;
MediaType contentType = FileCommonUtil . getImageMediaType ( fileSuffix ) ;
return ResponseEntity . ok ( )
. contentType ( contentType )
. header ( HttpHeaders . CONTENT_DISPOSITION ,
" inline; filename= \" " + encodedFileName + " \" " )
. body ( dataVo . getIconData ( ) ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
return ResponseEntity . status ( HttpStatus . INTERNAL_SERVER_ERROR ) . build ( ) ;
}
}
@Operation ( summary = " 根据类型查询图标列表 " )
@PostMapping ( " /iconList " )
public ApiResponse getIconList ( @RequestParam ( " iconTypeId " ) @Parameter ( description = " 图标类型ID " ) String typeId ) throws SQLException , IllegalAccessException , InstantiationException {
String iconPath = getIconLibrary ( ) ;
if ( iconPath = = null ) {
return ApiResponse . failure ( " 请先创建或导入图标库 " ) ;
}
// 获取当前类型及所有子类型ID( 递归)
List < String > typeIdList = getIconTypeIdsWithChildren ( typeId ) ;
if ( typeIdList = = null | | typeIdList . isEmpty ( ) ) {
return ApiResponse . success ( new ArrayList < > ( ) ) ;
}
// 构建IN条件( 处理SQL注入风险)
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 ) ;
// 查询并转换为VO
List < IconVo > iconVoList = SQLiteUtil . queryForList (
iconPath , querySql , null , IconVo . class
) ;
for ( IconVo vo : iconVoList ) {
vo . setIconDataUrl ( " /iconLibrary/data/icon/ " + vo . getId ( ) + " / " + vo . getIconType ( ) ) ;
}
return ApiResponse . success ( iconVoList ) ;
}
@Operation ( summary = " 更新图标名称 " )
@PostMapping ( " /updateIconInfo " )
public ApiResponse updateIconInfo (
@RequestParam ( " iconId " ) @Parameter ( description = " 图标ID " ) String iconId ,
@RequestParam ( " iconName " ) @Parameter ( description = " 新图标名称 " ) String iconName )
throws SQLException {
String iconPath = getIconLibrary ( ) ;
if ( iconPath = = null ) {
return ApiResponse . failure ( " 请先创建或导入图标库 " ) ;
}
String updateSql = " UPDATE icon SET icon_name = ?, updated_at = ? WHERE id = ? " ;
List < Object > params = new ArrayList < > ( ) ;
params . add ( iconName ) ;
params . add ( LocalDateTime . now ( ) . toString ( ) ) ;
params . add ( iconId ) ;
SQLiteUtil . executeUpdate ( iconPath , updateSql , params ) ;
return ApiResponse . success ( null ) ;
}
@Operation ( summary = " 删除图标 " )
@PostMapping ( " /deleteIcon " )
public ApiResponse deleteIcon ( @RequestParam ( " iconId " ) @Parameter ( description = " 图标ID " ) String iconId ) throws SQLException {
String iconPath = getIconLibrary ( ) ;
if ( iconPath = = null ) {
return ApiResponse . failure ( " 请先创建或导入图标库 " ) ;
}
// 执行删除
String deleteSql = " DELETE FROM icon WHERE id = ? " ;
List < Object > params = new ArrayList < > ( ) ;
params . add ( iconId ) ;
SQLiteUtil . executeUpdate ( iconPath , deleteSql , params ) ;
return ApiResponse . success ( " 删除图标成功 " ) ;
}
@Operation ( summary = " 拖动调整图标类型层级 " )
@PostMapping ( " /dragIconType " )
public ApiResponse dragIconType ( @RequestBody List < DragIconTypeDto > dragDtoList )
throws SQLException , IllegalAccessException , InstantiationException {
String iconPath = getIconLibrary ( ) ;
if ( iconPath = = null ) {
return ApiResponse . failure ( " 请先创建或导入图标库 " ) ;
}
// 批量更新层级和排序
for ( DragIconTypeDto dto : dragDtoList ) {
String updateSql = " UPDATE icon_type " +
" SET parent_id = ?, tree_index = ?, updated_at = ? " +
" WHERE id = ? " ;
List < Object > params = new ArrayList < > ( ) ;
params . add ( dto . getParentId ( ) ) ;
params . add ( dto . getTreeIndex ( ) ) ;
params . add ( LocalDateTime . now ( ) . toString ( ) ) ;
params . add ( dto . getId ( ) ) ;
SQLiteUtil . executeUpdate ( iconPath , updateSql , params ) ;
}
// 返回更新后的树形列表
List < IconTypeVo > treeList = iconTypeList ( ) ;
return ApiResponse . success ( treeList ) ;
}
/**
* 获取当前启用的图标库路径
*
* @return 图标库路径( null表示无启用的图标库)
*/
private String getIconLibrary ( ) {
LambdaQueryWrapper < IconLibrary > queryWrapper = new LambdaQueryWrapper < > ( ) ;
queryWrapper . eq ( IconLibrary : : getIsEnable , 1 ) ;
IconLibrary iconL ibrary = iconLibraryService . getOne ( queryWrapper ) ;
return iconL ibrary = = null ? null : iconL ibrary. getPath ( ) ;
queryWrapper . eq ( IconLibrary : : getIsEnable , 1 ) ; // 1=启用, 0=未启用
IconLibrary l ibrary = iconLibraryService . getOne ( queryWrapper ) ;
return l ibrary = = null ? null : l ibrary. getPath ( ) ;
}
private void addIconLibrary ( String iconPath ) {
// 查询 所有图标库并 置为禁用
List < IconLibrary > icon Libraries = iconLibraryService . list ( ) ;
for ( IconLibrary iconL ibrary : icon Libraries) {
iconL ibrary. setIsEnable ( 0 ) ;
iconLibraryService . updateById ( iconL ibrary) ;
// 所有已存在的 图标库设 置为「未启用」
List < IconLibrary > exist Libraries = iconLibraryService . list ( ) ;
for ( IconLibrary l ibrary : exist Libraries) {
l ibrary. setIsEnable ( 0 ) ;
iconLibraryService . updateById ( l ibrary) ;
}
// 检查路径是否已存在(存在则启用、 不存在则新增)
// 检查路径是否已存在(存在则启用, 不存在则新增)
LambdaQueryWrapper < IconLibrary > pathWrapper = new LambdaQueryWrapper < > ( ) ;
pathWrapper . eq ( IconLibrary : : getPath , iconPath ) ;
IconLibrary existingIconLib = iconLibraryService . getOne ( pathWrapper ) ;
IconLibrary existLibrary = iconLibraryService . getOne ( pathWrapper ) ;
if ( existingIconLib ! = null ) {
existingIconLib . setIsEnable ( 1 ) ;
iconLibraryService . updateById ( existingIconLib ) ;
if ( existLibrary ! = null ) {
existLibrary . setIsEnable ( 1 ) ;
iconLibraryService . updateById ( existLibrary ) ;
} else {
// 新增图标库记录
Icon Library newIconLib = new IconLibrary ( ) ;
File iconFile = FileUtil . file ( iconPath ) ;
newIconLib . setId ( UUID . fastUUID ( ) . toString ( true ) ) ;
newIconLib . setPath ( iconPath ) ;
newIconLib . setName ( FileUtil . extName ( iconFile ) ) ;
newI conLib. setIsEnable ( 1 ) ;
iconLibraryService . save ( newIconLib ) ;
IconLibrary newLibrary = new IconLibrary ( ) ;
new Library. setId ( UUID . fastUUID ( ) . toString ( true ) ) ;
newLibrary . setPath ( iconPath ) ;
newLibrary . setName ( FileUtil . mainName ( iconPath ) ) ;
newLibrary . setIsEnable ( 1 ) ;
newLibrary . setCreatedAt ( LocalDateTime . now ( ) ) ;
i conLibraryService . save ( newLibrary ) ;
}
}
private List < IconTypeVo > iconTypeList ( ) throws SQLException , IllegalAccessException , InstantiationException {
String iconPath = getIconLibrary ( ) ;
if ( iconPath = = null ) {
return new ArrayList < > ( ) ;
}
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 ) ;
// 构建树形结构
return buildIconTypeTree ( typeList ) ;
}
private List < IconTypeVo > buildIconTypeTree ( List < IconType > typeList ) {
// 转换为VO
List < IconTypeVo > voList = typeList . stream ( )
. map ( iconType - > new IconTypeVo ( iconType ) ) . collect ( Collectors . toList ( ) ) ;
// 构建ID→VO的映射( 方便快速查找父级)
Map < String , IconTypeVo > voMap = voList . stream ( )
. collect ( Collectors . toMap ( IconTypeVo : : getId , vo - > vo ) ) ;
// 组装树形结构
List < IconTypeVo > rootList = new ArrayList < > ( ) ;
for ( IconTypeVo vo : voList ) {
String parentId = vo . getParentId ( ) ;
if ( parentId = = null | | parentId . isEmpty ( ) ) {
rootList . add ( vo ) ;
} else {
IconTypeVo parentVo = voMap . get ( parentId ) ;
if ( parentVo ! = null ) {
parentVo . getChildren ( ) . add ( vo ) ;
}
}
}
// 排序
rootList . sort ( Comparator . comparingInt ( IconTypeVo : : getTreeIndex ) ) ;
sortIconTypeChildren ( rootList ) ;
return rootList ;
}
private void sortIconTypeChildren ( List < IconTypeVo > voList ) {
if ( voList = = null | | voList . isEmpty ( ) ) {
return ;
}
// 排序当前层级
voList . sort ( Comparator . comparingInt ( IconTypeVo : : getTreeIndex ) ) ;
// 递归排序子层级
for ( IconTypeVo vo : voList ) {
sortIconTypeChildren ( vo . getChildren ( ) ) ;
}
}
private List < String > getIconTypeIdsWithChildren ( String typeId )
throws SQLException , IllegalAccessException , InstantiationException {
List < String > idList = new ArrayList < > ( ) ;
if ( ! StringUtils . hasText ( typeId ) ) {
return idList ;
}
String iconPath = getIconLibrary ( ) ;
if ( iconPath = = null ) {
return idList ;
}
// 校验类型是否存在
if ( ! isIconTypeExist ( iconPath , typeId ) ) {
return idList ;
}
// 递归收集ID( 包含自身)
recursiveGetIconTypeChildren ( iconPath , typeId , idList ) ;
return idList ;
}
private void recursiveGetIconTypeChildren ( String iconPath , String currentId , List < String > idList )
throws SQLException , IllegalAccessException , InstantiationException {
// 先添加当前ID
idList . add ( currentId ) ;
// 查询直接子类型
String querySql = " SELECT id FROM icon_type WHERE parent_id = ? ORDER BY tree_index ASC " ;
List < Object > params = new ArrayList < > ( ) ;
params . add ( currentId ) ;
List < IconType > childList = SQLiteUtil . queryForList (
iconPath , querySql , params , IconType . class
) ;
// 递归查询子类型的子类型
if ( childList ! = null & & ! childList . isEmpty ( ) ) {
for ( IconType child : childList ) {
recursiveGetIconTypeChildren ( iconPath , child . getId ( ) , idList ) ;
}
}
}
private boolean isIconTypeExist ( String iconPath , String typeId )
throws SQLException , IllegalAccessException , InstantiationException {
String checkSql = " SELECT id FROM icon_type WHERE id = ? " ;
List < Object > params = new ArrayList < > ( ) ;
params . add ( typeId ) ;
List < IconType > existList = SQLiteUtil . queryForList (
iconPath , checkSql , params , IconType . class
) ;
return existList ! = null & & ! existList . isEmpty ( ) ;
}
}