665665 <div v-if =" kbSelectionMode === 'selected'" class =" setting-row" >
666666 <div class =" setting-info" >
667667 <label >{{ $t('agent.editor.selectKnowledgeBases') }}</label >
668- <p class =" desc" >选择要关联的知识库 </p >
668+ <p class =" desc" >{{ $t('agent.editor.selectKnowledgeBasesDesc') }} </p >
669669 </div >
670670 <div class =" setting-control" >
671671 <t-select
672672 v-model =" formData.config.knowledge_bases"
673673 multiple
674674 :placeholder =" $t('agent.editor.selectKnowledgeBases')"
675675 filterable
676+ :min-collapsed-num =" 3"
676677 >
677- <t-option
678- v-for =" kb in kbOptions"
679- :key =" kb.value"
680- :value =" kb.value"
681- :label =" kb.label"
682- >
683- <div class =" kb-option-item" >
684- <span class =" kb-option-icon" :class =" kb.type === 'faq' ? 'faq-icon' : 'doc-icon'" >
685- <t-icon :name =" kb.type === 'faq' ? 'chat-bubble-help' : 'folder'" />
686- </span >
687- <span class =" kb-option-label" >{{ kb.label }}</span >
688- <span class =" kb-option-count" >({{ kb.count || 0 }})</span >
689- </div >
690- </t-option >
678+ <t-option-group v-if =" myKbOptions.length" :label =" $t('agent.editor.myKnowledgeBases')" >
679+ <t-option
680+ v-for =" kb in myKbOptions"
681+ :key =" kb.value"
682+ :value =" kb.value"
683+ :label =" kb.label"
684+ >
685+ <div class =" kb-option-item" >
686+ <span class =" kb-option-icon" :class =" kb.type === 'faq' ? 'faq-icon' : 'doc-icon'" >
687+ <t-icon :name =" kb.type === 'faq' ? 'chat-bubble-help' : 'folder'" />
688+ </span >
689+ <span class =" kb-option-label" >{{ kb.label }}</span >
690+ <span class =" kb-option-count" >{{ kb.count || 0 }}</span >
691+ </div >
692+ </t-option >
693+ </t-option-group >
694+ <t-option-group v-if =" sharedKbOptions.length" :label =" $t('agent.editor.sharedKnowledgeBases')" >
695+ <t-option
696+ v-for =" kb in sharedKbOptions"
697+ :key =" kb.value"
698+ :value =" kb.value"
699+ :label =" kb.label"
700+ >
701+ <div class =" kb-option-item" >
702+ <span class =" kb-option-icon" :class =" kb.type === 'faq' ? 'faq-icon' : 'doc-icon'" >
703+ <t-icon :name =" kb.type === 'faq' ? 'chat-bubble-help' : 'folder'" />
704+ </span >
705+ <span class =" kb-option-label" >{{ kb.label }}</span >
706+ <span v-if =" kb.orgName" class =" kb-option-org" >{{ kb.orgName }}</span >
707+ <span class =" kb-option-count" >{{ kb.count || 0 }}</span >
708+ </div >
709+ </t-option >
710+ </t-option-group >
691711 </t-select >
692712 </div >
693713 </div >
@@ -1048,12 +1068,14 @@ import { listMCPServices, type MCPService } from '@/api/mcp-service';
10481068import { listSkills , type SkillInfo } from ' @/api/skill' ;
10491069import { getAgentConfig , getConversationConfig } from ' @/api/system' ;
10501070import { useUIStore } from ' @/stores/ui' ;
1071+ import { useOrganizationStore } from ' @/stores/organization' ;
10511072import AgentAvatar from ' @/components/AgentAvatar.vue' ;
10521073import PromptTemplateSelector from ' @/components/PromptTemplateSelector.vue' ;
10531074import ModelSelector from ' @/components/ModelSelector.vue' ;
10541075import AgentShareSettings from ' @/components/AgentShareSettings.vue' ;
10551076
10561077const uiStore = useUIStore ();
1078+ const orgStore = useOrganizationStore ();
10571079
10581080const { t } = useI18n ();
10591081
@@ -1072,7 +1094,7 @@ const emit = defineEmits<{
10721094const currentSection = ref (props .initialSection || ' basic' );
10731095const saving = ref (false );
10741096const allModels = ref <ModelConfig []>([]);
1075- const kbOptions = ref <{ label: string ; value: string ; type? : ' document' | ' faq' ; count? : number }[]>([]);
1097+ const kbOptions = ref <{ label: string ; value: string ; type? : ' document' | ' faq' ; count? : number ; shared ? : boolean ; orgName ? : string }[]>([]);
10761098const mcpOptions = ref <{ label: string ; value: string }[]>([]);
10771099const skillOptions = ref <{ name: string ; description: string }[]>([]);
10781100// 是否允许启用 Skills(取决于后端沙箱是否启用,disabled 时为 false;未请求前为 false 避免闪显)
@@ -1124,6 +1146,10 @@ const allTools = [
11241146 { value: ' data_schema' , label: ' 查看数据元信息' , description: ' 获取表格文件的元信息' , requiresKB: true },
11251147];
11261148
1149+ // 知识库分组:我的 vs 共享的
1150+ const myKbOptions = computed (() => kbOptions .value .filter (kb => ! kb .shared ));
1151+ const sharedKbOptions = computed (() => kbOptions .value .filter (kb => kb .shared ));
1152+
11271153// 根据知识库配置动态计算是否有知识库能力
11281154const hasKnowledgeBase = computed (() => {
11291155 return kbSelectionMode .value !== ' none' ;
@@ -1635,17 +1661,46 @@ const loadDependencies = async () => {
16351661 allModels .value = models ;
16361662 }
16371663
1638- // 加载知识库列表
1664+ // 加载知识库列表(我的 + 共享的)
16391665 const kbRes: any = await listKnowledgeBases ();
1666+ const myKbs: typeof kbOptions .value = [];
16401667 if (kbRes .data ) {
1641- kbOptions .value = kbRes .data .map ((kb : any ) => ({
1642- label: kb .name ,
1643- value: kb .id ,
1644- type: kb .type || ' document' ,
1645- count: kb .type === ' faq' ? (kb .chunk_count || 0 ) : (kb .knowledge_count || 0 )
1646- }));
1668+ kbRes .data .forEach ((kb : any ) => {
1669+ myKbs .push ({
1670+ label: kb .name ,
1671+ value: kb .id ,
1672+ type: kb .type || ' document' ,
1673+ count: kb .type === ' faq' ? (kb .chunk_count || 0 ) : (kb .knowledge_count || 0 ),
1674+ shared: false ,
1675+ });
1676+ });
1677+ }
1678+
1679+ // 加载共享给我的知识库
1680+ const sharedKbs: typeof kbOptions .value = [];
1681+ try {
1682+ const sharedList = await orgStore .fetchSharedKnowledgeBases ();
1683+ if (sharedList && sharedList .length > 0 ) {
1684+ const myKbIds = new Set (myKbs .map (kb => kb .value ));
1685+ sharedList .forEach ((shared : any ) => {
1686+ const kb = shared .knowledge_base ;
1687+ if (! kb || myKbIds .has (kb .id )) return ;
1688+ sharedKbs .push ({
1689+ label: kb .name ,
1690+ value: kb .id ,
1691+ type: kb .type || ' document' ,
1692+ count: kb .type === ' faq' ? (kb .chunk_count || 0 ) : (kb .knowledge_count || 0 ),
1693+ shared: true ,
1694+ orgName: shared .org_name ,
1695+ });
1696+ });
1697+ }
1698+ } catch (e ) {
1699+ console .warn (' Failed to load shared knowledge bases' , e );
16471700 }
16481701
1702+ kbOptions .value = [... myKbs , ... sharedKbs ];
1703+
16491704 // 加载 MCP 服务列表(只加载启用的)
16501705 try {
16511706 const mcpList = await listMCPServices ();
@@ -3404,23 +3459,29 @@ const handleSave = async () => {
34043459.kb-option-item {
34053460 display : flex ;
34063461 align-items : center ;
3407- gap : 6px ;
3462+ gap : 8px ;
3463+ padding : 2px 0 ;
34083464}
34093465
34103466.kb-option-icon {
34113467 display : flex ;
34123468 align-items : center ;
34133469 justify-content : center ;
34143470 flex-shrink : 0 ;
3415- font-size : 16px ;
3471+ width : 24px ;
3472+ height : 24px ;
3473+ border-radius : 6px ;
3474+ font-size : 14px ;
34163475
3417- // Document KB - Greenish
3476+ // Document KB
34183477 & .doc-icon {
3478+ background : rgba (16 , 185 , 129 , 0.1 );
34193479 color : #10b981 ;
34203480 }
34213481
3422- // FAQ KB - Blueish
3482+ // FAQ KB
34233483 & .faq-icon {
3484+ background : rgba (0 , 82 , 217 , 0.1 );
34243485 color : #0052d9 ;
34253486 }
34263487}
@@ -3430,12 +3491,30 @@ const handleSave = async () => {
34303491 overflow : hidden ;
34313492 text-overflow : ellipsis ;
34323493 white-space : nowrap ;
3494+ font-size : 13px ;
3495+ color : #1d2129 ;
3496+ }
3497+
3498+ .kb-option-org {
3499+ flex-shrink : 0 ;
3500+ font-size : 11px ;
3501+ color : #8c8c8c ;
3502+ background : #f2f3f5 ;
3503+ padding : 1px 6px ;
3504+ border-radius : 4px ;
3505+ max-width : 100px ;
3506+ overflow : hidden ;
3507+ text-overflow : ellipsis ;
3508+ white-space : nowrap ;
34333509}
34343510
34353511.kb-option-count {
34363512 flex-shrink : 0 ;
3437- font-size : 12px ;
3438- color : #999 ;
3513+ font-size : 11px ;
3514+ color : #8c8c8c ;
3515+ background : #f2f3f5 ;
3516+ padding : 1px 6px ;
3517+ border-radius : 4px ;
34393518}
34403519
34413520// FAQ 策略区域样式
0 commit comments