完善知识库容量权限与界面
This commit is contained in:
@@ -42,6 +42,9 @@ public class ComponentDto implements Serializable {
|
|||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
private Date created;
|
private Date created;
|
||||||
|
|
||||||
|
@Schema(description = "资源占用空间,单位字节,知识库有效")
|
||||||
|
private Long fileSize;
|
||||||
|
|
||||||
private Long creatorId;
|
private Long creatorId;
|
||||||
|
|
||||||
@Schema(description = "创建者信息")
|
@Schema(description = "创建者信息")
|
||||||
|
|||||||
@@ -105,6 +105,8 @@ public class ComponentApplicationServiceImpl implements ComponentApplicationServ
|
|||||||
componentDto.setType(ComponentTypeEnum.Knowledge);
|
componentDto.setType(ComponentTypeEnum.Knowledge);
|
||||||
componentDto.setExt(knowledgeConfigModel.getDataType());
|
componentDto.setExt(knowledgeConfigModel.getDataType());
|
||||||
componentDto.setIcon(knowledgeConfigModel.getIcon());
|
componentDto.setIcon(knowledgeConfigModel.getIcon());
|
||||||
|
Long fileSize = iKnowledgeConfigApplicationService.queryTotalFileSize(knowledgeConfigModel.getId());
|
||||||
|
componentDto.setFileSize(fileSize == null ? 0L : fileSize);
|
||||||
componentDto.setCreatorId(knowledgeConfigModel.getCreatorId());
|
componentDto.setCreatorId(knowledgeConfigModel.getCreatorId());
|
||||||
UserDto userDto = userDtoMap.get(knowledgeConfigModel.getCreatorId());
|
UserDto userDto = userDtoMap.get(knowledgeConfigModel.getCreatorId());
|
||||||
if (userDto != null) {
|
if (userDto != null) {
|
||||||
|
|||||||
@@ -103,7 +103,13 @@
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="queryTotalFileSize" resultType="java.lang.Long">
|
<select id="queryTotalFileSize" resultType="java.lang.Long">
|
||||||
select sum(file_size)
|
select coalesce(sum(
|
||||||
|
case
|
||||||
|
when coalesce(file_size, 0) > 0 then file_size
|
||||||
|
when data_type = 2 then octet_length(coalesce(file_content, ''))
|
||||||
|
else 0
|
||||||
|
end
|
||||||
|
), 0)
|
||||||
from knowledge_document
|
from knowledge_document
|
||||||
where kb_id = #{kbId}
|
where kb_id = #{kbId}
|
||||||
and yn = 1
|
and yn = 1
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.xspaceagi.knowledge.domain.repository.IKnowledgeConfigRepository;
|
|||||||
import com.xspaceagi.knowledge.domain.vectordb.VectorDBService;
|
import com.xspaceagi.knowledge.domain.vectordb.VectorDBService;
|
||||||
import com.xspaceagi.knowledge.man.ui.web.base.BaseController;
|
import com.xspaceagi.knowledge.man.ui.web.base.BaseController;
|
||||||
import com.xspaceagi.knowledge.man.ui.web.dto.config.*;
|
import com.xspaceagi.knowledge.man.ui.web.dto.config.*;
|
||||||
|
import com.xspaceagi.knowledge.man.ui.web.permission.KnowledgeWritePermissionChecker;
|
||||||
import com.xspaceagi.system.application.dto.SpaceDto;
|
import com.xspaceagi.system.application.dto.SpaceDto;
|
||||||
import com.xspaceagi.system.application.service.SpaceApplicationService;
|
import com.xspaceagi.system.application.service.SpaceApplicationService;
|
||||||
import com.xspaceagi.system.application.service.SysDataPermissionApplicationService;
|
import com.xspaceagi.system.application.service.SysDataPermissionApplicationService;
|
||||||
@@ -71,6 +72,9 @@ public class KnowledgeConfigController extends BaseController {
|
|||||||
@Resource
|
@Resource
|
||||||
private SysDataPermissionApplicationService sysDataPermissionApplicationService;
|
private SysDataPermissionApplicationService sysDataPermissionApplicationService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private KnowledgeWritePermissionChecker knowledgeWritePermissionChecker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 知识库的列表查询接口,合并为详情的权限(需要权限)
|
* 知识库的列表查询接口,合并为详情的权限(需要权限)
|
||||||
*
|
*
|
||||||
@@ -132,6 +136,7 @@ public class KnowledgeConfigController extends BaseController {
|
|||||||
|
|
||||||
var id = request.getId();
|
var id = request.getId();
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkKnowledge(id);
|
||||||
knowledgeConfigApplicationService.deleteById(id, userContext);
|
knowledgeConfigApplicationService.deleteById(id, userContext);
|
||||||
return ReqResult.success();
|
return ReqResult.success();
|
||||||
|
|
||||||
@@ -151,6 +156,9 @@ public class KnowledgeConfigController extends BaseController {
|
|||||||
public ReqResult<KnowledgeConfigVo> detailById(@Schema(description = "知识库ID") Long id) {
|
public ReqResult<KnowledgeConfigVo> detailById(@Schema(description = "知识库ID") Long id) {
|
||||||
|
|
||||||
var model = knowledgeConfigApplicationService.queryOneInfoById(id);
|
var model = knowledgeConfigApplicationService.queryOneInfoById(id);
|
||||||
|
if (model != null) {
|
||||||
|
model.setFileSize(knowledgeConfigApplicationService.queryTotalFileSize(id));
|
||||||
|
}
|
||||||
var knowledgeConfigVo = KnowledgeConfigVo.convert2Dto(model);
|
var knowledgeConfigVo = KnowledgeConfigVo.convert2Dto(model);
|
||||||
if (knowledgeConfigVo != null) {
|
if (knowledgeConfigVo != null) {
|
||||||
knowledgeConfigVo.setIcon(DefaultIconUrlUtil.setDefaultIconUrl(knowledgeConfigVo.getIcon(), knowledgeConfigVo.getName(), "knowledge"));
|
knowledgeConfigVo.setIcon(DefaultIconUrlUtil.setDefaultIconUrl(knowledgeConfigVo.getIcon(), knowledgeConfigVo.getName(), "knowledge"));
|
||||||
@@ -185,6 +193,7 @@ public class KnowledgeConfigController extends BaseController {
|
|||||||
public ReqResult<Long> update(@RequestBody KnowledgeConfigUpdateRequest updateDto) {
|
public ReqResult<Long> update(@RequestBody KnowledgeConfigUpdateRequest updateDto) {
|
||||||
|
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkKnowledge(updateDto.getId());
|
||||||
var model = KnowledgeConfigUpdateRequest.convert2Model(updateDto);
|
var model = KnowledgeConfigUpdateRequest.convert2Model(updateDto);
|
||||||
var id = knowledgeConfigApplicationService.updateInfo(model, userContext);
|
var id = knowledgeConfigApplicationService.updateInfo(model, userContext);
|
||||||
return ReqResult.success(id);
|
return ReqResult.success(id);
|
||||||
@@ -239,6 +248,7 @@ public class KnowledgeConfigController extends BaseController {
|
|||||||
@RequestMapping(path = "/initVectorDb", method = RequestMethod.POST)
|
@RequestMapping(path = "/initVectorDb", method = RequestMethod.POST)
|
||||||
public ReqResult<Long> add(Long id) {
|
public ReqResult<Long> add(Long id) {
|
||||||
|
|
||||||
|
knowledgeWritePermissionChecker.checkKnowledge(id);
|
||||||
var model = this.knowledgeConfigApplicationService.queryOneInfoById(id);
|
var model = this.knowledgeConfigApplicationService.queryOneInfoById(id);
|
||||||
Long embeddingModelId = null;
|
Long embeddingModelId = null;
|
||||||
if (model != null) {
|
if (model != null) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.xspaceagi.knowledge.domain.repository.IKnowledgeDocumentRepository;
|
|||||||
import com.xspaceagi.knowledge.man.ui.web.base.BaseController;
|
import com.xspaceagi.knowledge.man.ui.web.base.BaseController;
|
||||||
import com.xspaceagi.knowledge.man.ui.web.dto.config.KnowledgeConfigDeleteRequest;
|
import com.xspaceagi.knowledge.man.ui.web.dto.config.KnowledgeConfigDeleteRequest;
|
||||||
import com.xspaceagi.knowledge.man.ui.web.dto.document.*;
|
import com.xspaceagi.knowledge.man.ui.web.dto.document.*;
|
||||||
|
import com.xspaceagi.knowledge.man.ui.web.permission.KnowledgeWritePermissionChecker;
|
||||||
import com.xspaceagi.system.application.dto.SpaceDto;
|
import com.xspaceagi.system.application.dto.SpaceDto;
|
||||||
import com.xspaceagi.system.application.dto.UserDto;
|
import com.xspaceagi.system.application.dto.UserDto;
|
||||||
import com.xspaceagi.system.application.service.SpaceApplicationService;
|
import com.xspaceagi.system.application.service.SpaceApplicationService;
|
||||||
@@ -78,6 +79,9 @@ public class KnowledgeDocumentController extends BaseController {
|
|||||||
@Resource
|
@Resource
|
||||||
private IKnowledgeConfigApplicationService knowledgeConfigApplicationService;
|
private IKnowledgeConfigApplicationService knowledgeConfigApplicationService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private KnowledgeWritePermissionChecker knowledgeWritePermissionChecker;
|
||||||
|
|
||||||
@RequireResource(COMPONENT_LIB_QUERY_DETAIL)
|
@RequireResource(COMPONENT_LIB_QUERY_DETAIL)
|
||||||
@OperationLogReporter(actionType = ActionType.QUERY, action = "数据列表查询", objectName = "知识库文档", systemCode = SystemEnum.KNOWLEDGE_CONFIG)
|
@OperationLogReporter(actionType = ActionType.QUERY, action = "数据列表查询", objectName = "知识库文档", systemCode = SystemEnum.KNOWLEDGE_CONFIG)
|
||||||
@LogPrint(step = "知识库[知识库文档]-数据列表查询")
|
@LogPrint(step = "知识库[知识库文档]-数据列表查询")
|
||||||
@@ -161,6 +165,7 @@ public class KnowledgeDocumentController extends BaseController {
|
|||||||
var id = request.getId();
|
var id = request.getId();
|
||||||
|
|
||||||
var userContext = getUser();
|
var userContext = getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkDocument(id);
|
||||||
knowledgeDocumentApplicationService.deleteById(id, userContext);
|
knowledgeDocumentApplicationService.deleteById(id, userContext);
|
||||||
return ReqResult.success();
|
return ReqResult.success();
|
||||||
|
|
||||||
@@ -200,6 +205,7 @@ public class KnowledgeDocumentController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkDocument(updateDto.getDocId());
|
||||||
|
|
||||||
var model = KnowledgeDocumentUpdateRequest.convert2Model(updateDto);
|
var model = KnowledgeDocumentUpdateRequest.convert2Model(updateDto);
|
||||||
|
|
||||||
@@ -218,6 +224,7 @@ public class KnowledgeDocumentController extends BaseController {
|
|||||||
|
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
var docId = updateDto.getDocId();
|
var docId = updateDto.getDocId();
|
||||||
|
knowledgeWritePermissionChecker.checkDocument(docId);
|
||||||
var name = updateDto.getName();
|
var name = updateDto.getName();
|
||||||
var id = knowledgeDocumentApplicationService.updateDocName(docId, name, userContext);
|
var id = knowledgeDocumentApplicationService.updateDocName(docId, name, userContext);
|
||||||
return ReqResult.success(id);
|
return ReqResult.success(id);
|
||||||
@@ -236,6 +243,7 @@ public class KnowledgeDocumentController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkKnowledge(addDto.getKbId());
|
||||||
|
|
||||||
//新增权限内容
|
//新增权限内容
|
||||||
//知识库大小验证
|
//知识库大小验证
|
||||||
@@ -291,6 +299,7 @@ public class KnowledgeDocumentController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkKnowledge(addDto.getKbId());
|
||||||
var model = KnowledgeDocumentCustomAddRequest.convert2ModelForCustom(addDto);
|
var model = KnowledgeDocumentCustomAddRequest.convert2ModelForCustom(addDto);
|
||||||
|
|
||||||
var ids = knowledgeDocumentApplicationService.customAddInfo(model, userContext);
|
var ids = knowledgeDocumentApplicationService.customAddInfo(model, userContext);
|
||||||
@@ -306,6 +315,7 @@ public class KnowledgeDocumentController extends BaseController {
|
|||||||
public ReqResult<Void> generateQAs(@PathVariable Long docId) {
|
public ReqResult<Void> generateQAs(@PathVariable Long docId) {
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
|
||||||
|
knowledgeWritePermissionChecker.checkDocument(docId);
|
||||||
knowledgeDocumentApplicationService.generateForQa(docId, userContext);
|
knowledgeDocumentApplicationService.generateForQa(docId, userContext);
|
||||||
return ReqResult.success();
|
return ReqResult.success();
|
||||||
}
|
}
|
||||||
@@ -318,6 +328,7 @@ public class KnowledgeDocumentController extends BaseController {
|
|||||||
public ReqResult<Void> generateEmbeddings(@PathVariable Long docId) {
|
public ReqResult<Void> generateEmbeddings(@PathVariable Long docId) {
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
|
||||||
|
knowledgeWritePermissionChecker.checkDocument(docId);
|
||||||
knowledgeDocumentApplicationService.generateEmbeddings(docId, userContext);
|
knowledgeDocumentApplicationService.generateEmbeddings(docId, userContext);
|
||||||
return ReqResult.success();
|
return ReqResult.success();
|
||||||
}
|
}
|
||||||
@@ -340,6 +351,7 @@ public class KnowledgeDocumentController extends BaseController {
|
|||||||
public ReqResult<Void> autoRetryTaskByDocId(@PathVariable Long docId) {
|
public ReqResult<Void> autoRetryTaskByDocId(@PathVariable Long docId) {
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
var userId = userContext.getUserId();
|
var userId = userContext.getUserId();
|
||||||
|
knowledgeWritePermissionChecker.checkDocument(docId);
|
||||||
|
|
||||||
UserDto userDto = (UserDto) RequestContext.get().getUser();
|
UserDto userDto = (UserDto) RequestContext.get().getUser();
|
||||||
TenantRunnable tenantRunnable = new TenantRunnable(() -> {
|
TenantRunnable tenantRunnable = new TenantRunnable(() -> {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import com.xspaceagi.knowledge.man.ui.web.dto.qa.KnowledgeQaSegmentAddRequest;
|
|||||||
import com.xspaceagi.knowledge.man.ui.web.dto.qa.KnowledgeQaSegmentQueryRequest;
|
import com.xspaceagi.knowledge.man.ui.web.dto.qa.KnowledgeQaSegmentQueryRequest;
|
||||||
import com.xspaceagi.knowledge.man.ui.web.dto.qa.KnowledgeQaSegmentUpdateRequest;
|
import com.xspaceagi.knowledge.man.ui.web.dto.qa.KnowledgeQaSegmentUpdateRequest;
|
||||||
import com.xspaceagi.knowledge.man.ui.web.dto.qa.KnowledgeQaSegmentVo;
|
import com.xspaceagi.knowledge.man.ui.web.dto.qa.KnowledgeQaSegmentVo;
|
||||||
|
import com.xspaceagi.knowledge.man.ui.web.permission.KnowledgeWritePermissionChecker;
|
||||||
import com.xspaceagi.system.sdk.operate.ActionType;
|
import com.xspaceagi.system.sdk.operate.ActionType;
|
||||||
import com.xspaceagi.system.sdk.operate.OperationLogReporter;
|
import com.xspaceagi.system.sdk.operate.OperationLogReporter;
|
||||||
import com.xspaceagi.system.sdk.operate.SystemEnum;
|
import com.xspaceagi.system.sdk.operate.SystemEnum;
|
||||||
@@ -68,6 +69,9 @@ public class KnowledgeQaController extends BaseController {
|
|||||||
@Resource
|
@Resource
|
||||||
private SpaceApplicationService spaceApplicationService;
|
private SpaceApplicationService spaceApplicationService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private KnowledgeWritePermissionChecker knowledgeWritePermissionChecker;
|
||||||
|
|
||||||
@RequireResource(COMPONENT_LIB_QUERY_DETAIL)
|
@RequireResource(COMPONENT_LIB_QUERY_DETAIL)
|
||||||
@OperationLogReporter(actionType = ActionType.QUERY, action = "数据列表查询", objectName = "知识库问答", systemCode = SystemEnum.KNOWLEDGE_CONFIG)
|
@OperationLogReporter(actionType = ActionType.QUERY, action = "数据列表查询", objectName = "知识库问答", systemCode = SystemEnum.KNOWLEDGE_CONFIG)
|
||||||
@LogPrint(step = "知识库[知识库问答]-数据列表查询")
|
@LogPrint(step = "知识库[知识库问答]-数据列表查询")
|
||||||
@@ -114,6 +118,7 @@ public class KnowledgeQaController extends BaseController {
|
|||||||
throws IntrospectionException, InvocationTargetException, IllegalAccessException {
|
throws IntrospectionException, InvocationTargetException, IllegalAccessException {
|
||||||
|
|
||||||
var id = request.getId();
|
var id = request.getId();
|
||||||
|
knowledgeWritePermissionChecker.checkQa(id);
|
||||||
knowledgeQaSegmentApplicationService.deleteById(id);
|
knowledgeQaSegmentApplicationService.deleteById(id);
|
||||||
return ReqResult.success();
|
return ReqResult.success();
|
||||||
|
|
||||||
@@ -141,6 +146,7 @@ public class KnowledgeQaController extends BaseController {
|
|||||||
public ReqResult<Long> update(@RequestBody KnowledgeQaSegmentUpdateRequest updateDto)
|
public ReqResult<Long> update(@RequestBody KnowledgeQaSegmentUpdateRequest updateDto)
|
||||||
throws IntrospectionException, InvocationTargetException, IllegalAccessException {
|
throws IntrospectionException, InvocationTargetException, IllegalAccessException {
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkQa(updateDto.getId());
|
||||||
var model = KnowledgeQaSegmentUpdateRequest.convert2Model(updateDto);
|
var model = KnowledgeQaSegmentUpdateRequest.convert2Model(updateDto);
|
||||||
var id = knowledgeQaSegmentApplicationService.updateInfo(model, userContext);
|
var id = knowledgeQaSegmentApplicationService.updateInfo(model, userContext);
|
||||||
return ReqResult.success(id);
|
return ReqResult.success(id);
|
||||||
@@ -156,6 +162,7 @@ public class KnowledgeQaController extends BaseController {
|
|||||||
throws IntrospectionException, InvocationTargetException, IllegalAccessException {
|
throws IntrospectionException, InvocationTargetException, IllegalAccessException {
|
||||||
|
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkKnowledge(addDto.getKbId());
|
||||||
var model = KnowledgeQaSegmentAddRequest.convert2Model(addDto);
|
var model = KnowledgeQaSegmentAddRequest.convert2Model(addDto);
|
||||||
var id = knowledgeQaSegmentApplicationService.addInfo(model, userContext);
|
var id = knowledgeQaSegmentApplicationService.addInfo(model, userContext);
|
||||||
return ReqResult.success(id);
|
return ReqResult.success(id);
|
||||||
@@ -195,6 +202,7 @@ public class KnowledgeQaController extends BaseController {
|
|||||||
@RequestParam("kbId") Long kbId) {
|
@RequestParam("kbId") Long kbId) {
|
||||||
|
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkKnowledge(kbId);
|
||||||
|
|
||||||
knowledgeQaSegmentApplicationService.importQaFromExcel(kbId, file, userContext);
|
knowledgeQaSegmentApplicationService.importQaFromExcel(kbId, file, userContext);
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.xspaceagi.knowledge.man.ui.web.dto.segment.KnowledgeRawSegmentAddRequ
|
|||||||
import com.xspaceagi.knowledge.man.ui.web.dto.segment.KnowledgeRawSegmentQueryRequest;
|
import com.xspaceagi.knowledge.man.ui.web.dto.segment.KnowledgeRawSegmentQueryRequest;
|
||||||
import com.xspaceagi.knowledge.man.ui.web.dto.segment.KnowledgeRawSegmentUpdateRequest;
|
import com.xspaceagi.knowledge.man.ui.web.dto.segment.KnowledgeRawSegmentUpdateRequest;
|
||||||
import com.xspaceagi.knowledge.man.ui.web.dto.segment.KnowledgeRawSegmentVo;
|
import com.xspaceagi.knowledge.man.ui.web.dto.segment.KnowledgeRawSegmentVo;
|
||||||
|
import com.xspaceagi.knowledge.man.ui.web.permission.KnowledgeWritePermissionChecker;
|
||||||
import com.xspaceagi.system.application.dto.SpaceDto;
|
import com.xspaceagi.system.application.dto.SpaceDto;
|
||||||
import com.xspaceagi.system.application.service.SpaceApplicationService;
|
import com.xspaceagi.system.application.service.SpaceApplicationService;
|
||||||
import com.xspaceagi.system.domain.log.LogPrint;
|
import com.xspaceagi.system.domain.log.LogPrint;
|
||||||
@@ -56,6 +57,9 @@ public class KnowledgeRawSegmentController extends BaseController {
|
|||||||
@Resource
|
@Resource
|
||||||
private SpaceApplicationService spaceApplicationService;
|
private SpaceApplicationService spaceApplicationService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private KnowledgeWritePermissionChecker knowledgeWritePermissionChecker;
|
||||||
|
|
||||||
@RequireResource(COMPONENT_LIB_QUERY_DETAIL)
|
@RequireResource(COMPONENT_LIB_QUERY_DETAIL)
|
||||||
@OperationLogReporter(actionType = ActionType.QUERY, action = "数据列表查询", objectName = "知识库分段", systemCode = SystemEnum.KNOWLEDGE_CONFIG)
|
@OperationLogReporter(actionType = ActionType.QUERY, action = "数据列表查询", objectName = "知识库分段", systemCode = SystemEnum.KNOWLEDGE_CONFIG)
|
||||||
@LogPrint(step = "知识库[知识库分段]-数据列表查询")
|
@LogPrint(step = "知识库[知识库分段]-数据列表查询")
|
||||||
@@ -104,6 +108,7 @@ public class KnowledgeRawSegmentController extends BaseController {
|
|||||||
|
|
||||||
var id = request.getId();
|
var id = request.getId();
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkRawSegment(id);
|
||||||
knowledgeRawSegmentApplicationService.deleteById(id, userContext);
|
knowledgeRawSegmentApplicationService.deleteById(id, userContext);
|
||||||
return ReqResult.success();
|
return ReqResult.success();
|
||||||
|
|
||||||
@@ -132,6 +137,7 @@ public class KnowledgeRawSegmentController extends BaseController {
|
|||||||
throws IntrospectionException, InvocationTargetException, IllegalAccessException {
|
throws IntrospectionException, InvocationTargetException, IllegalAccessException {
|
||||||
|
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkRawSegment(updateDto.getRawSegmentId());
|
||||||
var model = KnowledgeRawSegmentUpdateRequest.convert2Model(updateDto);
|
var model = KnowledgeRawSegmentUpdateRequest.convert2Model(updateDto);
|
||||||
var id = knowledgeRawSegmentApplicationService.updateInfo(model, userContext);
|
var id = knowledgeRawSegmentApplicationService.updateInfo(model, userContext);
|
||||||
return ReqResult.success(id);
|
return ReqResult.success(id);
|
||||||
@@ -147,6 +153,7 @@ public class KnowledgeRawSegmentController extends BaseController {
|
|||||||
throws IntrospectionException, InvocationTargetException, IllegalAccessException {
|
throws IntrospectionException, InvocationTargetException, IllegalAccessException {
|
||||||
|
|
||||||
var userContext = this.getUser();
|
var userContext = this.getUser();
|
||||||
|
knowledgeWritePermissionChecker.checkDocument(addDto.getDocId());
|
||||||
var model = KnowledgeRawSegmentAddRequest.convert2Model(addDto);
|
var model = KnowledgeRawSegmentAddRequest.convert2Model(addDto);
|
||||||
|
|
||||||
var id = knowledgeRawSegmentApplicationService.addInfo(model, userContext);
|
var id = knowledgeRawSegmentApplicationService.addInfo(model, userContext);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import lombok.Getter;
|
|||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@Schema(description = "知识库文档-手动自定义新增")
|
@Schema(description = "知识库文档-手动自定义新增")
|
||||||
@@ -51,6 +52,9 @@ public class KnowledgeDocumentCustomAddRequest implements Serializable {
|
|||||||
knowledgeDocumentModel.setName(addDto.getName());
|
knowledgeDocumentModel.setName(addDto.getName());
|
||||||
//dataType = 2,自定义文本,才生效
|
//dataType = 2,自定义文本,才生效
|
||||||
knowledgeDocumentModel.setFileContent(addDto.getFileContent());
|
knowledgeDocumentModel.setFileContent(addDto.getFileContent());
|
||||||
|
knowledgeDocumentModel.setFileSize(addDto.getFileContent() == null
|
||||||
|
? 0L
|
||||||
|
: (long) addDto.getFileContent().getBytes(StandardCharsets.UTF_8).length);
|
||||||
//docUrl 给个空字符串,满足数据库非空要求
|
//docUrl 给个空字符串,满足数据库非空要求
|
||||||
knowledgeDocumentModel.setDocUrl("");
|
knowledgeDocumentModel.setDocUrl("");
|
||||||
knowledgeDocumentModel.setPubStatus(KnowledgePubStatusEnum.Waiting);
|
knowledgeDocumentModel.setPubStatus(KnowledgePubStatusEnum.Waiting);
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.xspaceagi.knowledge.man.ui.web.permission;
|
||||||
|
|
||||||
|
import com.xspaceagi.knowledge.core.application.service.IKnowledgeConfigApplicationService;
|
||||||
|
import com.xspaceagi.knowledge.core.application.service.IKnowledgeDocumentApplicationService;
|
||||||
|
import com.xspaceagi.knowledge.core.application.service.IKnowledgeQaSegmentApplicationService;
|
||||||
|
import com.xspaceagi.knowledge.core.application.service.IKnowledgeRawSegmentApplicationService;
|
||||||
|
import com.xspaceagi.knowledge.domain.model.KnowledgeConfigModel;
|
||||||
|
import com.xspaceagi.system.spec.common.RequestContext;
|
||||||
|
import com.xspaceagi.system.spec.enums.ErrorCodeEnum;
|
||||||
|
import com.xspaceagi.system.spec.exception.BizException;
|
||||||
|
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
|
||||||
|
import com.xspaceagi.system.spec.exception.KnowledgeException;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class KnowledgeWritePermissionChecker {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IKnowledgeConfigApplicationService knowledgeConfigApplicationService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IKnowledgeDocumentApplicationService knowledgeDocumentApplicationService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IKnowledgeRawSegmentApplicationService knowledgeRawSegmentApplicationService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IKnowledgeQaSegmentApplicationService knowledgeQaSegmentApplicationService;
|
||||||
|
|
||||||
|
public void checkKnowledge(Long knowledgeId) {
|
||||||
|
KnowledgeConfigModel knowledge = knowledgeConfigApplicationService.queryOneInfoById(knowledgeId);
|
||||||
|
if (knowledge == null) {
|
||||||
|
throw KnowledgeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||||
|
}
|
||||||
|
RequestContext<?> requestContext = RequestContext.get();
|
||||||
|
Long currentUserId = requestContext == null ? null : requestContext.getUserId();
|
||||||
|
if (knowledge.getCreatorId() == null
|
||||||
|
|| currentUserId == null
|
||||||
|
|| !Objects.equals(knowledge.getCreatorId(), currentUserId)) {
|
||||||
|
throw BizException.of(ErrorCodeEnum.PERMISSION_DENIED, BizExceptionCodeEnum.permissionDenied);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkDocument(Long documentId) {
|
||||||
|
var document = knowledgeDocumentApplicationService.queryOneInfoById(documentId);
|
||||||
|
if (document == null) {
|
||||||
|
throw KnowledgeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||||
|
}
|
||||||
|
checkKnowledge(document.getKbId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkRawSegment(Long rawSegmentId) {
|
||||||
|
var segment = knowledgeRawSegmentApplicationService.queryOneInfoById(rawSegmentId);
|
||||||
|
if (segment == null) {
|
||||||
|
throw KnowledgeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||||
|
}
|
||||||
|
checkKnowledge(segment.getKbId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkQa(Long qaId) {
|
||||||
|
var qa = knowledgeQaSegmentApplicationService.queryOneInfoById(qaId);
|
||||||
|
if (qa == null) {
|
||||||
|
throw KnowledgeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||||
|
}
|
||||||
|
checkKnowledge(qa.getKbId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.xspaceagi.knowledge.man.ui.web.dto.document;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class KnowledgeDocumentCustomAddRequestTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void calculatesUtf8ByteSizeForCustomText() {
|
||||||
|
KnowledgeDocumentCustomAddRequest request = new KnowledgeDocumentCustomAddRequest();
|
||||||
|
request.setKbId(1L);
|
||||||
|
request.setName("测试文档");
|
||||||
|
request.setFileContent("知识库 text");
|
||||||
|
|
||||||
|
var model = KnowledgeDocumentCustomAddRequest.convert2ModelForCustom(request);
|
||||||
|
|
||||||
|
assertThat(model.getFileSize())
|
||||||
|
.isEqualTo((long) request.getFileContent().getBytes(StandardCharsets.UTF_8).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void usesZeroSizeWhenCustomTextIsEmpty() {
|
||||||
|
KnowledgeDocumentCustomAddRequest request = new KnowledgeDocumentCustomAddRequest();
|
||||||
|
request.setKbId(1L);
|
||||||
|
request.setName("空文档");
|
||||||
|
|
||||||
|
var model = KnowledgeDocumentCustomAddRequest.convert2ModelForCustom(request);
|
||||||
|
|
||||||
|
assertThat(model.getFileSize()).isZero();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package com.xspaceagi.knowledge.man.ui.web.permission;
|
||||||
|
|
||||||
|
import com.xspaceagi.knowledge.core.application.service.IKnowledgeConfigApplicationService;
|
||||||
|
import com.xspaceagi.knowledge.core.application.service.IKnowledgeDocumentApplicationService;
|
||||||
|
import com.xspaceagi.knowledge.core.application.service.IKnowledgeQaSegmentApplicationService;
|
||||||
|
import com.xspaceagi.knowledge.core.application.service.IKnowledgeRawSegmentApplicationService;
|
||||||
|
import com.xspaceagi.knowledge.domain.model.KnowledgeConfigModel;
|
||||||
|
import com.xspaceagi.knowledge.domain.model.KnowledgeDocumentModel;
|
||||||
|
import com.xspaceagi.knowledge.domain.model.KnowledgeQaSegmentModel;
|
||||||
|
import com.xspaceagi.knowledge.domain.model.KnowledgeRawSegmentModel;
|
||||||
|
import com.xspaceagi.system.spec.common.RequestContext;
|
||||||
|
import com.xspaceagi.system.spec.exception.BizException;
|
||||||
|
import com.xspaceagi.system.spec.exception.KnowledgeException;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class KnowledgeWritePermissionCheckerTest {
|
||||||
|
|
||||||
|
private static final Long CURRENT_USER_ID = 10L;
|
||||||
|
private static final Long KNOWLEDGE_ID = 20L;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private IKnowledgeConfigApplicationService knowledgeConfigApplicationService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private IKnowledgeDocumentApplicationService knowledgeDocumentApplicationService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private IKnowledgeRawSegmentApplicationService knowledgeRawSegmentApplicationService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private IKnowledgeQaSegmentApplicationService knowledgeQaSegmentApplicationService;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private KnowledgeWritePermissionChecker permissionChecker;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUpRequestContext() {
|
||||||
|
RequestContext<Object> requestContext = new RequestContext<>();
|
||||||
|
requestContext.setUserId(CURRENT_USER_ID);
|
||||||
|
RequestContext.set(requestContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void clearRequestContext() {
|
||||||
|
RequestContext.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void allowsKnowledgeCreatorToWrite() {
|
||||||
|
when(knowledgeConfigApplicationService.queryOneInfoById(KNOWLEDGE_ID))
|
||||||
|
.thenReturn(knowledge(CURRENT_USER_ID));
|
||||||
|
|
||||||
|
assertDoesNotThrow(() -> permissionChecker.checkKnowledge(KNOWLEDGE_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void deniesOtherUsersEvenWhenKnowledgeIsAccessible() {
|
||||||
|
when(knowledgeConfigApplicationService.queryOneInfoById(KNOWLEDGE_ID))
|
||||||
|
.thenReturn(knowledge(99L));
|
||||||
|
|
||||||
|
assertThrows(BizException.class, () -> permissionChecker.checkKnowledge(KNOWLEDGE_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void deniesWriteWhenOwnershipCannotBeConfirmed() {
|
||||||
|
when(knowledgeConfigApplicationService.queryOneInfoById(KNOWLEDGE_ID))
|
||||||
|
.thenReturn(knowledge(null));
|
||||||
|
|
||||||
|
assertThrows(BizException.class, () -> permissionChecker.checkKnowledge(KNOWLEDGE_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rejectsMissingKnowledge() {
|
||||||
|
when(knowledgeConfigApplicationService.queryOneInfoById(KNOWLEDGE_ID)).thenReturn(null);
|
||||||
|
|
||||||
|
assertThrows(KnowledgeException.class, () -> permissionChecker.checkKnowledge(KNOWLEDGE_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolvesDocumentSegmentAndQaToOwningKnowledge() {
|
||||||
|
KnowledgeDocumentModel document = new KnowledgeDocumentModel();
|
||||||
|
document.setKbId(KNOWLEDGE_ID);
|
||||||
|
KnowledgeRawSegmentModel segment = new KnowledgeRawSegmentModel();
|
||||||
|
segment.setKbId(KNOWLEDGE_ID);
|
||||||
|
KnowledgeQaSegmentModel qa = new KnowledgeQaSegmentModel();
|
||||||
|
qa.setKbId(KNOWLEDGE_ID);
|
||||||
|
|
||||||
|
when(knowledgeDocumentApplicationService.queryOneInfoById(1L)).thenReturn(document);
|
||||||
|
when(knowledgeRawSegmentApplicationService.queryOneInfoById(2L)).thenReturn(segment);
|
||||||
|
when(knowledgeQaSegmentApplicationService.queryOneInfoById(3L)).thenReturn(qa);
|
||||||
|
when(knowledgeConfigApplicationService.queryOneInfoById(KNOWLEDGE_ID))
|
||||||
|
.thenReturn(knowledge(CURRENT_USER_ID));
|
||||||
|
|
||||||
|
assertDoesNotThrow(() -> permissionChecker.checkDocument(1L));
|
||||||
|
assertDoesNotThrow(() -> permissionChecker.checkRawSegment(2L));
|
||||||
|
assertDoesNotThrow(() -> permissionChecker.checkQa(3L));
|
||||||
|
}
|
||||||
|
|
||||||
|
private KnowledgeConfigModel knowledge(Long creatorId) {
|
||||||
|
KnowledgeConfigModel knowledge = new KnowledgeConfigModel();
|
||||||
|
knowledge.setId(KNOWLEDGE_ID);
|
||||||
|
knowledge.setCreatorId(creatorId);
|
||||||
|
return knowledge;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,6 @@ import {
|
|||||||
} from "antd";
|
} from "antd";
|
||||||
import {
|
import {
|
||||||
ArrowLeftOutlined,
|
ArrowLeftOutlined,
|
||||||
BookOutlined,
|
|
||||||
CheckOutlined,
|
CheckOutlined,
|
||||||
CloudUploadOutlined,
|
CloudUploadOutlined,
|
||||||
DatabaseOutlined,
|
DatabaseOutlined,
|
||||||
@@ -39,6 +38,7 @@ import {
|
|||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import type { ColumnsType } from "antd/es/table";
|
import type { ColumnsType } from "antd/es/table";
|
||||||
import ImageWithFallback from "../common/ImageWithFallback";
|
import ImageWithFallback from "../common/ImageWithFallback";
|
||||||
|
import { getCurrentAuth } from "../../services/core/auth";
|
||||||
import {
|
import {
|
||||||
AiAgentContext,
|
AiAgentContext,
|
||||||
AiManualComponent,
|
AiManualComponent,
|
||||||
@@ -183,6 +183,7 @@ function getPublishedWorkflowId(workflow: PublishedWorkflow): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function KnowledgePage() {
|
export default function KnowledgePage() {
|
||||||
|
const [currentUserId, setCurrentUserId] = useState<number | null>(null);
|
||||||
const [spaces, setSpaces] = useState<SpaceInfo[]>([]);
|
const [spaces, setSpaces] = useState<SpaceInfo[]>([]);
|
||||||
const [selectedSpaceId, setSelectedSpaceId] = useState<number | null>(null);
|
const [selectedSpaceId, setSelectedSpaceId] = useState<number | null>(null);
|
||||||
const [knowledges, setKnowledges] = useState<KnowledgeComponent[]>([]);
|
const [knowledges, setKnowledges] = useState<KnowledgeComponent[]>([]);
|
||||||
@@ -280,6 +281,26 @@ export default function KnowledgePage() {
|
|||||||
[knowledges, selectedKnowledgeId],
|
[knowledges, selectedKnowledgeId],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isKnowledgeOwner = useCallback(
|
||||||
|
(knowledge?: KnowledgeComponent | KnowledgeInfo | null) => {
|
||||||
|
if (!knowledge) return false;
|
||||||
|
const creator = (knowledge as KnowledgeComponent).creator;
|
||||||
|
const creatorId = Number(knowledge.creatorId || creator?.id || 0);
|
||||||
|
return Boolean(currentUserId && creatorId && currentUserId === creatorId);
|
||||||
|
},
|
||||||
|
[currentUserId],
|
||||||
|
);
|
||||||
|
|
||||||
|
const canManageSelectedKnowledge = isKnowledgeOwner(
|
||||||
|
knowledgeInfo || selectedKnowledgeComponent,
|
||||||
|
);
|
||||||
|
|
||||||
|
const ensureCanManageSelectedKnowledge = useCallback(() => {
|
||||||
|
if (canManageSelectedKnowledge) return true;
|
||||||
|
message.warning("该知识库由其他用户创建,仅支持查看和加入对话");
|
||||||
|
return false;
|
||||||
|
}, [canManageSelectedKnowledge]);
|
||||||
|
|
||||||
const loadAgentComponents = useCallback(async () => {
|
const loadAgentComponents = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const context = await resolveAiAgentContext();
|
const context = await resolveAiAgentContext();
|
||||||
@@ -489,6 +510,9 @@ export default function KnowledgePage() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadSpaces();
|
loadSpaces();
|
||||||
loadAgentComponents();
|
loadAgentComponents();
|
||||||
|
void getCurrentAuth().then((auth) => {
|
||||||
|
setCurrentUserId(auth.userInfo?.userId || null);
|
||||||
|
});
|
||||||
}, [loadAgentComponents, loadSpaces]);
|
}, [loadAgentComponents, loadSpaces]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -530,6 +554,10 @@ export default function KnowledgePage() {
|
|||||||
const openKnowledgeForm = async (
|
const openKnowledgeForm = async (
|
||||||
knowledge?: KnowledgeComponent | KnowledgeInfo,
|
knowledge?: KnowledgeComponent | KnowledgeInfo,
|
||||||
) => {
|
) => {
|
||||||
|
if (knowledge && !isKnowledgeOwner(knowledge)) {
|
||||||
|
message.warning("该知识库由其他用户创建,不能编辑");
|
||||||
|
return;
|
||||||
|
}
|
||||||
setKnowledgeModalOpen(true);
|
setKnowledgeModalOpen(true);
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const spaceId =
|
const spaceId =
|
||||||
@@ -591,6 +619,10 @@ export default function KnowledgePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const saveKnowledge = async () => {
|
const saveKnowledge = async () => {
|
||||||
|
if (editingKnowledge && !isKnowledgeOwner(editingKnowledge)) {
|
||||||
|
message.warning("该知识库由其他用户创建,不能编辑");
|
||||||
|
return;
|
||||||
|
}
|
||||||
let values: KnowledgeFormValues;
|
let values: KnowledgeFormValues;
|
||||||
try {
|
try {
|
||||||
values = await knowledgeForm.validateFields();
|
values = await knowledgeForm.validateFields();
|
||||||
@@ -643,6 +675,10 @@ export default function KnowledgePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const confirmDeleteKnowledge = (knowledge: KnowledgeComponent) => {
|
const confirmDeleteKnowledge = (knowledge: KnowledgeComponent) => {
|
||||||
|
if (!isKnowledgeOwner(knowledge)) {
|
||||||
|
message.warning("该知识库由其他用户创建,不能删除");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const knowledgeId = getKnowledgeId(knowledge);
|
const knowledgeId = getKnowledgeId(knowledge);
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: "删除知识库",
|
title: "删除知识库",
|
||||||
@@ -767,6 +803,7 @@ export default function KnowledgePage() {
|
|||||||
const files = Array.from(event.target.files || []);
|
const files = Array.from(event.target.files || []);
|
||||||
event.target.value = "";
|
event.target.value = "";
|
||||||
if (!files.length || !selectedKnowledgeId) return;
|
if (!files.length || !selectedKnowledgeId) return;
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
|
|
||||||
const validationError = files.map(validateKnowledgeFile).find(Boolean);
|
const validationError = files.map(validateKnowledgeFile).find(Boolean);
|
||||||
if (validationError) {
|
if (validationError) {
|
||||||
@@ -792,6 +829,7 @@ export default function KnowledgePage() {
|
|||||||
|
|
||||||
const saveCustomDocument = async () => {
|
const saveCustomDocument = async () => {
|
||||||
if (!selectedKnowledgeId) return;
|
if (!selectedKnowledgeId) return;
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
const values = await customDocForm.validateFields();
|
const values = await customDocForm.validateFields();
|
||||||
setSavingCustomDoc(true);
|
setSavingCustomDoc(true);
|
||||||
try {
|
try {
|
||||||
@@ -812,6 +850,7 @@ export default function KnowledgePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const openRenameDocument = (doc: KnowledgeDocumentInfo) => {
|
const openRenameDocument = (doc: KnowledgeDocumentInfo) => {
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
setRenamingDoc(doc);
|
setRenamingDoc(doc);
|
||||||
renameDocForm.setFieldsValue({ name: doc.name });
|
renameDocForm.setFieldsValue({ name: doc.name });
|
||||||
setRenameDocModalOpen(true);
|
setRenameDocModalOpen(true);
|
||||||
@@ -819,6 +858,7 @@ export default function KnowledgePage() {
|
|||||||
|
|
||||||
const saveDocumentName = async () => {
|
const saveDocumentName = async () => {
|
||||||
if (!renamingDoc) return;
|
if (!renamingDoc) return;
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
const values = await renameDocForm.validateFields();
|
const values = await renameDocForm.validateFields();
|
||||||
setSavingRename(true);
|
setSavingRename(true);
|
||||||
try {
|
try {
|
||||||
@@ -856,6 +896,7 @@ export default function KnowledgePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const confirmDeleteDocument = (doc: KnowledgeDocumentInfo) => {
|
const confirmDeleteDocument = (doc: KnowledgeDocumentInfo) => {
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: "删除文档",
|
title: "删除文档",
|
||||||
content: `确认删除「${doc.name}」吗?`,
|
content: `确认删除「${doc.name}」吗?`,
|
||||||
@@ -874,6 +915,7 @@ export default function KnowledgePage() {
|
|||||||
doc: KnowledgeDocumentInfo,
|
doc: KnowledgeDocumentInfo,
|
||||||
action: "qa" | "embedding" | "retry",
|
action: "qa" | "embedding" | "retry",
|
||||||
) => {
|
) => {
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
try {
|
try {
|
||||||
if (action === "qa") {
|
if (action === "qa") {
|
||||||
await generateKnowledgeDocumentQa(doc.id);
|
await generateKnowledgeDocumentQa(doc.id);
|
||||||
@@ -892,6 +934,7 @@ export default function KnowledgePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const openSegmentModal = (segment?: KnowledgeRawSegmentInfo) => {
|
const openSegmentModal = (segment?: KnowledgeRawSegmentInfo) => {
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
setEditingSegment(segment || null);
|
setEditingSegment(segment || null);
|
||||||
segmentForm.setFieldsValue({
|
segmentForm.setFieldsValue({
|
||||||
rawTxt: segment?.rawTxt || "",
|
rawTxt: segment?.rawTxt || "",
|
||||||
@@ -901,6 +944,7 @@ export default function KnowledgePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const saveSegment = async () => {
|
const saveSegment = async () => {
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
const spaceId =
|
const spaceId =
|
||||||
selectedDocument?.spaceId || knowledgeInfo?.spaceId || selectedSpaceId;
|
selectedDocument?.spaceId || knowledgeInfo?.spaceId || selectedSpaceId;
|
||||||
if (!selectedDocument || !spaceId) return;
|
if (!selectedDocument || !spaceId) return;
|
||||||
@@ -932,6 +976,7 @@ export default function KnowledgePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const confirmDeleteSegment = (segment: KnowledgeRawSegmentInfo) => {
|
const confirmDeleteSegment = (segment: KnowledgeRawSegmentInfo) => {
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: "删除分段",
|
title: "删除分段",
|
||||||
content: "确认删除该分段吗?",
|
content: "确认删除该分段吗?",
|
||||||
@@ -947,6 +992,7 @@ export default function KnowledgePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const openQaModal = (qa?: KnowledgeQaInfo) => {
|
const openQaModal = (qa?: KnowledgeQaInfo) => {
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
setEditingQa(qa || null);
|
setEditingQa(qa || null);
|
||||||
qaForm.setFieldsValue({
|
qaForm.setFieldsValue({
|
||||||
question: qa?.question || "",
|
question: qa?.question || "",
|
||||||
@@ -957,6 +1003,7 @@ export default function KnowledgePage() {
|
|||||||
|
|
||||||
const saveQa = async () => {
|
const saveQa = async () => {
|
||||||
if (!selectedKnowledgeId) return;
|
if (!selectedKnowledgeId) return;
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
const values = await qaForm.validateFields();
|
const values = await qaForm.validateFields();
|
||||||
try {
|
try {
|
||||||
if (editingQa) {
|
if (editingQa) {
|
||||||
@@ -983,6 +1030,7 @@ export default function KnowledgePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const confirmDeleteQa = (qa: KnowledgeQaInfo) => {
|
const confirmDeleteQa = (qa: KnowledgeQaInfo) => {
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: "删除 QA",
|
title: "删除 QA",
|
||||||
content: "确认删除该问答吗?",
|
content: "确认删除该问答吗?",
|
||||||
@@ -1001,6 +1049,7 @@ export default function KnowledgePage() {
|
|||||||
const file = event.target.files?.[0];
|
const file = event.target.files?.[0];
|
||||||
event.target.value = "";
|
event.target.value = "";
|
||||||
if (!file || !selectedKnowledgeId) return;
|
if (!file || !selectedKnowledgeId) return;
|
||||||
|
if (!ensureCanManageSelectedKnowledge()) return;
|
||||||
try {
|
try {
|
||||||
await importKnowledgeQaExcel({ kbId: selectedKnowledgeId, file });
|
await importKnowledgeQaExcel({ kbId: selectedKnowledgeId, file });
|
||||||
message.success("QA 已导入");
|
message.success("QA 已导入");
|
||||||
@@ -1068,7 +1117,7 @@ export default function KnowledgePage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "操作",
|
title: "操作",
|
||||||
width: 260,
|
width: canManageSelectedKnowledge ? 260 : 120,
|
||||||
fixed: "right",
|
fixed: "right",
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<div className={styles.tableActions}>
|
<div className={styles.tableActions}>
|
||||||
@@ -1082,6 +1131,8 @@ export default function KnowledgePage() {
|
|||||||
>
|
>
|
||||||
分段
|
分段
|
||||||
</Button>
|
</Button>
|
||||||
|
{canManageSelectedKnowledge && (
|
||||||
|
<>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -1110,6 +1161,8 @@ export default function KnowledgePage() {
|
|||||||
>
|
>
|
||||||
重命名
|
重命名
|
||||||
</Button>
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{record.docUrl && (
|
{record.docUrl && (
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
@@ -1119,6 +1172,7 @@ export default function KnowledgePage() {
|
|||||||
打开
|
打开
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
{canManageSelectedKnowledge && (
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -1127,6 +1181,7 @@ export default function KnowledgePage() {
|
|||||||
>
|
>
|
||||||
删除
|
删除
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -1149,10 +1204,12 @@ export default function KnowledgePage() {
|
|||||||
width: 170,
|
width: 170,
|
||||||
render: (_, record) => formatDateTime(record.modified || record.created),
|
render: (_, record) => formatDateTime(record.modified || record.created),
|
||||||
},
|
},
|
||||||
|
...(canManageSelectedKnowledge
|
||||||
|
? [
|
||||||
{
|
{
|
||||||
title: "操作",
|
title: "操作",
|
||||||
width: 120,
|
width: 120,
|
||||||
render: (_, record) => (
|
render: (_: unknown, record: KnowledgeRawSegmentInfo) => (
|
||||||
<div className={styles.tableActions}>
|
<div className={styles.tableActions}>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
@@ -1172,6 +1229,8 @@ export default function KnowledgePage() {
|
|||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
];
|
];
|
||||||
|
|
||||||
const qaColumns: ColumnsType<KnowledgeQaInfo> = [
|
const qaColumns: ColumnsType<KnowledgeQaInfo> = [
|
||||||
@@ -1191,12 +1250,18 @@ export default function KnowledgePage() {
|
|||||||
width: 170,
|
width: 170,
|
||||||
render: (_, record) => formatDateTime(record.modified || record.created),
|
render: (_, record) => formatDateTime(record.modified || record.created),
|
||||||
},
|
},
|
||||||
|
...(canManageSelectedKnowledge
|
||||||
|
? [
|
||||||
{
|
{
|
||||||
title: "操作",
|
title: "操作",
|
||||||
width: 120,
|
width: 120,
|
||||||
render: (_, record) => (
|
render: (_: unknown, record: KnowledgeQaInfo) => (
|
||||||
<div className={styles.tableActions}>
|
<div className={styles.tableActions}>
|
||||||
<Button type="link" size="small" onClick={() => openQaModal(record)}>
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
onClick={() => openQaModal(record)}
|
||||||
|
>
|
||||||
编辑
|
编辑
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -1210,6 +1275,8 @@ export default function KnowledgePage() {
|
|||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
];
|
];
|
||||||
|
|
||||||
const renderKnowledgeIcon = (
|
const renderKnowledgeIcon = (
|
||||||
@@ -1295,6 +1362,12 @@ export default function KnowledgePage() {
|
|||||||
<div className={styles.grid}>
|
<div className={styles.grid}>
|
||||||
{filteredKnowledges.map((knowledge) => {
|
{filteredKnowledges.map((knowledge) => {
|
||||||
const knowledgeId = getKnowledgeId(knowledge);
|
const knowledgeId = getKnowledgeId(knowledge);
|
||||||
|
const owned = isKnowledgeOwner(knowledge);
|
||||||
|
const creatorName =
|
||||||
|
knowledge.creator?.nickName ||
|
||||||
|
knowledge.creator?.userName ||
|
||||||
|
knowledge.creatorName ||
|
||||||
|
"未知创建人";
|
||||||
const joinedComponent = joinedKnowledgeMap.get(knowledgeId);
|
const joinedComponent = joinedKnowledgeMap.get(knowledgeId);
|
||||||
const joined =
|
const joined =
|
||||||
!!joinedComponent &&
|
!!joinedComponent &&
|
||||||
@@ -1311,7 +1384,19 @@ export default function KnowledgePage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.cardTitle}>
|
<div className={styles.cardTitle}>
|
||||||
<h3>{knowledge.name}</h3>
|
<h3>{knowledge.name}</h3>
|
||||||
<span>知识库资源</span>
|
<div className={styles.cardOwnerRow}>
|
||||||
|
<Tag
|
||||||
|
color={owned ? "cyan" : "default"}
|
||||||
|
className={styles.ownerTag}
|
||||||
|
>
|
||||||
|
{owned ? "我的知识库" : "只读"}
|
||||||
|
</Tag>
|
||||||
|
{!owned && (
|
||||||
|
<span title={creatorName}>
|
||||||
|
创建人:{creatorName}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className={styles.cardDescription}>
|
<p className={styles.cardDescription}>
|
||||||
@@ -1319,9 +1404,14 @@ export default function KnowledgePage() {
|
|||||||
</p>
|
</p>
|
||||||
<div className={styles.cardMeta}>
|
<div className={styles.cardMeta}>
|
||||||
<span>
|
<span>
|
||||||
{formatBytes(Number(knowledge.fileSize || 0))}
|
容量 {formatBytes(Number(knowledge.fileSize || 0))}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span
|
||||||
|
title={formatDateTime(
|
||||||
|
knowledge.modified || knowledge.created,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
更新{" "}
|
||||||
{formatDateTime(
|
{formatDateTime(
|
||||||
knowledge.modified || knowledge.created,
|
knowledge.modified || knowledge.created,
|
||||||
)}
|
)}
|
||||||
@@ -1329,6 +1419,7 @@ export default function KnowledgePage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.cardActions}>
|
<div className={styles.cardActions}>
|
||||||
<Button
|
<Button
|
||||||
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
icon={joined ? <CheckOutlined /> : <TeamOutlined />}
|
icon={joined ? <CheckOutlined /> : <TeamOutlined />}
|
||||||
loading={joiningIds.has(knowledgeId)}
|
loading={joiningIds.has(knowledgeId)}
|
||||||
@@ -1339,25 +1430,33 @@ export default function KnowledgePage() {
|
|||||||
>
|
>
|
||||||
{joined ? "已加入" : "加入对话"}
|
{joined ? "已加入" : "加入对话"}
|
||||||
</Button>
|
</Button>
|
||||||
|
{owned && (
|
||||||
|
<div className={styles.cardOwnerActions}>
|
||||||
|
<Tooltip title="编辑知识库">
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
icon={<EditOutlined />}
|
icon={<EditOutlined />}
|
||||||
|
aria-label="编辑知识库"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
openKnowledgeForm(knowledge);
|
openKnowledgeForm(knowledge);
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
编辑
|
</Tooltip>
|
||||||
</Button>
|
<Tooltip title="删除知识库">
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
danger
|
danger
|
||||||
icon={<DeleteOutlined />}
|
icon={<DeleteOutlined />}
|
||||||
|
aria-label="删除知识库"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
confirmDeleteKnowledge(knowledge);
|
confirmDeleteKnowledge(knowledge);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
);
|
);
|
||||||
@@ -1376,7 +1475,11 @@ export default function KnowledgePage() {
|
|||||||
allowClear
|
allowClear
|
||||||
placeholder="搜索文档"
|
placeholder="搜索文档"
|
||||||
value={documentKeyword}
|
value={documentKeyword}
|
||||||
onChange={(event) => setDocumentKeyword(event.target.value)}
|
onChange={(event) => {
|
||||||
|
const value = event.target.value;
|
||||||
|
setDocumentKeyword(value);
|
||||||
|
if (!value) void loadDocuments("");
|
||||||
|
}}
|
||||||
onSearch={(value) => loadDocuments(value)}
|
onSearch={(value) => loadDocuments(value)}
|
||||||
className={styles.innerSearch}
|
className={styles.innerSearch}
|
||||||
/>
|
/>
|
||||||
@@ -1387,6 +1490,8 @@ export default function KnowledgePage() {
|
|||||||
className={styles.hiddenInput}
|
className={styles.hiddenInput}
|
||||||
onChange={handleDocumentFiles}
|
onChange={handleDocumentFiles}
|
||||||
/>
|
/>
|
||||||
|
{canManageSelectedKnowledge && (
|
||||||
|
<>
|
||||||
<Button
|
<Button
|
||||||
icon={<CloudUploadOutlined />}
|
icon={<CloudUploadOutlined />}
|
||||||
loading={uploadingDocs}
|
loading={uploadingDocs}
|
||||||
@@ -1403,6 +1508,8 @@ export default function KnowledgePage() {
|
|||||||
>
|
>
|
||||||
自定义文本
|
自定义文本
|
||||||
</Button>
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Tooltip title="刷新文档状态">
|
<Tooltip title="刷新文档状态">
|
||||||
<Button icon={<ReloadOutlined />} onClick={refreshDocumentStatus} />
|
<Button icon={<ReloadOutlined />} onClick={refreshDocumentStatus} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -1443,6 +1550,7 @@ export default function KnowledgePage() {
|
|||||||
}}
|
}}
|
||||||
options={documents.map((doc) => ({ label: doc.name, value: doc.id }))}
|
options={documents.map((doc) => ({ label: doc.name, value: doc.id }))}
|
||||||
/>
|
/>
|
||||||
|
{canManageSelectedKnowledge && (
|
||||||
<Button
|
<Button
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
disabled={!selectedDocument}
|
disabled={!selectedDocument}
|
||||||
@@ -1450,6 +1558,7 @@ export default function KnowledgePage() {
|
|||||||
>
|
>
|
||||||
新增分段
|
新增分段
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
icon={<ReloadOutlined />}
|
icon={<ReloadOutlined />}
|
||||||
disabled={!selectedDocument}
|
disabled={!selectedDocument}
|
||||||
@@ -1498,13 +1607,19 @@ export default function KnowledgePage() {
|
|||||||
allowClear
|
allowClear
|
||||||
placeholder="搜索问题"
|
placeholder="搜索问题"
|
||||||
value={qaKeyword}
|
value={qaKeyword}
|
||||||
onChange={(event) => setQaKeyword(event.target.value)}
|
onChange={(event) => {
|
||||||
|
const value = event.target.value;
|
||||||
|
setQaKeyword(value);
|
||||||
|
if (!value) void loadQaList("");
|
||||||
|
}}
|
||||||
onSearch={(value) => loadQaList(value)}
|
onSearch={(value) => loadQaList(value)}
|
||||||
className={styles.innerSearch}
|
className={styles.innerSearch}
|
||||||
/>
|
/>
|
||||||
|
{canManageSelectedKnowledge && (
|
||||||
<Button icon={<PlusOutlined />} onClick={() => openQaModal()}>
|
<Button icon={<PlusOutlined />} onClick={() => openQaModal()}>
|
||||||
新增 QA
|
新增 QA
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
<input
|
<input
|
||||||
ref={qaFileInputRef}
|
ref={qaFileInputRef}
|
||||||
type="file"
|
type="file"
|
||||||
@@ -1512,12 +1627,14 @@ export default function KnowledgePage() {
|
|||||||
className={styles.hiddenInput}
|
className={styles.hiddenInput}
|
||||||
onChange={handleQaImport}
|
onChange={handleQaImport}
|
||||||
/>
|
/>
|
||||||
|
{canManageSelectedKnowledge && (
|
||||||
<Button
|
<Button
|
||||||
icon={<CloudUploadOutlined />}
|
icon={<CloudUploadOutlined />}
|
||||||
onClick={() => qaFileInputRef.current?.click()}
|
onClick={() => qaFileInputRef.current?.click()}
|
||||||
>
|
>
|
||||||
导入 Excel
|
导入 Excel
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
<Button icon={<DownloadOutlined />} onClick={handleDownloadQaTemplate}>
|
<Button icon={<DownloadOutlined />} onClick={handleDownloadQaTemplate}>
|
||||||
下载模板
|
下载模板
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1563,6 +1680,13 @@ export default function KnowledgePage() {
|
|||||||
const joining =
|
const joining =
|
||||||
selectedKnowledgeId !== null && joiningIds.has(selectedKnowledgeId);
|
selectedKnowledgeId !== null && joiningIds.has(selectedKnowledgeId);
|
||||||
const knowledgeForAction = knowledgeInfo || selectedKnowledgeComponent;
|
const knowledgeForAction = knowledgeInfo || selectedKnowledgeComponent;
|
||||||
|
const owned = isKnowledgeOwner(knowledgeForAction);
|
||||||
|
const creator = (knowledgeForAction as KnowledgeComponent | null)?.creator;
|
||||||
|
const creatorName =
|
||||||
|
creator?.nickName ||
|
||||||
|
creator?.userName ||
|
||||||
|
knowledgeForAction?.creatorName ||
|
||||||
|
"未知创建人";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -1584,6 +1708,12 @@ export default function KnowledgePage() {
|
|||||||
<strong>{knowledgeForAction?.name || "知识库详情"}</strong>
|
<strong>{knowledgeForAction?.name || "知识库详情"}</strong>
|
||||||
</div>
|
</div>
|
||||||
<h1>{knowledgeForAction?.name || "知识库详情"}</h1>
|
<h1>{knowledgeForAction?.name || "知识库详情"}</h1>
|
||||||
|
<div className={styles.detailOwnerRow}>
|
||||||
|
<Tag color={owned ? "cyan" : "default"}>
|
||||||
|
{owned ? "我的知识库" : "只读知识库"}
|
||||||
|
</Tag>
|
||||||
|
{!owned && <span>创建人:{creatorName}</span>}
|
||||||
|
</div>
|
||||||
<p>{knowledgeForAction?.description || "暂无描述"}</p>
|
<p>{knowledgeForAction?.description || "暂无描述"}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1598,6 +1728,7 @@ export default function KnowledgePage() {
|
|||||||
>
|
>
|
||||||
{joined ? "已加入对话" : "加入对话"}
|
{joined ? "已加入对话" : "加入对话"}
|
||||||
</Button>
|
</Button>
|
||||||
|
{owned && (
|
||||||
<Button
|
<Button
|
||||||
icon={<EditOutlined />}
|
icon={<EditOutlined />}
|
||||||
disabled={!knowledgeForAction}
|
disabled={!knowledgeForAction}
|
||||||
@@ -1607,6 +1738,7 @@ export default function KnowledgePage() {
|
|||||||
>
|
>
|
||||||
编辑
|
编辑
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<main className={styles.detailContent}>
|
<main className={styles.detailContent}>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import { t } from "./i18n";
|
|||||||
// ========== 类型定义 ===
|
// ========== 类型定义 ===
|
||||||
export interface AuthUserInfo {
|
export interface AuthUserInfo {
|
||||||
id?: number;
|
id?: number;
|
||||||
|
userId?: number;
|
||||||
username: string;
|
username: string;
|
||||||
displayName?: string;
|
displayName?: string;
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
@@ -333,6 +334,7 @@ export async function loginAndRegister(
|
|||||||
|
|
||||||
await setUserInfo({
|
await setUserInfo({
|
||||||
id: response.id,
|
id: response.id,
|
||||||
|
userId: response.userId,
|
||||||
username,
|
username,
|
||||||
displayName: response.name,
|
displayName: response.name,
|
||||||
currentDomain: domain,
|
currentDomain: domain,
|
||||||
@@ -509,6 +511,7 @@ export async function reRegisterClient(): Promise<ClientRegisterResponse | null>
|
|||||||
await setUserInfo({
|
await setUserInfo({
|
||||||
...currentUserInfo,
|
...currentUserInfo,
|
||||||
id: response.id,
|
id: response.id,
|
||||||
|
userId: response.userId,
|
||||||
username: username || "",
|
username: username || "",
|
||||||
displayName: response.name,
|
displayName: response.name,
|
||||||
currentDomain: domain || currentUserInfo?.currentDomain,
|
currentDomain: domain || currentUserInfo?.currentDomain,
|
||||||
@@ -675,6 +678,7 @@ export async function syncConfigToServer(options?: {
|
|||||||
await setUserInfo({
|
await setUserInfo({
|
||||||
...currentUserInfo,
|
...currentUserInfo,
|
||||||
id: response.id,
|
id: response.id,
|
||||||
|
userId: response.userId,
|
||||||
username: username || "",
|
username: username || "",
|
||||||
displayName: response.name,
|
displayName: response.name,
|
||||||
currentDomain: preservedCurrentDomain,
|
currentDomain: preservedCurrentDomain,
|
||||||
|
|||||||
@@ -74,7 +74,15 @@ export interface KnowledgeComponent {
|
|||||||
spaceId?: number;
|
spaceId?: number;
|
||||||
created?: string;
|
created?: string;
|
||||||
modified?: string;
|
modified?: string;
|
||||||
|
creatorId?: number;
|
||||||
creatorName?: string;
|
creatorName?: string;
|
||||||
|
creator?: {
|
||||||
|
id?: number;
|
||||||
|
userName?: string;
|
||||||
|
nickName?: string;
|
||||||
|
avatar?: string;
|
||||||
|
};
|
||||||
|
permissions?: string[];
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +99,7 @@ export interface KnowledgeInfo {
|
|||||||
pubStatus?: string;
|
pubStatus?: string;
|
||||||
created?: string;
|
created?: string;
|
||||||
modified?: string;
|
modified?: string;
|
||||||
|
creatorId?: number;
|
||||||
creatorName?: string;
|
creatorName?: string;
|
||||||
workflowId?: string | number;
|
workflowId?: string | number;
|
||||||
workflowName?: string;
|
workflowName?: string;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export interface AuthUserInfo {
|
|||||||
username: string;
|
username: string;
|
||||||
displayName?: string;
|
displayName?: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
userId?: string;
|
userId?: number;
|
||||||
email?: string;
|
email?: string;
|
||||||
currentDomain?: string;
|
currentDomain?: string;
|
||||||
agentId?: number;
|
agentId?: number;
|
||||||
|
|||||||
@@ -82,19 +82,20 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search,
|
.search {
|
||||||
.innerSearch {
|
|
||||||
width: min(420px, 100%);
|
width: min(420px, 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.innerSearch {
|
||||||
|
width: min(360px, 100%);
|
||||||
|
}
|
||||||
|
|
||||||
.toolbarCreateButton {
|
.toolbarCreateButton {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search :global(.ant-input-affix-wrapper),
|
.search :global(.ant-input-affix-wrapper),
|
||||||
.search:global(.ant-input-affix-wrapper),
|
.search:global(.ant-input-affix-wrapper) {
|
||||||
.innerSearch :global(.ant-input-affix-wrapper),
|
|
||||||
.innerSearch:global(.ant-input-affix-wrapper) {
|
|
||||||
height: 42px;
|
height: 42px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border-color: #dcd9d1;
|
border-color: #dcd9d1;
|
||||||
@@ -102,6 +103,35 @@
|
|||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.innerSearch :global(.ant-input-group) {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.innerSearch :global(.ant-input-affix-wrapper) {
|
||||||
|
height: 38px;
|
||||||
|
border-color: #dcd9d1;
|
||||||
|
border-radius: 7px 0 0 7px;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.innerSearch :global(.ant-input-search-button) {
|
||||||
|
width: 42px;
|
||||||
|
height: 38px;
|
||||||
|
padding: 0;
|
||||||
|
border-color: #dcd9d1;
|
||||||
|
border-radius: 0 7px 7px 0 !important;
|
||||||
|
color: #5e625c;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.innerSearch :global(.ant-input-affix-wrapper-focused),
|
||||||
|
.innerSearch :global(.ant-input-affix-wrapper:focus-within),
|
||||||
|
.innerSearch :global(.ant-input-search-button:hover) {
|
||||||
|
border-color: #74aaa5;
|
||||||
|
}
|
||||||
|
|
||||||
.count {
|
.count {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
color: #888b85;
|
color: #888b85;
|
||||||
@@ -132,15 +162,17 @@
|
|||||||
|
|
||||||
.grid {
|
.grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 340px));
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
justify-content: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
min-height: 202px;
|
min-width: 0;
|
||||||
|
min-height: 218px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 18px;
|
padding: 16px;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
border: 1px solid #e8e4dc;
|
border: 1px solid #e8e4dc;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -210,11 +242,28 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cardTitle span {
|
.cardOwnerRow {
|
||||||
display: block;
|
min-width: 0;
|
||||||
margin-top: 4px;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardOwnerRow span {
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
color: #8a8d89;
|
color: #8a8d89;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ownerTag {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-inline-end: 0;
|
||||||
|
line-height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cardDescription {
|
.cardDescription {
|
||||||
@@ -235,7 +284,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
padding-top: 14px;
|
padding-top: 12px;
|
||||||
color: #8a8d89;
|
color: #8a8d89;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
@@ -251,10 +300,19 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-top: 14px;
|
margin-top: 12px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #efede7;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cardOwnerActions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.detailHeader {
|
.detailHeader {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
@@ -274,6 +332,20 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.detailOwnerRow {
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 7px;
|
||||||
|
color: #777b75;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailOwnerRow :global(.ant-tag) {
|
||||||
|
margin-inline-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.detailActions {
|
.detailActions {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -504,6 +576,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1180px) {
|
@media (max-width: 1180px) {
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 340px));
|
||||||
|
}
|
||||||
|
|
||||||
.statRow {
|
.statRow {
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
@@ -533,4 +609,20 @@
|
|||||||
.statRow {
|
.statRow {
|
||||||
grid-template-columns: minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: minmax(0, 340px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 420px) {
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardMeta {
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user