| | |
| | | <template> |
| | | <div class="h100 overflow-y-auto p-[24px]"> |
| | | <div class="flex flex-col h100 mt-[16px] border-solid border-1"> |
| | | <div class="h100 overflow-y-auto p-[16px]"> |
| | | <div class="flex flex-col h100"> |
| | | <div class="text-[16px] font-[500] h-[22px]">知识库管理</div> |
| | | <div class="mx-0 mt-[12px] mb-[16px] flex justify-between items-center"> |
| | | <el-input |
| | | v-model="state.knowledgeBaseForm.Name" |
| | | style="width: 226.4px" |
| | | placeholder="搜索知识库名称" |
| | | clearable |
| | | :suffix-icon="Search" |
| | | ></el-input> |
| | | <el-button icon="ele-Plus" @click="importData()" type="primary"> 创建知识库 </el-button> |
| | | <div class="flex-col"> |
| | | <el-input |
| | | v-model="knowledgeBaseForm.title" |
| | | style="width: 230px; margin-right: 10px; background: #ffffff; border-radius: 6px; transition: all 0.2s" |
| | | placeholder="搜索知识库名称" |
| | | clearable |
| | | ></el-input> |
| | | <el-button type="primary" icon="ele-Search" @click="handleQueryTable"> 查询 </el-button> |
| | | <el-button icon="ele-Refresh" @click="resetQuery">重置 </el-button> |
| | | </div> |
| | | <el-button icon="ele-Plus" @click="createKnowledgeBase()" type="primary"> 创建知识库 </el-button> |
| | | </div> |
| | | <div class="flex flex-wrap gap-3 overflow-x-auto set_item_jel"></div> |
| | | <div class="flex flex-wrap gap-[12px]"> |
| | | <div class="flex flex-wrap gap-3 overflow-x-auto set_item_jel" v-for="item in displayTableData" :key="item.id"> |
| | | <img :src="knowledgeLeft" class="set_item_img" /> |
| | | <div class="set_item_content"> |
| | | <div class="flex items-center"> |
| | | <div class="mr-[10px] text-[14px] font-[500] h-[22px]">{{ item.title }}</div> |
| | | <span class="set_desc_text"> |
| | | <span class="set_desc_icon ywifont ywicon-wendang"> </span> |
| | | 1个知识 |
| | | </span> |
| | | <span class="set_desc_text"> |
| | | <span class="set_desc_icon ywifont ywicon-fenshu_an"> </span> |
| | | {{ item.scope }} |
| | | </span> |
| | | <span class="set_desc_text"> |
| | | <span class="set_desc_icon ywifont ywicon-cshy-shizhong"> </span> |
| | | {{ item.create_time }}更新 |
| | | </span> |
| | | <span |
| | | :class="{ |
| | | 'text-orange-500': item.publish === SupervisorPublished.N, |
| | | 'text-green-500': item.publish === SupervisorPublished.Y, |
| | | }" |
| | | class="text-[12px]" |
| | | > |
| | | {{ supervisorPublishedMap[item.publish] }} |
| | | </span> |
| | | </div> |
| | | </div> |
| | | <div class="set_btn_group"> |
| | | <el-button |
| | | link |
| | | class="text-[12px]" |
| | | @click="publishKnowledgeBase(item)" |
| | | :style="{ color: item.publish === SupervisorPublished.Y ? '#f97316' : '#22c55e' }" |
| | | >{{ item.publish === SupervisorPublished.Y ? '下架' : '发布' }} |
| | | </el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button link class="text-[12px] text-[#686682]" @click="viewKnowledgeBase(item)">查看 </el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button link class="text-[12px] text-[#686682]" @click="openChatTest(item)">对话测试 </el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button link class="text-[12px] text-[#686682]" @click="editKnowledgeBase(item)">编辑 </el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button link class="text-[12px]" @click="deleteKnowledgeBase(item)" style="color: #f00">删除 </el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div |
| | | v-if="chatTestIsShow" |
| | | ref="draggableChatRef" |
| | | :style="style" |
| | | class="fixed z-50 w-[700px] h-[800px] flex flex-col bg-[rgb(239,244,253)] right-0 bottom-0 rounded-lg" |
| | | > |
| | | <div ref="chatDragHandlerRef" class="flex-0"> |
| | | <div class="flex items-center justify-between py-2 px-4"> |
| | | <div class="font-bold cursor-move"> |
| | | WI水务智能管家——【{{ chatTestMapRow?.title }}】测试 |
| | | <!-- <img src="/static/images/logo/logo-mini.svg" width="10" height="10" /> --> |
| | | </div> |
| | | <i class="ywifont ywicon-guanbi font-[10px] font-bold cursor-pointer" @click="closeChatTest"></i> |
| | | </div> |
| | | </div> |
| | | <Chat ref="chatRef" class="flex-auto px-2" :questionApi="questionAi"> </Chat> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { computed, nextTick, onMounted, reactive, ref } from 'vue'; |
| | | import { Search } from '@element-plus/icons-vue'; |
| | | const state = reactive({ |
| | | knowledgeBaseForm: { |
| | | Name: '', |
| | | import { useDraggable } from '@vueuse/core'; |
| | | import axios, { CancelTokenSource } from 'axios'; |
| | | import { ElMessage, ElMessageBox } from 'element-plus'; |
| | | import { nextTick, onMounted, ref } from 'vue'; |
| | | import { useRouter } from 'vue-router'; |
| | | import { |
| | | check_docvector_validate, |
| | | delete_docvector_name, |
| | | get_docvector_list, |
| | | publish_docvector_name, |
| | | } from '/@/api/knowledge/docvector'; |
| | | import Chat from '/@/components/chat/Chat.vue'; |
| | | import { useQueryTable } from '/@/hooks/useQueryTable'; |
| | | import mittBus from '/@/utils/mitt'; |
| | | import { useCompRef } from '/@/utils/types'; |
| | | import { SupervisorPublished, supervisorPublishedMap } from '/@/views/project/yw/lowCode/sqlAmis/types'; |
| | | import knowledgeLeft from '/static/images/knowledge/data_type_1.png'; |
| | | const router = useRouter(); |
| | | //#region ====================== 获取知识库sheet列表 ====================== |
| | | const knowledgeBaseList = ref([]); |
| | | //创建知识库 |
| | | const createKnowledgeBase = () => { |
| | | router.push({ |
| | | name: 'AddKnowledge', |
| | | }); |
| | | }; |
| | | //获取知识库列表 |
| | | const docvectorList = async () => { |
| | | const res = await get_docvector_list(); |
| | | if (res.json_ok) { |
| | | res.values.forEach((item) => { |
| | | item.create_time = new Date(item.create_time).toLocaleString(); |
| | | }); |
| | | knowledgeBaseList.value = res.values; |
| | | } else { |
| | | return ElMessage.error('获取列表索引失败' + (res?.json_msg ? `,${JSON.stringify(res.json_msg)}` : '')); |
| | | } |
| | | }; |
| | | const deleteKnowledgeBase = async (row) => { |
| | | ElMessageBox.confirm(`确定删除当前的知识库:【${row.title}】?`, '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | }).then(async () => { |
| | | const res = await delete_docvector_name({ |
| | | knowlg_id: row.id, |
| | | }); |
| | | if (res.json_ok) { |
| | | ElMessage.success('删除知识库成功'); |
| | | const index = knowledgeBaseList.value.findIndex((d) => d.id === row.id); |
| | | knowledgeBaseList.value.splice(index, 1); |
| | | } |
| | | }); |
| | | }; |
| | | //#endregion |
| | | //#region ====================== 对知识库进行编辑查看操作 ====================== |
| | | const editKnowledgeBase = (row) => { |
| | | router.push({ |
| | | name: 'EditKnowledge', |
| | | query: { |
| | | knowledge_id: row.id, |
| | | knowledge_title: row.title, |
| | | knowledge_desc: row.desc, |
| | | knowledge_prompt: row.prompt, |
| | | knowledge_scope: row.scope, |
| | | }, |
| | | }); |
| | | }; |
| | | const viewKnowledgeBase = (row) => { |
| | | router.push({ |
| | | name: 'ViewKnowledge', |
| | | query: { |
| | | knowledge_id: row.id, |
| | | knowledge_title: row.title, |
| | | }, |
| | | }); |
| | | }; |
| | | //发布 |
| | | const publishKnowledgeBase = async (row) => { |
| | | const res = await publish_docvector_name({ |
| | | knowlg_id: row.id, |
| | | publish: row.publish === SupervisorPublished.Y ? SupervisorPublished.N : SupervisorPublished.Y, |
| | | }); |
| | | if (res.json_ok) { |
| | | row.publish = row.publish === SupervisorPublished.Y ? SupervisorPublished.N : SupervisorPublished.Y; |
| | | ElMessage.success('同步成功'); |
| | | } |
| | | }; |
| | | //#endregion |
| | | |
| | | //#region ====================== 搜索表格,对表格排序 ====================== |
| | | const knowledgeBaseForm = ref({ |
| | | title: '', |
| | | }); |
| | | const { resetQuery, handleQueryTable, displayTableData } = useQueryTable(knowledgeBaseList, knowledgeBaseForm, () => { |
| | | displayTableData.value = knowledgeBaseList.value; |
| | | }); |
| | | //#endregion |
| | | //#region ====================== Chat 测试 ====================== |
| | | |
| | | const chatRef = useCompRef(Chat); |
| | | const chatTestMapRow = ref(null); |
| | | const chatTestIsShow = ref(false); |
| | | const openChatTest = (row) => { |
| | | chatTestMapRow.value = row; |
| | | chatTestIsShow.value = true; |
| | | nextTick(() => { |
| | | chatRef.value.clear(); |
| | | // setTimeout(() => { |
| | | // chatRef.value.autoSend(row.title); |
| | | // }, 30); |
| | | }); |
| | | }; |
| | | |
| | | const closeChatTest = () => { |
| | | chatTestMapRow.value = null; |
| | | chatTestIsShow.value = false; |
| | | }; |
| | | |
| | | const draggableChatRef = ref<HTMLElement | null>(null); |
| | | const chatDragHandlerRef = ref<HTMLDivElement>(null); |
| | | const chatDragContainerRef = ref<HTMLDivElement>(null); |
| | | |
| | | // `style` will be a helper computed for `left: ?px; top: ?px;` |
| | | const { x, y, style } = useDraggable(draggableChatRef, { |
| | | handle: chatDragHandlerRef, |
| | | initialValue: { |
| | | x: document.body.clientWidth / 2 - 350, |
| | | y: document.body.clientHeight / 2 - 400, |
| | | }, |
| | | }); |
| | | |
| | | const questionAi = async (text, sourceObj: { source: CancelTokenSource }) => { |
| | | const currentSource = axios.CancelToken.source(); |
| | | sourceObj.source = currentSource; |
| | | const res = await check_docvector_validate( |
| | | { |
| | | knowlg_id: chatTestMapRow.value.id, |
| | | question: text, |
| | | }, |
| | | { |
| | | loading: false, |
| | | cancelToken: currentSource.token, |
| | | } |
| | | ); |
| | | return res; |
| | | }; |
| | | onMounted(() => { |
| | | docvectorList(); |
| | | mittBus.on('addKnowledgeBaseObj', (obj) => { |
| | | knowledgeBaseList.value.push(obj); |
| | | }); |
| | | }); |
| | | </script> |
| | | <style scoped lang="scss"> |
| | |
| | | align-items: center; |
| | | background: #fff; |
| | | border-radius: 16px; |
| | | display: flex; |
| | | min-width: 700px; |
| | | max-width: calc(50% - 6px); |
| | | padding: 16px 20px; |
| | | width: 100%; |
| | | box-sizing: border-box; |
| | | .set_item_img { |
| | | width: 40px; |
| | | flex-shrink: 0; |
| | | border-style: none; |
| | | vertical-align: middle; |
| | | } |
| | | .set_item_content { |
| | | flex: 1; |
| | | margin: 0 12px 0 16px; |
| | | width: calc(100% - 300px); |
| | | .set_desc_text { |
| | | align-items: center; |
| | | display: flex; |
| | | gap: 2px; |
| | | color: rgba(135, 138, 171, 0.75); |
| | | font-size: 12px; |
| | | } |
| | | .set_desc_text:not(:last-child) { |
| | | margin-right: 10px; |
| | | } |
| | | .set_desc_icon { |
| | | color: rgba(135, 138, 171, 0.75); |
| | | align-items: center; |
| | | display: inline-flex; |
| | | font-size: 16px; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | .set_btn_group { |
| | | flex-shrink: 0; |
| | | } |
| | | } |
| | | </style> |