Compare commits

...

2 Commits

15 changed files with 459 additions and 64 deletions

70
pom.xml
View File

@ -164,41 +164,41 @@
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.2</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis.spring</artifactId>
</exclusion>
<exclusion>
<groupId>log4j-slf4j-impl</groupId>
<artifactId>org.apache.logging.log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
<version>2.1.0</version>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.mybatis</groupId>-->
<!-- <artifactId>mybatis</artifactId>-->
<!-- </exclusion>-->
<!-- <exclusion>-->
<!-- <groupId>org.mybatis</groupId>-->
<!-- <artifactId>mybatis.spring</artifactId>-->
<!-- </exclusion>-->
<!-- <exclusion>-->
<!-- <groupId>log4j-slf4j-impl</groupId>-->
<!-- <artifactId>org.apache.logging.log4j</artifactId>-->
<!-- </exclusion>-->
<!-- <exclusion>-->
<!-- <groupId>org.slf4j</groupId>-->
<!-- <artifactId>slf4j-api</artifactId>-->
<!-- </exclusion>-->
<!-- <exclusion>-->
<!-- <groupId>ch.qos.logback</groupId>-->
<!-- <artifactId>logback-classic</artifactId>-->
<!-- </exclusion>-->
<!-- <exclusion>-->
<!-- <groupId>org.slf4j</groupId>-->
<!-- <artifactId>log4j-over-slf4j</artifactId>-->
<!-- </exclusion>-->
<!-- <exclusion>-->
<!-- <groupId>org.slf4j</groupId>-->
<!-- <artifactId>jul-to-slf4j</artifactId>-->
<!-- </exclusion>-->
<!-- <exclusion>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-logging</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<!-- Sa-Token 核心依赖 -->

View File

@ -16,16 +16,16 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {
@Value("${common.redis.host}")
@Value("${spring.redis.host}")
private String host;
@Value("${common.redis.port}")
@Value("${spring.redis.port}")
private int port;
@Value("${common.redis.password}")
@Value("${spring.redis.password}")
private String password;
@Value("${common.redis.database}")
@Value("${spring.redis.database}")
private int database;
@Bean(destroyMethod = "shutdown")
@ -35,12 +35,16 @@ public class RedissonConfig {
// 单节点模式
config.useSingleServer()
.setAddress("redis://" + host + ":" + port)
.setPassword(password)
//.setPassword(password)
.setDatabase(database)
.setConnectionMinimumIdleSize(5)
.setConnectionPoolSize(20)
.setTimeout(10000);
// 处理密码如果有密码则设置否则不设置
if (password != null && !password.isEmpty()) {
config.useSingleServer().setPassword(password);
}
return Redisson.create(config);
}

View File

@ -1,11 +1,19 @@
package com.kexue.skills.controller;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.request.SkillRequest;
import com.kexue.skills.entity.response.SkillResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
/**
* 技能生成控制器
@ -13,6 +21,7 @@ import javax.annotation.Resource;
* @author 维哥
* @since 2026-01-28
*/
@Slf4j
@RestController
@RequestMapping("api/skillGen")
@Tag(name = "技能生成 Api")
@ -23,17 +32,65 @@ public class SkillGenController {
private com.kexue.skills.service.SkillGenService skillGenService;
/**
* 生成技能
* 预生成skill,产生相关的描述信息
*
* @param request 生成请求
* @return 生成结果
*/
@PostMapping("/generate")
@Operation(summary = "生成技能", description = "生成技能")
public CommonResult<SkillResponse> generate(@RequestBody com.kexue.skills.entity.request.SkillGenRequest request) {
return CommonResult.success(skillGenService.generateSkill(request));
@PostMapping("/preGenerate")
@Operation(summary = "预生成技能", description = "预生成技能")
public CommonResult<SkillResponse> preGenerate(com.kexue.skills.entity.request.SkillGenRequest request,
@RequestPart(value = "file", required = false) MultipartFile file) {
try {
// 如果上传了文件读取文件内容
if (file != null && !file.isEmpty()) {
String fileContent = readTextFile(file);
// 将文件内容设置到请求对象中需要修改 SkillGenRequest
// request.setFileContent(fileContent);
// request.setFileName(file.getOriginalFilename());
// request.setFileSize(file.getSize());
// request.setFileType(file.getContentType());
log.info("文件上传成功: {}, 大小: {} bytes, 类型: {}",
file.getOriginalFilename(), file.getSize(), file.getContentType());
return CommonResult.success(skillGenService.preGenerateSkill(request,fileContent));
}
return CommonResult.success(skillGenService.preGenerateSkill(request,null));
} catch (Exception e) {
log.error("处理文件上传失败", e);
return CommonResult.failed("文件处理失败: " + e.getMessage());
}
}
/**
* 读取文本文件内容为字符串
* @param file 上传的文件
* @return 文件内容字符串
*/
private String readTextFile(MultipartFile file) throws IOException {
// 使用 Apache Commons IO
try (InputStream inputStream = file.getInputStream()) {
return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
}
}
/**
* 生成技能
*
* @param
* @return 分析结果
*/
@PostMapping("/generate")
@Operation(summary = "生成技能", description = "生成技能")
public CommonResult<SkillResponse> generate(@RequestBody SkillRequest request) {
Integer skillId=request.getSkillId();
return CommonResult.success(skillGenService.generateSkill(skillId));
}
/**
* 分析技能
*

View File

@ -132,6 +132,17 @@ public class CmsContent extends BaseEntity implements Serializable {
@Schema(description ="父分类ID")
private Long parentCategoryId;
@Schema(description ="用户上传的文件内容")
private String userUpload;
@Schema(description ="标签列表,逗号分隔")
private String tagIds;
@Schema(description ="技能的文件地址")
private String skillPath;
@Schema(description ="技能文件内容")
private String skillContent;
// 用于接收前端发送的分类ID数组
@JsonProperty("categoryIds")
public void setCategoryIdsFromArray(List<Long> categoryIdList) {

View File

@ -44,4 +44,7 @@ public class CmsContentDto extends BaseQueryDto {
private Long parentCategoryId;
private String userLoad;
private String tagIds;
}

View File

@ -19,6 +19,8 @@ public class SkillRequest implements Serializable {
private double temperature;
private int max_tokens;
private ResponseFormat response_format;
private int skillId;
private int contentId;
public SkillRequest(boolean useDefaultSettings) {
if (useDefaultSettings) {
@ -52,7 +54,7 @@ public class SkillRequest implements Serializable {
systemMessage.setRole("system");
systemMessage.setContent("你是一个专业的AI技能设计助手。请严格按照指定的JSON格式输出仅包含要求的字段以中文形式返回。");
this.messages.add(systemMessage);
//获取系统存在的标签
Message userMessage = new Message();
userMessage.setRole("user");
userMessage.setContent("主题:"+ prompt +"。请根据agent skills撰写规范帮我生成这个skill的名称、描述并从以下标签列表中选择一个或者多个标签\"软件开发系统集成网络工程云计算大数据人工智能物联网区块链信息安全运维服务测试认证IT 咨询,外包服务,电商技术,移动开发,前端开发,后端开发,全栈开发,数据库管理\"。输出json格式仅输出以上所提到的名称、描述、标签节点名称分别为name、description、tags节点内容以中文形式返回。");
@ -65,6 +67,53 @@ public class SkillRequest implements Serializable {
this.response_format.setType("json_object");
}
}
// String systemPrompt = """
// 请严格按照以下格式输出信息
//
// ## 标题 ##
// [这里填写标题]
//
// ## 关键点 ##
// - 第一点
// - 第二点
// - 第三点
//
// ## 详细说明 ##
// [这里填写详细说明]
//
// ## 建议 ##
// [这里填写建议]
//
// 不要添加任何其他内容严格按照上述格式输出
// """;
public SkillRequest(boolean useDefaultSettings, String model, Double temperature, Integer maxTokens,String prompt,String description,String tags,String userUpload) {
String systemPrompt2="你是一个专业的AI技能设计助手。请基于用户提供的Skill名称、描述、标签生成完整的skills.md文档内容仅输出skills.md本体内容无需其他额外说明。";
if (useDefaultSettings) {
this.model = model;
this.messages = new ArrayList<>();
Message systemMessage = new Message();
systemMessage.setRole("system");
systemMessage.setContent(systemPrompt2);
this.messages.add(systemMessage);
Message userMessage = new Message();
userMessage.setRole("user");
if(userUpload!=null&&!userUpload.equals("")){
userMessage.setContent("请根据以下Skill信息生成skills.md文档内容Skill名称"+prompt+"Skill描述"+description+"Skill标签"+tags+"。请仅输出skills.md本体内容无需其他额外说明。内容的生成需要参考如下内容"+userUpload);
}else{
userMessage.setContent("请根据以下Skill信息生成skills.md文档内容Skill名称"+prompt+"Skill描述"+description+"Skill标签"+tags+"。请仅输出skills.md本体内容无需其他额外说明。");
}
this.messages.add(userMessage);
this.temperature = temperature;
this.max_tokens = maxTokens;
// this.response_format = new ResponseFormat();
// this.response_format.setType("json_object");
}
}
public static SkillRequest createDefault() {
return new SkillRequest(true);

View File

@ -1,5 +1,6 @@
package com.kexue.skills.entity.response;
import com.kexue.skills.entity.CmsContent;
import lombok.Data;
import java.io.Serializable;
@ -12,4 +13,6 @@ public class SkillResponse implements Serializable {
private String name;
private String description;
private List<String> tags;
private Long skillId;
private List<CmsContent> cmsContents;
}

View File

@ -13,12 +13,16 @@ import com.kexue.skills.entity.response.SkillResponse;
public interface SkillGenService {
/**
* 生成技能
* 生成技能
*
* @param request 生成请求
* @param fileContent 上传的文件内容
* @return 生成结果
*/
SkillResponse generateSkill(SkillGenRequest request);
SkillResponse preGenerateSkill(SkillGenRequest request,String fileContent);
SkillResponse generateSkill(Integer skillId);
/**
* 分析技能

View File

@ -1,5 +1,6 @@
package com.kexue.skills.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.entity.CmsContent;

View File

@ -4,16 +4,29 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kexue.skills.common.util.HttpUtil;
import com.kexue.skills.config.DeepSeekConfig;
import com.kexue.skills.entity.CmsContent;
import com.kexue.skills.entity.CmsTag;
import com.kexue.skills.entity.dto.CmsContentDto;
import com.kexue.skills.entity.dto.CmsTagDto;
import com.kexue.skills.entity.request.SkillAnalyzeRequest;
import com.kexue.skills.entity.request.SkillGenRequest;
import com.kexue.skills.entity.request.SkillRequest;
import com.kexue.skills.entity.response.SkillResponse;
import com.kexue.skills.mapper.CmsContentMapper;
import com.kexue.skills.service.CmsContentService;
import com.kexue.skills.service.CmsTagService;
import com.kexue.skills.service.SkillGenService;
import com.kexue.skills.utils.FileManager;
import com.kexue.skills.utils.MarkdownProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 技能生成服务实现
@ -28,6 +41,10 @@ public class SkillGenServiceImpl implements SkillGenService {
@Autowired
private DeepSeekConfig deepSeekConfig;
@Resource
private CmsContentService cmsContentService;
@Resource
private CmsTagService cmsTagService;
/**
* 生成技能
*
@ -35,8 +52,10 @@ public class SkillGenServiceImpl implements SkillGenService {
* @return 生成结果
*/
@Override
public SkillResponse generateSkill(SkillGenRequest request) {
log.info("生成技能请求: {}", request);
public SkillResponse preGenerateSkill(SkillGenRequest request,String fileContent) {
log.info("预生成技能请求: {}", request);
// List<CmsTag> tags = cmsTagService.getList(new CmsTagDto());
String url = deepSeekConfig.getBaseUrl() + "/v1/chat/completions";
SkillRequest skillRequest = new SkillRequest(true, deepSeekConfig.getChat().getModel(),
deepSeekConfig.getChat().getTemperature(), deepSeekConfig.getChat().getMaxTokens(),request.getPrompt());
@ -61,9 +80,57 @@ public class SkillGenServiceImpl implements SkillGenService {
SkillResponse skillResponse = new SkillResponse();
skillResponse.setName(skillJson.getString("name"));
skillResponse.setDescription(skillJson.getString("description"));
skillResponse.setTags(skillJson.getJSONArray("tags").toJavaList(String.class));
final List<String> tags = skillJson.getJSONArray("tags").toJavaList(String.class);
//tags需要解析出id
// List<Long> targetTagIds = new ArrayList<>();
// List<CmsContent> resultContents =new ArrayList<>();
// for (String tag : tags) {
// CmsTagDto tagDto = new CmsTagDto();
// tagDto.setTagName(tag);
// List<CmsTag> list = cmsTagService.getList(tagDto);
// if (list != null && !list.isEmpty()) {
// targetTagIds.add(list.get(0).getTagId());
// }
// }
skillResponse.setTags(tags);
log.info("解析技能响应: {}", skillResponse);
//skill需要记录到数据库
CmsContent cmsContent = new CmsContent();
cmsContent.setTitle(skillJson.getString("name"));
cmsContent.setSummary(skillJson.getString("description"));
cmsContent.setContentType(1);
cmsContent.setContent(skillJson.getString("content"));
cmsContent.setUserUpload(fileContent);
if(!tags.isEmpty()){
String result=tags.stream()
//.map(String::valueOf)
.collect(Collectors.joining(","));
cmsContent.setTagIds(result);
}else{
cmsContent.setTagIds("通用技能,");
}
//记录到数据库
final CmsContent insert = cmsContentService.insert(cmsContent);
//根据tags在去匹配skill作为推荐,推荐已经发布的skill
List<CmsContent> resultContents =new ArrayList<>();
CmsContentDto cmsContentDto = new CmsContentDto();
cmsContentDto.setPublishStatus(2);
final List<CmsContent> list = cmsContentService.getList(cmsContentDto);
for (CmsContent c:list) {
List<String> currentTags = Arrays.stream(c.getTagIds().split(","))
//.map(Long::valueOf)
.toList();
if(tags.stream().anyMatch(currentTags::contains)) {
//存在交集需要被推荐
resultContents.add(c);
}
}
if(resultContents.isEmpty()&& !list.isEmpty()) {
//如果没匹配到就先给第一个
resultContents.add(list.get(0));
}
skillResponse.setSkillId(insert.getContentId());
skillResponse.setCmsContents(resultContents);
return skillResponse;
}
} catch (Exception e) {
@ -73,6 +140,63 @@ public class SkillGenServiceImpl implements SkillGenService {
return null;
}
@Override
public SkillResponse generateSkill(Integer skillId) {
//根据skillId获取用户预创建时的信息以此来生成skill文档
final CmsContent cmsContent = cmsContentService.queryById(Long.valueOf(skillId));
String name = cmsContent.getTitle();
String description = cmsContent.getSummary();
String userUpload = cmsContent.getUserUpload();
String tags=cmsContent.getTagIds();
log.info("生成技能请求: {}", skillId);
String url = deepSeekConfig.getBaseUrl() + "/v1/chat/completions";
SkillRequest skillRequest = new SkillRequest(true, deepSeekConfig.getChat().getModel(),
deepSeekConfig.getChat().getTemperature(), deepSeekConfig.getChat().getMaxTokens(),name,description,tags,userUpload);
try {
// 发送HTTP请求到deepseek API
String deepseekResponse = HttpUtil.sendPostRequest(url, skillRequest, deepSeekConfig.getApiKey(), null);
log.info("Deepseek API响应: {}", deepseekResponse);
// 解析deepseek返回结果
JSONObject responseJson = JSON.parseObject(deepseekResponse);
List<JSONObject> 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");
log.info("输出结果:{}",content);
FileManager manager = new FileManager();
FileManager.FileInfo fileInfo = manager.processAndWrite(content, name);
String storedFilePath = "";
if (fileInfo != null) {
log.info("文件信息: " + fileInfo);
// 可以将文件路径存储到数据库或其他地方
storedFilePath = fileInfo.getFilePath();
log.info("存储的文件路径: " + storedFilePath);
}
CmsContent c = new CmsContent();
c.setSkillPath(storedFilePath);
c.setSkillContent(content);
c.setContentId(Long.valueOf(skillId));
cmsContentService.update(c);
// 解析content中的JSON
SkillResponse skillResponse = new SkillResponse();
skillResponse.setDescription(MarkdownProcessor.unescapeString(content));
skillResponse.setSkillId(Long.valueOf(skillId));
return skillResponse;
}
} catch (Exception e) {
log.error("调用Deepseek API失败: {}", e.getMessage(), e);
}
return null;
}
/**

View File

@ -0,0 +1,107 @@
package com.kexue.skills.utils;
import java.io.*;
import java.nio.file.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
public class FileManager {
private String outputDirectory;
private String fileExtension;
public FileManager() {
this.outputDirectory = "skill_output";
this.fileExtension = ".md";
}
public FileManager(String outputDirectory, String fileExtension) {
this.outputDirectory = outputDirectory;
this.fileExtension = fileExtension;
}
// 处理内容并写入文件
public FileInfo processAndWrite(String content, String customFileName) {
try {
// 生成文件名
String fileName = generateFileName(customFileName);
// 写入文件
String filePath = writeToFile(content, fileName);
// 返回文件信息
return new FileInfo(filePath, fileName);
} catch (IOException e) {
System.err.println("写入文件失败: " + e.getMessage());
return null;
}
}
private List<String> parseTagIds(String tagIds) {
if (tagIds == null || tagIds.trim().isEmpty()) {
return Collections.emptyList();
}
return Arrays.stream(tagIds.split(","))
.map(String::trim)
.filter(tag -> !tag.isEmpty())
.toList();
}
private String generateFileName(String customName) {
if (customName != null && !customName.trim().isEmpty()) {
return customName.endsWith(fileExtension) ? customName : customName + fileExtension;
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");
String timestamp = LocalDateTime.now().format(formatter);
return "skills_" + timestamp + fileExtension;
}
private String writeToFile(String content, String fileName) throws IOException {
// 创建输出目录
Path dirPath = Paths.get(outputDirectory);
if (!Files.exists(dirPath)) {
Files.createDirectories(dirPath);
}
// 构建完整文件路径
Path filePath = dirPath.resolve(fileName);
// 写入文件
Files.writeString(
filePath,
content,
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.WRITE
);
return filePath.toAbsolutePath().toString();
}
// 文件信息类
public static class FileInfo {
private final String filePath;
private final String fileName;
public FileInfo(String filePath, String fileName) {
this.filePath = filePath;
this.fileName = fileName;
}
// getters
public String getFilePath() { return filePath; }
public String getFileName() { return fileName; }
@Override
public String toString() {
return String.format("文件: %s, 路径: %s",
fileName, filePath);
}
}
}

View File

@ -0,0 +1,18 @@
package com.kexue.skills.utils;
import org.apache.commons.lang3.StringEscapeUtils;
public class MarkdownProcessor {
public static String unescapeString(String escapedString) {
// \n 转换为真正的换行符
return escapedString.replace("\\n", "\n")
.replace("\\t", "\t")
.replace("\\\"", "\"");
}
public static String convertToMarkdown(String escapedString) {
// 使用Apache Commons Text库
return StringEscapeUtils.unescapeJava(escapedString);
}
}

View File

@ -14,10 +14,10 @@ spring:
maximum-pool-size: 30
# Redis配置引用公共配置
redis:
host: ${common.redis.host}
port: ${common.redis.port}
password: ${common.redis.password}
database: ${common.redis.database}
host: 192.168.153.100
port: 6379
password:
database: 1
timeout: 10000
lettuce:
pool:

View File

@ -2,7 +2,7 @@
<configuration scan="true" scanPeriod="60 seconds">
<!-- 定义日志文件的存储路径 -->
<property name="LOG_HOME" value="/data/service/logs/yuelong-portal" />
<property name="LOG_HOME" value="./logs" />
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
@ -13,10 +13,10 @@
<!-- 每日滚动文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/hyxp-portal.log</file>
<file>${LOG_HOME}/skill.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天生成一个新的日志文件 -->
<fileNamePattern>${LOG_HOME}/hyxp-portal.%d{yyyy-MM-dd}.log</fileNamePattern>
<fileNamePattern>${LOG_HOME}/skill.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 保留 30 天的历史日志文件 -->
<maxHistory>30</maxHistory>
</rollingPolicy>

View File

@ -118,7 +118,7 @@
select
content_id, title, subtitle, parent_category_id, content_type, category_ids, summary, 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, create_time, update_time, create_by, update_by, delete_flag
view_count, like_count, comment_count, sort, is_paid, price, required_points, support_points_pay, is_official, share_count, file_url, icon, background, create_time, update_time, create_by, update_by, delete_flag,user_upload,tag_ids
from cms_content
<where>
<if test="contentId != null">
@ -161,6 +161,12 @@
<if test="parentCategoryId != null">
and parent_category_id = #{parentCategoryId}
</if>
<if test="userLoad != null">
and userLoad = #{userLoad}
</if>
<if test="tagIds != null">
and tagIds = #{tagIds}
</if>
</where>
order by sort asc, create_time desc
</select>
@ -169,10 +175,12 @@
<insert id="insert" keyProperty="contentId" useGeneratedKeys="true">
insert into cms_content(title, subtitle, parent_category_id, content_type, category_ids, summary, 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, create_time, update_time, create_by, update_by, delete_flag)
view_count, like_count, comment_count, sort, is_paid, price, required_points, support_points_pay, is_official, share_count, file_url, icon, background, create_time, update_time, create_by, update_by, delete_flag,user_upload,tag_ids)
values (#{title}, #{subtitle}, #{parentCategoryId}, #{contentType}, #{categoryIds}, #{summary}, #{content}, #{coverImage}, #{authorId}, #{authorName},
#{reviewerId}, #{reviewerName}, #{auditStatus}, #{auditComment}, #{publishStatus}, #{publishTime},
#{viewCount}, #{likeCount}, #{commentCount}, #{sort}, #{isPaid}, #{price}, #{requiredPoints}, #{supportPointsPay}, #{isOfficial}, #{shareCount}, #{fileUrl}, #{icon}, #{background}, #{createTime}, #{updateTime}, #{createBy}, #{updateBy}, #{deleteFlag})
#{viewCount}, #{likeCount}, #{commentCount}, #{sort}, #{isPaid}, #{price}, #{requiredPoints}, #{supportPointsPay}, #{isOfficial}, #{shareCount}, #{fileUrl}, #{icon}, #{background}, #{createTime}, #{updateTime}, #{createBy}, #{updateBy}, #{deleteFlag},
#{userUpload},#{tagIds} )
</insert>
<!--通过主键修改数据-->
@ -272,6 +280,12 @@
<if test="updateBy != null">
update_by = #{updateBy},
</if>
<if test="skillPath != null">
skill_path = #{skillPath},
</if>
<if test="skillContent != null">
skill_content = #{skillContent},
</if>
</set>
where content_id = #{contentId}
</update>