Ver código fonte

feat(conversation): 动态化对话相关接口

1. 连通标签、智能体大全、历史记录的接口
2. 完善智能体大全页面组件
3. 完善对话列表界面组件
zhupei@smartai.com 1 ano atrás
pai
commit
b7b886ffa9

+ 4 - 1
public/i18n/lang-en.json

@@ -88,6 +88,9 @@
     "history_earlier": "Earlier",
     "history_loadmore": "Load more",
     "history_nomore": "No more",
-    "history_empty": "Empty"
+    "history_empty": "Empty",
+
+    "hello": "Welcome",
+    "nice_day": "Let's spend a wonderful day together"
   }
 }

+ 4 - 1
public/i18n/lang-zh.json

@@ -88,6 +88,9 @@
     "history_earlier": "更早以前",
     "history_loadmore": "加载更多",
     "history_nomore": "没有更多了",
-    "history_empty": "暂无数据"
+    "history_empty": "暂无数据",
+
+    "hello": "你好",
+    "nice_day": "让我们一起度过美好的一天"
   }
 }

+ 5 - 1
src/modules/conversation-board/BoardAgentItem.vue

@@ -25,7 +25,6 @@ const handleClick = () => {
 
 <style lang="css" scoped>
 .conversation-agent-item {
-  /* background-color: #fff; */
   background-color: var(--color-bg-1);
   padding: 30px 40px 30px 40px;
   border-radius: 20px;
@@ -43,6 +42,8 @@ const handleClick = () => {
 
   margin-right: 5px;
 
+  flex-shrink: 0;
+
   cursor: pointer;
 }
 
@@ -58,5 +59,8 @@ const handleClick = () => {
 }
 
 .agent-item-intro-desc {
+  /* white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis; */
 }
 </style>

+ 1 - 52
src/modules/conversation-board/BoardAgentList.vue

@@ -4,7 +4,7 @@
       v-for="(item, index) of list"
       :key="index"
       :title="item.name"
-      :desc="item.type"
+      :desc="item.description"
       :id="item.id"
       @active="handleActive"
     />
@@ -20,57 +20,6 @@ const props = defineProps({
 
 const emit = defineEmits(['itemActive']);
 
-// const list = [
-//   {
-//     title: '智能问答',
-//     desc: '你说一句话,我写万字长文'
-//   },
-//   {
-//     title: '智能客服',
-//     desc: '你说一句话,我写万字长文'
-//   },
-//   {
-//     title: '出题组卷',
-//     desc: '你说一句话,我写万字长文'
-//   },
-//   {
-//     title: '以文生图',
-//     desc: '你说一句话,我写万字长文'
-//   },
-//   {
-//     title: '数据分析',
-//     desc: '你说一句话,我写万字长文'
-//   },
-//   {
-//     title: '报告自动生成',
-//     desc: '你说一句话,我写万字长文'
-//   },
-//   {
-//     title: '智能问答',
-//     desc: '你说一句话,我写万字长文'
-//   },
-//   {
-//     title: '文档创作',
-//     desc: '你说一句话,我写万字长文'
-//   },
-//   {
-//     title: '设备检测',
-//     desc: '你说一句话,我写万字长文'
-//   },
-//   {
-//     title: '智能客服',
-//     desc: '你说一句话,我写万字长文'
-//   },
-//   {
-//     title: '以文生图',
-//     desc: '你说一句话,我写万字长文'
-//   },
-//   {
-//     title: '出题组卷',
-//     desc: '你说一句话,我写万字长文'
-//   }
-// ];
-
 const handleActive = (target_id) => {
   emit('itemActive', target_id);
 };

+ 38 - 6
src/modules/conversation-board/BoardTags.vue

@@ -1,18 +1,45 @@
 <template>
   <div class="conversation-board-tags">
-    <div class="board-tag" @click="handleClick"><span>分类名称</span></div>
-    <div class="board-tag" @click="handleClick"><span>会话</span></div>
-    <div class="board-tag" @click="handleClick"><span>知识库管理</span></div>
-    <div class="board-tag" @click="handleClick"><span>AI会话</span></div>
+    <div
+      v-for="(item, index) of list_labels"
+      class="board-tag"
+      :class="{ 'is-active': item.labelId === current_id }"
+      :key="item.labelId"
+      @click="handleClick(item)"
+    >
+      <span>{{ item.labelName }}</span>
+    </div>
   </div>
 </template>
 
 <script setup>
+import { ref, onMounted } from 'vue';
+
+import useTagList from './use-tag-list';
+
 const emits = defineEmits(['change']);
 
-const handleClick = (type) => {
-  emits('change', type);
+const current_id = ref('');
+
+const handleClick = (item) => {
+  const target_id = item.labelId;
+
+  if (target_id === current_id.value) {
+    // 已经选中了
+    current_id.value = '';
+  } else {
+    // 没有选中
+    current_id.value = target_id;
+  }
+
+  emits('change', current_id.value);
 };
+
+const { getTagList, api_status, api_message, list_labels } = useTagList();
+
+onMounted(() => {
+  getTagList();
+});
 </script>
 
 <style lang="css" scoped>
@@ -38,4 +65,9 @@ const handleClick = (type) => {
   background-color: var(--color-bg-1);
   color: var(--color-text-1);
 }
+
+.conversation-board-tags .board-tag.is-active {
+  background-color: rgb(var(--primary-6));
+  color: #fff;
+}
 </style>

+ 3 - 3
src/modules/conversation-board/BoardWelcome.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="conversation-board-welcome">
-    <div>你好,{{ current_u_name }}</div>
-    <div>让我们一起度过美好的一天</div>
+    <div>{{ $t('conversation.hello') }},{{ current_u_name }}</div>
+    <div>{{ $t('conversation.nice_day') }}</div>
   </div>
 </template>
 
@@ -12,7 +12,7 @@ import { useCurrentUserStore } from '../../base/store/use-current-user';
 const curUserStore = useCurrentUserStore();
 
 const current_u_name = computed(() => {
-  return curUserStore.name;
+  return curUserStore.username;
 });
 </script>
 

+ 70 - 72
src/modules/conversation-board/api-conversation-board.js

@@ -1,81 +1,79 @@
-import { jsonStringify } from '../../utils/utils';
+import ajax from '../../base/ajax';
 
-const res_list_example = {
-  code: 200,
-  msg: '',
-  data: [
-    {
-      id: '94873c72-d194-4306-a965-286affe426bf',
-      name: '报告生成',
-      agent_type: 2,
-      type: 'report'
-    },
-    {
-      id: 'basic_excel_merge',
-      name: '报表合并',
-      agent_type: 3,
-      type: 'excelMerge'
-    },
-    {
-      id: '42e4fcdc9bea11efac300242ac160006',
-      name: '知识问答',
-      agent_type: 1,
-      type: 'knowledgeQA'
-    },
-    {
-      id: 'c684bab4-f05b-423e-8727-f50497e73ebf',
-      name: '文档智能',
-      agent_type: 2,
-      type: 'report'
-    },
-    {
-      id: '90d533729c0211efbf6b0242ac160006',
-      name: '智能问答',
-      agent_type: 1,
-      type: 'chat'
-    },
-    {
-      id: 'basic_excel_talk',
-      name: '智能数据',
-      agent_type: 3,
-      type: 'excelTalk'
-    },
-    {
-      id: 'basic_question_talk',
-      name: '出题组卷',
-      agent_type: 3,
-      type: 'questionTalk'
-    },
-    {
-      id: '9d75142a-66eb-4e23-b7d4-03efe4584915',
-      name: '小数绘图',
-      agent_type: 4,
-      type: 'imageTalk'
-    },
-    {
-      id: 'basic_paper_talk',
-      name: '文档出卷',
-      agent_type: 3,
-      type: 'paperTalk'
-    },
-    {
-      id: 'basic_report_clean',
-      name: '文档报告',
-      agent_type: 4,
-      type: 'reportWorkflow'
-    }
-  ]
+/**
+ * 获取所有对话可用的智能体
+ * @see https://app.apifox.com/link/project/5404857/apis/api-233232945
+ */
+export const conversationBoardAgentList = (params) => {
+  const request_url = `/api/dialog/list`;
+
+  const send_data = {
+    status: 1,
+    current: 1,
+    pageSize: 50 // 后端默认是 10,此处需要一次性返回
+  };
+
+  if ('search' in params && params.search) {
+    send_data.keyword = params.search;
+  }
+
+  if ('label' in params && params.label) {
+    send_data.label = params.label;
+  }
+
+  return new Promise((resolve, reject) => {
+    ajax({
+      url: request_url,
+      method: 'get',
+      params: send_data
+    })
+      .then((res) => {
+        if (res.code / 1 === 200) {
+          resolve({
+            code: res.code,
+            data: res.data.rows,
+            msg: res.msg
+          });
+        } else {
+          resolve(res);
+        }
+      })
+      .catch(reject);
+  });
 };
 
 /**
- * 获取所有对话可用的智能体
+ * 获取标签列表
+ * @see https://app.apifox.com/link/project/5404857/apis/api-243257552
+ * @param {object} params
+ * @returns
  */
-export const conversationBoardList = () => {
-  // http://192.168.20.119:9301/api/agent/list
+export const conversationBoardTagList = (params) => {
+  const request_url = `/api/label/list`;
+
+  const send_data = {};
+
+  if ('search' in params && params.search) {
+    send_data.keyword = params.search;
+  }
 
   return new Promise((resolve, reject) => {
-    setTimeout(() => {
-      resolve(res_list_example);
-    }, 1000);
+    ajax({
+      url: request_url,
+      method: 'get',
+      params: send_data
+    })
+      .then((res) => {
+        if (res.code / 1 === 200) {
+          resolve({
+            code: res.code,
+            data: res.data.rows,
+            msg: res.msg
+          });
+        } else {
+          resolve(res);
+        }
+      })
+      .catch(reject);
   });
 };

+ 61 - 0
src/modules/conversation-board/use-tag-list.js

@@ -0,0 +1,61 @@
+import { ref } from 'vue';
+
+import { conversationBoardTagList } from './api-conversation-board';
+
+export default function useTagList() {
+  // api请求的状态
+  const api_status = ref(1); // api状态 1 请求未启动 2 请求进心中 3 请求已成功 4 请求失败(网络成功,但是code不等于200) 5 请求出错
+  const api_message = ref(''); // 请求消息 与 api_status 对应的 message 消息内容
+
+  // 历史记录列表数据
+  const list_labels = ref([]); // 历史记录的列表数据
+
+  /**
+   * 处理请求参数
+   */
+  const formatListOptions = () => {
+    return {};
+  };
+
+  /**
+   * 调用api请求
+   */
+  const handleApiRequest = () => {
+    // 处理查询参数
+    const opts = formatListOptions();
+
+    // 进入加载状态
+    api_status.value = 2;
+    api_message.value = '';
+    conversationBoardTagList(opts)
+      .then((res) => {
+        if (res.code / 1 === 200) {
+          // 成功
+          const res_list = res.data; // 历史记录列表
+
+          list_labels.value = res_list;
+
+          // api请求成功
+          api_status.value = 3;
+          api_message.value = 'success';
+        } else {
+          // api请求成功,但是业务失败
+          api_status.value = 4;
+          api_message.value = res.msg;
+        }
+      })
+      .catch((err) => {
+        console.log(err);
+        // api请求出错
+        api_status.value = 5;
+        api_message.value = err.message;
+      });
+  };
+
+  return {
+    getTagList: handleApiRequest,
+    api_status,
+    api_message,
+    list_labels
+  };
+}

+ 38 - 24
src/modules/conversation-chat/DialogList.vue

@@ -1,32 +1,46 @@
 <template>
-  <div class="dialog-list">
-    <DialogItem />
-
-    <DialogItem />
-
-    <DialogItem />
-
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-    <DialogItem />
-  </div>
+  <a-scrollbar type="track" :style="container_style">
+    <div class="dialog-list">
+      <DialogItem />
+
+      <DialogItem />
+
+      <DialogItem />
+
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+      <DialogItem />
+    </div>
+  </a-scrollbar>
 </template>
 
 <script setup>
+import { computed } from 'vue';
 import DialogItem from './DialogItem.vue';
+
+const props = defineProps({
+  height: Number
+});
+
+const container_style = computed(() => {
+  return {
+    height: props.height + 'px',
+    overflow: 'auto'
+  };
+});
 </script>
 
 <style lang="css" scoped>

+ 9 - 0
src/modules/conversation-dialog/api-dialog.js

@@ -2,3 +2,12 @@
  * 获取会话历史记录,来自于小数系统
  * http://192.168.20.119:9301/api/agent/90d533729c0211efbf6b0242ac160006/sessions
  */
+
+/**
+ * 获取某个对话的记录 http://192.168.20.119:9301/api/agent/42e4fcdc9bea11efac300242ac160006/c0f286901bcb48b3a1fb04c5d6f1871b/session_log
+ */
+
+/**
+ * 新建会话
+ * http://192.168.20.119:9301/api/agent/get-chat-id/42e4fcdc9bea11efac300242ac160006
+ */

+ 0 - 18
src/modules/conversation-dialog/example-api-agent-sessions.json

@@ -1,18 +0,0 @@
-{
-  "code": 200,
-  "msg": "",
-  "data": [
-    {
-      "id": "a7d63ccf38fe4d3d958aa202482d54c3",
-      "updated_time": 1732857994295,
-      "update_date": "2024-11-29 13:26:34",
-      "name": "什么情况啊"
-    },
-    {
-      "id": "5b50f408cbe5449da3ec8b3bff226442",
-      "updated_time": 1732176887294,
-      "update_date": "2024-11-21 16:14:47",
-      "name": "你好"
-    }
-  ]
-}

+ 2 - 2
src/modules/conversation-history/HistoryTypeDropdown.vue

@@ -18,7 +18,7 @@
 
 <script setup>
 import { ref, computed, onMounted } from 'vue';
-import { conversationBoardList } from '../conversation-board/api-conversation-board';
+import { conversationBoardAgentList } from '../conversation-board/api-conversation-board';
 
 import { useAllAgentStore } from '../../base/store/use-all-agents';
 
@@ -90,7 +90,7 @@ const handleApiRequest = () => {
   // 进入加载状态
   api_status.value = 2;
   api_message.value = '';
-  conversationBoardList(opts)
+  conversationBoardAgentList(opts)
     .then((res) => {
       if (res.code / 1 === 200) {
         // 成功

+ 35 - 0
src/utils/use-ele-size.js

@@ -0,0 +1,35 @@
+import { ref, getCurrentInstance, onMounted, onUnmounted, computed } from 'vue';
+
+/**
+ * 获取对话区域的DOM元素尺寸
+ * @param {string} ref_name
+ * @returns
+ */
+export default function useEleSize(ref_name) {
+  const ele_height = ref(0);
+  const ele_width = ref(0);
+
+  const { proxy } = getCurrentInstance();
+
+  const getDOMElementSize = () => {
+    const ele = proxy.$refs[ref_name];
+
+    ele_height.value = ele.offsetHeight;
+    ele_width.value = ele.offsetWidth;
+  };
+
+  onMounted(() => {
+    getDOMElementSize();
+
+    window.addEventListener('resize', getDOMElementSize);
+  });
+
+  onUnmounted(() => {
+    window.removeEventListener('resize', getDOMElementSize);
+  });
+
+  return {
+    height: ele_height,
+    width: ele_width
+  };
+}

+ 2 - 25
src/views/common/Header.vue

@@ -55,28 +55,6 @@ import BtnCurrentUser from './header-btns/BtnCurrentUser.vue';
 
 const currentUser = useCurrentUserStore();
 
-/**
- * 设置系统语言
- * @param lange - 语言 zh/en
- */
-const handleLangaugeChange = (lange) => {
-  setI18nLanguage(lange);
-};
-
-/**
- * 设置系统主题
- * @param {string} theme - 主题 dark/theme
- */
-const handleThemeChange = (theme) => {
-  if (theme === 'dark') {
-    setThemeDark();
-  }
-
-  if (theme === 'light') {
-    setThemeLight();
-  }
-};
-
 /**
  * 请求网页全屏
  */
@@ -85,9 +63,8 @@ const handleFullScreen = () => {
 };
 
 const handleNameChange = () => {
-  const nm = Math.random() * 99989 + '';
-
-  currentUser.updateName(nm);
+  // const nm = Math.random() * 99989 + '';
+  // currentUser.updateName(nm);
 };
 </script>
 

+ 1 - 1
src/views/common/header-btns/BtnCurrentUser.vue

@@ -1,7 +1,7 @@
 <template>
   <a-dropdown trigger="hover" @select="handleSelect">
     <div class="header-right-profile">
-      <span>{{ currentUser.name }}</span>
+      <span>{{ currentUser.username }}</span>
     </div>
 
     <template #content>

+ 26 - 15
src/views/conversation/ConversationBoardContainer.vue

@@ -7,14 +7,15 @@
 
       <BoardTags @change="handleTagChange" />
 
-      <BoardAgentList @itemActive="handleItemActive" :list="list_agents" />
       <template v-if="api_status === 2">
         <div class="infomations-container">
           <a-spin :size="32" />
         </div>
       </template>
-      <template v-if="api_status === 3 && list_agents.length === 0">
-        <div class="infomations-container">
+      <template v-if="api_status === 3">
+        <BoardAgentList @itemActive="handleItemActive" :list="list_agents" />
+
+        <div class="infomations-container" v-if="list_agents.length === 0">
           <a-empty> {{ $t('conversation.history_empty') }} </a-empty>
         </div>
       </template>
@@ -43,11 +44,13 @@ import BoardWelcome from '../../modules/conversation-board/BoardWelcome.vue';
 import BoardTags from '../../modules/conversation-board/BoardTags.vue';
 import BoardAgentList from '../../modules/conversation-board/BoardAgentList.vue';
 
-import { conversationBoardList } from '../../modules/conversation-board/api-conversation-board';
+import { conversationBoardAgentList } from '../../modules/conversation-board/api-conversation-board';
 import { useAllAgentStore } from '../../base/store/use-all-agents';
 
 const emit = defineEmits(['agentActive']);
 
+const selected_id = ref('');
+
 // api请求的状态
 const api_status = ref(1); // api状态 1 请求未启动 2 请求进心中 3 请求已成功 4 请求失败(网络成功,但是code不等于200) 5 请求出错
 const api_message = ref(''); // 请求消息 与 api_status 对应的 message 消息内容
@@ -58,8 +61,10 @@ const list_agents = ref([]); // 历史记录的列表数据
 // store中保存的agents
 const allAgents = useAllAgentStore();
 
-const handleTagChange = (type) => {
-  console.log(type);
+const handleTagChange = (tag_id) => {
+  selected_id.value = tag_id;
+
+  handleApiRequest();
 };
 
 const handleItemActive = (target_id) => {
@@ -70,18 +75,24 @@ const handleItemActive = (target_id) => {
  * 处理请求参数
  */
 const formatListOptions = () => {
-  return {};
+  const obj = {};
+
+  if (selected_id.value) {
+    obj.label = selected_id.value;
+  }
+
+  return obj;
 };
 
 /**
  * 调用api请求
  */
 const handleApiRequest = () => {
-  const cache_agents = allAgents.agents;
-  if (cache_agents.length !== 0) {
-    list_agents.value = cache_agents;
-    return;
-  }
+  // const cache_agents = allAgents.agents;
+  // if (cache_agents.length !== 0) {
+  //   list_agents.value = cache_agents;
+  //   return;
+  // }
 
   // 处理查询参数
   const opts = formatListOptions();
@@ -89,15 +100,15 @@ const handleApiRequest = () => {
   // 进入加载状态
   api_status.value = 2;
   api_message.value = '';
-  conversationBoardList(opts)
+  conversationBoardAgentList(opts)
     .then((res) => {
       if (res.code / 1 === 200) {
         // 成功
         const res_list = res.data; // 历史记录列表
 
         list_agents.value = res_list;
-        // 在store中缓存数据
-        allAgents.setList(res_list);
+        // // 在store中缓存数据
+        // allAgents.setList(res_list);
 
         // api请求成功
         api_status.value = 3;

+ 24 - 11
src/views/conversation/ConversationChatContainer.vue

@@ -4,16 +4,16 @@
       <DialogAsideLeft />
     </div>
 
-    <div class="conversation-chat-main">
-      <DialogHeader />
+    <div class="conversation-chat-main" ref="chat_main">
+      <DialogHeader class="conversation-chat-header" :style="{ height: header_height + 'px' }" />
 
       <div class="conversation-chat-content">
-        <DialogList class="conversation-chat-list" />
+        <DialogList class="conversation-chat-list" :height="list_height" />
 
-        <DialogInput class="conversation-chat-input" />
+        <DialogInput class="conversation-chat-input" :style="{ height: input_height + 'px' }" />
       </div>
 
-      <DialogFooter />
+      <DialogFooter class="conversation-chat-footer" :style="{ height: footer_height + 'px' }" />
     </div>
 
     <div class="conversation-chat-right">
@@ -23,7 +23,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue';
+import { ref, getCurrentInstance, onMounted, onUnmounted, computed } from 'vue';
 
 import DialogAsideLeft from '../../modules/conversation-chat/DialogAsideLeft.vue';
 import DialogHeader from '../../modules/conversation-chat/DialogHeader.vue';
@@ -32,6 +32,8 @@ 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 useEleSize from '../../utils/use-ele-size';
+
 /**
  * 1. 历史会话进入此页面,展示历史会话内容
  * 2. 点击智能体,新建会话
@@ -44,6 +46,19 @@ const props = defineProps({
    */
   chat_id: String
 });
+
+const header_height = 30;
+const footer_height = 30;
+const input_height = 100;
+
+const { width: chat_width, height: chat_height } = useEleSize('chat_main');
+
+/**
+ * 对话列表区域的高度
+ */
+const list_height = computed(() => {
+  return chat_height.value - header_height - footer_height - input_height;
+});
 </script>
 
 <style lang="css" scoped>
@@ -66,7 +81,6 @@ const props = defineProps({
   flex-shrink: 0;
 }
 .conversation-chat-main {
-  /* width: 60%; */
   flex-grow: 1;
   height: 100%;
   margin-left: auto;
@@ -76,8 +90,6 @@ const props = defineProps({
   flex-direction: column;
 
   background-color: #aaa;
-
-  /* overflow: hidden; */
 }
 .conversation-chat-content {
   flex-grow: 1;
@@ -88,11 +100,12 @@ const props = defineProps({
   overflow: hidden;
 }
 .conversation-chat-list {
-  overflow-y: auto;
+  flex-grow: 1;
+  overflow: auto;
 }
 .conversation-chat-input {
   height: 100px;
-  background-color: #aaa;
+  background-color: #a67777;
   flex-shrink: 0;
 }
 </style>