| | |
| | | :model="state.knowledgeFile" |
| | | label-width="120px" |
| | | label-position="left" |
| | | class="h100" |
| | | ref="knowledgeFileRef" |
| | | :rules="knowledgeFormRules" |
| | | > |
| | | <el-divider content-position="left"><span class="text-[18px] font-[500]">选择文件</span></el-divider> |
| | | |
| | | <div class="flex items-start gap-[16px] max-h-[686px] min-h-[360px] set-file-height"> |
| | | <div class="min-h-[360px] h100 set_file_left"> |
| | | <div class="font-[500] mb-2">请选择文档</div> |
| | | <div class="left_content"> |
| | | <div class="file_menu"> |
| | | <LeftTreeByMgr |
| | | title-name="类目" |
| | | ref="leftTreeRef" |
| | | :treedata="state.knowledgeBaseData" |
| | | :current-node-key="currentListID" |
| | | :defaultProps="{ |
| | | children: 'Children', |
| | | label: 'title', |
| | | id: 'id', |
| | | }" |
| | | @click="handleClickNode" |
| | | > |
| | | </LeftTreeByMgr> |
| | | </div> |
| | | <div class="file_table"> |
| | | <el-table |
| | | :data="state.fileData" |
| | | border |
| | | @select="handleSelectItem" |
| | | highlight-current-row |
| | | ref="multipleTableRef" |
| | | :class="{ 'hidden-checkbox-all': state.isRadio }" |
| | | @select-all=" |
| | | (selection) => { |
| | | handleSelectAll(selection, state.fileData); |
| | | } |
| | | " |
| | | > |
| | | <el-table-column type="selection" width="55" /> |
| | | <el-table-column prop="name" label="文件名称" /> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="set_file_right"> |
| | | <div class="h100"> |
| | | <div class="font-[500] mb-[12px]">已选文档{{ multipleSelection.length }}/50个</div> |
| | | <div class="selected_file"> |
| | | <div v-for="(item, index) in multipleSelection" :key="index" class="set_file_item"> |
| | | <span class="set_file_name">{{ item.name }}</span> |
| | | <span class="ywifont ywicon-guanbi set_file_close" @click="handleRemoveItem(item)"></span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <el-divider content-position="left"><span class="text-[18px]">数据处理</span></el-divider> |
| | | <el-form-item label="配置模式:"> |
| | | <el-form-item label="文档切分chunk:"> |
| | | <div class="flex-auto flex flex-col"> |
| | | <div class="flex"> |
| | | <div v-for="(item, index) in state.configurationList" :key="index"> |
| | | <div v-for="(item, index) in state.segmentationList" :key="index"> |
| | | <div |
| | | class="bg-[#fff] border-[1px] border-solid border-[#d8d9e6] py-[12px] w-[215px] mr-[10px] px-[16px] rounded-lg cursor-pointer" |
| | | :class="{ activeColor: state.knowledgeForm.configurationMode === item.ID }" |
| | | :class="{ activeColor: state.knowledgeForm.segmentationMode === item.ID }" |
| | | @click="activeConfigurationType(item.ID)" |
| | | > |
| | | <div class="flex items-center"> |
| | |
| | | <img :src="item.ImageURL" class="w-[40px] h-[40px] mr-[10px]" /> |
| | | </div> |
| | | <div class="data_right"> |
| | | <el-radio v-model="state.knowledgeForm.configurationMode" size="large" :label="item.ID"> |
| | | <el-radio v-model="state.knowledgeForm.segmentationMode" size="large" :label="item.ID"> |
| | | <span class="font-[500] text[16px]">{{ item.Name }}</span> |
| | | </el-radio> |
| | | |
| | |
| | | <script setup lang="ts"> |
| | | import { ElMessage, type FormRules } from 'element-plus'; |
| | | import moment from 'moment'; |
| | | import { reactive, ref } from 'vue'; |
| | | import { computed, nextTick, reactive, ref } from 'vue'; |
| | | import { useRouter } from 'vue-router'; |
| | | import { add_docvector_name } from '/@/api/knowledge/docvector'; |
| | | import { get_knowledge_group_list, list_knowledge_file } from '/@/api/knowledge/group'; |
| | | import LeftTreeByMgr from '/@/components/tree/leftTreeByMgr.vue'; |
| | | import mittBus from '/@/utils/mitt'; |
| | | import { convertListToTree } from '/@/utils/util'; |
| | | // 定义变量内容 |
| | | const state = reactive({ |
| | | soliderValue: 0, |
| | |
| | | prompt: '', |
| | | dataType: 1, |
| | | configurationMode: 1, |
| | | segmentationMode: 1, |
| | | }, |
| | | knowledgeFile: {}, |
| | | dataTypeList: [ |
| | |
| | | ImageURL: 'static/images/knowledge/data_type_2.png', |
| | | DemoDesc: '选择数据管理功能中已创建的数据表', |
| | | }, |
| | | ], |
| | | ], //数据类型 |
| | | configurationList: [ |
| | | { |
| | | ID: 1, |
| | |
| | | Name: '自定义', |
| | | ImageURL: 'static/images/knowledge/data_type_4.png', |
| | | DemoDesc: '完全开放的离线知识库配置,按照检索需求自由配置,获得推理效果和时延方面的不同体验', |
| | | }, |
| | | ], //配置模式 |
| | | segmentationList: [ |
| | | { |
| | | ID: 1, |
| | | Name: '智能切分', |
| | | ImageURL: 'static/images/knowledge/data_type_3.png', |
| | | DemoDesc: '在通用文档上的最优chunk切分方法,经过评测可在多数文档上获得最佳的检索效果', |
| | | }, |
| | | { |
| | | ID: 3, |
| | | Name: '自定义切分', |
| | | ImageURL: 'static/images/knowledge/data_type_4.png', |
| | | DemoDesc: '完全开放的chunk切分配置,按照实际文档情况自由配置,通过调试获得更好的检索效果', |
| | | }, |
| | | ], |
| | | modeList: [ |
| | |
| | | }, |
| | | ], |
| | | showKnowledgeForm: false, |
| | | knowledgeBaseData: [], //知识库类目 |
| | | fileData: [], //文件数据源 |
| | | isRadio: false, //是否单选 |
| | | }); |
| | | const knowledgeFormRules = reactive<FormRules>({ |
| | | title: [ |
| | |
| | | }); |
| | | const knowledgeFormRef = ref(); |
| | | const router = useRouter(); |
| | | |
| | | //#region ====================== 知识库表单操作 ====================== |
| | | //返回 |
| | | const handleExitFlow = () => { |
| | | //是否显示返回 |
| | |
| | | const valid = await knowledgeFormRef.value.validate().catch(() => {}); |
| | | if (!valid) return; |
| | | state.showKnowledgeForm = true; |
| | | getFileTreeData(true); |
| | | }; |
| | | const backKnowledge = () => { |
| | | state.showKnowledgeForm = false; |
| | | }; |
| | | //#endregion |
| | | //#region ====================== 空知识库的创建 ====================== |
| | | |
| | | //创建一个空知识库 |
| | | const emptyKnowledgeBase = async () => { |
| | | var currentTime = moment().format('YYYY-MM-DD HH:mm:ss'); |
| | |
| | | router.push({ name: 'Knowledge' }); |
| | | } |
| | | }; |
| | | //导入完成 |
| | | const importCompleted = () => { |
| | | return; |
| | | ElMessage.success('导入完成'); |
| | | router.push({ name: 'Knowledge' }); |
| | | }; |
| | | //#endregion |
| | | //#region ====================== 知识库文件上传 ========== |
| | | const treeLoading = ref(false); |
| | | const currentTreeNode = ref(null); |
| | | const leftTreeRef = ref(null); |
| | | const currentListID = computed(() => currentTreeNode.value?.id); |
| | | //获取文件列表 |
| | | const getFileTreeData = async (selectFirst = false) => { |
| | | treeLoading.value = true; |
| | | const res = await get_knowledge_group_list().finally(() => { |
| | | treeLoading.value = false; |
| | | }); |
| | | if (res?.json_ok) { |
| | | const resData = (res.values || []) as []; |
| | | state.knowledgeBaseData = convertListToTree(resData, { |
| | | ID: 'id', |
| | | Children: 'Children', |
| | | ParentID: 'parent', |
| | | }); |
| | | if (selectFirst) { |
| | | const firstListTreeNode = state.knowledgeBaseData[0]; |
| | | if (firstListTreeNode) { |
| | | handleClickNode(firstListTreeNode); |
| | | } else { |
| | | state.fileData = []; |
| | | multipleSelection.value = []; |
| | | } |
| | | } else { |
| | | currentTreeNode.value && handleClickNode(currentTreeNode.value); |
| | | } |
| | | } |
| | | }; |
| | | const handleClickNode = (data: any) => { |
| | | multipleSelection.value = []; |
| | | nextTick(() => { |
| | | leftTreeRef.value?.treeRef.setCurrentKey(data.id); |
| | | }); |
| | | currentTreeNode.value = data; |
| | | getFileTableData(); |
| | | }; |
| | | //获取文件表格列表 |
| | | const getFileTableData = async () => { |
| | | const res = await list_knowledge_file({ |
| | | group_id: currentListID.value, |
| | | }).finally(() => {}); |
| | | if (res?.json_ok) { |
| | | const resData = (res.values || []) as []; |
| | | state.fileData = resData; |
| | | } else { |
| | | ElMessage.error('获取文档列表失败' + (res?.json_msg ? `,${JSON.stringify(res.json_msg)}` : '')); |
| | | } |
| | | }; |
| | | let multipleSelection = ref([]); |
| | | const multipleTableRef = ref(null); |
| | | //表格单选和多选 |
| | | const handleSelectAll = (selection: any[], pageSelectionData: any[]) => { |
| | | let checked = selection.length ? true : false; // selection为空数组时代表取消全选 |
| | | if (checked) { |
| | | let mIds = multipleSelection.value.map((v) => v.id); |
| | | let filterData = pageSelectionData.filter((v) => { |
| | | // 筛选出非重复项 |
| | | return !mIds.includes(v.id); |
| | | }); |
| | | multipleSelection.value = multipleSelection.value.concat(filterData); |
| | | } else { |
| | | let pIds = pageSelectionData.map((v) => v.id); |
| | | multipleSelection.value = multipleSelection.value.filter((v) => !pIds.includes(v.id)); |
| | | } |
| | | }; |
| | | |
| | | const handleSelectItem = (selection: any[], row) => { |
| | | multipleSelection.value = selection; |
| | | }; |
| | | // 移除已选文件 |
| | | const handleRemoveItem = (item) => { |
| | | multipleSelection.value = multipleSelection.value.filter((v) => v.id !== item.id); |
| | | multipleTableRef.value.toggleRowSelection(item, false); |
| | | }; |
| | | //#endregion |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | .set-form-height { |
| | |
| | | margin-top: 12px; |
| | | padding: 16px 24px; |
| | | } |
| | | .slider-demo-block { |
| | | max-width: 600px; |
| | | display: flex; |
| | | align-items: center; |
| | | .set-file-height { |
| | | height: calc(100% - 48px); |
| | | } |
| | | .set_file_left { |
| | | border: 1px solid #e7e8ee; |
| | | border-radius: 12px; |
| | | flex: 1; |
| | | padding: 12px 16px 16px; |
| | | box-sizing: border-box; |
| | | .left_content { |
| | | align-items: flex-start; |
| | | display: flex; |
| | | gap: 12px; |
| | | height: calc(100% - 29px); |
| | | .file_menu { |
| | | flex-shrink: 0; |
| | | height: 100%; |
| | | overflow-y: auto; |
| | | border: 1px solid #e7e8ee; |
| | | border-radius: 6px; |
| | | max-height: 627px; |
| | | padding: 20px; |
| | | width: 280px; |
| | | } |
| | | .file_table { |
| | | flex-shrink: 0; |
| | | height: 100%; |
| | | overflow-y: auto; |
| | | border-radius: 8px 8px 0 0; |
| | | flex: 1; |
| | | } |
| | | } |
| | | } |
| | | .set_file_right { |
| | | border: 1px solid #e7e8ee; |
| | | border-radius: 6px; |
| | | flex-shrink: 0; |
| | | height: 100%; |
| | | padding: 12px 16px 16px; |
| | | width: 417px; |
| | | min-height: 360px; |
| | | } |
| | | .selected_file { |
| | | max-height: calc(100% - 36px); |
| | | overflow-y: auto; |
| | | box-sizing: border-box; |
| | | .set_file_item { |
| | | align-items: center; |
| | | background: linear-gradient(0deg, #f7f8fe, #f7f8fe), #fff; |
| | | border-radius: 8px; |
| | | display: flex; |
| | | font-size: 12px; |
| | | gap: 8px; |
| | | height: 40px; |
| | | justify-content: space-between; |
| | | padding: 0 16px; |
| | | margin-bottom: 9px; |
| | | .set_file_name { |
| | | max-width: calc(100% - 22px); |
| | | } |
| | | .set_file_close { |
| | | color: #878aab; |
| | | cursor: pointer; |
| | | flex-shrink: 0; |
| | | font-size: 14px; |
| | | align-items: center; |
| | | display: inline-flex; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | } |
| | | .hidden-checkbox-all :deep(.el-table__header .el-table-column--selection .el-checkbox) { |
| | | // 隐藏全选checkbox |
| | | display: none; |
| | | } |
| | | </style> |
| | | <style> |