Prechádzať zdrojové kódy

Merge branch 'master' of http://gitlab.smartai.com/zhupei/smartai2dian0

张涛 1 rok pred
rodič
commit
d16adad333
32 zmenil súbory, kde vykonal 595 pridanie a 241 odobranie
  1. 23 0
      src/base/store/use-all-agents.js
  2. 57 0
      src/modules/common/icon-map.js
  3. 2 2
      src/modules/conversation-board/api-conversation-board.js
  4. 49 0
      src/modules/conversation-board/get-agent-client-config.js
  5. 6 2
      src/modules/conversation-chat/DialogHeader.vue
  6. 29 6
      src/modules/conversation-chat/DialogInput.vue
  7. 6 4
      src/modules/conversation-chat/dialog-item/DialogActions.vue
  8. 7 1
      src/modules/conversation-chat/use-file-select-v2.js
  9. 45 20
      src/modules/conversation-dialog/api-dialog.js
  10. 4 0
      src/modules/conversation-dialog/format-dialog-answer-from-websocket_receive_message.js
  11. 7 0
      src/modules/conversation-dialog/format-dialog-send-options.js
  12. 18 2
      src/modules/file-upload/FileItemDocPreview.vue
  13. 3 9
      src/modules/file-upload/FileUploadPreview.vue
  14. 14 0
      src/modules/file-upload/files-2-formdata.js
  15. 20 0
      src/modules/file-upload/is-image-by-filename.js
  16. 21 1
      src/modules/intelligent/MessageBody.vue
  17. 1 1
      src/modules/intelligent/ModalSelectIcon.vue
  18. 2 1
      src/modules/intelligent/ModelAddItem.vue
  19. 44 8
      src/modules/knowledge/MessageBody.vue
  20. 6 2
      src/modules/knowledge/ModalCreateKb.vue
  21. 1 1
      src/modules/knowledge/ModalSelectIcon.vue
  22. 7 8
      src/modules/knowledge/rgflow/knowledgeLib/config.vue
  23. 11 11
      src/modules/knowledge/rgflow/knowledgeLib/index.vue
  24. 48 33
      src/modules/knowledge/rgflow/knowledgeLib/test.vue
  25. 6 1
      src/modules/knowledge/rgflow/knowledgeLib/tool.vue
  26. 26 21
      src/views/ConversationQA.vue
  27. 1 1
      src/views/Xiaoshu.vue
  28. 1 0
      src/views/conversation/ChatAsideMenu.vue
  29. 11 0
      src/views/conversation/ConversationBoardContainer.vue
  30. 115 48
      src/views/conversation/ConversationChatContainer.vue
  31. 4 0
      src/views/manage/CardItem.vue
  32. 0 58
      src/views/manage/common.js

+ 23 - 0
src/base/store/use-all-agents.js

@@ -49,6 +49,29 @@ export const useAllAgentStore = defineStore('all_agents', {
 
       return this.agents;
     },
+    /**
+     * 根据agent id获取到相关的记录
+     * @param {string} agent_id
+     */
+    getInfo(agent_id) {
+      if (!agent_id) {
+        return null;
+      }
+
+      const list = this.getList();
+      console.log(list, '所有的agent');
+
+      const total = list.length;
+      for (let i = 0; i < total; i++) {
+        const item = list[i];
+
+        if (item.id === agent_id) {
+          return item;
+        }
+      }
+
+      return null;
+    },
     setList(arr) {
       const list = jsonParse(jsonStringify(arr));
 

+ 57 - 0
src/modules/common/icon-map.js

@@ -0,0 +1,57 @@
+import knowledgeFrame1 from '../../assets/image/management/knowledge-frame1.png';
+import knowledgeFrame2 from '../../assets/image/management/knowledge-frame2.png';
+import knowledgeFrame3 from '../../assets/image/management/knowledge-frame3.png';
+import knowledgeFrame4 from '../../assets/image/management/knowledge-frame4.png';
+import intelligentFrame1 from '../../assets/image/management/intelligent-frame1.png';
+import intelligentFrame2 from '../../assets/image/management/intelligent-frame2.png';
+import intelligentFrame3 from '../../assets/image/management/intelligent-frame3.png';
+import intelligentFrame4 from '../../assets/image/management/intelligent-frame4.png';
+import intelligentFrame5 from '../../assets/image/management/intelligent-frame5.png';
+import intelligentFrame6 from '../../assets/image/management/intelligent-frame6.png';
+import intelligentFrame7 from '../../assets/image/management/intelligent-frame7.png';
+import intelligentFrame8 from '../../assets/image/management/intelligent-frame8.png';
+import intellFrame1 from '../../assets/image/management/intellFrame1.png';
+import intellFrame2 from '../../assets/image/management/intellFrame2.png';
+import intellFrame3 from '../../assets/image/management/intellFrame3.png';
+import intellFrame4 from '../../assets/image/management/intellFrame4.png';
+import intellFrame5 from '../../assets/image/management/intellFrame5.png';
+import intellFrame6 from '../../assets/image/management/intellFrame6.png';
+
+const image_knowLedge_map = {
+  knowledgeFrame1: knowledgeFrame1,
+  knowledgeFrame2: knowledgeFrame2,
+  knowledgeFrame3: knowledgeFrame3,
+  knowledgeFrame4: knowledgeFrame4
+};
+const image_intelligent_map = {
+  intelligentFrame1: intelligentFrame1,
+  intelligentFrame2: intelligentFrame2,
+  intelligentFrame3: intelligentFrame3,
+  intelligentFrame4: intelligentFrame4,
+  intelligentFrame5: intelligentFrame5,
+  intelligentFrame6: intelligentFrame6,
+  intelligentFrame7: intelligentFrame7,
+  intelligentFrame8: intelligentFrame8
+};
+const icon_intelligent_map = {
+  intellFrame1: intellFrame1,
+  intellFrame2: intellFrame2,
+  intellFrame3: intellFrame3,
+  intellFrame4: intellFrame4,
+  intellFrame5: intellFrame5,
+  intellFrame6: intellFrame6
+};
+
+/**
+ * @description: 图片映射表
+ * avatar: 图片名称
+ */
+export const getImageKnowLedge = (avatar) => {
+  return image_knowLedge_map[avatar] || knowledgeFrame1;
+};
+export const getImageIntelligent = (avatar) => {
+  return image_intelligent_map[avatar];
+};
+export const getIconIntelligent = (avatar) => {
+  return icon_intelligent_map[avatar] || intellFrame1;
+};

+ 2 - 2
src/modules/conversation-board/api-conversation-board.js

@@ -65,7 +65,7 @@ const res_list_example = {
  * 获取所有对话可用的智能体
  * @see https://app.apifox.com/link/project/5404857/apis/api-233232945
  */
-export const conversationBoardAgentList = (params) => {
+export const conversationBoardAgentListBackup = (params) => {
   return new Promise((resolve, reject) => {
     setTimeout(() => {
       resolve(res_list_example);
@@ -78,7 +78,7 @@ export const conversationBoardAgentList = (params) => {
  * 正式环境需要使用的会话列表
  * @see https://app.apifox.com/link/project/5404857/apis/api-233232945
  */
-export const conversationBoardAgentListBackup = (params) => {
+export const conversationBoardAgentList = (params) => {
   const request_url = `/api/dialog/list`;
 
   const send_data = {

+ 49 - 0
src/modules/conversation-board/get-agent-client-config.js

@@ -0,0 +1,49 @@
+/**
+ * 此文件是针对对话agent进行个性化配置
+ * 如有新增配置项,请写清楚注释
+ *
+ * 配置项的 key 为 /api/dialog/list?status=1&current=1&pageSize=50 接口返回的 data中的每一项的ID值
+ */
+
+const client_agent_config = {
+  /**
+   * 小数绘图
+   * 文生图、图生文
+   */
+  '9d75142a-66eb-4e23-b7d4-03efe4584915': {
+    // 文本限制的长度
+    text_limit: 250,
+
+    // 是否支持文件上传
+    file_upload: true,
+
+    // 以下与文件上传配置有关的项目,必须在 file_upload = true 情况下才生效
+    // 可以接收的文件类型
+    file_accept: '.jpg,.png',
+    // 允许多少个文件上传
+    file_limit: 1,
+    // 文件上传组件的提示信息
+    file_message: '支持上传 .png, .jpg,大小不超过10M'
+  }
+};
+
+/**
+ * 客户端对agent的个性化配置
+ * 配置项大致如下:
+ * 1. 文件上传配置
+ *    是否支持文件上传
+ *    支持多少个文件上传
+ *    支持什么类型的文件上传
+ * @param {string} agent_id
+ */
+export default function getAgentClientConfig(agent_id) {
+  if (!agent_id) {
+    return null;
+  }
+
+  if (agent_id in client_agent_config) {
+    return client_agent_config[agent_id];
+  }
+
+  return null;
+}

+ 6 - 2
src/modules/conversation-chat/DialogHeader.vue

@@ -1,10 +1,14 @@
 <template>
   <div class="dialog-header">
-    <div>修改名称</div>
+    <div>{{ agent_info.agent.name }}</div>
   </div>
 </template>
 
-<script setup></script>
+<script setup>
+const props = defineProps({
+  agent_info: Object
+});
+</script>
 
 <style lang="css" scoped>
 .dialog-header {

+ 29 - 6
src/modules/conversation-chat/DialogInput.vue

@@ -35,7 +35,7 @@
 </template>
 
 <script setup>
-import { ref } from 'vue';
+import { ref, onMounted, onUnmounted } from 'vue';
 import InputActions from './dialog-input/InputActions.vue';
 
 import FileUploadPreview from '../file-upload/FileUploadPreview.vue';
@@ -55,6 +55,15 @@ const props = defineProps({
     default: false,
     required: false
   },
+  // 智能体的基本信息
+  agent_info: {
+    type: Object
+  },
+  // 智能体的配置项
+  agent_config: {
+    type: Object
+  },
+
   /**
    * 是否开启文件上传功能
    * 默认 true,即默认开启
@@ -142,7 +151,7 @@ const props = defineProps({
 const input_text_value = ref('');
 const input_file_list = ref([]);
 
-const emit = defineEmits(['inputTextChange', 'inputFileChange', 'submit']);
+const emit = defineEmits(['submit']);
 
 // const fileSelect = useFileSelect('file_upload_input');
 const { select, remove } = useFileSelectedV2();
@@ -153,11 +162,20 @@ const handleSubmit = () => {
     return;
   }
 
-  emit('submit');
+  const real_file_list = [];
+  input_file_list.value.forEach((item) => {
+    real_file_list.push(item.file);
+  });
+
+  emit('submit', {
+    text: input_text_value.value,
+    files: real_file_list
+  });
 };
 
 const clear = () => {
   input_text_value.value = '';
+  input_file_list.value = [];
 };
 
 /**
@@ -199,7 +217,7 @@ const handleFileUpload = () => {
       }
     }
 
-    console.log(files, '文件列表', id, input_file_list.value);
+    // console.log(files, '文件列表', id, input_file_list.value);
   });
 };
 /**
@@ -230,7 +248,7 @@ const handleTextInput = (value, event) => {
 
   input_text_value.value = value;
 
-  emit('inputTextChange', input_text_value.value);
+  // emit('inputTextChange', input_text_value.value);
 };
 
 /**
@@ -253,11 +271,16 @@ const handleTextKeyUp = (e) => {
       removeBreakLineFlag();
 
       // 提交
-      emit('submit');
+      // emit('submit');
+      handleSubmit();
     }
   }
 };
 
+onUnmounted(() => {
+  remove();
+});
+
 defineExpose({
   clear: clear
 });

+ 6 - 4
src/modules/conversation-chat/dialog-item/DialogActions.vue

@@ -2,12 +2,14 @@
   <div class="dialog-actions-container">
     <div class="dialog-action-part dialog-action-left">
       <div class="action-btn-item" @click="handleCopy">复制</div>
-      <div class="action-btn-item" @click="handleRetry">再试一次</div>
-      <div class="action-btn-item" @click="handleShare">分享</div>
+      <!-- <div class="action-btn-item" @click="handleRetry">再试一次</div>
+      <div class="action-btn-item" @click="handleShare">分享</div> -->
     </div>
 
     <div class="dialog-action-part dialog-action-right">
-      <div class="action-btn-item" @click="handleLike">
+      <div class="action-btn-item"></div>
+
+      <!-- <div class="action-btn-item" @click="handleLike">
         <svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
           <use xlink:href="#mshd-vote-up"></use>
         </svg>
@@ -16,7 +18,7 @@
         <svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
           <use xlink:href="#mshd-vote-down"></use>
         </svg>
-      </div>
+      </div> -->
     </div>
   </div>
 </template>

+ 7 - 1
src/modules/conversation-chat/use-file-select-v2.js

@@ -1,17 +1,23 @@
 export default function useFileSelectedV2(options) {
   const input_list = [];
 
+  let ele_index = 0;
+
   return {
     select(fn) {
       /**
        * https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input/file
        */
+      const cur = Date.now();
       const input = document.createElement('input');
       input.type = 'file';
-      input.id = Date.now();
+      input.id = `9d75142a66eb4e23b7d403efe4584915-${cur}-${ele_index}`;
       input.setAttribute('multiple', true);
+      input.setAttribute('style', 'display: none;');
       document.body.appendChild(input);
 
+      ele_index = ele_index + 1;
+
       input.click();
       input.onchange = (e) => {
         if (typeof fn === 'function') {

+ 45 - 20
src/modules/conversation-dialog/api-dialog.js

@@ -16,30 +16,55 @@ import { kuky_Authorization } from '../../base/storage';
  * http://192.168.20.119:9301/api/agent/get-chat-id/42e4fcdc9bea11efac300242ac160006
  */
 
+// /**
+//  * 上传文档
+//  * @param {string} id - agentId
+//  * @param {files} files - files
+//  * @returns {Promise<Object>}
+//  */
+// const uploadFiles = (id, file) => {
+//   return ajax.post(`/api/files/upload/${id}`, file, {
+//     headers: {
+//       'Content-Type': 'multipart/form-data'
+//     }
+//   });
+// };
+
+// const uploadExcels = (file) => {
+//   return ajax.post('/api/document/excel/upload', file, {
+//     headers: {
+//       'Content-Type': 'multipart/form-data'
+//     }
+//   });
+// };
+
 /**
- * 上传文档
- * @param {string} id - agentId
- * @param {files} files - files
- * @returns {Promise<Object>}
+ * 上传文件
+ * @param {string} agent_id
+ * @param {string} chat_id
+ * @param {FormData} file
+ * @returns
  */
-const uploadFiles = (id, file) => {
-  return ajax.post(`/api/files/upload/${id}`, file, {
-    headers: {
-      'Content-Type': 'multipart/form-data'
+export const uploadFiles = (agent_id, chat_id, file) => {
+  /**
+   * 响应数据示例
+   * 单文件
+   */
+  const res_example1 = {
+    code: 200,
+    msg: '',
+    data: {
+      id: 'faf0d7f5-ba4d-4dcc-81bd-be826accfeb9',
+      name: 'juejin.pdf',
+      size: 1432958,
+      extension: 'pdf',
+      mime_type: 'application/pdf',
+      created_by: '714172d6-5be3-4891-b413-2eb5a5047d02',
+      created_at: 1734487728
     }
-  });
-};
-
-const uploadExcels = (file) => {
-  return ajax.post('/api/document/excel/upload', file, {
-    headers: {
-      'Content-Type': 'multipart/form-data'
-    }
-  });
-};
+  };
 
-const uploadFile = (id, chatId, file) => {
-  return ajax.post(`/api/files/upload/${id}?chat_id=${chatId}`, file, {
+  return ajax.post(`/api/files/upload/${agent_id}?chat_id=${chat_id}`, file, {
     headers: {
       'Content-Type': 'multipart/form-data'
     }

+ 4 - 0
src/modules/conversation-dialog/format-dialog-answer-from-websocket_receive_message.js

@@ -239,6 +239,10 @@ export default function formatDialogAnswerFromWebsocketReceiveMessage(message_st
   if (resType === 'error') {
     // 错误消息
     chat_status = 3;
+    currentMsg.client_custom_chat_status = 2; // 次轮会话已结束
+    currentMsg.client_custom_chat_type = 1; // 修改消息类型: 改为 结束
+
+    currentMsg.answer = resMessage;
   }
 
   /**

+ 7 - 0
src/modules/conversation-dialog/format-dialog-send-options.js

@@ -3,6 +3,13 @@ import { jsonParse, jsonStringify } from '../../utils/utils';
 /**
  * 格式化websocket发送消息的参数
  */
+
+/**
+ * 组装发送websocket消息时的参数
+ * @param {string} text - 纯文本数据
+ * @param {object[]} file_list - 文件上传后,接口返回的数据信息,某些场景需要携带文件数据
+ * @returns
+ */
 export default function formatDialogSendOptions(text, file_list) {
   /**
    * 组装socket参数

+ 18 - 2
src/modules/file-upload/FileItemDocPreview.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div class="file-item-doc-preview">
     <div>{{ file.name }}</div>
   </div>
 </template>
@@ -10,6 +10,22 @@ import { ref, computed } from 'vue';
 const props = defineProps({
   file: Object
 });
+
+console.log(props.file, '文档内容');
+
+/**
+ * lastModified: 1733385125049
+ * lastModifiedDate: Date,
+ * name: 'juejin.pdf',
+ * size: 143258,
+ * type: 'application/pdf',
+ * webkitRelativePath: ''
+ */
 </script>
 
-<style lang="css" scoped></style>
+<style lang="css" scoped>
+.file-item-doc-preview {
+  background-color: #fff;
+  padding: 5px;
+}
+</style>

+ 3 - 9
src/modules/file-upload/FileUploadPreview.vue

@@ -14,6 +14,7 @@
 import { ref, computed } from 'vue';
 import FileItemDocPreview from './FileItemDocPreview.vue';
 import FileItemImagePreview from './FileItemImagePreview.vue';
+import isImageByFileName from './is-image-by-filename';
 
 const props = defineProps({
   file_list: Array
@@ -35,10 +36,8 @@ const file_images_list = computed(() => {
 
   props.file_list.forEach((item, index) => {
     const file_name = item.file.name;
-    const name_info_arr = file_name.split('.');
-    const end_fix = name_info_arr[name_info_arr.length - 1];
 
-    const is_image = isImageEndfix(end_fix);
+    const is_image = isImageByFileName(file_name);
 
     if (is_image) {
       arr.push(item);
@@ -56,10 +55,8 @@ const file_doc_list = computed(() => {
 
   props.file_list.forEach((item, index) => {
     const file_name = item.file.name;
-    const name_info_arr = file_name.split('.');
-    const end_fix = name_info_arr[name_info_arr.length - 1];
 
-    const is_image = isImageEndfix(end_fix);
+    const is_image = isImageByFileName(file_name);
 
     if (!is_image) {
       arr.push(item);
@@ -72,9 +69,6 @@ const file_doc_list = computed(() => {
 
 <style lang="css" scoped>
 .file-upload-preview-area {
-  /* display: flex;
-  justify-content: space-between;
-  align-items: center; */
 }
 
 .file-doc-preview-container {

+ 14 - 0
src/modules/file-upload/files-2-formdata.js

@@ -0,0 +1,14 @@
+/**
+ * 将 File 转换为文件上传用到的 formdata 数据
+ * @param {File[]} f_list
+ * @returns
+ */
+export default function files2Formdata(f_list) {
+  const formData = new FormData();
+
+  f_list.forEach((item) => {
+    formData.append('file', item);
+  });
+
+  return formData;
+}

+ 20 - 0
src/modules/file-upload/is-image-by-filename.js

@@ -0,0 +1,20 @@
+/**
+ * 判断一个文件的后缀名是否是图片
+ * @param endfix
+ */
+const isImageEndfix = (endfix) => {
+  return endfix === 'jpg' || endfix === 'png' || endfix === 'jpeg' || endfix === 'gif';
+};
+
+/**
+ * 根据文件名检查一个文件是否是图片类型
+ * @param {string} file_name
+ */
+export default function isImageByFileName(file_name) {
+  const name_info_arr = file_name.split('.');
+  const end_fix = name_info_arr[name_info_arr.length - 1];
+
+  const is_image = isImageEndfix(end_fix);
+
+  return is_image;
+}

+ 21 - 1
src/modules/intelligent/MessageBody.vue

@@ -59,6 +59,8 @@
       <div v-if="scroll_bottom && pages.current >= total_pages">{{ $t('management.noMoreData') }}</div>
     </div>
   </div>
+  <a-spin v-if="loading_data" :size="32" />
+  <a-empty v-if="!moke_data.length"></a-empty>
   <ManageTags v-model:visible="visible" :labels="label_list" @updateLabels="updateLabels"></ManageTags>
 </template>
 
@@ -67,7 +69,7 @@ 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 { getIconIntelligent, getImageIntelligent } from '../common/icon-map.js';
 import LabelSelected from './LabelSelected.vue';
 import { getDialogList } from '../../apis/intelligent';
 import { bus_intelligentSearch, bus_intelligentEdit } from '../../base/event-bus';
@@ -98,8 +100,12 @@ const search_label = ref('');
 const label_list = ref([]);
 const dropdown = ref(null);
 const visible = ref(false);
+const loading_data = ref(false);
 
 const getDialog = async () => {
+  if (pages.current == 1) {
+    loading_data.value = true;
+  }
   try {
     const res = await getDialogList(pages.current, pages.pageSize, search_text.value);
     const data = res.data.rows.map((item) => {
@@ -116,6 +122,8 @@ const getDialog = async () => {
     moke_data.value.push(...data);
   } catch (err) {
     console.log(err);
+  } finally {
+    loading_data.value = false;
   }
 };
 const scrollHandler = (e) => {
@@ -298,4 +306,16 @@ onBeforeUnmount(() => {
   visibility: visible;
   background-color: var(--color-bg-1);
 }
+.arco-spin {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+}
+.arco-empty {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+}
 </style>

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

@@ -26,7 +26,7 @@
 
 <script setup>
 import { ref, computed } from 'vue';
-import { getIconIntelligent } from '../../views/manage/common';
+import { getIconIntelligent } from '../common/icon-map.js';
 
 const props = defineProps({
   show_select_icon: {

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

@@ -21,7 +21,8 @@
 import { ref, computed } from 'vue';
 import { createDify } from '../../apis/rgflow-dify';
 import { createDialog } from '../../apis/intelligent';
-import { getIconIntelligent, dialogType } from '../../views/manage/common';
+import { dialogType } from '../../views/manage/common';
+import { getIconIntelligent } from '../common/icon-map.js';
 const props = defineProps({
   show_model_item: {
     type: Boolean,

+ 44 - 8
src/modules/knowledge/MessageBody.vue

@@ -23,14 +23,18 @@
       <div v-if="scroll_bottom && pages.current >= total_pages">{{ $t('management.noMoreData') }}</div>
     </div>
   </div>
+  <a-spin v-if="loading_data" :size="32" />
+  <a-empty v-if="!moke_data.length"></a-empty>
 </template>
 
 <script setup>
 import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
+import { Message, Modal } from '@arco-design/web-vue';
 import { useRouter } from 'vue-router';
 import CardItem from '../../views/manage/CardItem.vue';
-import { getImageKnowLedge } from '../../views/manage/common';
+import { getImageKnowLedge } from '../common/icon-map.js';
 import { getKnowledgeList } from '../../apis/knowledge';
+import { deleteKnow } from '../../apis/rgflow-dify.js';
 import { bus_knowledgeSearch } from '../../base/event-bus';
 
 const router = useRouter();
@@ -47,6 +51,7 @@ const pages = reactive({
   current: 1,
   pageSize: 30
 });
+const loading_data = ref(false);
 // 总页码
 const total_pages = ref(0);
 const body_container = ref(null);
@@ -65,10 +70,33 @@ const handleSelect = ({ value }, item) => {
       }
     });
   } else {
+    toRemove(item);
   }
 };
+const toRemove = (item) => {
+  Modal.warning({
+    title: '提示',
+    content: '确认删除吗',
+    okText: '确定',
+    hideCancel: false,
+    onOk: async () => {
+      let data = await deleteKnow({
+        kb_id: item.id
+      });
+      if (data.retcode == 0) {
+        Message.success('删除成功');
+        pages.current = 1;
+        moke_data.value = [];
+        getKnowledge();
+      }
+    },
+    onCancel: () => {}
+  });
+};
 const getKnowledge = async () => {
-  // TODO: 等待接口修改后,需要将searchText传到接口中
+  if (pages.current == 1) {
+    loading_data.value = true;
+  }
   try {
     const res = await getKnowledgeList(pages.current, pages.pageSize, search_text.value);
     if (res.code == 200) {
@@ -85,6 +113,8 @@ const getKnowledge = async () => {
     }
   } catch (err) {
     console.log(err, 'flag');
+  } finally {
+    loading_data.value = false;
   }
 };
 const scrollHandler = (e) => {
@@ -137,14 +167,20 @@ 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);
 }
+.arco-spin {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+}
+.arco-empty {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+}
 </style>

+ 6 - 2
src/modules/knowledge/ModalCreateKb.vue

@@ -19,10 +19,12 @@
 
 <script setup>
 import { ref, computed } from 'vue';
+import { Message } from '@arco-design/web-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';
+import { dialogType } from '../../views/manage/common';
+import { getImageKnowLedge } from '../common/icon-map.js';
 
 const props = defineProps({
   visible: {
@@ -50,7 +52,7 @@ const handleOk = () => {
     // TODO:添加知识库b
     createKnowledgeBase();
   } else {
-    return false;
+    Message.warning('名称不能为空');
   }
 };
 const handleCancel = () => {
@@ -78,9 +80,11 @@ const createOwnKnowledgeBase = async (data) => {
       bus_knowledgeSearch.emit('');
       form.value = Object.assign({}, formInit);
       emit('update:visible', false);
+      Message.success('创建成功');
     }
   } catch (error) {
     console.log('创建知识库失败', error);
+    Message.error('创建失败');
   }
 };
 const handleSelectIcon = () => {

+ 1 - 1
src/modules/knowledge/ModalSelectIcon.vue

@@ -26,7 +26,7 @@
 
 <script setup>
 import { ref, computed } from 'vue';
-import { getImageKnowLedge } from '../../views/manage/common';
+import { getImageKnowLedge } from '../common/icon-map.js';
 
 const props = defineProps({
   show_select_icon: {

+ 7 - 8
src/modules/knowledge/rgflow/knowledgeLib/config.vue

@@ -18,7 +18,7 @@
           <a-form-item field="name" label="知识库名称">
             <a-input v-model="form.name" placeholder="请输入" />
           </a-form-item>
-          <a-form-item field="section" label="知识库图片">
+          <!-- <a-form-item field="section" label="知识库图片">
             <a-space direction="vertical" :style="{ width: '100%' }">
               <Upload
                 v-if="avatarShow"
@@ -29,7 +29,7 @@
                 @success="handleSuccess"
               ></Upload>
             </a-space>
-          </a-form-item>
+          </a-form-item> -->
           <a-form-item field="section" label="描述">
             <a-textarea placeholder="" v-model="form.description" allow-clear />
           </a-form-item>
@@ -289,7 +289,7 @@ const updateFileList = (newFileList) => {
 };
 
 const handleSuccess = (urls) => {
-  imageUrls.value = urls; // 拿到上传的图片地址
+  // imageUrls.value = urls; // 拿到上传的图片地址
   form.avatar = urls[0];
 };
 
@@ -349,7 +349,7 @@ function randomNumber() {
 
 const handleBeforeOk = (done) => {
   formRef.value.validate().then((res) => {
-    console.log('form:', form);
+    // console.log('form:', form);
     if (!form.name) {
       done(false);
     } else {
@@ -386,7 +386,7 @@ const changekbObj = (value) => {
   formRef.value.resetFields();
   nextTick(() => {
     kbObj = value;
-    console.log(kbObj, 'kbObj');
+    // console.log(kbObj, 'kbObj');
     let configObj = {
       name: kbObj.name,
       avatar: kbObj.avatar,
@@ -414,7 +414,7 @@ const changekbObj = (value) => {
       });
     }
     imageUrls.value = [kbObj.avatar];
-    console.log(form, '配置页面表单信息');
+    // console.log(form, '配置页面表单信息');
     avatarShow.value = false;
     setTimeout(() => {
       avatarShow.value = true;
@@ -449,8 +449,7 @@ export default {
   display: flex;
   justify-content: space-between;
   height: 100%;
-  overflow-y: auto;
-  overflow-x: hidden;
+  overflow: hidden;
   border-radius: 8px;
   background: var(--color-bg-2);
   padding-top: 80px;

+ 11 - 11
src/modules/knowledge/rgflow/knowledgeLib/index.vue

@@ -611,7 +611,7 @@ const fetchData = async (params) => {
   setLoading(true);
   try {
     const data = await queryKbDocumentList(params);
-    console.log(data, 'data');
+    // console.log(data, 'data');
     if (data.retcode == '0') {
       parser_ids = kbtenantInfo.parser_ids.split(',').reduce((acc, pair) => {
         const [key, value] = pair.split(':');
@@ -687,11 +687,11 @@ const onPageChange = (current) => {
 };
 
 const selectTabAll = (val) => {
-  console.log(val, '全选');
+  // console.log(val, '全选');
   checkedAll.value = val;
 };
 const selectTabChange = (val) => {
-  console.log(val, '单选');
+  // console.log(val, '单选');
   checkedArr.value = val;
 };
 
@@ -732,7 +732,7 @@ const getKbdetail = async (kb_id) => {
   const data = await queryKbdetail({
     kb_id: kb_id
   });
-  console.log('targetID', kb_id);
+  // console.log('targetID', kb_id);
   kbdetail = data.data;
   testForm.value.changekbid(kbdetail.id);
   configForm.value.changekbObj(kbdetail);
@@ -743,7 +743,7 @@ const getknowledge = async (id) => {
   try {
     const { data } = await queryKbList({ page: 1, page_size: 10 });
 
-    console.log(data, '查询知识库列表');
+    // console.log(data, '查询知识库列表');
     tabs.value = data;
     if (tabs.value.length > 0) {
       // 定位到新增的知识库单元
@@ -784,7 +784,7 @@ const reset = () => {
 
 function handleTabChange(key) {
   // 处理标签改变事件
-  console.log('Changed to tab:', key);
+  // console.log('Changed to tab:', key);
   activeKey.value = key;
 }
 
@@ -909,7 +909,7 @@ const exchangeArray = (array, beforeIdx, newIdx, isDeep = false) => {
 // };
 
 function upTabdateItem(id, newName) {
-  console.log(id, newName);
+  // console.log(id, newName);
   const itemToUpdate = renderData.value.find((item) => item.id === id);
   if (itemToUpdate) {
     itemToUpdate.name = newName;
@@ -917,7 +917,7 @@ function upTabdateItem(id, newName) {
 }
 
 const deleteItem = async (row) => {
-  console.log(row);
+  // console.log(row);
   let data = await kbdocumentrm({ doc_id: row.id });
   if (data.retcode == 0) {
     Message.success('删除成功');
@@ -929,7 +929,7 @@ const deleteItem = async (row) => {
   }
 };
 const onDownloadDocument = async (record) => {
-  console.log(record);
+  // console.log(record);
   await downloadFile({
     url: `/api/v1/document/get/${record.id}`,
     filename: record.name
@@ -939,7 +939,7 @@ const previewArea = async (row) => {
   Object.assign(seeObj, row);
   // console.log(seeObj.name, 'seeObj');
   let type = row.name.split('.')[1];
-  console.log(type);
+  // console.log(type);
   if (type == 'pdf') {
     documenttype.value = 'txtPdf';
   } else if (type == 'docx') {
@@ -958,7 +958,7 @@ const previewArea = async (row) => {
 };
 
 const handleChangeStatus = async (row) => {
-  console.log(row);
+  // console.log(row);
   let data = await kbdocumentchangeStatus({
     doc_id: row.id,
     status: row.status

+ 48 - 33
src/modules/knowledge/rgflow/knowledgeLib/test.vue

@@ -56,22 +56,25 @@
     <div class="main-container-rt">
       <a-collapse style="width: 96%; margin-top: 1rem; margin-left: 2%" @change="handleCollapseChange">
         <a-collapse-item :header="check_count + '/' + doc_total + '选定的文件'" key="3">
-          <a-list :bordered="false" :pagination-props="doc_pagination_props" style="background: var(--color-bg-1)">
-            <a-list-item v-for="doc in docList" :key="doc.doc_id" style="border-left: none; border-right: none">
-              <a-list-item-meta :title="doc.doc_name">
-                <template #avatar>
-                  <a-checkbox v-model="doc.checked"></a-checkbox>
+          <a-checkbox-group v-model="checked_list" @change="handleCheckedChange" :style="{ width: '100%' }">
+            <a-list :bordered="false" :pagination-props="doc_pagination_props" style="background: var(--color-bg-1)">
+              <a-list-item v-for="doc in docList" :key="doc.doc_id" style="border-left: none; border-right: none">
+                <a-list-item-meta :title="doc.doc_name">
+                  <template #avatar>
+                    <a-checkbox :value="doc.doc_id"></a-checkbox>
+                  </template>
+                </a-list-item-meta>
+                <template #actions>
+                  {{ doc.count }}
+                  <a-tooltip content="预览">
+                    <div class="action-icon">
+                      <icon-eye @click="handlePreview(doc.doc_id)" />
+                    </div>
+                  </a-tooltip>
                 </template>
-              </a-list-item-meta>
-              <template #actions>
-                {{ doc.count }}
-                <icon-eye @click="handlePreview(doc.doc_id)" />
-              </template>
-            </a-list-item>
-          </a-list>
-          <div>
-            <!-- <a-empty /> -->
-          </div>
+              </a-list-item>
+            </a-list>
+          </a-checkbox-group>
         </a-collapse-item>
       </a-collapse>
       <div
@@ -91,9 +94,9 @@
           </div>
         </a-card>
       </div>
-      <div class="footer-page">
+      <!-- <div class="footer-page">
         <a-pagination :total="chunk_total" show-total />
-      </div>
+      </div> -->
     </div>
   </div>
 </template>
@@ -127,16 +130,16 @@ let form = reactive({
 const chunks = ref([]);
 const all_chunks = ref([]);
 const docList = ref([]);
-
+const checked_list = ref([]);
 const doc_total = ref(0);
 const chunk_total = ref(0);
 const collapse_status = ref(false);
 const check_count = computed(() => {
-  return docList.value.filter((item) => item.checked).length || 0;
+  return checked_list.value.length || 0;
 }); // 选中的文件数
 const doc_pagination_props = reactive({
   defaultPageSize: 3,
-  total: doc_total.value
+  total: 0
 });
 
 const formatter = (value) => {
@@ -166,15 +169,10 @@ const handleSubmit = async ({ values, errors }) => {
     if (data.retcode == 0) {
       Message.success('测试成功');
       all_chunks.value = data.data.chunks;
-      docList.value = data.data.doc_aggs?.map((item) => {
-        return {
-          ...item,
-          checked: false
-        };
-      });
-      docList.value[0].checked = true;
-      chunks.value = all_chunks.value.filter((item) => item.doc_id == docList.value[0].doc_id);
-
+      docList.value = data.data.doc_aggs;
+      checked_list.value.push(docList.value[0].doc_id);
+      chunks.value = all_chunks.value.filter((item) => item.doc_id == checked_list.value[0]);
+      doc_pagination_props.total = docList.value.length;
       doc_total.value = data.data.doc_aggs.length;
       chunk_total.value = data.data.chunks.length;
     } else {
@@ -200,7 +198,7 @@ const handleOpened = (el) => {
 };
 
 const changekbid = (value) => {
-  console.log(value, 'kbid的value');
+  // console.log(value, 'kbid的value');
   kbid.value = value;
 };
 
@@ -221,6 +219,12 @@ const queryModel = async (params) => {
 const handlePreview = (doc_id) => {
   window.open(`${window.RGFLOW_BASE_URL}/document/${doc_id}?ext=docx&prefix=document`);
 };
+const handleCheckedChange = (doc_ids) => {
+  chunks.value = [];
+  doc_ids.forEach((doc_id) => {
+    chunks.value.push(...all_chunks.value.filter((item) => item.doc_id == doc_id));
+  });
+};
 
 // watch(()=>)
 
@@ -328,11 +332,22 @@ export default {
     }
   }
 }
-
-:deep .arco-collapse-item-content {
+.action-icon {
+  width: 20px;
+  height: 20px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  border-radius: 2px;
+}
+.action-icon:hover {
+  cursor: pointer;
+  background-color: var(--color-neutral-4);
+}
+:deep(.arco-collapse-item-content) {
   padding: 0;
 }
-:deep .arco-collapse-item-content-box {
+:deep(.arco-collapse-item-content-box) {
   padding: 0;
 }
 </style>

+ 6 - 1
src/modules/knowledge/rgflow/knowledgeLib/tool.vue

@@ -596,7 +596,12 @@ defineExpose({
     }
   }
 }
-
+.arco-slider {
+  display: flex;
+}
+.arco-spin {
+  width: 100%;
+}
 :deep(.emphaRed em) {
   color: red !important;
 }

+ 26 - 21
src/views/ConversationQA.vue

@@ -105,34 +105,39 @@ onMounted(async () => {
 
   if (!agent_id) {
     // 不存在参数
-    query_value_status.value = 3;
-    query_value_message.value = '非法操作:参数异常';
 
-    // TODO: 使用默认的通用agent创建对话
+    // 使用默认的通用agent创建对话
+    /**
+     * 如果没有agent参数,则使用默认的agent
+     * 默认的agent,和赵秦刚沟通,为知识问答(2024-12-18)
+     * 下列为知识问答的ID
+     */
+    const default_agent_id = '42e4fcdc-9bea-11ef-ac30-0242ac160006';
+    chat_agent.value = default_agent_id;
+
+    query_value_status.value = 2;
+    query_value_message.value = 'success';
+  } else {
+    // 有agent参数
+    // 判断已经缓存的agent列表是否存在
 
-    return;
-  }
+    const is_valid = await isValidAgent(agent_id);
 
-  // 有agent参数
-  // 判断已经缓存的agent列表是否存在
+    if (!is_valid) {
+      // 不存在参数
+      query_value_status.value = 3;
+      query_value_message.value = '非法操作:参数异常';
 
-  const is_valid = await isValidAgent(agent_id);
+      return;
+    }
 
-  if (!is_valid) {
-    // 不存在参数
-    query_value_status.value = 3;
-    query_value_message.value = '非法操作:参数异常';
+    chat_agent.value = agent_id;
+    chat_session.value = session_id;
+    // 如果存在history_id则获取历史会话内容
 
-    return;
+    query_value_status.value = 2;
+    query_value_message.value = 'success';
   }
-
-  query_value_status.value = 2;
-  query_value_message.value = 'success';
-
-  chat_agent.value = agent_id;
-  chat_session.value = session_id;
-
-  // 如果存在history_id则获取历史会话内容
 });
 
 /**

+ 1 - 1
src/views/Xiaoshu.vue

@@ -79,7 +79,7 @@ onMounted(() => {
       height: 40px;
       line-height: 40px;
       text-align: center;
-      background-color: red;
+      background-color: #165dff;
       color: #fff;
       display: inline-block;
       cursor: pointer;

+ 1 - 0
src/views/conversation/ChatAsideMenu.vue

@@ -43,6 +43,7 @@ import { computed } from 'vue';
 import { useRouter } from 'vue-router';
 import { useThemeStore } from '../../base/store/use-theme';
 import { useRecentAgentStore } from '../../base/store/use-recent-agents';
+import { useAllAgentStore } from '../../base/store/use-all-agents';
 
 import ChatAsideBtn from './ChatAsideBtn.vue';
 

+ 11 - 0
src/views/conversation/ConversationBoardContainer.vue

@@ -46,13 +46,24 @@ import BoardAgentList from '../../modules/conversation-board/BoardAgentList.vue'
 
 import useAgentList4Board from '../../modules/conversation-board/use-agent-list-4-board';
 
+import { useRecentAgentStore } from '../../base/store/use-recent-agents';
+import { useAllAgentStore } from '../../base/store/use-all-agents';
+
 const emit = defineEmits(['agentActive']);
 
 const selected_id = ref('');
 
 const { api_status, api_message, list_agents, getAgentList } = useAgentList4Board();
 
+const recentAgents = useRecentAgentStore();
+const allAgents = useAllAgentStore();
+
 const handleItemActive = (target_id) => {
+  const target_info = allAgents.getInfo(target_id);
+
+  // 添加记录
+  recentAgents.addItem(target_id, 'name', 'icon');
+
   emit('agentActive', target_id);
 };
 

+ 115 - 48
src/views/conversation/ConversationChatContainer.vue

@@ -5,7 +5,11 @@
     </div>
 
     <div class="conversation-chat-main" ref="chat_main">
-      <DialogHeader class="conversation-chat-header" :style="{ height: header_height + 'px' }" />
+      <DialogHeader
+        class="conversation-chat-header"
+        :agent_info="CHAT_AGENT_INFOMATION"
+        :style="{ height: header_height + 'px' }"
+      />
 
       <div class="conversation-chat-content">
         <DialogWelcome v-if="show_welcome" class="conversation-chat-area" />
@@ -25,9 +29,9 @@
           ref="dialog_input"
           class="conversation-chat-input"
           :style="{ height: input_height + 'px' }"
+          :agent_info="CHAT_AGENT_INFOMATION.agent"
+          :agent_config="CHAT_AGENT_INFOMATION.config"
           :disabled="input_disabled"
-          @inputTextChange="handleTextChange"
-          @inputFileChange="handleFileChange"
           @submit="handleInputSubmit"
         />
       </div>
@@ -52,8 +56,12 @@ import DialogInput from '../../modules/conversation-chat/DialogInput.vue';
 import DialogFooter from '../../modules/conversation-chat/DialogFooter.vue';
 import DialogAsideRight from '../../modules/conversation-chat/DialogAsideRight.vue';
 
+import { useAllAgentStore } from '../../base/store/use-all-agents';
+import getAgentClientConfig from '../../modules/conversation-board/get-agent-client-config';
+
 import useWebSocketChat from '../../modules/conversation-dialog/use-websocket-chat';
-import { getHistoryLogs, getDialogChatId } from '../../modules/conversation-dialog/api-dialog';
+import { getHistoryLogs, getDialogChatId, uploadFiles } from '../../modules/conversation-dialog/api-dialog';
+import files2Formdata from '../../modules/file-upload/files-2-formdata';
 
 import formatDialogSendOptions from '../../modules/conversation-dialog/format-dialog-send-options';
 
@@ -87,6 +95,19 @@ const props = defineProps({
   chat_type: String
 });
 
+const allAgents = useAllAgentStore();
+
+/**
+ * 对话使用到的agent信息
+ * agent属性是由接口返回的数据
+ * config属性是客户端自定义的数据,针对特定的agent的一些个性化配置,可由此进行配置
+ * 二者结合,形成对话组件所需要的一些参数
+ */
+const CHAT_AGENT_INFOMATION = ref({
+  agent: {},
+  config: {}
+});
+
 const header_height = 30;
 const footer_height = 30;
 const input_height = 100;
@@ -168,31 +189,11 @@ const handleSuggestSubmit = (suggest) => {};
 
 // ---------------------------------------------
 
-/**
- * 输入区域数据控制
- */
-const input_text = ref('');
-const input_files = ref([]);
-
 /**
  * 是否禁用输入组件
  */
 const input_disabled = ref(false);
 
-/**
- * 输入文本发生了变化
- * @param value
- */
-const handleTextChange = (value) => {
-  input_text.value = value;
-};
-/**
- * 输入的文件发生了变化
- * @param files
- */
-const handleFileChange = (files) => {
-  input_files.value = files;
-};
 /**
  * 输入已经确认要提交了
  *
@@ -201,7 +202,12 @@ const handleFileChange = (files) => {
  * 3. 连接socket,socket 发送文本与文件数据内容
  * 4. 接收 socket 返回的数据项
  */
-const handleInputSubmit = async () => {
+const handleInputSubmit = async (options) => {
+  const ask_text = options.text; // 文本
+  const ask_files = options.files; // 文件列表
+
+  const agent_id = props.agent_id;
+
   /**
    * 创建会话 get chat id
    * 判断对话是否已经创建
@@ -211,7 +217,7 @@ const handleInputSubmit = async () => {
   if (chat_new_id.value === null) {
     // 未创建chat,开始创建
     try {
-      const chatResult = await getDialogChatId(props.agent_id);
+      const chatResult = await getDialogChatId(agent_id);
 
       if (chatResult.code / 1 === 200) {
         // 成功
@@ -234,24 +240,52 @@ const handleInputSubmit = async () => {
     console.log(chat_new_id.value, '已创建');
   }
 
+  // 文件上传后的信息
+  let files_response = null;
   /**
    * 如果存在文件数据,则进行文件上传
    */
-  if (input_files.value.length !== 0) {
+  if (ask_files.length !== 0) {
     // 进行文件上传,获取文件信息
+    const file_params = files2Formdata(ask_files);
+    const chat_id = chat_new_id.value;
+
+    try {
+      const uploadResult = await uploadFiles(agent_id, chat_id, file_params);
+
+      if (uploadResult.code / 1 === 200) {
+        // 文件上传成功
+        const file_uploaded = uploadResult.data;
+
+        if (Array.isArray(file_uploaded)) {
+          files_response = file_uploaded;
+        } else {
+          files_response = [file_uploaded];
+        }
+      } else {
+        // 文件上传异常
+        // TODO: 处理错误
+        return;
+      }
+    } catch (err) {
+      console.log(err);
+      // 文件上传失败
+      // TODO: 处理错误
+      return;
+    }
   }
 
   /**
    * 获取文件参数
    * 组装socket参数
    */
-  const msg = formatDialogSendOptions(input_text.value, input_files.value);
+  const msg = formatDialogSendOptions(ask_text, files_response);
 
   /**
    * 整理客户端提问的数据
    * 组装Question数据
    */
-  const client_question = formatDialogQuestionByClient(input_text.value, input_files.value);
+  const client_question = formatDialogQuestionByClient(ask_text, ask_files);
   // 保存用户的提问信息
   // 当消息正式发出后,将提问数据放入列表中
   chat_new_question.value = client_question;
@@ -333,8 +367,6 @@ function handleWSSend(chat_id, value) {
    */
   show_welcome.value = false;
   // 清空文本数据和文件数据,避免下一次会话冲突
-  input_text.value = '';
-  input_files.value = [];
   // 清空表单里的数据
   inputClear();
   // 清空可能存在的推荐项目
@@ -364,40 +396,51 @@ function handleWSMessage(e) {
   const currentChat = formatDialogAnswerFromWebsocketReceiveMessage(res_data, last_msg);
   const chat_status = currentChat.status;
   const chat_message = currentChat.message;
-  const chat_data = currentChat.data;
-
-  if (chat_status === 0) {
-    // 未开始: 此状态不存在,无需处理
-  }
 
-  if (chat_status === 1) {
-    // 此轮对话仍然在进行中
+  // 处理对话数据
+  const handleChatData = () => {
+    const chat_data = currentChat.data; // 对话相关的数据项
 
     // 原来的最后一项弹出
     chat_new_list.value.pop();
     // 添加新的最后一项
     chat_new_list.value.push(chat_data);
+
     // 滚动到底部
     scroll2ListBottom();
+  };
+
+  if (chat_status === 0) {
+    // 未开始: 此状态不存在,无需处理
+  }
+
+  if (chat_status === 1) {
+    // 此轮对话仍然在进行中
+    handleChatData();
   }
 
   if (chat_status === 2) {
     // 此轮对话已结束
+    handleChatData();
 
-    // 原来的最后一项弹出
-    chat_new_list.value.pop();
-    // 添加新的最后一项
-    chat_new_list.value.push(chat_data);
-    // 滚动到底部
-    scroll2ListBottom();
+    // 对话已结束:检查是否存在推荐数据
+    const chat_suggest = currentChat.suggest; // 对话相关的推荐数据
+    if (chat_suggest) {
+      chat_suggestion.value = chat_suggest;
+    }
 
-    // 文件上传、文本输入区域放开使用
+    // 对话已结束:文件上传、文本输入区域放开使用
     input_disabled.value = false;
   }
 
   if (chat_status === 3) {
     // 此轮对话出错了
     // TODO: 错误处理
+
+    // 此轮对话已结束
+    handleChatData();
+    // 对话已结束:文件上传、文本输入区域放开使用
+    input_disabled.value = false;
   }
 }
 
@@ -414,10 +457,13 @@ function handleWSError(e) {}
 function handleWSClose(e) {}
 
 onMounted(() => {
+  const agent_id = props.agent_id;
+  const session_id = props.session_id;
+
   // 组件挂载
-  if (props.session_id) {
+  if (session_id) {
     // 有历史记录:获取历史记录内容进行展示
-    getHistoryLogs(props.agent_id, props.session_id)
+    getHistoryLogs(agent_id, session_id)
       .then((res) => {
         if (res.code / 1 === 200) {
           // 成功
@@ -447,6 +493,27 @@ onMounted(() => {
   } else {
     // 无历史记录:等待创建会话内容(用户开始输入、提交完成),列表区域显示欢迎界面
   }
+
+  /**
+   * 根据agent_id 查询到agent的基本信息
+   * 从而确定agent的相关功能支持,例如:是否需要上传文件,支持上传什么类型的文件、支持上传多少个文件?
+   * 例如:主题、背景、等等
+   */
+  const agentInfo = allAgents.getInfo(agent_id);
+  if (agentInfo) {
+    const client_config = getAgentClientConfig(agent_id);
+    if (client_config) {
+      CHAT_AGENT_INFOMATION.value = {
+        config: client_config,
+        agent: agentInfo
+      };
+    } else {
+      CHAT_AGENT_INFOMATION.value = {
+        config: {},
+        agent: agentInfo
+      };
+    }
+  }
 });
 
 // ---------------------------------------------------------
@@ -484,7 +551,7 @@ onUnmounted(() => {
   display: flex;
   flex-direction: column;
 
-  background-color: #aaa;
+  /* background-color: #aaa; */
 }
 .conversation-chat-content {
   flex-grow: 1;

+ 4 - 0
src/views/manage/CardItem.vue

@@ -41,6 +41,7 @@ const props = defineProps({
   position: relative;
   padding: 10px 20px;
   background-color: var(--color-bg-2);
+  border-radius: 5px;
   overflow: hidden;
   cursor: pointer;
 }
@@ -49,6 +50,9 @@ const props = defineProps({
   font-size: 16px;
   font-weight: bold;
   color: var(--color-neutral-8);
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
 }
 .card-label {
   width: 100%;

+ 0 - 58
src/views/manage/common.js

@@ -1,46 +1,3 @@
-import knowledgeFrame1 from '../../assets/image/management/knowledge-frame1.png';
-import knowledgeFrame2 from '../../assets/image/management/knowledge-frame2.png';
-import knowledgeFrame3 from '../../assets/image/management/knowledge-frame3.png';
-import knowledgeFrame4 from '../../assets/image/management/knowledge-frame4.png';
-import intelligentFrame1 from '../../assets/image/management/intelligent-frame1.png';
-import intelligentFrame2 from '../../assets/image/management/intelligent-frame2.png';
-import intelligentFrame3 from '../../assets/image/management/intelligent-frame3.png';
-import intelligentFrame4 from '../../assets/image/management/intelligent-frame4.png';
-import intelligentFrame5 from '../../assets/image/management/intelligent-frame5.png';
-import intelligentFrame6 from '../../assets/image/management/intelligent-frame6.png';
-import intelligentFrame7 from '../../assets/image/management/intelligent-frame7.png';
-import intelligentFrame8 from '../../assets/image/management/intelligent-frame8.png';
-import intellFrame1 from '../../assets/image/management/intellFrame1.png';
-import intellFrame2 from '../../assets/image/management/intellFrame2.png';
-import intellFrame3 from '../../assets/image/management/intellFrame3.png';
-import intellFrame4 from '../../assets/image/management/intellFrame4.png';
-import intellFrame5 from '../../assets/image/management/intellFrame5.png';
-import intellFrame6 from '../../assets/image/management/intellFrame6.png';
-
-const image_knowLedge_map = {
-  knowledgeFrame1: knowledgeFrame1,
-  knowledgeFrame2: knowledgeFrame2,
-  knowledgeFrame3: knowledgeFrame3,
-  knowledgeFrame4: knowledgeFrame4
-};
-const image_intelligent_map = {
-  intelligentFrame1: intelligentFrame1,
-  intelligentFrame2: intelligentFrame2,
-  intelligentFrame3: intelligentFrame3,
-  intelligentFrame4: intelligentFrame4,
-  intelligentFrame5: intelligentFrame5,
-  intelligentFrame6: intelligentFrame6,
-  intelligentFrame7: intelligentFrame7,
-  intelligentFrame8: intelligentFrame8
-};
-const icon_intelligent_map = {
-  intellFrame1: intellFrame1,
-  intellFrame2: intellFrame2,
-  intellFrame3: intellFrame3,
-  intellFrame4: intellFrame4,
-  intellFrame5: intellFrame5,
-  intellFrame6: intellFrame6
-};
 /**
  * @description: 智能体类型
  * */
@@ -51,21 +8,6 @@ export const dialogType = {
   DIFY: '4'
 };
 
-/**
- * @description: 图片映射表
- * avatar: 图片名称
- * defaultImg: 默认图片
- */
-export const getImageKnowLedge = (avatar) => {
-  return image_knowLedge_map[avatar] || knowledgeFrame1;
-};
-export const getImageIntelligent = (avatar) => {
-  return image_intelligent_map[avatar];
-};
-export const getIconIntelligent = (avatar) => {
-  return icon_intelligent_map[avatar] || intellFrame1;
-};
-
 /**
  * @description: 默认智能体数据
  */