知识库文件日志

This commit is contained in:
2025-12-31 16:30:42 +08:00
parent 1bb1dba4d6
commit 8cb8692b84
15 changed files with 636 additions and 76 deletions

View File

@@ -169,3 +169,20 @@ COMMENT ON COLUMN ai.tb_knowledge_file.update_time IS '更新时间';
COMMENT ON COLUMN ai.tb_knowledge_file.delete_time IS '删除时间';
COMMENT ON COLUMN ai.tb_knowledge_file.deleted IS '是否删除';
DROP TABLE IF EXISTS ai.tb_knowledge_file_log CASCADE;
CREATE TABLE ai.tb_knowledge_file_log(
optsn VARCHAR(50) NOT NULL, -- 流水号
log_id VARCHAR(50) NOT NULL, -- 日志ID
knowledge_id VARCHAR(50) NOT NULL, -- 知识库ID
file_root_id VARCHAR(50) NOT NULL, -- 文件根ID
file_id VARCHAR(50) NOT NULL, -- 文件ID
file_name VARCHAR(100) NOT NULL, -- 文件名
service VARCHAR(50) NOT NULL, -- 所属服务 workcase、bidding
version INTEGER NOT NULL DEFAULT 1, -- 文件版本
action VARCHAR(50) NOT NULL, -- 操作类型 upload、update、delete
creator VARCHAR(50) NOT NULL, -- 创建者用户ID
creator_name VARCHAR(100) NOT NULL, -- 创建者姓名
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
PRIMARY KEY (optsn),
UNIQUE (knowledge_id, file_id)
);

View File

@@ -7,7 +7,6 @@ import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
@@ -16,9 +15,11 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.xyzh.api.ai.service.DifyProxyService;
import org.xyzh.api.ai.service.KnowledgeFileLogService;
import org.xyzh.api.ai.service.KnowledgeService;
import org.xyzh.api.ai.dto.TbKnowledge;
import org.xyzh.api.ai.dto.TbKnowledgeFile;
import org.xyzh.api.ai.dto.TbKnowledgeFileLog;
import org.xyzh.api.ai.vo.KnowledgeFileVO;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageRequest;
@@ -46,6 +47,9 @@ public class KnowledgeController {
@Autowired
private KnowledgeService knowledgeService;
@Autowired
private KnowledgeFileLogService knowledgeFileLogService;
@Autowired
private DifyProxyService difyProxyService;
@@ -347,4 +351,29 @@ public class KnowledgeController {
logger.info("更新文档状态: datasetId={}, action={}", datasetId, action);
return difyProxyService.updateDocumentStatus(datasetId, action, requestBody);
}
// ================================ 知识库文件操作日志 =======================
/**
* @description 查询知识库操作日志列表
* @param fileLog
* @author yslg
* @since 2025-12-18
*/
@PreAuthorize("hasAuthority('ai:knowledge:file:view')")
@PostMapping("/datasets/log/list")
public ResultDomain<TbKnowledgeFileLog> getKnowledgeFileLogList(@RequestBody TbKnowledgeFileLog fileLog){
return knowledgeFileLogService.getKnowledgeFileLogList(fileLog);
}
/**
* @description 查询知识库操作日志分页
* @param pageRequest
* @author yslg
* @since 2025-12-18
*/
@PreAuthorize("hasAuthority('ai:knowledge:file:view')")
@PostMapping("/datasets/log/page")
public ResultDomain<TbKnowledgeFileLog> getKnowledgeFileLogPage(@RequestBody PageRequest<TbKnowledgeFileLog> pageRequest){
return knowledgeFileLogService.getKnowledgeFileLogPage(pageRequest);
}
}

View File

@@ -0,0 +1,31 @@
package org.xyzh.ai.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.xyzh.api.ai.dto.TbKnowledgeFile;
import org.xyzh.api.ai.dto.TbKnowledgeFileLog;
import org.xyzh.api.ai.vo.KnowledgeFileVO;
import org.xyzh.common.core.page.PageParam;
import java.util.List;
/**
* @description 知识库文件数据访问层
* @filename KnowledgeFileMapper.java
* @author yslg
* @copyright xyzh
* @since 2025-12-17
*/
@Mapper
public interface TbKnowledgeFileLogMapper {
int addKnowledgeFileLog(TbKnowledgeFileLog tbKnowledgeFileLog);
List<TbKnowledgeFileLog> getKnowledgeFileLogList(@Param("filter") TbKnowledgeFileLog filter);
List<TbKnowledgeFileLog> getKnowledgeFileLogPage(@Param("pageParam") PageParam pageParam,@Param("filter") TbKnowledgeFileLog filter);
int countKnowledgeFileLog(@Param("filter") TbKnowledgeFileLog filter);
}

View File

@@ -0,0 +1,88 @@
package org.xyzh.ai.service.impl;
import java.util.Arrays;
import java.util.List;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.xyzh.ai.mapper.TbKnowledgeFileLogMapper;
import org.xyzh.api.ai.dto.TbKnowledgeFileLog;
import org.xyzh.api.ai.service.KnowledgeFileLogService;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageDomain;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.utils.NonUtils;
import org.xyzh.common.utils.id.IdUtil;
import org.xyzh.common.utils.validation.ValidationResult;
import org.xyzh.common.utils.validation.ValidationUtils;
@DubboService(version="1.0.0", group="ai", timeout=3000, retries=0)
public class KnowledgeFileLogServiceImpl implements KnowledgeFileLogService{
private static final Logger logger = LoggerFactory.getLogger(KnowledgeServiceImpl.class);
@Autowired
private TbKnowledgeFileLogMapper knowledgeFileLogMapper;
/**
* @description 新增知识库文件操作日志
* @param knowledgeFileLog
* @return 日志
* @author yslg
* @since 2025-12-31
*/
@Override
public ResultDomain<TbKnowledgeFileLog> addKnowledgeFileLog(TbKnowledgeFileLog knowledgeFileLog){
knowledgeFileLog.setOptsn(IdUtil.getOptsn());
knowledgeFileLog.setLogId(IdUtil.generateID());
ValidationResult rt = ValidationUtils.validate(knowledgeFileLog, Arrays.asList(
));
if(!rt.isValid()){
return ResultDomain.failure("日志参数校验失败");
}
int result = knowledgeFileLogMapper.addKnowledgeFileLog(knowledgeFileLog);
if(result >0){
return ResultDomain.success("添加知识库文件日志成功", knowledgeFileLog);
}else {
return ResultDomain.failure("添加知识库文件日志失败");
}
}
/**
* @description 查询知识库日志操作列表
* @param filter
* @return 日志列表
* @author yslg
* @since 2025-12-31
*/
@Override
public ResultDomain<TbKnowledgeFileLog> getKnowledgeFileLogList(TbKnowledgeFileLog filter){
List<TbKnowledgeFileLog> logs = knowledgeFileLogMapper.getKnowledgeFileLogList(filter);
return ResultDomain.success("查询知识库日志成功",logs);
}
/**
* @description 查询知识库日志操作分页
* @param pageRequest
* @return 日志分页数据
* @author yslg
* @since 2025-12-31
*/
@Override
public ResultDomain<TbKnowledgeFileLog> getKnowledgeFileLogPage(PageRequest<TbKnowledgeFileLog> pageRequest){
List<TbKnowledgeFileLog> logs = knowledgeFileLogMapper.getKnowledgeFileLogPage(pageRequest.getPageParam(), pageRequest.getFilter());
int total = knowledgeFileLogMapper.countKnowledgeFileLog(pageRequest.getFilter());
PageDomain<TbKnowledgeFileLog> pageDomain = new PageDomain<>();
pageDomain.setDataList(logs);
PageParam pageParam = pageRequest.getPageParam();
pageParam.setTotal(total);
pageDomain.setPageParam(pageParam);
return ResultDomain.success("查询知识库日志成功", pageDomain);
}
}

View File

@@ -16,7 +16,10 @@ import org.xyzh.ai.mapper.TbKnowledgeFileMapper;
import org.xyzh.ai.mapper.TbKnowledgeMapper;
import org.xyzh.api.ai.dto.TbKnowledge;
import org.xyzh.api.ai.dto.TbKnowledgeFile;
import org.xyzh.api.ai.dto.TbKnowledgeFileLog;
import org.xyzh.api.ai.constance.KnowledgeFileLogAction;
import org.xyzh.api.ai.service.AIFileUploadService;
import org.xyzh.api.ai.service.KnowledgeFileLogService;
import org.xyzh.api.ai.service.KnowledgeService;
import org.xyzh.api.ai.vo.KnowledgeFileVO;
import org.xyzh.api.file.dto.TbSysFileDTO;
@@ -58,6 +61,9 @@ public class KnowledgeServiceImpl implements KnowledgeService {
@DubboReference(version = "1.0.0", group = "file", timeout = 30000, retries = 0)
private FileService fileService;
@Autowired
private KnowledgeFileLogService knowledgeFileLogService;
@Autowired
private AIFileUploadService aiFileUploadService;
@@ -537,6 +543,18 @@ public class KnowledgeServiceImpl implements KnowledgeService {
int rows = knowledgeFileMapper.insertKnowledgeFile(knowledgeFile);
if (rows > 0) {
logger.info("保存知识库文件记录成功: knowledgeId={}, fileId={}, difyFileId={}", knowledgeId, fileId, difyFileId);
// 记录日志
TbKnowledgeFileLog log = new TbKnowledgeFileLog();
log.setKnowledgeId(knowledgeId);
log.setFileRootId(fileId);
log.setFileId(fileId);
log.setFileName(file.getOriginalFilename());
log.setVersion(1);
log.setAction(KnowledgeFileLogAction.UPLOAD.getAction());
log.setService("workcase");
log.setCreator(LoginUtil.getCurrentUserId());
log.setCreatorName(LoginUtil.getCurrentUserName());
knowledgeFileLogService.addKnowledgeFileLog(log);
return ResultDomain.success("上传成功", knowledgeFile);
}
@@ -683,6 +701,18 @@ public class KnowledgeServiceImpl implements KnowledgeService {
int rows = knowledgeFileMapper.insertKnowledgeFile(newKnowledgeFile);
if (rows > 0) {
logger.info("保存新版本记录成功: knowledgeId={}, fileRootId={}, newVersion={}", knowledgeId, fileRootId, newVersion);
// 记录日志
TbKnowledgeFileLog log = new TbKnowledgeFileLog();
log.setKnowledgeId(knowledgeId);
log.setFileRootId(fileRootId);
log.setFileId(newFileId);
log.setFileName(file.getOriginalFilename());
log.setVersion(newVersion);
log.setAction(KnowledgeFileLogAction.UPDATE.getAction());
log.setService("workcase");
log.setCreator(LoginUtil.getCurrentUserId());
log.setCreatorName(LoginUtil.getCurrentUserName());
knowledgeFileLogService.addKnowledgeFileLog(log);
return ResultDomain.success("更新成功", newKnowledgeFile);
}
@@ -735,6 +765,15 @@ public class KnowledgeServiceImpl implements KnowledgeService {
for (TbKnowledgeFile file : versions) {
fileService.deleteFile(file.getFileId());
}
// 记录日志
TbKnowledgeFileLog log = new TbKnowledgeFileLog();
log.setKnowledgeId(knowledge.getKnowledgeId());
log.setFileRootId(fileRootId);
log.setAction(KnowledgeFileLogAction.DELETE.getAction());
log.setService("workcase");
log.setCreator(LoginUtil.getCurrentUserId());
log.setCreatorName(LoginUtil.getCurrentUserName());
knowledgeFileLogService.addKnowledgeFileLog(log);
return ResultDomain.success("删除成功", true);
}

View File

@@ -47,7 +47,7 @@
<AppenderRef ref="RollingFile"/>
</Logger>
<Logger name="org.xyzh.agent" level="debug" additivity="false">
<Logger name="org.xyzh.ai" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Logger>

View File

@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.xyzh.ai.mapper.TbKnowledgeFileLogMapper">
<resultMap id="BaseResultMap" type="org.xyzh.api.ai.dto.TbKnowledgeFileLog">
<result column="optsn" property="optsn" jdbcType="VARCHAR"/>
<result column="log_id" property="logId" jdbcType="VARCHAR"/>
<result column="knowledge_id" property="knowledgeId" jdbcType="VARCHAR"/>
<result column="file_root_id" property="fileRootId" jdbcType="VARCHAR"/>
<result column="file_id" property="fileId" jdbcType="VARCHAR"/>
<result column="file_name" property="fileName" jdbcType="VARCHAR"/>
<result column="action" property="action" jdbcType="VARCHAR"/>
<result column="version" property="version" jdbcType="INTEGER"/>
<result column="creator" property="creator" jdbcType="VARCHAR"/>
<result column="creator_name" property="creatorName" jdbcType="VARCHAR"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
optsn, log_id, knowledge_id, file_root_id, file_id, file_name, version,
action, creator, creator_name, create_time
</sql>
<insert id="addKnowledgeFileLog" parameterType="org.xyzh.api.ai.dto.TbKnowledgeFileLog">
INSERT INTO ai.tb_knowledge_file_log (
optsn, log_id, knowledge_id, file_root_id, file_id, file_name, version,
action, service, creator, creator_name, create_time
) VALUES (
#{optsn}, #{logId}, #{knowledgeId}, #{fileRootId}, #{fileId}, #{fileName}, #{version},
#{action}, #{service}, #{creator}, #{creatorName}, NOW()
)
</insert>
<select id="getKnowledgeFileLogList" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM ai.tb_knowledge_file_log
WHERE 1=1
<if test="filter.knowledgeId != null and filter.knowledgeId != ''">
AND knowledge_id = #{filter.knowledgeId}
</if>
<if test="filter.service != null and filter.service != ''">
AND service = #{filter.service}
</if>
<if test="filter.fileName != null and filter.fileName != ''">
AND file_name LIKE CONCAT('%', #{filter.fileName}, '%')
</if>
<if test="filter.creatorName != null and filter.creatorName != ''">
AND creator_name LIKE CONCAT('%', #{filter.creatorName}, '%')
</if>
ORDER BY create_time DESC
</select>
<select id="getKnowledgeFileLogPage" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM ai.tb_knowledge_file_log
WHERE 1=1
<if test="filter.knowledgeId != null and filter.knowledgeId != ''">
AND knowledge_id = #{filter.knowledgeId}
</if>
<if test="filter.service != null and filter.service != ''">
AND service = #{filter.service}
</if>
<if test="filter.fileName != null and filter.fileName != ''">
AND file_name LIKE CONCAT('%', #{filter.fileName}, '%')
</if>
<if test="filter.creatorName != null and filter.creatorName != ''">
AND creator_name LIKE CONCAT('%', #{filter.creatorName}, '%')
</if>
ORDER BY create_time DESC
LIMIT #{pageParam.pageSize} OFFSET #{pageParam.offset}
</select>
<select id="countKnowledgeFileLog" resultType="int">
SELECT
count(log_id)
FROM ai.tb_knowledge_file_log
WHERE 1=1
<if test="filter.knowledgeId != null and filter.knowledgeId != ''">
AND knowledge_id = #{filter.knowledgeId}
</if>
<if test="filter.service != null and filter.service != ''">
AND service = #{filter.service}
</if>
<if test="filter.fileName != null and filter.fileName != ''">
AND file_name LIKE CONCAT('%', #{filter.fileName}, '%')
</if>
<if test="filter.creatorName != null and filter.creatorName != ''">
AND creator_name LIKE CONCAT('%', #{filter.creatorName}, '%')
</if>
</select>
</mapper>

View File

@@ -0,0 +1,28 @@
package org.xyzh.api.ai.constance;
public enum KnowledgeFileLogAction {
UPLOAD("upload", "上传文件"),
DELETE("delete", "删除文件"),
DOWNLOAD("download", "下载文件"),
UPDATE("update", "更新文件"),
SEGMENT_CREATE("segment_create", "创建分段"),
SEGMENT_UPDATE("segment_update", "更新分段"),
SEGMENT_DELETE("segment_delete", "更新分段");
private String action;
private String description;
private KnowledgeFileLogAction(String action, String description) {
this.action = action;
this.description = description;
}
public String getAction() {
return action;
}
public String getDescription(){
return description;
}
}

View File

@@ -0,0 +1,38 @@
package org.xyzh.api.ai.dto;
import org.xyzh.common.dto.BaseDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "知识库文件日志")
public class TbKnowledgeFileLog extends BaseDTO {
private static final long serialVersionUID = 1L;
@Schema(description = "日志Id")
private String logId;
@Schema(description = "知识库Id")
private String knowledgeId;
@Schema(description = "文件根Id")
private String fileRootId;
@Schema(description = "文件Id")
private String fileId;
@Schema(description = "文件名称")
private String fileName;
@Schema(description = "服务名称")
private String service;
@Schema(description = "文件版本")
private Integer version;
@Schema(description = "操作")
private String action;
@Schema(description = "操作人用户名")
private String creatorName;
}

View File

@@ -0,0 +1,43 @@
package org.xyzh.api.ai.service;
import org.xyzh.api.ai.dto.TbKnowledgeFileLog;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageRequest;
/**
* @description 知识库文件操作日志
* @filename KnowledgeFileLogService.java
* @author yslg
* @copyright yslg
* @since 2025-12-31
*/
public interface KnowledgeFileLogService {
/**
* @description 新增知识库文件操作日志
* @param knowledgeFileLog
* @return 日志
* @author yslg
* @since 2025-12-31
*/
ResultDomain<TbKnowledgeFileLog> addKnowledgeFileLog(TbKnowledgeFileLog knowledgeFileLog);
/**
* @description 查询知识库日志操作列表
* @param filter
* @return 日志列表
* @author yslg
* @since 2025-12-31
*/
ResultDomain<TbKnowledgeFileLog> getKnowledgeFileLogList(TbKnowledgeFileLog filter);
/**
* @description 查询知识库日志操作分页
* @param pageRequest
* @return 日志分页数据
* @author yslg
* @since 2025-12-31
*/
ResultDomain<TbKnowledgeFileLog> getKnowledgeFileLogPage(PageRequest<TbKnowledgeFileLog> pageRequest);
}

View File

@@ -54,7 +54,7 @@
<insert id="insertChatMessage" parameterType="org.xyzh.api.workcase.dto.TbChatRoomMessageDTO">
INSERT INTO workcase.tb_chat_room_message (
optsn, message_id, room_id, sender_id, sender_type, sender_name, content, creator
optsn, message_id, room_id, sender_id, sender_type, sender_name, content, creator,send_time
<if test="messageType != null">, message_type</if>
<if test="files != null">, files</if>
<if test="contentExtra != null">, content_extra</if>
@@ -62,10 +62,9 @@
<if test="isAiMessage != null">, is_ai_message</if>
<if test="aiMessageId != null">, ai_message_id</if>
<if test="status != null">, status</if>
<if test="sendTime != null">, send_time</if>
<if test="createTime != null">, create_time</if>
) VALUES (
#{optsn}, #{messageId}, #{roomId}, #{senderId}, #{senderType}, #{senderName}, #{content}, #{creator}
#{optsn}, #{messageId}, #{roomId}, #{senderId}, #{senderType}, #{senderName}, #{content}, #{creator},#{sendTime}
<if test="messageType != null">, #{messageType}</if>
<if test="files != null">, #{files, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler}</if>
<if test="contentExtra != null">, #{contentExtra, typeHandler=org.xyzh.common.jdbc.handler.FastJson2TypeHandler}::jsonb</if>
@@ -73,7 +72,6 @@
<if test="isAiMessage != null">, #{isAiMessage}</if>
<if test="aiMessageId != null">, #{aiMessageId}</if>
<if test="status != null">, #{status}</if>
<if test="sendTime != null">, send_time</if>
<if test="createTime != null">, #{createTime}</if>
)
</insert>