From 6398b0495e1f2806e21103d7a9d947cffac5b8af Mon Sep 17 00:00:00 2001 From: wangzhiwei Date: Wed, 11 Mar 2026 15:36:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(content):=20=E6=B7=BB=E5=8A=A0=E5=A4=9A?= =?UTF-8?q?=E8=AF=AD=E8=A8=80=E6=94=AF=E6=8C=81=E5=92=8CExcel=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在CmsContent实体类中增加英文标题、描述、介绍和内容字段 - 实现根据语言类型查询内容的功能,支持中英文切换 - 添加从Excel文件批量导入内容数据的功能 - 实现上传技能压缩包并解析生成技能内容的功能 - 优化分页查询逻辑,支持按标签过滤和内存分页 - 修改数据库映射配置以支持多语言字段存储 - 重构点赞功能的安全检查逻辑 --- .../controller/CmsContentController.java | 23 ++ .../skills/controller/SkillGenController.java | 12 + .../com/kexue/skills/entity/CmsContent.java | 12 + .../skills/entity/dto/CmsContentDto.java | 13 +- .../kexue/skills/mapper/CmsContentMapper.java | 16 + .../skills/service/CmsContentService.java | 9 + .../kexue/skills/service/SkillGenService.java | 8 + .../service/impl/CmsContentServiceImpl.java | 284 +++++++++++++++++- .../service/impl/SkillGenServiceImpl.java | 87 ++++++ .../resources/mapper/CmsContentMapper.xml | 81 ++++- 10 files changed, 517 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/kexue/skills/controller/CmsContentController.java b/src/main/java/com/kexue/skills/controller/CmsContentController.java index 0e7f3d2..1721452 100644 --- a/src/main/java/com/kexue/skills/controller/CmsContentController.java +++ b/src/main/java/com/kexue/skills/controller/CmsContentController.java @@ -10,8 +10,10 @@ import com.kexue.skills.service.CmsContentService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import java.io.IOException; /** * (CmsContent)表控制层 @@ -261,4 +263,25 @@ public class CmsContentController { public CommonResult> getUserCreated(@RequestBody CmsContentDto queryDto) { return CommonResult.success(cmsContentService.getPageListByUserCreated(queryDto)); } + + /** + * 导入Excel数据到CmsContent + * + * @param file Excel文件 + * @param createBy 创建人 + * @return 导入结果 + */ + @PostMapping("/importFromExcel") + @Operation(summary = "导入Excel数据", description = "从Excel文件导入数据到CmsContent") + @RequireAuth + public CommonResult importFromExcel(@RequestParam("file") MultipartFile file, @RequestParam("createBy") String createBy) { + try { + byte[] fileBytes = file.getBytes(); + int successCount = cmsContentService.importFromExcel(fileBytes, createBy); + return CommonResult.success(successCount); + } catch (IOException e) { + e.printStackTrace(); + return CommonResult.failed("导入失败:" + e.getMessage()); + } + } } \ No newline at end of file diff --git a/src/main/java/com/kexue/skills/controller/SkillGenController.java b/src/main/java/com/kexue/skills/controller/SkillGenController.java index b6acdc8..b5c37a0 100644 --- a/src/main/java/com/kexue/skills/controller/SkillGenController.java +++ b/src/main/java/com/kexue/skills/controller/SkillGenController.java @@ -80,4 +80,16 @@ public class SkillGenController { public CommonResult genIntroduce(@RequestBody GenIntroduceRequest request) { return CommonResult.success(skillGenService.genIntroduce(request.getContent())); } + + /** + * 上传技能压缩包 + * + * @param skillUrl 技能压缩包URL + * @return 生成的技能内容 + */ + @PostMapping("/uploadSkill") + @Operation(summary = "上传技能压缩包", description = "上传技能压缩包并生成技能") + public CommonResult uploadSkill(@RequestBody String skillUrl) { + return CommonResult.success(skillGenService.uploadSkill(skillUrl)); + } } diff --git a/src/main/java/com/kexue/skills/entity/CmsContent.java b/src/main/java/com/kexue/skills/entity/CmsContent.java index 90dac17..3b71248 100644 --- a/src/main/java/com/kexue/skills/entity/CmsContent.java +++ b/src/main/java/com/kexue/skills/entity/CmsContent.java @@ -27,6 +27,9 @@ public class CmsContent extends BaseEntity implements Serializable { @Schema(description ="标题") private String title; + @Schema(description ="英文标题") + private String titleEn; + @Schema(description ="是否是官方:0否,1是") private Boolean isOfficial; @@ -45,12 +48,18 @@ public class CmsContent extends BaseEntity implements Serializable { @Schema(description ="详细描述") private String description; + @Schema(description ="英文描述") + private String descriptionEn; + @Schema(description ="需求说明") private String requirement; @Schema(description ="介绍信息") private String introduce; + @Schema(description ="英文介绍") + private String introduceEn; + @Schema(description ="分享数量") private Integer shareCount; @@ -70,6 +79,9 @@ public class CmsContent extends BaseEntity implements Serializable { @Schema(description ="内容详情") private String content; + @Schema(description ="英文内容") + private String contentEn; + @Schema(description ="封面图片") private String coverImage; diff --git a/src/main/java/com/kexue/skills/entity/dto/CmsContentDto.java b/src/main/java/com/kexue/skills/entity/dto/CmsContentDto.java index 8bef0d4..dd4dbd4 100644 --- a/src/main/java/com/kexue/skills/entity/dto/CmsContentDto.java +++ b/src/main/java/com/kexue/skills/entity/dto/CmsContentDto.java @@ -20,12 +20,6 @@ public class CmsContentDto extends BaseQueryDto { private Integer contentType; - private String categoryIds; - - private Long categoryId; - - private List categoryIdList; - private Boolean isOfficial; private Integer shareCount; @@ -51,9 +45,14 @@ public class CmsContentDto extends BaseQueryDto { */ private List tagIdList; + /** + * 语言类型:0 中文,1 英文 + */ + private Integer languageType; + /** * 搜索关键字,同时搜索 title、description、tags */ private String keyword; - + } diff --git a/src/main/java/com/kexue/skills/mapper/CmsContentMapper.java b/src/main/java/com/kexue/skills/mapper/CmsContentMapper.java index 1e73a3e..c05c1f8 100644 --- a/src/main/java/com/kexue/skills/mapper/CmsContentMapper.java +++ b/src/main/java/com/kexue/skills/mapper/CmsContentMapper.java @@ -56,6 +56,14 @@ public interface CmsContentMapper { * @return 实例对象 */ CmsContent queryById(Long contentId); + + /** + * 通过ID和语言类型查询单条数据 + * + * @param queryDto 筛选条件 + * @return 实例对象 + */ + CmsContent queryByIdWithLanguage(CmsContentDto queryDto); /** * 新增数据 @@ -64,6 +72,14 @@ public interface CmsContentMapper { * @return 影响行数 */ int insert(CmsContent cmsContent); + + /** + * 批量新增数据 + * + * @param cmsContentList 实例对象列表 + * @return 影响行数 + */ + int batchInsert(@Param("cmsContentList") List cmsContentList); /** * 更新数据 diff --git a/src/main/java/com/kexue/skills/service/CmsContentService.java b/src/main/java/com/kexue/skills/service/CmsContentService.java index cbd1c8a..6eed341 100644 --- a/src/main/java/com/kexue/skills/service/CmsContentService.java +++ b/src/main/java/com/kexue/skills/service/CmsContentService.java @@ -165,4 +165,13 @@ public interface CmsContentService extends BaseService { * @return 查询结果 */ PageInfo getPageListByUserCreated(CmsContentDto queryDto); + + /** + * 导入Excel数据到CmsContent + * + * @param fileBytes Excel文件字节数组 + * @param createBy 创建人 + * @return 导入结果 + */ + int importFromExcel(byte[] fileBytes, String createBy); } \ No newline at end of file diff --git a/src/main/java/com/kexue/skills/service/SkillGenService.java b/src/main/java/com/kexue/skills/service/SkillGenService.java index 95769c5..cad89f5 100644 --- a/src/main/java/com/kexue/skills/service/SkillGenService.java +++ b/src/main/java/com/kexue/skills/service/SkillGenService.java @@ -43,4 +43,12 @@ public interface SkillGenService { * @return 技能介绍 */ String genIntroduce(String content); + + /** + * 上传技能压缩包并生成技能 + * + * @param skillUrl 技能压缩包URL + * @return 生成的技能内容 + */ + CmsContent uploadSkill(String skillUrl); } diff --git a/src/main/java/com/kexue/skills/service/impl/CmsContentServiceImpl.java b/src/main/java/com/kexue/skills/service/impl/CmsContentServiceImpl.java index 1052430..89ea101 100644 --- a/src/main/java/com/kexue/skills/service/impl/CmsContentServiceImpl.java +++ b/src/main/java/com/kexue/skills/service/impl/CmsContentServiceImpl.java @@ -2,6 +2,7 @@ package com.kexue.skills.service.impl; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; +import com.github.pagehelper.util.StringUtil; import com.kexue.skills.common.LoginUserCacheUtil; import com.kexue.skills.entity.CmsContent; import com.kexue.skills.entity.CmsContentView; @@ -12,10 +13,15 @@ import com.kexue.skills.mapper.CmsContentMapper; import com.kexue.skills.mapper.CmsContentViewMapper; import com.kexue.skills.mapper.CmsContentLikeMapper; import com.kexue.skills.service.CmsContentService; +import cn.hutool.poi.excel.ExcelReader; +import cn.hutool.poi.excel.ExcelUtil; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @@ -60,12 +66,15 @@ public class CmsContentServiceImpl implements CmsContentService { // 使用 PageHelper 进行分页 PageHelper.startPage(queryDto.getPageNum(), queryDto.getPageSize()); + // 设置默认语言类型为中文 + if (queryDto.getLanguageType() == null) { + queryDto.setLanguageType(0); + } List list = this.cmsContentMapper.getPageList(queryDto); PageInfo pageInfo = new PageInfo<>(list); - // 如果使用了 keyword 搜索且返回结果小于等于 3 条,则根据第一个 skill 的标签查询相关 skill - if (queryDto.getKeyword() != null && !queryDto.getKeyword().trim().isEmpty() - && list.size() <= 3 && !list.isEmpty()) { + + if (queryDto.getTitle() != null && !queryDto.getTitle().trim().isEmpty() && list.size() <= 3 && !list.isEmpty()) { // 获取第一个 skill 的标签 CmsContent firstSkill = list.get(0); String tagsStr = firstSkill.getTags(); @@ -86,6 +95,11 @@ public class CmsContentServiceImpl implements CmsContentService { } } + //如果传入的tagId不为空,则添加到tagIdSet中 + if (queryDto.getTagId() != null) { + tagIdSet.add(queryDto.getTagId()); + } + // 如果有有效的标签 ID,查询相关内容 if (!tagIdSet.isEmpty()) { // 排除已返回的 contentId @@ -100,22 +114,29 @@ public class CmsContentServiceImpl implements CmsContentService { tagQueryDto.setTagIdList(new ArrayList<>(tagIdSet)); tagQueryDto.setPageNum(1); tagQueryDto.setPageSize(1000); - + // 查询包含这些标签的所有 skill List taggedContents = this.cmsContentMapper.getPageList(tagQueryDto); // 过滤掉已返回的内容 - List relatedContents = taggedContents.stream() - .filter(content -> !existingIds.contains(content.getContentId())) - .collect(Collectors.toList()); +// List relatedContents = taggedContents.stream() +// .filter(content -> !existingIds.contains(content.getContentId())) +// .collect(Collectors.toList()); + + //如果tag传参,则根据tag再次过滤 + if (queryDto.getTagId() != null) { + taggedContents = taggedContents.stream().filter(content -> content.getTags().contains(queryDto.getTagId().toString())).toList() ; + } + + List finalList = new ArrayList<>(taggedContents); // 如果有相关 skill,添加到结果中 - if (!relatedContents.isEmpty()) { + if (!finalList.isEmpty()) { // 按 sort 和 create_time 排序 - relatedContents.sort((a, b) -> { + finalList.sort((a, b) -> { int sortCompare = Integer.compare( - a.getSort() != null ? a.getSort() : 0, - b.getSort() != null ? b.getSort() : 0); + a.getViewCount() != null ? a.getViewCount() : 0, + b.getViewCount() != null ? b.getViewCount() : 0); if (sortCompare != 0) { return sortCompare; } @@ -125,10 +146,10 @@ public class CmsContentServiceImpl implements CmsContentService { return b.getCreateTime().compareTo(a.getCreateTime()); }); - list.addAll(relatedContents); - // 重新构建 PageInfo - pageInfo = new PageInfo<>(list); - pageInfo.setTotal(list.size()); + // 计算需要添加的数量,确保总数量不超过 pageSize + PageInfo newPageInfo = new PageInfo<>(memoryPagination(finalList, queryDto.getPageNum(), queryDto.getPageSize())); + newPageInfo.setTotal(finalList.size()); + pageInfo = newPageInfo; } } } @@ -138,6 +159,42 @@ public class CmsContentServiceImpl implements CmsContentService { return pageInfo; } + /** + * 内存分页方法 + * + * @param list 原始数据列表 + * @param pageNum 页码 + * @param pageSize 每页大小 + * @return 当前页的 list,对应的页码没有数据则返回空 list + */ + private List memoryPagination(List list, int pageNum, int pageSize) { + // 参数校验 + if (list == null) { + return new ArrayList<>(); + } + if (pageNum < 1) { + pageNum = 1; + } + if (pageSize < 1) { + pageSize = 10; + } + + // 计算总记录数 + int total = list.size(); + + // 计算分页参数 + int startIndex = (pageNum - 1) * pageSize; + int endIndex = Math.min(startIndex + pageSize, total); + + // 截取分页数据 + List pageList = new ArrayList<>(); + if (startIndex < total) { + pageList = list.subList(startIndex, endIndex); + } + + return pageList; + } + /** * 查询列表 * @@ -146,6 +203,10 @@ public class CmsContentServiceImpl implements CmsContentService { */ @Override public List getList(CmsContentDto queryDto) { + // 设置默认语言类型为中文 + if (queryDto.getLanguageType() == null) { + queryDto.setLanguageType(0); + } return this.cmsContentMapper.getList(queryDto); } @@ -374,7 +435,7 @@ public class CmsContentServiceImpl implements CmsContentService { result = cmsContentLikeMapper.deleteById(existingLike.getLikeId()); // 减少内容的点赞数 - if (content.getLikeCount() > 0) { + if (content != null && content.getLikeCount() > 0) { content.setLikeCount(content.getLikeCount() - 1); this.cmsContentMapper.update(content); } @@ -648,4 +709,195 @@ public class CmsContentServiceImpl implements CmsContentService { return pageInfo; } + + @Override + public int importFromExcel(byte[] fileBytes, String createBy) { + int successCount = 0; + final int BATCH_SIZE = 100; // 批量处理大小 + + try (InputStream inputStream = new ByteArrayInputStream(fileBytes); + ExcelReader reader = ExcelUtil.getReader(inputStream)) { + + // 获取总行数(包括标题行) + int totalRows = reader.getRowCount(); + if (totalRows <= 1) { + // 只有标题行或空文件 + return 0; + } + + Date now = new Date(); + List batchList = new ArrayList<>(BATCH_SIZE); + + // 读取标题行 + List headerObjList = reader.readRow(0); + if (headerObjList == null || headerObjList.isEmpty()) { + return 0; + } + // 转换为List + List headerList = new ArrayList<>(); + for (Object obj : headerObjList) { + headerList.add(obj != null ? obj.toString() : ""); + } + + // 从第二行开始读取数据(第一行为标题行) + for (int rowIndex = 1; rowIndex < totalRows; rowIndex++) { + List rowList = reader.readRow(rowIndex); + if (rowList == null || rowList.isEmpty()) { + continue; + } + + // 转换为Map + Map row = new HashMap<>(); + for (int i = 0; i < headerList.size() && i < rowList.size(); i++) { + row.put(headerList.get(i), rowList.get(i)); + } + if (row.isEmpty()) { + continue; + } + + CmsContent cmsContent = new CmsContent(); + + // 设置创建时间和更新时间 + cmsContent.setCreateTime(now); + cmsContent.setUpdateTime(now); + cmsContent.setCreateBy(createBy); + cmsContent.setUpdateBy(createBy); + + // 设置默认值 + cmsContent.setDeleteFlag(0); + cmsContent.setAuditStatus(1); // 默认草稿状态 + cmsContent.setPublishStatus(1); // 默认未发布状态 + cmsContent.setViewCount(0); + cmsContent.setLikeCount(0); + cmsContent.setCommentCount(0); + cmsContent.setSort(0); + + // 读取Excel中的字段 + // content_id - 数据库自动生成,不需要读取 + cmsContent.setTitle(getStringValue(row, "title")); + cmsContent.setTitleEn(getStringValue(row, "title_en")); + cmsContent.setOrigin(getStringValue(row, "origin")); + cmsContent.setTags(Objects.requireNonNull(getStringValue(row, "tags")).replaceAll(" ","")); + cmsContent.setIcon(getStringValue(row, "icon")); + cmsContent.setIsOfficial(getBooleanValue(row, "is_official")); + cmsContent.setPrice(getBigDecimalValue(row, "price")); + cmsContent.setLikeCount(getIntegerValue(row, "like_count")); + cmsContent.setShareCount(getIntegerValue(row, "share_count")); + cmsContent.setContentType(getIntegerValue(row, "content_type")); + cmsContent.setContent(getStringValue(row, "content")); + cmsContent.setContentEn(getStringValue(row, "content_en")); + cmsContent.setAuditStatus(getIntegerValue(row, "audit_status")); + cmsContent.setPublishStatus(getIntegerValue(row, "publish_status")); + cmsContent.setPublishTime(getDateValue(row, "publish_time")); + cmsContent.setViewCount(getIntegerValue(row, "view_count")); + cmsContent.setCommentCount(getIntegerValue(row, "comment_count")); + cmsContent.setIsPaid(getIntegerValue(row, "is_paid")); + cmsContent.setSupportPointsPay(getIntegerValue(row, "support_points_pay")); + cmsContent.setDescription(getStringValue(row, "description")); + cmsContent.setDescriptionEn(getStringValue(row, "description_en")); + cmsContent.setIntroduce(getStringValue(row, "introduce")); + cmsContent.setIntroduceEn(getStringValue(row, "introduce_en")); + // create_time - 由系统生成,不需要读取 + // update_time - 由系统生成,不需要读取 + cmsContent.setDeleteFlag(getIntegerValue(row, "delete_flag")); + + batchList.add(cmsContent); + + // 达到批量大小或最后一行时,执行批量插入 + if (batchList.size() >= BATCH_SIZE || rowIndex == totalRows - 1) { + if (!batchList.isEmpty()) { + // 执行批量插入 + this.cmsContentMapper.batchInsert(batchList); + successCount += batchList.size(); + batchList.clear(); // 清空批次 + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + return successCount; + } + + /** + * 从Map中获取字符串值 + */ + private String getStringValue(Map row, String key) { + Object value = row.get(key); + return value != null ? value.toString() : null; + } + + /** + * 从Map中获取布尔值 + */ + private Boolean getBooleanValue(Map row, String key) { + Object value = row.get(key); + if (value == null) { + return null; + } + if (value instanceof Boolean) { + return (Boolean) value; + } + if (value instanceof String) { + return Boolean.parseBoolean((String) value); + } + return null; + } + + /** + * 从Map中获取整数值 + */ + private Integer getIntegerValue(Map row, String key) { + Object value = row.get(key); + if (value == null) { + return null; + } + if (value instanceof Number) { + return ((Number) value).intValue(); + } + if (value instanceof String) { + try { + return Integer.parseInt((String) value); + } catch (NumberFormatException e) { + return null; + } + } + return null; + } + + /** + * 从Map中获取BigDecimal值 + */ + private BigDecimal getBigDecimalValue(Map row, String key) { + Object value = row.get(key); + if (value == null) { + return null; + } + if (value instanceof Number) { + return BigDecimal.valueOf(((Number) value).doubleValue()); + } + if (value instanceof String) { + try { + return new BigDecimal((String) value); + } catch (NumberFormatException e) { + return null; + } + } + return null; + } + + /** + * 从Map中获取日期值 + */ + private Date getDateValue(Map row, String key) { + Object value = row.get(key); + if (value == null) { + return null; + } + if (value instanceof Date) { + return (Date) value; + } + return null; + } } \ No newline at end of file diff --git a/src/main/java/com/kexue/skills/service/impl/SkillGenServiceImpl.java b/src/main/java/com/kexue/skills/service/impl/SkillGenServiceImpl.java index 172e771..75247a5 100644 --- a/src/main/java/com/kexue/skills/service/impl/SkillGenServiceImpl.java +++ b/src/main/java/com/kexue/skills/service/impl/SkillGenServiceImpl.java @@ -310,4 +310,91 @@ public class SkillGenServiceImpl implements SkillGenService { return null; } + + @Override + public CmsContent uploadSkill(String skillUrl) { + log.info("上传技能压缩包请求: {}", skillUrl); + String url = deepSeekConfig.getBaseUrl() + "/v1/chat/completions"; + + // 从数据库中读取cms_tag表的标签信息 + CmsTagDto tagDto = new CmsTagDto(); + tagDto.setDeleteFlag(0); + tagDto.setStatus(1); + List tags = cmsTagService.getList(tagDto); + + // 将标签名称拼接成逗号分隔的字符串 + StringBuilder tagsList = new StringBuilder(); + for (int i = 0; i < tags.size(); i++) { + CmsTag tag = tags.get(i); + tagsList.append(tag.getTagId()+"."+tag.getTagName()); + if (i < tags.size() - 1) { + tagsList.append(","); + } + } + + // 构建系统消息内容 + String systemContent = """ + 你是一位专业的AI技能包解析助手,需完成以下任务: + 1. 我会提供一个技能包压缩包(格式包含zip/rar)的URL,你需解析该压缩包根目录下的SKILL.md文件; 或者提供一个在线的SKILL.md文件的url; + 2. 基于SKILL.md内容,提炼出: + - skill的核心描述(description); + - 详细功能介绍(introduce); + - 从指定标签列表中选取至少3个适配标签(tagList),标签范围:TAG_LIST; + - 选择标签的时候只需要输出对应的标签编号 + 3. 生成content字段:基于技能包的名称、描述、标签,按照skills目录结构输出完整的技能包YAML内容(包含skills.md本体、scripts目录脚本等),需遵循以下严格规范: + - 包含技能包必需的文件和目录; + - 多行内容使用「|」字面块表示; + - 所有内容从行首开始,无前置空格; + - 空目录标注为「children: []」; + - 文件内容需具备实际使用价值; + - YAML文档需完整,核心概要包含name、version、description、author、created、tags等属性; + - 核心节点为structure,用于描述技能包文件目录结构;structure下每个节点需包含基础属性:name、type、path、format、description;content和children为互选属性(type为file时,content字段填写文件内容;type为directory时,children数组填写子目录/文件节点)。 + 请将最终结果以JSON格式输出,JSON结构必须包含:description(技能描述)、introduce(功能介绍)、tagList(标签列表)、content(完整YAML格式技能包内容),无需额外说明,仅输出符合要求的JSON内容。 + """; + systemContent = systemContent.replace("TAG_LIST", tagsList.toString()); + + // 构建用户消息内容 + String userContent = skillUrl; + + // 创建技能请求 + SkillRequest skillRequest = new SkillRequest(true, deepSeekConfig.getChat().getModel(), systemContent, userContent, 0.5, 8192, "json_object"); + + try { + // 发送HTTP请求到DeepSeek API + String deepseekResponse = HttpUtil.sendPostRequest(url, skillRequest, deepSeekConfig.getApiKey(), null); + log.info("Deepseek API响应: {}", deepseekResponse); + + // 解析返回结果 + JSONObject responseJson = JSON.parseObject(deepseekResponse); + List choices = responseJson.getJSONArray("choices").toJavaList(JSONObject.class); + + if (choices != null && !choices.isEmpty()) { + // 获取最新的choice + JSONObject latestChoice = choices.get(0); + JSONObject message = latestChoice.getJSONObject("message"); + String content = message.getString("content"); + + // 解析content中的JSON + JSONObject skillJson = JSON.parseObject(content); + + // 构建技能生成请求 + SkillGenRequest request = new SkillGenRequest(); + request.setName(skillJson.getString("name")); + request.setDescription(skillJson.getString("description")); + request.setRequirement(skillJson.getString("introduce")); + request.setTags(skillJson.getJSONArray("tagList").toJavaList(String.class)); + + // 生成CmsContent对象 + CmsContent cmsContent = getCmsContent(request, skillJson.getString("content"), StpUtil.getLoginIdAsLong(), ""); + + // 保存到数据库 + cmsContentMapper.insert(cmsContent); + return cmsContent; + } + } catch (Exception e) { + log.error("调用Deepseek API失败: {}", e.getMessage(), e); + } + + return null; + } } diff --git a/src/main/resources/mapper/CmsContentMapper.xml b/src/main/resources/mapper/CmsContentMapper.xml index cf6285d..ba5cb35 100644 --- a/src/main/resources/mapper/CmsContentMapper.xml +++ b/src/main/resources/mapper/CmsContentMapper.xml @@ -5,13 +5,17 @@ + + + + @@ -52,11 +56,37 @@ from cms_content where content_id = #{contentId} + + + select - content_id, title, subtitle, content_type, summary, description, requirement, introduce, content, cover_image, author_id, author_name, + content_id, + case when #{queryDto.languageType} = 1 then title_en else title end as title, + subtitle, + content_type, summary, + case when #{queryDto.languageType} = 1 then description_en else description end as description, + requirement, + case when #{queryDto.languageType} = 1 then introduce_en else introduce end as introduce, + case when #{queryDto.languageType} = 1 then content_en else content end as content, + cover_image, author_id, author_name, reviewer_id, reviewer_name, audit_status, audit_comment, publish_status, publish_time, view_count, like_count, comment_count, sort, is_paid, price, required_points, support_points_pay, is_official, share_count, file_url, icon, background, origin, tags, create_time, update_time, create_by, update_by, delete_flag from cms_content @@ -217,7 +255,15 @@