Procházet zdrojové kódy

feat(知识库):知识库新增接口调试

hanyang před 1 rokem
rodič
revize
d8a70f55fa

+ 12 - 1
public/config.js

@@ -9,8 +9,19 @@ window.DMX_VERSION = '1.0.1';
  */
 // window.API_BASE_URL = 'http://192.168.20.119:9201/api';
 window.API_BASE_URL = 'http://192.168.20.119:9301';
-
 /**
  * 小数系统访问地址
  */
 window.XIAOSHU_URL = 'http://192.168.20.119:9301/';
+
+/**
+ * rgflow 接口地址
+ *
+ * */
+window.RGFLOW_BASE_URL = 'http://192.168.20.119:28002/';
+
+/**
+ * dify 接口地址
+ *
+ * */
+window.DIFY_BASE_URL = 'http://192.168.20.119:28003/';

+ 15 - 2
src/apis/knowledge.js

@@ -5,10 +5,23 @@ import request from '../base/ajax';
  * @param {number} current 当前页数
  * @param {number} pageSize 每页条数
  * @param {string} keyword 搜索
+ * @param {string} location rg智能体1 默认全部
  * */
-export function getKnowledgeList(current, pageSize, keyword) {
+export function getKnowledgeList(current, pageSize, keyword, location = '0') {
+  const baseUrl =
+    location == '1'
+      ? `/api/knowledge/list?current=${current}&pageSize=${pageSize}&keyword=${keyword}&location=${location}`
+      : `/api/knowledge/list?current=${current}&pageSize=${pageSize}&keyword=${keyword}`;
   return request({
-    url: `/api/knowledge/list?current=${current}&pageSize=${pageSize}&keyword=${keyword}`,
+    url: baseUrl,
     method: 'get'
   });
 }
+// 创建知识库
+export function createOwnKnowledge(data) {
+  return request({
+    url: '/api/knowledge/create',
+    method: 'post',
+    data
+  });
+}

+ 18 - 0
src/apis/rgflow-dify.js

@@ -16,6 +16,13 @@ export function createDify(data) {
     data: initData
   });
 }
+// 删除dify智能体
+export function deleteDify(id) {
+  return request({
+    url: `/dify/console/api/apps/${id}`,
+    method: 'delete'
+  });
+}
 
 // 创建rgflow智能体
 export function createRgFlow(data) {
@@ -58,3 +65,14 @@ export function getRagFlowData(id) {
     method: 'get'
   });
 }
+
+// 新增知识库
+export function createKb(name) {
+  return request({
+    url: `/rgflow/v1/kb/create`,
+    method: 'post',
+    data: {
+      name
+    }
+  });
+}

+ 21 - 2
src/base/ajax.js

@@ -32,10 +32,28 @@ function applyRequestProxyUrl(config) {
         throw new Error('关键配置项 API_BASE_URL 不存在,请在 /config.js 进行配置');
       }
 
-      const replace_str = base_url + '/';
+      // const replace_str = base_url + '/';
 
-      const real_url = cur_url.replace('/api/', replace_str);
+      // const real_url = cur_url.replace('/api/', replace_str);
 
+      config.url = base_url + cur_url;
+    }
+    if (cur_url.startsWith('/rgflow/')) {
+      const base_url = getConfigField('RGFLOW_BASE_URL');
+      if (!base_url) {
+        throw new Error('关键配置项 RGFLOW_BASE_URL 不存在,请在 /config.js 进行配置');
+      }
+      const replace_str = base_url + '/';
+      const real_url = cur_url.replace('/rgflow/', replace_str);
+      config.url = real_url;
+    }
+    if (cur_url.startsWith('/dify/')) {
+      const base_url = getConfigField('DIFY_BASE_URL');
+      if (!base_url) {
+        throw new Error('关键配置项 MITY_BASE_URL 不存在,请在 /config.js 进行配置');
+      }
+      const replace_str = base_url + '/';
+      const real_url = cur_url.replace('/dify/', replace_str);
       config.url = real_url;
     }
   } else {
@@ -55,6 +73,7 @@ const ajax = axios.create({
 
 ajax.interceptors.request.use(
   (config) => {
+    console.log('请求地址:', config.url);
     applyRequestProxyUrl(config);
 
     const token = kuky_Authorization.get();

+ 4 - 2
src/modules/dify/MessageBody.vue

@@ -28,7 +28,8 @@ const props = defineProps({
   }
 });
 const DIFY_TOKEN = ref('');
-const BASE_URL = 'http://192.168.20.119:28003/app';
+const BASE_URL = window.RGFLOW_BASE_URL;
+// const BASE_URL = 'http://192.168.20.119:28003/app';
 const getToken = async () => {
   const res = await tokenExchange();
   if (res.code == 200) {
@@ -39,7 +40,8 @@ const defaultURL = ref('');
 
 onMounted(async () => {
   await getToken();
-  defaultURL.value = BASE_URL + '/' + props.id + `/workflow?token=${DIFY_TOKEN.value}`;
+  defaultURL.value = BASE_URL + '/app/' + props.id + `/workflow?token=${DIFY_TOKEN.value}`;
+  console.log('defaultURL', defaultURL.value);
   const element = document.getElementById('dify');
   element.onload = function () {
     if (element && element.contentWindow) {

+ 6 - 2
src/modules/dify/TopSetting.vue

@@ -4,11 +4,15 @@
     <a-breadcrumb-item>
       <router-link to="/intelligent">智能体</router-link>
     </a-breadcrumb-item>
-    <a-breadcrumb-item>智能体详情</a-breadcrumb-item>
+    <a-breadcrumb-item>{{ current_label }}</a-breadcrumb-item>
   </a-breadcrumb>
 </template>
 
-<script setup></script>
+<script setup>
+const props = defineProps({
+  current_label: String
+});
+</script>
 
 <style lang="css" scoped>
 .breadcrumb {

+ 2 - 8
src/modules/intelligent/LabelSelected.vue

@@ -1,12 +1,6 @@
 <template>
   <div class="label-select">
-    <a-input
-      v-model="searchText"
-      :placeholder="$t('management.search')"
-      style="width: 100%"
-      allow-clear
-      @input="handleSearch"
-    >
+    <a-input v-model="searchText" :placeholder="$t('management.search')" style="width: 100%" @input="handleSearch">
       <template #prefix>
         <icon-search />
       </template>
@@ -60,6 +54,6 @@ const handleToAdd = (checkedList) => {
   cursor: pointer;
 }
 .arco-input-wrapper {
-  background-color: var(--color-neutral-3);
+  background-color: var(--color-neutral-2);
 }
 </style>

+ 1 - 1
src/modules/intelligent/ManageTags.vue

@@ -114,6 +114,6 @@ const handleAdd = async () => {
 </script>
 <style scoped lang="css">
 .arco-input-wrapper {
-  background-color: var(--color-neutral-3);
+  background-color: var(--color-neutral-2);
 }
 </style>

+ 55 - 11
src/modules/intelligent/MessageBody.vue

@@ -1,6 +1,13 @@
 <template>
   <div class="body-container" ref="body_container">
-    <CardItem v-for="item in moke_data" :key="item.id" :name="item.name" :img_src="item.img_src" :height="200">
+    <CardItem
+      class="card_box"
+      v-for="item in moke_data"
+      :key="item.id"
+      :name="item.name"
+      :img_src="item.img_src"
+      :height="200"
+    >
       <template #description> {{ item.desc }} </template>
       <template #settings>
         <a-switch v-model="item.online" @change="changeStatus(item)">
@@ -11,7 +18,6 @@
       <template #labelBtn>
         <a-dropdown
           ref="dropdown"
-          v-model="show_down"
           position="bl"
           :popup-max-height="false"
           @popup-visible-change="changeDropdownVisible($event, item.id)"
@@ -19,8 +25,8 @@
           <a-button v-if="!item.label.length" class="label-btn">
             <icon-subscribe /> &nbsp;{{ $t('management.addLabelBtn') }}</a-button
           >
-          <a-button v-else class="label-btn">
-            <icon-subscribe />&nbsp;{{ item.label.map((it) => it.labelName).join(',') }}</a-button
+          <a-button v-else class="label-btn btn-content">
+            <icon-subscribe />&nbsp;{{ item.label.map((it) => it.labelName).join('') }}</a-button
           >
           <template #content>
             <div class="label-add">
@@ -39,11 +45,11 @@
         <div class="bottom">
           <div class="user"><icon-user /> {{ $t('management.createUser') }}:{{ item.user }}</div>
           <div class="tools" v-if="item.online">
-            <icon-more :style="{ fontSize: '20px' }" />
+            <icon-more :style="{ cursor: 'pointer' }" />
           </div>
           <div class="tools" v-if="!item.online">
-            <icon-settings :style="{ fontSize: '20px', cursor: 'pointer' }" @click="editIntelligent(item)" />
-            <icon-delete :style="{ fontSize: '20px', cursor: 'pointer' }" @click="deleteIntelligent" />
+            <icon-settings :style="{ cursor: 'pointer' }" @click.stop="editIntelligent(item)" />
+            <icon-delete :style="{ cursor: 'pointer' }" @click.stop="deleteIntelligent(item)" />
           </div>
         </div>
       </template>
@@ -58,13 +64,16 @@
 
 <script setup>
 import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
+import { Modal } from '@arco-design/web-vue';
 import CardItem from '../../views/manage/CardItem.vue';
 import ManageTags from './ManageTags.vue';
 import { getIconIntelligent, getImageIntelligent } from '../../views/manage/common';
 import LabelSelected from './LabelSelected.vue';
 import { getDialogList } from '../../apis/intelligent';
 import { bus_intelligentSearch, bus_intelligentEdit } from '../../base/event-bus';
+import { dialogType } from '../../views/manage/common';
 import { getLabelList, addLabelToDialog, changeDialogStatus } from '../../apis/intelligent';
+import { deleteDify } from '../../apis/rgflow-dify';
 
 const moke_data = ref([
   // {
@@ -96,7 +105,7 @@ const getDialog = async () => {
     const data = res.data.rows.map((item) => {
       return {
         ...item,
-        time: new Date(item.update_time).toLocaleString('zh-CN'),
+        time: new Date(item.create_time).toLocaleString('zh-CN'),
         desc: item.description,
         img_src: getImageIntelligent(item.icon) || getIconIntelligent(item.icon),
         user: item.user.userName || '-',
@@ -127,8 +136,31 @@ const openManageTags = () => {
 const editIntelligent = (item) => {
   bus_intelligentEdit.emit(item);
 };
-const deleteIntelligent = () => {
-  console.log('deleteIntelligent');
+const deleteIntelligent = (item) => {
+  Modal.warning({
+    title: '提示',
+    okText: '确定',
+    cancelText: '取消',
+    hideCancel: false,
+    content: '确定删除该智能体吗?',
+    async onOk(e) {
+      console.log('确定', item.agentType, dialogType.DIFY);
+      // dify删除
+      if (item.agentType == dialogType.DIFY) {
+        await deleteDify(item.id);
+        // TODO:刷新页面
+        bus_intelligentSearch.emit('');
+      }
+    },
+    onCancel(e) {
+      console.log('取消');
+    }
+  });
+  // if (item.agentType == dialogType.DIFY) {
+
+  //   deleteDify(item.id).then((res) => {});
+  // }
+  // console.log('deleteIntelligent');
 };
 
 // 获取标签列表
@@ -224,7 +256,6 @@ onBeforeUnmount(() => {
 }
 .label-btn {
   text-align: left;
-  padding: 8px 10px;
   background-color: var(--color-neutral-2);
   color: var(--color-neutral-6);
   font-size: 12px;
@@ -235,6 +266,7 @@ onBeforeUnmount(() => {
   -webkit-line-clamp: 1;
   -webkit-box-orient: vertical;
   text-overflow: ellipsis;
+  visibility: hidden;
 }
 .label-add {
   width: 240px;
@@ -253,5 +285,17 @@ onBeforeUnmount(() => {
 .tools {
   display: flex;
   gap: 5px;
+  visibility: hidden;
+}
+.card_box:hover .tools {
+  cursor: pointer;
+  visibility: visible;
+}
+.card_box:hover .label-btn {
+  visibility: visible;
+}
+.btn-content {
+  visibility: visible;
+  background-color: var(--color-bg-1);
 }
 </style>

+ 2 - 2
src/modules/intelligent/ModelAddItem.vue

@@ -11,7 +11,7 @@
       </div>
       <div class="form-item">
         <div class="label">描述</div>
-        <a-input v-model="form.description" placeholder="请输入名称" />
+        <a-textarea v-model="form.description" placeholder="描述" :auto-size="{ minRows: 2, maxRows: 5 }" />
       </div>
     </div>
   </a-modal>
@@ -114,6 +114,6 @@ const handleSelectIcon = () => {
 }
 .arco-input-wrapper {
   height: 32px;
-  background-color: var(--color-neutral-3);
+  background-color: var(--color-neutral-2);
 }
 </style>

+ 28 - 10
src/modules/intelligent/TopSetting.vue

@@ -1,7 +1,12 @@
 <template>
   <a-space size="large">
-    <a-input v-model="searchText" :placeholder="$t('management.search')" style="width: 300px" allow-clear
-      @input="handleSearch">
+    <a-input
+      v-model="searchText"
+      :placeholder="$t('management.search')"
+      style="width: 300px"
+      allow-clear
+      @input="handleSearch"
+    >
       <template #prefix>
         <icon-search />
       </template>
@@ -13,15 +18,29 @@
       {{ $t('management.createIntelligent') }}
     </a-button>
   </a-space>
-  <ModalAddIntel v-model:visible="visible" @add_intelligent="addIntelligent"
-    @createRAGFLOWIntelligent="createRAGFLOWIntelligent"></ModalAddIntel>
-  <ModelAddItem v-model:show_model_item="show_model_item" :target_icon="target_icon"
-    :target_intell_type="target_intell_type" @select_icon="selectIcon" @updateIntelligentList="updateIntelligentList">
+  <ModalAddIntel
+    v-model:visible="visible"
+    @add_intelligent="addIntelligent"
+    @createRAGFLOWIntelligent="createRAGFLOWIntelligent"
+  ></ModalAddIntel>
+  <ModelAddItem
+    v-model:show_model_item="show_model_item"
+    :target_icon="target_icon"
+    :target_intell_type="target_intell_type"
+    @select_icon="selectIcon"
+    @updateIntelligentList="updateIntelligentList"
+  >
   </ModelAddItem>
   <ModelSelectIcon v-model:show_select_icon="show_select_icon" @sendIcon="sendIcon"></ModelSelectIcon>
   <!-- v-if="show_rg_config" -->
-  <AgentConfig v-model:show_rg_config="show_rg_config" ref="editAgentKuai" :typeAngint="add_type" :formData="itemObj"
-    @queryList="queryList" @updateIntelligentList="updateIntelligentList"></AgentConfig>
+  <AgentConfig
+    v-model:show_rg_config="show_rg_config"
+    ref="editAgentKuai"
+    :typeAngint="add_type"
+    :formData="itemObj"
+    @queryList="queryList"
+    @updateIntelligentList="updateIntelligentList"
+  ></AgentConfig>
 </template>
 
 <script setup>
@@ -131,8 +150,7 @@ bus_intelligentEdit.on((item) => {
       break;
     case '4':
       // TODO: 进入Dify智能体配置
-      router.push({ path: '/difydetail', query: { id: item.id } });
-      console.log('item1', item);
+      router.push({ path: '/intelligent/detail', query: { id: item.id, name: item.name } });
       break;
     default:
       console.log('暂不支持该智能体类型');

+ 16 - 11
src/modules/intelligent/rgflow/AgentConfig.vue

@@ -264,9 +264,9 @@
 
 <script setup>
 import { onMounted, onBeforeMount, reactive, ref, nextTick, onUnmounted, onBeforeUnmount, computed } from 'vue';
-// import { kbdocumentupload, queryKbList, queryModelList } from '../../../apis/rgflow-dify';
 import { queryKbList, queryModelList, createRgFlow } from '../../../apis/rgflow-dify';
 import { createDialog } from '../../../apis/intelligent';
+import { getKnowledgeList } from '../../../apis/knowledge';
 import { dialogType } from '../../../views/manage/common';
 import useLoading from './loading';
 import Upload from './Upload.vue';
@@ -456,7 +456,7 @@ const handleBeforeOk = async (done) => {
     // console.log('res:', res)
   });
   // TODO: 先写死知识库和模型
-  form.kb_ids = ['5e96cc5aad3111ef93990242ac130006'];
+  // form.kb_ids = ['5e96cc5aad3111ef93990242ac130006'];
   form.llm_id = 'qwen-2.5-72b-instruct___OpenAI-API@OpenAI-API-Compatible';
   if (form.name && form.kb_ids.length > 0 && form.prompt_config.system && form.llm_id) {
     let title = '创建成功';
@@ -476,8 +476,6 @@ const handleBeforeOk = async (done) => {
       };
     });
 
-    console.log(formNew, 'formNew');
-
     if (props.typeAngint == 'edit') {
       formNew.dialog_id = form.id;
       delete formNew.id;
@@ -528,7 +526,6 @@ const handleBeforeOk = async (done) => {
 const editClick = (data) => {
   visible.value = true;
   nextTick(() => {
-    // console.log(props.formData,'传入数据');
     if (props.formData.llm_setting.max_tokens == '') {
       max_tokens.value = false;
       delete props.formData.llm_setting.max_tokens;
@@ -588,10 +585,18 @@ const queryModel = async () => {
 const knowledgeData = async () => {
   setLoading(true);
   try {
-    const { data } = await queryKbList();
-    nextTick(() => {
-      tabs.value = data;
-    });
+    const params = {
+      current: 1,
+      pageSize: 1000,
+      keyword: '',
+      location: '1'
+    };
+    const res = await getKnowledgeList(params.current, params.pageSize, params.keyword, params.location);
+    if (res.code == 200) {
+      nextTick(() => {
+        tabs.value = res.data.rows;
+      });
+    }
   } catch (err) {
     // you can report use errorHandler or other
   } finally {
@@ -612,7 +617,7 @@ defineExpose({
 });
 </script>
 <style scoped>
-::v-deep .arco-tabs-nav-tab-list {
+:deep .arco-tabs-nav-tab-list {
   width: 100%;
 
   .arco-tabs-tab {
@@ -625,7 +630,7 @@ defineExpose({
     }
   }
 }
-::v-deep .arco-input-wrapper {
+:deep .arco-input-wrapper {
   background-color: var(--color-neutral-2);
 }
 </style>

+ 27 - 4
src/modules/knowledge/MessageBody.vue

@@ -9,7 +9,7 @@
         </div>
       </template>
       <template #settings>
-        <a-dropdown trigger="hover" @select="handleSelect">
+        <a-dropdown trigger="hover" @select="handleSelect($event, item)">
           <icon-more :style="{ fontSize: '20px' }" />
           <template #content>
             <a-doption :value="{ value: 'edit' }">{{ $t('management.edit') }}</a-doption>
@@ -27,11 +27,14 @@
 
 <script setup>
 import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
+import { useRouter } from 'vue-router';
 import CardItem from '../../views/manage/CardItem.vue';
 import { getImageKnowLedge } from '../../views/manage/common';
 import { getKnowledgeList } from '../../apis/knowledge';
 import { bus_knowledgeSearch } from '../../base/event-bus';
 
+const router = useRouter();
+
 const moke_data = ref([
   // {
   //   name: '知识库1',
@@ -50,8 +53,17 @@ const body_container = ref(null);
 const scroll_bottom = ref(false);
 // 搜索文本
 const search_text = ref('');
-const handleSelect = ({ value }) => {
+
+const handleSelect = ({ value }, item) => {
   if (value === 'edit') {
+    console.log('edit', item);
+    router.push({
+      path: '/knowledge/detail',
+      query: {
+        id: item.id,
+        name: item.name
+      }
+    });
   } else {
   }
 };
@@ -63,8 +75,8 @@ const getKnowledge = async () => {
       const data = res.data.rows.map((item) => {
         return {
           ...item,
-          time: new Date(item.update_time).toLocaleString('zh-CN'),
-          img_src: getImageKnowLedge(item.avatar),
+          time: new Date(item.create_time).toLocaleString('zh-CN'),
+          img_src: getImageKnowLedge(item.icon),
           count: item.count ? item.count : 0
         };
       });
@@ -110,6 +122,7 @@ onBeforeUnmount(() => {
   align-content: flex-start;
   gap: 20px;
   overflow-y: scroll;
+  width: 100%;
   height: calc(100% - 80px);
 }
 .body-container::-webkit-scrollbar {
@@ -124,4 +137,14 @@ onBeforeUnmount(() => {
   grid-row-start: auto;
   text-align: center;
 }
+.container {
+  position: absolute;
+  top: 140px;
+  height: calc(100% - 140px);
+  background-color: #fff;
+}
+.arco-spin-loading {
+  /* width:  */
+  height: calc(100% - 80px);
+}
 </style>

+ 113 - 0
src/modules/knowledge/ModalCreateKb.vue

@@ -0,0 +1,113 @@
+<template>
+  <a-modal v-model:visible="show_modal" :align-center="false" top="15vh" @ok="handleOk" @cancel="handleCancel">
+    <template #title> 添加知识库 </template>
+    <div class="section">
+      <div class="form-item">
+        <div class="label">图标&名称</div>
+        <div class="value">
+          <img class="icon" :src="getImageKnowLedge(target_icon)" alt="" @click="handleSelectIcon" />
+          <a-input v-model="form.name" placeholder="请输入名称" />
+        </div>
+      </div>
+      <div class="form-item">
+        <div class="label">描述</div>
+        <a-textarea v-model="form.description" placeholder="描述" :auto-size="{ minRows: 2, maxRows: 5 }" />
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue';
+import { bus_knowledgeSearch } from '../../base/event-bus';
+import { createKb } from '../../apis/rgflow-dify';
+import { createOwnKnowledge } from '../../apis/knowledge';
+import { getImageKnowLedge, dialogType } from '../../views/manage/common';
+
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: false
+  },
+  target_icon: {
+    type: String,
+    default: 'knowledgeFrame1'
+  }
+});
+
+const emit = defineEmits(['update:visible', 'select_icon']);
+
+const formInit = {
+  name: '',
+  description: '',
+  icon: '',
+  klgType: dialogType.RAGFLOW
+};
+const form = ref(Object.assign({}, formInit));
+const show_modal = computed(() => props.visible);
+const handleOk = () => {
+  if (form.value.name.trim().length) {
+    // TODO:添加知识库b
+    createKnowledgeBase();
+  } else {
+    return false;
+  }
+};
+const handleCancel = () => {
+  form.value.name = '';
+  emit('update:visible', false);
+};
+const createKnowledgeBase = async () => {
+  const { name, description } = form.value;
+  const res = await createKb(name);
+  if (res.data && res.data.kb_id) {
+    const data = {
+      id: res.data.kb_id,
+      name,
+      description,
+      icon: props.target_icon,
+      klgType: dialogType.RAGFLOW
+    };
+    createOwnKnowledgeBase(data);
+  }
+};
+const createOwnKnowledgeBase = async (data) => {
+  try {
+    const res = await createOwnKnowledge(data);
+    if (res.code == 200) {
+      bus_knowledgeSearch.emit('');
+      form.value = Object.assign({}, formInit);
+      emit('update:visible', false);
+    }
+  } catch (error) {
+    console.log('创建知识库失败', error);
+  }
+};
+const handleSelectIcon = () => {
+  emit('select_icon');
+};
+</script>
+<style scoped lang="css">
+.section {
+  padding: 0 20px;
+}
+.form-item {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  margin-top: 20px;
+}
+.value {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.value .icon {
+  width: 44px;
+  cursor: pointer;
+}
+.arco-input-wrapper {
+  height: 32px;
+  background-color: var(--color-neutral-2);
+}
+</style>

+ 0 - 52
src/modules/knowledge/ModalItem.vue

@@ -1,52 +0,0 @@
-<template>
-  <a-modal
-    v-model:visible="showModal"
-    title="添加知识库"
-    title-align="start"
-    :align-center="false"
-    top="15vh"
-    @cancel="handleCancel"
-    @before-ok="handleBeforeOk"
-  >
-    <a-form :model="form">
-      <a-form-item field="name" label="名称" validate-trigger="input" required>
-        <a-input v-model="form.name" placeholder="请输入名称" />
-      </a-form-item>
-    </a-form>
-  </a-modal>
-</template>
-
-<script setup>
-import { ref, computed } from 'vue';
-
-const props = defineProps({
-  visible: {
-    type: Boolean,
-    default: false
-  }
-});
-
-const emit = defineEmits(['update:visible']);
-
-const form = ref({
-  name: ''
-});
-const showModal = computed(() => props.visible);
-const handleBeforeOk = (done) => {
-  if (form.value.name.trim().length) {
-    // TODO:添加知识库
-    done();
-  } else {
-    return false;
-  }
-};
-const handleCancel = () => {
-  form.value.name = '';
-  emit('update:visible', false);
-};
-</script>
-<style scoped lang="css">
-.arco-form-item-content-wrapper {
-  border-color: var(--color-neutral-4);
-}
-</style>

+ 106 - 0
src/modules/knowledge/ModalSelectIcon.vue

@@ -0,0 +1,106 @@
+<template>
+  <a-modal
+    v-model:visible="showModal"
+    :align-center="false"
+    top="15vh"
+    @cancel="handleCancel"
+    @before-ok="handleBeforeOk"
+  >
+    <template #title>替换图标</template>
+    <div class="section">
+      <div class="labels">全部图标</div>
+      <div class="icons">
+        <div
+          class="icon-border"
+          v-for="icon in icons"
+          :key="icon.icon"
+          :class="{ 'icon-border-active': icon.id === target_icon }"
+          @click="changeItem(icon.id)"
+        >
+          <img class="icon" :src="getImageKnowLedge(icon.name)" alt="" />
+        </div>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue';
+import { getImageKnowLedge } from '../../views/manage/common';
+
+const props = defineProps({
+  show_select_icon: {
+    type: Boolean,
+    default: false
+  }
+});
+const icons = ref([
+  {
+    id: 1,
+    name: 'knowledgeFrame1'
+  },
+  {
+    id: 2,
+    name: 'knowledgeFrame2'
+  },
+  {
+    id: 3,
+    name: 'knowledgeFrame3'
+  },
+  {
+    id: 4,
+    name: 'knowledgeFrame4'
+  }
+]);
+
+const target_icon = ref(icons.value[0].id);
+const emit = defineEmits(['update:show_model_item', 'sendIcon']);
+
+const showModal = computed(() => props.show_select_icon);
+
+const changeItem = (id) => {
+  target_icon.value = id;
+};
+const handleBeforeOk = (done) => {
+  emit('sendIcon', icons.value.filter((icon) => icon.id === target_icon.value)[0].name);
+  emit('update:show_select_icon', false);
+  done();
+};
+const handleCancel = () => {
+  emit('update:show_select_icon', false);
+};
+</script>
+<style scoped lang="css">
+.section {
+  height: 200px;
+  padding: 0 20px;
+}
+.icons {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+  margin-top: 10px;
+}
+.icons .icon-border {
+  /* width: 50px;
+  height: 50px; */
+  padding: 5px 10px;
+  cursor: pointer;
+}
+.icon-border:hover {
+  border: 1px solid var(--color-neutral-4);
+  border-radius: 5px;
+}
+.icon-border .icon {
+  width: 44px;
+  height: 44px;
+}
+.icon-border-active {
+  border: 1px solid var(--color-neutral-4);
+  border-radius: 5px;
+}
+.arco-input-wrapper {
+  height: 32px;
+  background-color: var(--color-neutral-3);
+}
+</style>

+ 22 - 4
src/modules/knowledge/TopSetting.vue

@@ -1,7 +1,12 @@
 <template>
   <a-space size="large">
-    <a-input v-model="searchText" :placeholder="$t('management.search')" style="width: 300px" allow-clear
-      @input="handleSearch">
+    <a-input
+      v-model="searchText"
+      :placeholder="$t('management.search')"
+      style="width: 300px"
+      allow-clear
+      @input="handleSearch"
+    >
       <template #prefix>
         <icon-search />
       </template>
@@ -13,18 +18,23 @@
       {{ $t('management.createKnowledgeBase') }}
     </a-button>
   </a-space>
-  <ModalItem v-model:visible="visible"></ModalItem>
+  <ModalCreateKb v-model:visible="visible" :target_icon="target_icon" @select_icon="selectIcon"></ModalCreateKb>
+  <ModalSelectIcon v-model:show_select_icon="show_select_icon" @sendIcon="sendIcon"></ModalSelectIcon>
 </template>
 
 <script setup>
 import { ref } from 'vue';
-import ModalItem from './ModalItem.vue';
+import ModalCreateKb from './ModalCreateKb.vue';
+import ModalSelectIcon from './ModalSelectIcon.vue';
 import { funcDebounce } from '../../utils/utils';
 import { bus_knowledgeSearch } from '../../base/event-bus';
 
 const searchText = ref('');
 // 模态框控制
 const visible = ref(false);
+const show_select_icon = ref(false);
+const target_icon = ref('');
+
 // 搜索
 const handleSearch = funcDebounce(
   () => {
@@ -37,6 +47,14 @@ const handleSearch = funcDebounce(
 const handleCreate = () => {
   visible.value = true;
 };
+
+const selectIcon = () => {
+  show_select_icon.value = true;
+};
+const sendIcon = (icon) => {
+  console.log('sendIcon', icon);
+  target_icon.value = icon;
+};
 </script>
 <style scoped lang="css">
 .arco-input-wrapper {

+ 6 - 0
src/modules/knowledge/rgflow/MessageDetail.vue

@@ -0,0 +1,6 @@
+<template>
+  <div class="message-detail">知识库详情</div>
+</template>
+
+<script setup></script>
+<style scoped lang="css"></style>

+ 21 - 0
src/modules/knowledge/rgflow/TopBreadCrumb.vue

@@ -0,0 +1,21 @@
+<template>
+  <a-breadcrumb class="breadcrumb">
+    <a-breadcrumb-item><icon-apps /></a-breadcrumb-item>
+    <a-breadcrumb-item>
+      <router-link to="/knowledge">知识库管理</router-link>
+    </a-breadcrumb-item>
+    <a-breadcrumb-item>{{ current_label }}</a-breadcrumb-item>
+  </a-breadcrumb>
+</template>
+
+<script setup>
+const props = defineProps({
+  current_label: String
+});
+</script>
+
+<style lang="css" scoped>
+.breadcrumb {
+  margin-bottom: 16px;
+}
+</style>

+ 1 - 1
src/modules/login/FormItem.vue

@@ -161,7 +161,7 @@ const changeFormType = (e) => {
   background-color: var(--color-bg-1);
   border-color: var(--color-neutral-3);
 }
-::v-deep .arco-form-item-label-col > .arco-form-item-label {
+:deep .arco-form-item-label-col > .arco-form-item-label {
   display: none;
 }
 </style>

+ 18 - 13
src/modules/permission/group/MembertConfigModal.vue

@@ -1,16 +1,22 @@
 <template>
   <a-modal width="50%" v-model:visible="visible" title="权限配置" @cancel="handleCancel" @ok="ok">
     <div class="membert-config-modal">
-      <a-transfer show-search :data="memberList" :model-value="selectedMemberList" :source-input-search-props="{
-        placeholder: '请输入用户名搜索',
-      }" :target-input-search-props="{
-        placeholder: '请输入用户名搜索',
-      }" @change="handleChange">
+      <a-transfer
+        show-search
+        :data="memberList"
+        :model-value="selectedMemberList"
+        :source-input-search-props="{
+          placeholder: '请输入用户名搜索'
+        }"
+        :target-input-search-props="{
+          placeholder: '请输入用户名搜索'
+        }"
+        @change="handleChange"
+      >
         <template #source-title>可选成员</template>
         <template #target-title>已选成员</template>
       </a-transfer>
     </div>
-
   </a-modal>
 </template>
 
@@ -22,12 +28,12 @@ const props = defineProps({
   visible: Boolean,
   memberList: {
     type: Array,
-    default: () => [],
+    default: () => []
   },
   selectedMemberList: {
     type: Array,
-    default: () => [],
-  },
+    default: () => []
+  }
 });
 const { visible, memberList, selectedMemberList } = toRefs(props);
 const emit = defineEmits(['cancel', 'ok']);
@@ -42,22 +48,21 @@ const ok = () => {
 };
 const handleChange = (selected) => {
   // 计算新增的成员
-  const addedMembers = selected.filter(member => !tempSelectedMemberList.value.includes(member));
+  const addedMembers = selected.filter((member) => !tempSelectedMemberList.value.includes(member));
   // 计算减少的成员
-  const removedMembers = tempSelectedMemberList.value.filter(member => !selected.includes(member));
+  const removedMembers = tempSelectedMemberList.value.filter((member) => !selected.includes(member));
 
   // 根据需要处理增加和减少的成员
   if (addedMembers.length > 0) {
     tempSelectedMemberList.value = [...tempSelectedMemberList.value, ...addedMembers];
   }
   if (removedMembers.length > 0) {
-    tempSelectedMemberList.value = tempSelectedMemberList.value.filter(member => !removedMembers.includes(member));
+    tempSelectedMemberList.value = tempSelectedMemberList.value.filter((member) => !removedMembers.includes(member));
   }
 
   // 更新父组件的 selectedMemberList
   emit('update:selectedMemberList', tempSelectedMemberList.value);
 };
-
 </script>
 
 <style scoped>

+ 21 - 0
src/views/KnowledgeDetail.vue

@@ -0,0 +1,21 @@
+<template>
+  <LayoutExperience>
+    <ContentContainer>
+      <TopBreadCrumb :current_label="name"></TopBreadCrumb>
+      <MessageDetail :id="id"></MessageDetail>
+    </ContentContainer>
+  </LayoutExperience>
+</template>
+
+<script setup>
+import { useRoute } from 'vue-router';
+import LayoutExperience from './layout/LayoutExperience.vue';
+import ContentContainer from './layout/ContentContainer.vue';
+import TopBreadCrumb from '../modules/knowledge/rgflow/TopBreadCrumb.vue';
+import MessageDetail from '../modules/knowledge/rgflow/MessageDetail.vue';
+
+const route = useRoute();
+
+const { id, name } = route.query;
+console.log(id, name);
+</script>

+ 12 - 0
src/views/common/NavItem.vue

@@ -25,6 +25,12 @@ const target = props.to;
 const isChatType = (cur_path) => {
   return cur_path === '/chat' || cur_path === '/chat/history' || cur_path === '/chat/board' || cur_path === '/chat/qa';
 };
+const isKnowLedgeType = (cur_path) => {
+  return cur_path === '/knowledge' || cur_path === '/knowledge/detail';
+};
+const isIntelligentType = (cur_path) => {
+  return cur_path === '/intelligent' || cur_path === '/intelligent/detail';
+};
 
 const is_active = computed(() => {
   const cur_path = route.path;
@@ -39,6 +45,12 @@ const is_active = computed(() => {
       return false;
     }
   }
+  if (['/knowledge', '/knowledge/detail'].includes(target)) {
+    return isKnowLedgeType(cur_path);
+  }
+  if (['/intelligent', '/intelligent/detail'].includes(target)) {
+    return isIntelligentType(cur_path);
+  }
 
   return cur_path === target;
 });

+ 2 - 2
src/views/difyDetail.vue

@@ -1,7 +1,7 @@
 <template>
   <LayoutExperience>
     <ContentContainer>
-      <TopSetting></TopSetting>
+      <TopSetting :current_label="name"></TopSetting>
       <MessageBody :id="id"></MessageBody>
     </ContentContainer>
   </LayoutExperience>
@@ -16,5 +16,5 @@ import MessageBody from '../modules/dify/MessageBody.vue';
 
 const route = useRoute();
 
-const id = route.query.id;
+const { id, name } = route.query;
 </script>

+ 2 - 1
src/views/manage/CardItem.vue

@@ -42,6 +42,7 @@ const props = defineProps({
   padding: 10px 20px;
   background-color: var(--color-bg-2);
   overflow: hidden;
+  cursor: pointer;
 }
 .card-name .name {
   margin-top: 10px;
@@ -52,7 +53,7 @@ const props = defineProps({
 .card-label {
   width: 100%;
   margin-top: 15px;
-  color: var(--color-neutral-4);
+  color: var(--color-neutral-2);
 }
 
 .card-des {

+ 2 - 2
src/views/manage/common.js

@@ -45,8 +45,8 @@ const icon_intelligent_map = {
  * @description: 智能体类型
  * */
 export const dialogType = {
-  RAGFLOW_TYPE: '1',
-  BS_TYPE: '2',
+  RAGFLOW: '1',
+  BS: '2',
   BASIC: '3',
   DIFY: '4'
 };

+ 2 - 1
src/views/routes.js

@@ -18,6 +18,7 @@ const routes = [
 
   // 知识库
   { path: '/knowledge', component: () => import('./Knowledge.vue') },
+  { path: '/knowledge/detail', component: () => import('./KnowledgeDetail.vue') },
   // 模型
   { path: '/model', component: () => import('./Model.vue') },
   // Agent
@@ -25,7 +26,7 @@ const routes = [
   // 智能体
   { path: '/intelligent', component: () => import('./Intelligent.vue') },
   // dify智能体详情
-  { path: '/difydetail', component: () => import('./difyDetail.vue') },
+  { path: '/intelligent/detail', component: () => import('./difyDetail.vue') },
 
   // 权限管理
   {