文件上传修复
This commit is contained in:
@@ -11,7 +11,7 @@ CREATE TABLE file.tb_sys_file (
|
|||||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||||
deleted INTEGER NOT NULL DEFAULT 0, -- 是否已删除(0-未删除,1-已删除)
|
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否已删除(false-未删除,true-已删除)
|
||||||
|
|
||||||
-- TbSysFileDTO 特有字段
|
-- TbSysFileDTO 特有字段
|
||||||
file_id VARCHAR(50) NOT NULL, -- 文件ID (主键)
|
file_id VARCHAR(50) NOT NULL, -- 文件ID (主键)
|
||||||
@@ -48,7 +48,7 @@ COMMENT ON COLUMN file.tb_sys_file.remark IS '备注';
|
|||||||
COMMENT ON COLUMN file.tb_sys_file.create_time IS '创建时间';
|
COMMENT ON COLUMN file.tb_sys_file.create_time IS '创建时间';
|
||||||
COMMENT ON COLUMN file.tb_sys_file.update_time IS '更新时间';
|
COMMENT ON COLUMN file.tb_sys_file.update_time IS '更新时间';
|
||||||
COMMENT ON COLUMN file.tb_sys_file.delete_time IS '删除时间';
|
COMMENT ON COLUMN file.tb_sys_file.delete_time IS '删除时间';
|
||||||
COMMENT ON COLUMN file.tb_sys_file.deleted IS '是否已删除(0-未删除,1-已删除)';
|
COMMENT ON COLUMN file.tb_sys_file.deleted IS '是否已删除(false-未删除,true-已删除)';
|
||||||
|
|
||||||
-- TbSysFileDTO 特有字段注释
|
-- TbSysFileDTO 特有字段注释
|
||||||
COMMENT ON COLUMN file.tb_sys_file.file_id IS '文件ID (主键)';
|
COMMENT ON COLUMN file.tb_sys_file.file_id IS '文件ID (主键)';
|
||||||
@@ -71,9 +71,9 @@ COMMENT ON COLUMN file.tb_sys_file.md5_hash IS '文件MD5值';
|
|||||||
COMMENT ON COLUMN file.tb_sys_file.extension IS '文件扩展名';
|
COMMENT ON COLUMN file.tb_sys_file.extension IS '文件扩展名';
|
||||||
|
|
||||||
-- 文件表索引
|
-- 文件表索引
|
||||||
CREATE INDEX idx_file_module_business ON file.tb_sys_file(module, business_id) WHERE deleted = 0;
|
-- CREATE INDEX idx_file_module_business ON file.tb_sys_file(module, business_id) WHERE deleted = false;
|
||||||
CREATE INDEX idx_file_uploader ON file.tb_sys_file(uploader) WHERE deleted = 0;
|
-- CREATE INDEX idx_file_uploader ON file.tb_sys_file(uploader) WHERE deleted = false;
|
||||||
CREATE INDEX idx_file_bucket ON file.tb_sys_file(bucket_name) WHERE deleted = 0;
|
-- CREATE INDEX idx_file_bucket ON file.tb_sys_file(bucket_name) WHERE deleted = false;
|
||||||
CREATE INDEX idx_file_status ON file.tb_sys_file(status) WHERE deleted = 0;
|
-- CREATE INDEX idx_file_status ON file.tb_sys_file(status) WHERE deleted = false;
|
||||||
CREATE INDEX idx_file_create_time ON file.tb_sys_file(create_time) WHERE deleted = 0;
|
-- CREATE INDEX idx_file_create_time ON file.tb_sys_file(create_time) WHERE deleted = false;
|
||||||
CREATE INDEX idx_file_md5 ON file.tb_sys_file(md5_hash) WHERE deleted = 0;
|
-- CREATE INDEX idx_file_md5 ON file.tb_sys_file(md5_hash) WHERE deleted = false;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.xyzh.ai.controller;
|
package org.xyzh.ai.controller;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -30,7 +30,7 @@ import java.util.Arrays;
|
|||||||
@RequestMapping("/ai/agent")
|
@RequestMapping("/ai/agent")
|
||||||
public class AgentController {
|
public class AgentController {
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "ai", timeout = 3000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private AgentService agentService;
|
private AgentService agentService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package org.xyzh.ai.controller;
|
|||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -38,10 +38,10 @@ import java.util.Map;
|
|||||||
@RequestMapping("/ai/chat")
|
@RequestMapping("/ai/chat")
|
||||||
public class ChatController {
|
public class ChatController {
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "ai", timeout = 30000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private AgentChatService chatService;
|
private AgentChatService chatService;
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "ai", timeout = 30000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private AIFileUploadService fileUploadService;
|
private AIFileUploadService fileUploadService;
|
||||||
|
|
||||||
// ====================== 会话管理 ======================
|
// ====================== 会话管理 ======================
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import jakarta.validation.constraints.NotEmpty;
|
|||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
@@ -40,10 +42,10 @@ import java.util.Map;
|
|||||||
public class KnowledgeController {
|
public class KnowledgeController {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(KnowledgeController.class);
|
private static final Logger logger = LoggerFactory.getLogger(KnowledgeController.class);
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "ai", timeout = 30000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private KnowledgeService knowledgeService;
|
private KnowledgeService knowledgeService;
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "ai", timeout = 30000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private DifyProxyService difyProxyService;
|
private DifyProxyService difyProxyService;
|
||||||
|
|
||||||
// ====================== 知识库管理 ======================
|
// ====================== 知识库管理 ======================
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.xyzh.ai.service.impl;
|
package org.xyzh.ai.service.impl;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.apache.dubbo.config.annotation.DubboService;
|
import org.apache.dubbo.config.annotation.DubboService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -35,7 +34,7 @@ public class AIFileUploadServiceImpl implements AIFileUploadService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private DifyApiClient difyApiClient;
|
private DifyApiClient difyApiClient;
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "ai", timeout = 30000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private AgentService agentService;
|
private AgentService agentService;
|
||||||
|
|
||||||
// ============================ 对话文件管理 ============================
|
// ============================ 对话文件管理 ============================
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.xyzh.ai.service.impl;
|
|||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.apache.dubbo.config.annotation.DubboService;
|
import org.apache.dubbo.config.annotation.DubboService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -58,7 +57,7 @@ public class AgentChatServiceImpl implements AgentChatService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TbChatMessageMapper chatMessageMapper;
|
private TbChatMessageMapper chatMessageMapper;
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "ai", timeout = 3000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private AgentService agentService;
|
private AgentService agentService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class KnowledgeServiceImpl implements KnowledgeService {
|
|||||||
@DubboReference(version = "1.0.0", group = "file", timeout = 30000)
|
@DubboReference(version = "1.0.0", group = "file", timeout = 30000)
|
||||||
private FileService fileService;
|
private FileService fileService;
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "ai", timeout = 30000, scope = "local")
|
@Autowired
|
||||||
private AIFileUploadService aiFileUploadService;
|
private AIFileUploadService aiFileUploadService;
|
||||||
|
|
||||||
// ================================= 知识库管理 =================================
|
// ================================= 知识库管理 =================================
|
||||||
@@ -464,8 +464,16 @@ public class KnowledgeServiceImpl implements KnowledgeService {
|
|||||||
return ResultDomain.failure("知识库未关联Dify");
|
return ResultDomain.failure("知识库未关联Dify");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 调用FileService上传到minio
|
// 3. 调用FileService上传到minio(使用字节数组方式,支持跨模块Dubbo调用)
|
||||||
ResultDomain<TbSysFileDTO> fileResult = fileService.uploadFile(file, "knowledge", knowledgeId);
|
byte[] fileBytes;
|
||||||
|
try {
|
||||||
|
fileBytes = file.getBytes();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("读取文件字节失败", e);
|
||||||
|
return ResultDomain.failure("读取文件失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
ResultDomain<TbSysFileDTO> fileResult = fileService.uploadFileBytes(
|
||||||
|
fileBytes, file.getOriginalFilename(), file.getContentType(), "knowledge", knowledgeId);
|
||||||
if (!fileResult.getSuccess() || fileResult.getData() == null) {
|
if (!fileResult.getSuccess() || fileResult.getData() == null) {
|
||||||
return ResultDomain.failure("上传文件到存储服务失败: " + fileResult.getMessage());
|
return ResultDomain.failure("上传文件到存储服务失败: " + fileResult.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,4 +95,17 @@ public interface FileService {
|
|||||||
*/
|
*/
|
||||||
ResultDomain<TbSysFileDTO> uploadFileVersion(MultipartFile file, String module, String businessId, String fileRootId);
|
ResultDomain<TbSysFileDTO> uploadFileVersion(MultipartFile file, String module, String businessId, String fileRootId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 通过字节数组上传文件(用于跨模块 Dubbo 调用)
|
||||||
|
* @param fileBytes 文件字节数组
|
||||||
|
* @param fileName 文件名
|
||||||
|
* @param contentType 文件类型
|
||||||
|
* @param module 所属模块
|
||||||
|
* @param businessId 业务ID
|
||||||
|
* @return ResultDomain<TbSysFileDTO> 上传结果
|
||||||
|
* @author yslg
|
||||||
|
* @since 2025-12-20
|
||||||
|
*/
|
||||||
|
ResultDomain<TbSysFileDTO> uploadFileBytes(byte[] fileBytes, String fileName, String contentType, String module, String businessId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -375,6 +375,74 @@ public class FileServiceImpl implements FileService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResultDomain<TbSysFileDTO> uploadFileBytes(byte[] fileBytes, String fileName, String contentType, String module, String businessId) {
|
||||||
|
try {
|
||||||
|
if (fileBytes == null || fileBytes.length == 0) {
|
||||||
|
return ResultDomain.failure("文件不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成文件信息
|
||||||
|
String extension = getFileExtension(fileName);
|
||||||
|
long size = fileBytes.length;
|
||||||
|
|
||||||
|
// 生成唯一的对象名称
|
||||||
|
String objectName = generateObjectName(fileName, module);
|
||||||
|
|
||||||
|
// 计算文件MD5
|
||||||
|
String md5Hash = calculateMD5(fileBytes);
|
||||||
|
|
||||||
|
// 上传到MinIO
|
||||||
|
String bucketName = minioConfig.getBucketName();
|
||||||
|
java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(fileBytes);
|
||||||
|
boolean uploadSuccess = minioUtil.uploadFile(
|
||||||
|
bucketName,
|
||||||
|
objectName,
|
||||||
|
inputStream,
|
||||||
|
size,
|
||||||
|
contentType
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!uploadSuccess) {
|
||||||
|
return ResultDomain.failure("文件上传到MinIO失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成文件URL
|
||||||
|
String fileUrl = minioConfig.getEndpoint() + "/" + bucketName + "/" + objectName;
|
||||||
|
|
||||||
|
// 创建文件DTO
|
||||||
|
TbSysFileDTO fileDTO = new TbSysFileDTO();
|
||||||
|
fileDTO.setOptsn(UUID.randomUUID().toString());
|
||||||
|
fileDTO.setFileId(UUID.randomUUID().toString().replace("-", ""));
|
||||||
|
fileDTO.setName(fileName);
|
||||||
|
fileDTO.setPath(objectName);
|
||||||
|
fileDTO.setUrl(fileUrl);
|
||||||
|
fileDTO.setSize(size);
|
||||||
|
fileDTO.setMimeType(contentType);
|
||||||
|
fileDTO.setExtension(extension);
|
||||||
|
fileDTO.setMd5Hash(md5Hash);
|
||||||
|
fileDTO.setModule(module);
|
||||||
|
fileDTO.setBusinessId(businessId);
|
||||||
|
fileDTO.setVersion(1);
|
||||||
|
fileDTO.setFileRootId(fileDTO.getFileId());
|
||||||
|
fileDTO.setCreateTime(new java.util.Date());
|
||||||
|
|
||||||
|
// 保存到数据库
|
||||||
|
int result = fileMapper.insertFile(fileDTO);
|
||||||
|
if (result <= 0) {
|
||||||
|
minioUtil.deleteFile(bucketName, objectName);
|
||||||
|
return ResultDomain.failure("文件信息保存失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("字节数组文件上传成功: {}", fileName);
|
||||||
|
return ResultDomain.success("文件上传成功", fileDTO);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("字节数组文件上传失败", e);
|
||||||
|
return ResultDomain.failure("文件上传失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成唯一的对象名称
|
* 生成唯一的对象名称
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.xyzh.system.controller;
|
package org.xyzh.system.controller;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -26,7 +25,7 @@ public class DeptRoleController {
|
|||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(DeptRoleController.class);
|
private static final Logger logger = LoggerFactory.getLogger(DeptRoleController.class);
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "system", timeout = 3000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private DeptRoleService deptRoleService;
|
private DeptRoleService deptRoleService;
|
||||||
|
|
||||||
// ================= 部门角色相关接口 =================
|
// ================= 部门角色相关接口 =================
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package org.xyzh.system.controller;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@@ -32,7 +32,7 @@ import jakarta.validation.constraints.NotNull;
|
|||||||
@RequestMapping("/system/guest")
|
@RequestMapping("/system/guest")
|
||||||
public class GuestController {
|
public class GuestController {
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "system", timeout = 3000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private GuestService guestService;
|
private GuestService guestService;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.xyzh.system.controller;
|
package org.xyzh.system.controller;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -25,7 +24,7 @@ public class PermissionController {
|
|||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(PermissionController.class);
|
private static final Logger logger = LoggerFactory.getLogger(PermissionController.class);
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "system", timeout = 3000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private ModulePermissionService modulePermissionService;
|
private ModulePermissionService modulePermissionService;
|
||||||
|
|
||||||
// ================= 模块相关接口 =================
|
// ================= 模块相关接口 =================
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.xyzh.system.controller;
|
package org.xyzh.system.controller;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -24,7 +23,7 @@ public class SysConfigController {
|
|||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(SysConfigController.class);
|
private static final Logger logger = LoggerFactory.getLogger(SysConfigController.class);
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "system", timeout = 3000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private SysConfigService sysConfigService;
|
private SysConfigService sysConfigService;
|
||||||
|
|
||||||
// ================= 系统配置相关接口 =================
|
// ================= 系统配置相关接口 =================
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.xyzh.system.controller;
|
package org.xyzh.system.controller;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -26,7 +25,7 @@ public class UserController {
|
|||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
|
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "system", timeout = 3000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private SysUserService sysUserService;
|
private SysUserService sysUserService;
|
||||||
|
|
||||||
// ================= 用户相关接口 =================
|
// ================= 用户相关接口 =================
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.xyzh.system.controller;
|
package org.xyzh.system.controller;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -23,7 +22,7 @@ public class ViewController {
|
|||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ViewController.class);
|
private static final Logger logger = LoggerFactory.getLogger(ViewController.class);
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "system", timeout = 3000, retries = 0, scope = "local")
|
@Autowired
|
||||||
private ViewService viewService;
|
private ViewService viewService;
|
||||||
|
|
||||||
// ================= 视图相关接口 =================
|
// ================= 视图相关接口 =================
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.xyzh.workcase.controller;
|
package org.xyzh.workcase.controller;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@@ -42,7 +41,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
@RequestMapping("/workcase/chat")
|
@RequestMapping("/workcase/chat")
|
||||||
public class WorkcaseChatContorller {
|
public class WorkcaseChatContorller {
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "workcase", check = false, scope = "local")
|
@Autowired
|
||||||
private WorkcaseChatService workcaseChatService;
|
private WorkcaseChatService workcaseChatService;
|
||||||
|
|
||||||
// ========================= AI对话管理 =========================
|
// ========================= AI对话管理 =========================
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.xyzh.workcase.controller;
|
package org.xyzh.workcase.controller;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@@ -36,7 +36,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
@RequestMapping("/workcase")
|
@RequestMapping("/workcase")
|
||||||
public class WorkcaseController {
|
public class WorkcaseController {
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "workcase", check = false, scope = "local")
|
@Autowired
|
||||||
private WorkcaseService workcaseService;
|
private WorkcaseService workcaseService;
|
||||||
|
|
||||||
// ========================= 工单管理 =========================
|
// ========================= 工单管理 =========================
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.xyzh.workcase.service;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.apache.dubbo.config.annotation.DubboService;
|
import org.apache.dubbo.config.annotation.DubboService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -38,7 +37,7 @@ public class WorkcaseServiceImpl implements WorkcaseService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TbWorkcaseDeviceMapper workcaseDeviceMapper;
|
private TbWorkcaseDeviceMapper workcaseDeviceMapper;
|
||||||
|
|
||||||
@DubboReference(version = "1.0.0", group = "workcase", check = false, scope = "local")
|
@Autowired
|
||||||
private WorkcaseChatService workcaseChatService;
|
private WorkcaseChatService workcaseChatService;
|
||||||
|
|
||||||
// ====================== 工单管理 ======================
|
// ====================== 工单管理 ======================
|
||||||
|
|||||||
@@ -169,6 +169,8 @@ interface Props {
|
|||||||
maxCount?: number
|
maxCount?: number
|
||||||
title?: string
|
title?: string
|
||||||
buttonText?: string
|
buttonText?: string
|
||||||
|
// 是否自动上传,默认 true,设为 false 时需要手动调用 uploadFiles
|
||||||
|
autoUpload?: boolean
|
||||||
// 自定义上传函数,如果提供则使用外部实现,否则使用默认上传逻辑
|
// 自定义上传函数,如果提供则使用外部实现,否则使用默认上传逻辑
|
||||||
customUpload?: (files: File[]) => Promise<TbSysFileDTO[] | void>
|
customUpload?: (files: File[]) => Promise<TbSysFileDTO[] | void>
|
||||||
}
|
}
|
||||||
@@ -181,6 +183,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
maxCount: 10,
|
maxCount: 10,
|
||||||
title: '文件上传',
|
title: '文件上传',
|
||||||
buttonText: '上传文件',
|
buttonText: '上传文件',
|
||||||
|
autoUpload: true,
|
||||||
customUpload: undefined
|
customUpload: undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -234,7 +237,7 @@ const handleDrop = (event: DragEvent) => {
|
|||||||
addFiles(Array.from(files))
|
addFiles(Array.from(files))
|
||||||
|
|
||||||
// cover模式和content模式下拖拽文件后立即上传
|
// cover模式和content模式下拖拽文件后立即上传
|
||||||
if (props.mode === 'cover' || props.mode === 'content') {
|
if (props.autoUpload && (props.mode === 'cover' || props.mode === 'content')) {
|
||||||
uploadFiles()
|
uploadFiles()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,8 +324,8 @@ const handleFileSelect = (event: Event) => {
|
|||||||
// 清空 input,允许重复选择同一文件
|
// 清空 input,允许重复选择同一文件
|
||||||
target.value = ''
|
target.value = ''
|
||||||
|
|
||||||
// cover模式和content模式下选择文件后立即上传
|
// cover模式和content模式下,如果 autoUpload 为 true 则立即上传
|
||||||
if (props.mode === 'cover' || props.mode === 'content') {
|
if (props.autoUpload && (props.mode === 'cover' || props.mode === 'content')) {
|
||||||
uploadFiles()
|
uploadFiles()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<AdminLayout title="知识库管理" info="管理外部和内部知识库文档">
|
<AdminLayout title="知识库管理" info="管理外部和内部知识库文档">
|
||||||
<template #action>
|
<template #action>
|
||||||
<el-button type="primary" @click="showUploadDialog = true">
|
<el-button type="primary" @click="openUploadDialog">
|
||||||
<el-icon><Upload /></el-icon>
|
<el-icon><Upload /></el-icon>
|
||||||
上传文档
|
上传文档
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -68,42 +68,18 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 上传文档弹窗 -->
|
<!-- 上传文档组件 -->
|
||||||
<el-dialog v-model="showUploadDialog" title="上传文档" width="500px">
|
<FileUpload
|
||||||
<el-form :model="uploadForm" label-width="80px">
|
ref="fileUploadRef"
|
||||||
<el-form-item label="知识库" required>
|
mode="dialog"
|
||||||
<el-select v-model="uploadForm.knowledgeId" placeholder="请选择知识库" style="width: 100%">
|
:title="'上传文档到:' + currentKnowledgeName"
|
||||||
<el-option
|
button-text="上传文档"
|
||||||
v-for="kb in knowledges"
|
accept=".pdf,.doc,.docx,.txt,.md"
|
||||||
:key="kb.knowledgeId"
|
:max-size="50 * 1024 * 1024"
|
||||||
:label="kb.title"
|
:max-count="10"
|
||||||
:value="kb.knowledgeId"
|
:custom-upload="customKnowledgeUpload"
|
||||||
|
@upload-error="handleUploadError"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="文件" required>
|
|
||||||
<el-upload
|
|
||||||
action="#"
|
|
||||||
:auto-upload="false"
|
|
||||||
:on-change="handleFileChange"
|
|
||||||
:limit="1"
|
|
||||||
drag
|
|
||||||
>
|
|
||||||
<el-icon class="el-icon--upload"><Upload /></el-icon>
|
|
||||||
<div class="el-upload__text">
|
|
||||||
拖拽文件到此或 <em>点击上传</em>
|
|
||||||
</div>
|
|
||||||
<template #tip>
|
|
||||||
<div class="el-upload__tip">支持 PDF、Word、TXT 等文档格式</div>
|
|
||||||
</template>
|
|
||||||
</el-upload>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<el-button @click="showUploadDialog = false">取消</el-button>
|
|
||||||
<el-button type="primary" @click="handleUpload" :loading="uploading">上传</el-button>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</AdminLayout>
|
</AdminLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -111,8 +87,9 @@
|
|||||||
import { ref, computed, onMounted, watch } from 'vue'
|
import { ref, computed, onMounted, watch } from 'vue'
|
||||||
import AdminLayout from '@/views/admin/AdminLayout.vue'
|
import AdminLayout from '@/views/admin/AdminLayout.vue'
|
||||||
import { Upload, Search, Document, View, Download, Delete } from '@element-plus/icons-vue'
|
import { Upload, Search, Document, View, Download, Delete } from '@element-plus/icons-vue'
|
||||||
import { ElMessage, ElMessageBox, type UploadFile } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { aiKnowledgeAPI } from 'shared/api/ai'
|
import { aiKnowledgeAPI } from 'shared/api/ai'
|
||||||
|
import { FileUpload } from 'shared/components'
|
||||||
import type { TbKnowledge } from 'shared/types'
|
import type { TbKnowledge } from 'shared/types'
|
||||||
|
|
||||||
// Tab 配置
|
// Tab 配置
|
||||||
@@ -123,9 +100,8 @@ const tabConfig = [
|
|||||||
|
|
||||||
const activeTab = ref('external')
|
const activeTab = ref('external')
|
||||||
const searchKeyword = ref('')
|
const searchKeyword = ref('')
|
||||||
const showUploadDialog = ref(false)
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const uploading = ref(false)
|
const fileUploadRef = ref<InstanceType<typeof FileUpload> | null>(null)
|
||||||
|
|
||||||
// 知识库列表
|
// 知识库列表
|
||||||
const knowledges = ref<TbKnowledge[]>([])
|
const knowledges = ref<TbKnowledge[]>([])
|
||||||
@@ -146,11 +122,6 @@ interface DocumentItem {
|
|||||||
}
|
}
|
||||||
const documents = ref<DocumentItem[]>([])
|
const documents = ref<DocumentItem[]>([])
|
||||||
|
|
||||||
const uploadForm = ref({
|
|
||||||
knowledgeId: '',
|
|
||||||
file: null as File | null
|
|
||||||
})
|
|
||||||
|
|
||||||
// 当前 Tab 配置
|
// 当前 Tab 配置
|
||||||
const currentTabConfig = computed(() => tabConfig.find(t => t.name === activeTab.value) || tabConfig[0])
|
const currentTabConfig = computed(() => tabConfig.find(t => t.name === activeTab.value) || tabConfig[0])
|
||||||
const currentTabDesc = computed(() => currentTabConfig.value.desc)
|
const currentTabDesc = computed(() => currentTabConfig.value.desc)
|
||||||
@@ -285,45 +256,50 @@ const deleteFile = async (row: DocumentItem) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFileChange = (uploadFile: UploadFile) => {
|
// 自定义知识库文件上传
|
||||||
uploadForm.value.file = uploadFile.raw || null
|
const customKnowledgeUpload = async (files: File[]) => {
|
||||||
}
|
if (!activeKnowledgeId.value) {
|
||||||
|
ElMessage.error('请先选择知识库')
|
||||||
|
throw new Error('请先选择知识库')
|
||||||
|
}
|
||||||
|
const targetKnowledgeId = activeKnowledgeId.value
|
||||||
|
|
||||||
const handleUpload = async () => {
|
// 单文件上传
|
||||||
if (!uploadForm.value.knowledgeId) {
|
if (files.length === 1) {
|
||||||
ElMessage.error('请选择知识库')
|
const result = await aiKnowledgeAPI.uploadToKnowledge(files[0], targetKnowledgeId)
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!uploadForm.value.file) {
|
|
||||||
ElMessage.error('请选择要上传的文件')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const targetKnowledgeId = uploadForm.value.knowledgeId
|
|
||||||
uploading.value = true
|
|
||||||
try {
|
|
||||||
const result = await aiKnowledgeAPI.uploadToKnowledge(
|
|
||||||
uploadForm.value.file,
|
|
||||||
targetKnowledgeId
|
|
||||||
)
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
ElMessage.success('文件上传成功')
|
ElMessage.success('文件上传成功')
|
||||||
showUploadDialog.value = false
|
|
||||||
uploadForm.value = { knowledgeId: '', file: null }
|
|
||||||
fetchKnowledges()
|
fetchKnowledges()
|
||||||
if (targetKnowledgeId === activeKnowledgeId.value) {
|
|
||||||
fetchDocuments(activeKnowledgeId.value)
|
fetchDocuments(activeKnowledgeId.value)
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || '上传失败')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(result.message || '上传失败')
|
// 批量上传
|
||||||
|
const result = await aiKnowledgeAPI.batchUploadToKnowledge(files, targetKnowledgeId)
|
||||||
|
if (result.success) {
|
||||||
|
ElMessage.success('文件上传成功')
|
||||||
|
fetchKnowledges()
|
||||||
|
fetchDocuments(activeKnowledgeId.value)
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || '上传失败')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
console.error('上传文件失败:', error)
|
|
||||||
ElMessage.error('上传文件失败')
|
|
||||||
} finally {
|
|
||||||
uploading.value = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleUploadError = (error: string) => {
|
||||||
|
ElMessage.error(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开上传弹窗
|
||||||
|
const openUploadDialog = () => {
|
||||||
|
if (!activeKnowledgeId.value) {
|
||||||
|
ElMessage.warning('请先选择一个知识库')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileUploadRef.value?.openDialog()
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchKnowledges()
|
fetchKnowledges()
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user