mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 10:12:51 +00:00
feat: paragraph
This commit is contained in:
parent
ba078a9aab
commit
72d9833038
|
|
@ -14,13 +14,29 @@ Object.defineProperty(prefix, 'value', {
|
|||
})
|
||||
|
||||
/**
|
||||
* 文档分页列表
|
||||
* 文档列表(无分页)
|
||||
* @param 参数 knowledge_id,
|
||||
* param {
|
||||
" name": "string",
|
||||
}
|
||||
*/
|
||||
|
||||
const getDocumentList: (knowledge_id: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
|
||||
knowledge_id,
|
||||
loading,
|
||||
) => {
|
||||
return get(`${prefix.value}/${knowledge_id}/document`, undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档分页列表
|
||||
* @param 参数 knowledge_id,
|
||||
* param {
|
||||
"name": "string",
|
||||
folder_id: "string",
|
||||
}
|
||||
*/
|
||||
|
||||
const getDocumentPage: (
|
||||
knowledge_id: string,
|
||||
page: pageRequest,
|
||||
|
|
@ -549,15 +565,9 @@ const importLarkDocument: (
|
|||
return post(`${prefix.value}/lark/${knowledge_id}/import`, data, null, loading)
|
||||
}
|
||||
|
||||
// todo
|
||||
const getAllDocument: (knowledge_id: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
|
||||
knowledge_id,
|
||||
loading,
|
||||
) => {
|
||||
return get(`${prefix.value}/${knowledge_id}/document`, undefined, loading)
|
||||
}
|
||||
|
||||
export default {
|
||||
getDocumentList,
|
||||
getDocumentPage,
|
||||
getDocumentDetail,
|
||||
putDocument,
|
||||
|
|
|
|||
|
|
@ -239,6 +239,11 @@ const putBatchGenerateRelated: (
|
|||
/**
|
||||
* 批量迁移段落
|
||||
* @param 参数 knowledge_id,target_knowledge_id,
|
||||
* {
|
||||
"id_list": [
|
||||
"3fa85f64-5717-4562-b3fc-2c963f66afa6"
|
||||
]
|
||||
}
|
||||
*/
|
||||
const putMigrateMulParagraph: (
|
||||
knowledge_id: string,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
width="650"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
@click.stop
|
||||
>
|
||||
<div class="content-height">
|
||||
<el-form
|
||||
|
|
|
|||
|
|
@ -4,15 +4,16 @@ export default {
|
|||
syncDocument: 'Sync Document',
|
||||
selected: 'Selected',
|
||||
items: 'Items',
|
||||
migrateDocument: 'Migrate to',
|
||||
searchBar: {
|
||||
placeholder: 'Search by document name'
|
||||
placeholder: 'Search by document name',
|
||||
},
|
||||
setting: {
|
||||
migration: 'Move',
|
||||
cancelGenerateQuestion: 'Cancel Generating Questions',
|
||||
cancelVectorization: 'Cancel Vectorization',
|
||||
cancelGenerate: 'Cancel Generation',
|
||||
export: 'Export to'
|
||||
export: 'Export to',
|
||||
},
|
||||
tip: {
|
||||
saveMessage: 'Current changes have not been saved. Confirm exit?',
|
||||
|
|
@ -21,7 +22,7 @@ export default {
|
|||
vectorizationSuccess: 'Successful',
|
||||
nameMessage: 'Document name cannot be empty!',
|
||||
importMessage: 'Successful',
|
||||
migrationSuccess: 'Successful'
|
||||
migrationSuccess: 'Successful',
|
||||
},
|
||||
upload: {
|
||||
selectFile: 'Select File',
|
||||
|
|
@ -34,71 +35,71 @@ export default {
|
|||
errorMessage3: 'File cannot be empty',
|
||||
errorMessage4: 'Up to 50 files can be uploaded at once',
|
||||
template: 'Template',
|
||||
download: 'Download'
|
||||
download: 'Download',
|
||||
},
|
||||
|
||||
fileType: {
|
||||
txt: {
|
||||
label: 'Text File',
|
||||
tip1: '1. It is recommended to standardize the segment markers in the file before uploading.',
|
||||
tip2: '2. Up to 50 files can be uploaded at once, with each file not exceeding 100MB.'
|
||||
tip2: '2. Up to 50 files can be uploaded at once, with each file not exceeding 100MB.',
|
||||
},
|
||||
table: {
|
||||
label: 'Table',
|
||||
tip1: '1. Click to download the corresponding template and complete the information:',
|
||||
tip2: '2. The first row must be column headers, and the column headers must be meaningful terms. Each record in the table will be treated as a segment.',
|
||||
tip3: '3. Each sheet in the uploaded spreadsheet file will be treated as a document, with the sheet name as the document name.',
|
||||
tip4: '4. Up to 50 files can be uploaded at once, with each file not exceeding 100MB.'
|
||||
tip4: '4. Up to 50 files can be uploaded at once, with each file not exceeding 100MB.',
|
||||
},
|
||||
QA: {
|
||||
label: 'QA Pairs',
|
||||
tip1: '1. Click to download the corresponding template and complete the information:',
|
||||
tip2: '2. Each sheet in the uploaded spreadsheet file will be treated as a document, with the sheet name as the document name.',
|
||||
tip3: '3. Up to 50 files can be uploaded at once, with each file not exceeding 100MB.'
|
||||
}
|
||||
tip3: '3. Up to 50 files can be uploaded at once, with each file not exceeding 100MB.',
|
||||
},
|
||||
},
|
||||
setRules: {
|
||||
title: {
|
||||
setting: 'Set Segment Rules',
|
||||
preview: 'Preview'
|
||||
preview: 'Preview',
|
||||
},
|
||||
intelligent: {
|
||||
label: 'Automatic Segmentation (Recommended)',
|
||||
text: 'If you are unsure how to set segmentation rules, it is recommended to use automatic segmentation.'
|
||||
text: 'If you are unsure how to set segmentation rules, it is recommended to use automatic segmentation.',
|
||||
},
|
||||
advanced: {
|
||||
label: 'Advanced Segmentation',
|
||||
text: 'Users can customize segmentation delimiters, segment length, and cleaning rules based on document standards.'
|
||||
text: 'Users can customize segmentation delimiters, segment length, and cleaning rules based on document standards.',
|
||||
},
|
||||
patterns: {
|
||||
label: 'Segment Delimiters',
|
||||
tooltip:
|
||||
'Recursively split according to the selected symbols in order. If the split result exceeds the segment length, it will be truncated to the segment length.',
|
||||
placeholder: 'Please select'
|
||||
placeholder: 'Please select',
|
||||
},
|
||||
limit: {
|
||||
label: 'Segment Length'
|
||||
label: 'Segment Length',
|
||||
},
|
||||
with_filter: {
|
||||
label: 'Auto Clean',
|
||||
text: 'Remove duplicate extra symbols, spaces, blank lines, and tab words.'
|
||||
text: 'Remove duplicate extra symbols, spaces, blank lines, and tab words.',
|
||||
},
|
||||
checkedConnect: {
|
||||
label: 'Add "Related Questions" section for question-based QA pairs during import.'
|
||||
}
|
||||
label: 'Add "Related Questions" section for question-based QA pairs during import.',
|
||||
},
|
||||
},
|
||||
buttons: {
|
||||
prev: 'Previous',
|
||||
next: 'Next',
|
||||
import: 'Start Import',
|
||||
preview: 'Apply'
|
||||
preview: 'Apply',
|
||||
},
|
||||
table: {
|
||||
name: 'Document Name',
|
||||
char_length: 'Character',
|
||||
paragraph: 'Segment',
|
||||
all: 'All',
|
||||
updateTime: 'Update Time'
|
||||
updateTime: 'Update Time',
|
||||
},
|
||||
fileStatus: {
|
||||
label: 'File Status',
|
||||
|
|
@ -109,12 +110,12 @@ export default {
|
|||
GENERATE: 'Generating',
|
||||
SYNC: 'Syncing',
|
||||
REVOKE: 'Cancelling',
|
||||
finish: 'Finish'
|
||||
finish: 'Finish',
|
||||
},
|
||||
enableStatus: {
|
||||
label: 'Status',
|
||||
enable: 'Enabled',
|
||||
close: 'Disabled'
|
||||
close: 'Disabled',
|
||||
},
|
||||
sync: {
|
||||
label: 'Sync',
|
||||
|
|
@ -122,7 +123,7 @@ export default {
|
|||
confirmMessage1:
|
||||
'Syncing will delete existing data and retrieve new data. Please proceed with caution.',
|
||||
confirmMessage2: 'Cannot sync, please set the document URL first.',
|
||||
successMessage: 'Successful'
|
||||
successMessage: 'Successful',
|
||||
},
|
||||
delete: {
|
||||
confirmTitle1: 'Confirm batch deletion of',
|
||||
|
|
@ -132,31 +133,31 @@ export default {
|
|||
successMessage: 'Successful',
|
||||
confirmTitle3: 'Confirm deleting document:',
|
||||
confirmMessage1: 'Under this document',
|
||||
confirmMessage2: 'All segments will be deleted, please operate with caution. '
|
||||
confirmMessage2: 'All segments will be deleted, please operate with caution. ',
|
||||
},
|
||||
form: {
|
||||
source_url: {
|
||||
label: 'Document URL',
|
||||
placeholder: 'Enter document URL, one per line. Incorrect URL will cause import failure.',
|
||||
requiredMessage: 'Please enter a document URL'
|
||||
requiredMessage: 'Please enter a document URL',
|
||||
},
|
||||
selector: {
|
||||
label: 'Selector',
|
||||
placeholder: 'Default is body, you can input .classname/#idname/tagname'
|
||||
placeholder: 'Default is body, you can input .classname/#idname/tagname',
|
||||
},
|
||||
hit_handling_method: {
|
||||
label: 'Retrieve-Respond',
|
||||
tooltip: 'When user asks a question, handle matched segments according to the set method.'
|
||||
tooltip: 'When user asks a question, handle matched segments according to the set method.',
|
||||
},
|
||||
similarity: {
|
||||
label: 'Similarity Higher Than',
|
||||
placeholder: 'Directly return segment content',
|
||||
requiredMessage: 'Please enter similarity value'
|
||||
}
|
||||
requiredMessage: 'Please enter similarity value',
|
||||
},
|
||||
},
|
||||
hitHandlingMethod: {
|
||||
optimization: 'Model optimization',
|
||||
directly_return: 'Respond directly'
|
||||
directly_return: 'Respond directly',
|
||||
},
|
||||
generateQuestion: {
|
||||
title: 'Generate Questions',
|
||||
|
|
@ -167,12 +168,12 @@ export default {
|
|||
tip4: 'The generation effect depends on the selected model and prompt. Users can adjust to achieve the best effect.',
|
||||
prompt1:
|
||||
'Content: {data}\n \n Please summarize the above and generate 5 questions based on the summary. \nAnswer requirements: \n - Please output only questions; \n - Please place each question in',
|
||||
prompt2: 'tag.'
|
||||
prompt2: 'tag.',
|
||||
},
|
||||
feishu: {
|
||||
selectDocument: 'Select Document',
|
||||
tip1: 'Only documents and tables are supported. Documents will be segmented based on titles, and tables will be converted to Markdown format before segmentation.',
|
||||
tip2: 'The system does not store the original document. Before importing the document, it is recommended to standardize the document segmentation markers.',
|
||||
allCheck: 'Select All'
|
||||
}
|
||||
allCheck: 'Select All',
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ export default {
|
|||
syncDocument: '同步文档',
|
||||
selected: '已选',
|
||||
items: '项',
|
||||
migrateDocument:'文档迁移到',
|
||||
searchBar: {
|
||||
placeholder: '按 文档名称 搜索'
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ export default {
|
|||
syncDocument: '同步文檔',
|
||||
selected: '已選',
|
||||
items: '項',
|
||||
migrateDocument: '文檔遷移到',
|
||||
searchBar: {
|
||||
placeholder: '按 文檔名稱 搜索'
|
||||
placeholder: '按 文檔名稱 搜索',
|
||||
},
|
||||
setting: {
|
||||
migration: '遷移',
|
||||
|
|
@ -21,7 +22,7 @@ export default {
|
|||
vectorizationSuccess: '批量向量化成功',
|
||||
nameMessage: '文件名稱不能为空!',
|
||||
importMessage: '導入成功',
|
||||
migrationSuccess: '遷移成功'
|
||||
migrationSuccess: '遷移成功',
|
||||
},
|
||||
upload: {
|
||||
selectFile: '選擇文件',
|
||||
|
|
@ -34,70 +35,70 @@ export default {
|
|||
errorMessage3: '文件不能为空',
|
||||
errorMessage4: '每次最多上傳50個文件',
|
||||
template: '模板',
|
||||
download: '下載'
|
||||
download: '下載',
|
||||
},
|
||||
|
||||
fileType: {
|
||||
txt: {
|
||||
label: '文本文件',
|
||||
tip1: '1、文件上傳前,建議規範文件的分段標識',
|
||||
tip2: '2、每次最多上傳 50 個文件,每個文件不超过 100MB'
|
||||
tip2: '2、每次最多上傳 50 個文件,每個文件不超过 100MB',
|
||||
},
|
||||
table: {
|
||||
label: '表格',
|
||||
tip1: '1、點擊下載對應模板並完善信息:',
|
||||
tip2: '2、第一行必須是列標題,且列標題必須是有意義的術語,表中每條記錄將作為一個分段',
|
||||
tip3: '3、上傳的表格文件中每個 sheet 會作為一個文檔,sheet 名稱為文檔名稱',
|
||||
tip4: '4、每次最多上傳 50 個文件,每個文件不超过 100MB'
|
||||
tip4: '4、每次最多上傳 50 個文件,每個文件不超过 100MB',
|
||||
},
|
||||
QA: {
|
||||
label: 'QA 問答對',
|
||||
tip1: '1、點擊下載對應模板並完善信息',
|
||||
tip2: '2、上傳的表格文件中每個 sheet 會作為一個文檔,sheet 名稱為文檔名稱',
|
||||
tip3: '3、每次最多上傳 50 個文件,每個文件不超过 100MB'
|
||||
}
|
||||
tip3: '3、每次最多上傳 50 個文件,每個文件不超过 100MB',
|
||||
},
|
||||
},
|
||||
setRules: {
|
||||
title: {
|
||||
setting: '設置分段規則',
|
||||
preview: '分段預覽'
|
||||
preview: '分段預覽',
|
||||
},
|
||||
intelligent: {
|
||||
label: '智能分段(推薦)',
|
||||
text: '不了解如何設置分段規則推薦使用智能分段'
|
||||
text: '不了解如何設置分段規則推薦使用智能分段',
|
||||
},
|
||||
advanced: {
|
||||
label: '高級分段',
|
||||
text: '用戶可根據文檔規範自行設置分段標識符、分段長度以及清洗規則'
|
||||
text: '用戶可根據文檔規範自行設置分段標識符、分段長度以及清洗規則',
|
||||
},
|
||||
patterns: {
|
||||
label: '分段標識',
|
||||
tooltip: '按照所選符號先後順序做遞歸分割,分割結果超出分段長度將截取至分段長度。',
|
||||
placeholder: '請選擇'
|
||||
placeholder: '請選擇',
|
||||
},
|
||||
limit: {
|
||||
label: '分段長度'
|
||||
label: '分段長度',
|
||||
},
|
||||
with_filter: {
|
||||
label: '自動清洗',
|
||||
text: '去掉重複多餘符號空格、空行、制表符'
|
||||
text: '去掉重複多餘符號空格、空行、制表符',
|
||||
},
|
||||
checkedConnect: {
|
||||
label: '導入時添加分段標題為關聯問題(適用於標題為問題的問答對)'
|
||||
}
|
||||
label: '導入時添加分段標題為關聯問題(適用於標題為問題的問答對)',
|
||||
},
|
||||
},
|
||||
buttons: {
|
||||
prev: '上一步',
|
||||
next: '下一步',
|
||||
import: '開始導入',
|
||||
preview: '生成預覽'
|
||||
preview: '生成預覽',
|
||||
},
|
||||
table: {
|
||||
name: '文件名稱',
|
||||
char_length: '字符數',
|
||||
paragraph: '分段',
|
||||
all: '全部',
|
||||
updateTime: '更新時間'
|
||||
updateTime: '更新時間',
|
||||
},
|
||||
fileStatus: {
|
||||
label: '文件狀態',
|
||||
|
|
@ -108,19 +109,19 @@ export default {
|
|||
GENERATE: '生成中',
|
||||
SYNC: '同步中',
|
||||
REVOKE: '取消中',
|
||||
finish: '完圓'
|
||||
finish: '完圓',
|
||||
},
|
||||
enableStatus: {
|
||||
label: '啟用狀態',
|
||||
enable: '開啟',
|
||||
close: '關閉'
|
||||
close: '關閉',
|
||||
},
|
||||
sync: {
|
||||
label: '同步',
|
||||
confirmTitle: '確認同步文檔?',
|
||||
confirmMessage1: '同步將刪除已有數據重新獲取新數據,請謹慎操作。',
|
||||
confirmMessage2: '無法同步,請先去設置文檔 URL地址',
|
||||
successMessage: '同步文檔成功'
|
||||
successMessage: '同步文檔成功',
|
||||
},
|
||||
delete: {
|
||||
confirmTitle1: '是否批量刪除',
|
||||
|
|
@ -129,31 +130,31 @@ export default {
|
|||
successMessage: '批量刪除成功',
|
||||
confirmTitle3: '是否刪除文檔:',
|
||||
confirmMessage1: '此文檔下的',
|
||||
confirmMessage2: '個分段都會被刪除,請謹慎操作。'
|
||||
confirmMessage2: '個分段都會被刪除,請謹慎操作。',
|
||||
},
|
||||
form: {
|
||||
source_url: {
|
||||
label: '文檔地址',
|
||||
placeholder: '請輸入文檔地址,一行一個,地址不正確文檔會導入失敗。',
|
||||
requiredMessage: '請輸入文檔地址'
|
||||
requiredMessage: '請輸入文檔地址',
|
||||
},
|
||||
selector: {
|
||||
label: '選擇器',
|
||||
placeholder: '默認為 body,可輸入 .classname/#idname/tagname'
|
||||
placeholder: '默認為 body,可輸入 .classname/#idname/tagname',
|
||||
},
|
||||
hit_handling_method: {
|
||||
label: '命中處理方式',
|
||||
tooltip: '用戶提問時,命中文檔下的分段時按照設置的方式進行處理。'
|
||||
tooltip: '用戶提問時,命中文檔下的分段時按照設置的方式進行處理。',
|
||||
},
|
||||
similarity: {
|
||||
label: '相似度高于',
|
||||
placeholder: '直接返回分段内容',
|
||||
requiredMessage: '请输入相似度'
|
||||
requiredMessage: '请输入相似度',
|
||||
},
|
||||
},
|
||||
hitHandlingMethod: {
|
||||
optimization: '模型優化',
|
||||
directly_return: '直接回答'
|
||||
directly_return: '直接回答',
|
||||
},
|
||||
generateQuestion: {
|
||||
title: '生成問題',
|
||||
|
|
@ -169,6 +170,6 @@ export default {
|
|||
selectDocument: '選擇文檔',
|
||||
tip1: '僅支持文檔和表格類型,文檔會根據標題分段,表格會轉為Markdown格式後再分段。',
|
||||
tip2: '系統不存儲原始文檔,導入文檔前,建議規範文檔的分段標識。',
|
||||
allCheck: '全選'
|
||||
}
|
||||
allCheck: '全選',
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import { type Ref } from 'vue'
|
|||
const useDocumentStore = defineStore('document', {
|
||||
state: () => ({}),
|
||||
actions: {
|
||||
async asyncGetAllDocument(id: string, loading?: Ref<boolean>) {
|
||||
async asyncGetKnowledgeDocument(id: string, loading?: Ref<boolean>) {
|
||||
return new Promise((resolve, reject) => {
|
||||
documentApi
|
||||
.getAllDocument(id, loading)
|
||||
.getDocumentList(id, loading)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,29 +1,22 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
:title="$t('views.chatLog.selectKnowledge')"
|
||||
:title="`${$t('views.document.migrateDocument')}`"
|
||||
v-model="dialogVisible"
|
||||
width="600"
|
||||
class="select-knowledge-dialog"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<h4 :id="titleId" :class="titleClass">{{ '文档迁移到' }}</h4>
|
||||
</template>
|
||||
<el-form
|
||||
ref="FormRef"
|
||||
:model="form"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
>
|
||||
<el-form ref="FormRef" :model="form" label-position="top" require-asterisk-position="right">
|
||||
<el-form-item :label="$t('views.chatLog.selectKnowledge')" required>
|
||||
<el-tree-select
|
||||
v-model="form.selectKnowledge"
|
||||
:props="defaultProps"
|
||||
node-key="id"
|
||||
:default-expanded-keys="['default']"
|
||||
lazy
|
||||
:load="loadTree"
|
||||
:placeholder="$t('views.chatLog.selectKnowledgePlaceholder')"
|
||||
:loading="loading"
|
||||
>
|
||||
<template #default="{ data }">
|
||||
<div class="flex align-center">
|
||||
|
|
@ -81,6 +74,9 @@ const loading = ref<boolean>(false)
|
|||
const dialogVisible = ref<boolean>(false)
|
||||
const knowledgeList = ref<any>([])
|
||||
const documentList = ref<any>([])
|
||||
const form = ref<any>({
|
||||
selectKnowledge: '',
|
||||
})
|
||||
|
||||
const defaultProps = {
|
||||
children: 'children',
|
||||
|
|
@ -91,9 +87,14 @@ const defaultProps = {
|
|||
},
|
||||
}
|
||||
|
||||
const form = ref<any>({
|
||||
selectKnowledge: '',
|
||||
})
|
||||
const loadTree = (node: any, resolve: any) => {
|
||||
console.log(node)
|
||||
if (node.isLeaf) return resolve([])
|
||||
const folder_id = node.level === 0 ? '' : node.data.id
|
||||
knowledge.asyncGetFolderKnowledge(folder_id, loading).then((res: any) => {
|
||||
resolve(res.data)
|
||||
})
|
||||
}
|
||||
|
||||
watch(dialogVisible, (bool) => {
|
||||
if (!bool) {
|
||||
|
|
@ -108,14 +109,6 @@ const open = (list: any) => {
|
|||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const loadTree = (node: any, resolve: any) => {
|
||||
console.log(node)
|
||||
if (node.isLeaf) return resolve([])
|
||||
const folder_id = node.level === 0 ? '' : node.data.id
|
||||
knowledge.asyncGetFolderKnowledge(folder_id, loading).then((res: any) => {
|
||||
resolve(res.data)
|
||||
})
|
||||
}
|
||||
const submitHandle = () => {
|
||||
documentApi
|
||||
.putMigrateMulDocument(id, form.value.selectKnowledge, documentList.value, loading)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
@click.stop="editParagraph(data)"
|
||||
>
|
||||
<h2 class="mb-16">{{ data.title || '-' }}</h2>
|
||||
<div v-show="show" class="mk-sticky">
|
||||
<div v-show="show" class="mk-sticky" v-if="!disabled">
|
||||
<el-card
|
||||
class="paragraph-box-operation mt-8 mr-8"
|
||||
shadow="always"
|
||||
|
|
@ -79,7 +79,6 @@ import GenerateRelatedDialog from '@/components/generate-related-dialog/index.vu
|
|||
import ParagraphDialog from '@/views/paragraph/component/ParagraphDialog.vue'
|
||||
import SelectDocumentDialog from '@/views/paragraph/component/SelectDocumentDialog.vue'
|
||||
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||
import { elPaginationKey } from 'element-plus'
|
||||
|
||||
const { paragraph } = useStore()
|
||||
|
||||
|
|
@ -89,9 +88,10 @@ const {
|
|||
} = route as any
|
||||
const props = defineProps<{
|
||||
data: any
|
||||
disabled?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['changeState', 'deleteParagraph'])
|
||||
const emit = defineEmits(['changeState', 'deleteParagraph', 'refresh', 'refreshMigrateParagraph'])
|
||||
const loading = ref(false)
|
||||
const changeStateloading = ref(false)
|
||||
const show = ref(false)
|
||||
|
|
@ -127,13 +127,6 @@ function openGenerateDialog(row: any) {
|
|||
GenerateRelatedDialogRef.value.open([], 'paragraph', row.id)
|
||||
}
|
||||
}
|
||||
function openSelectDocumentDialog(row?: any) {
|
||||
// if (row) {
|
||||
// multipleSelection.value = [row.id]
|
||||
// }
|
||||
// SelectDocumentDialogRef.value.open(multipleSelection.value)
|
||||
}
|
||||
|
||||
function deleteParagraph(row: any) {
|
||||
MsgConfirm(
|
||||
`${t('views.paragraph.delete.confirmTitle')} ${row.title || '-'} ?`,
|
||||
|
|
@ -151,17 +144,28 @@ function deleteParagraph(row: any) {
|
|||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
const SelectDocumentDialogRef = ref()
|
||||
|
||||
const ParagraphDialogRef = ref()
|
||||
const title = ref('')
|
||||
function editParagraph(row: any) {
|
||||
title.value = t('views.paragraph.paragraphDetail')
|
||||
ParagraphDialogRef.value.open(row)
|
||||
if (!props.disabled) {
|
||||
title.value = t('views.paragraph.paragraphDetail')
|
||||
ParagraphDialogRef.value.open(row)
|
||||
}
|
||||
}
|
||||
|
||||
function refresh() {}
|
||||
const SelectDocumentDialogRef = ref()
|
||||
function openSelectDocumentDialog(row?: any) {
|
||||
SelectDocumentDialogRef.value.open([row.id])
|
||||
}
|
||||
|
||||
function refreshMigrateParagraph() {}
|
||||
function refresh(data?: any) {
|
||||
emit('refresh', data)
|
||||
}
|
||||
|
||||
function refreshMigrateParagraph() {
|
||||
emit('refreshMigrateParagraph', props.data)
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.paragraph-box {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<el-col :span="18">
|
||||
<el-scrollbar height="500" wrap-class="paragraph-scrollbar">
|
||||
<div class="p-24" style="padding-bottom: 8px">
|
||||
<div style="position: absolute; right: 20px; top: 20px; ">
|
||||
<div style="position: absolute; right: 20px; top: 20px">
|
||||
<el-button text @click="isEdit = true" v-if="problemId && !isEdit">
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-button>
|
||||
|
|
@ -22,9 +22,9 @@
|
|||
</div>
|
||||
</el-scrollbar>
|
||||
<div class="text-right p-24 pt-0" v-if="problemId && isEdit">
|
||||
<el-button @click.prevent="cancelEdit"> {{$t('common.cancel')}} </el-button>
|
||||
<el-button @click.prevent="cancelEdit"> {{ $t('common.cancel') }} </el-button>
|
||||
<el-button type="primary" :disabled="loading" @click="handleDebounceClick">
|
||||
{{$t('common.save')}}
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
|
|
@ -40,9 +40,9 @@
|
|||
</el-row>
|
||||
<template #footer v-if="!problemId">
|
||||
<span class="dialog-footer">
|
||||
<el-button @click.prevent="dialogVisible = false"> {{$t('common.cancel')}} </el-button>
|
||||
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="handleDebounceClick">
|
||||
{{$t('common.submit')}}
|
||||
{{ $t('common.submit') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
|
|
@ -58,14 +58,14 @@ import paragraphApi from '@/api/knowledge/paragraph'
|
|||
import useStore from '@/stores'
|
||||
|
||||
const props = defineProps({
|
||||
title: String
|
||||
title: String,
|
||||
})
|
||||
|
||||
const { paragraph } = useStore()
|
||||
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { id, documentId }
|
||||
params: { id, documentId },
|
||||
} = route as any
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
|
@ -122,7 +122,7 @@ const submitHandle = async () => {
|
|||
documentId || document_id.value,
|
||||
problemId.value,
|
||||
paragraphFormRef.value?.form,
|
||||
loading
|
||||
loading,
|
||||
)
|
||||
.then((res: any) => {
|
||||
isEdit.value = false
|
||||
|
|
@ -133,7 +133,7 @@ const submitHandle = async () => {
|
|||
ProblemRef.value.problemList.length > 0
|
||||
? {
|
||||
problem_list: ProblemRef.value.problemList,
|
||||
...paragraphFormRef.value?.form
|
||||
...paragraphFormRef.value?.form,
|
||||
}
|
||||
: paragraphFormRef.value?.form
|
||||
paragraphApi.postParagraph(id, documentId, obj, loading).then((res) => {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
width="500"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
@click.stop
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
|
|
@ -14,22 +15,37 @@
|
|||
:rules="rules"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item :label="$t('views.chatLog.selectKnowledge')" prop="dataset_id">
|
||||
<el-select
|
||||
v-model="form.dataset_id"
|
||||
filterable
|
||||
<el-form-item :label="$t('views.chatLog.selectKnowledge')" prop="knowledge_id">
|
||||
<el-tree-select
|
||||
v-model="form.knowledge_id"
|
||||
:props="defaultProps"
|
||||
node-key="id"
|
||||
lazy
|
||||
:load="loadTree"
|
||||
:placeholder="$t('views.chatLog.selectKnowledgePlaceholder')"
|
||||
@change="changeKnowledge"
|
||||
:loading="optionLoading"
|
||||
@change="changeDataset"
|
||||
>
|
||||
<el-option v-for="item in datasetList" :key="item.id" :label="item.name" :value="item.id">
|
||||
<span class="flex align-center">
|
||||
<KnowledgeIcon v-if="!item.dataset_id" :type="item.type" />
|
||||
<template #default="{ data }">
|
||||
<div class="flex align-center">
|
||||
<KnowledgeIcon
|
||||
class="mr-12"
|
||||
:size="20"
|
||||
v-if="data.resource_type !== 'folder'"
|
||||
:type="data.type"
|
||||
/>
|
||||
<el-avatar v-else class="mr-12" shape="square" :size="20" style="background: none">
|
||||
<img
|
||||
src="@/assets/knowledge/icon_file-folder_colorful.svg"
|
||||
style="width: 100%"
|
||||
alt=""
|
||||
/>
|
||||
</el-avatar>
|
||||
|
||||
{{ item.name }}
|
||||
</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
{{ data.name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-tree-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('views.chatLog.saveToDocument')" prop="document_id">
|
||||
<el-select
|
||||
|
|
@ -70,7 +86,7 @@ const { knowledge, document } = useStore()
|
|||
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { id, documentId },
|
||||
params: { id, documentId }, // id为knowledgeID
|
||||
} = route as any
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
|
@ -80,18 +96,19 @@ const dialogVisible = ref<boolean>(false)
|
|||
const loading = ref(false)
|
||||
|
||||
const form = ref<any>({
|
||||
dataset_id: '',
|
||||
knowledge_id: '',
|
||||
document_id: '',
|
||||
})
|
||||
|
||||
const rules = reactive<FormRules>({
|
||||
dataset_id: [
|
||||
knowledge_id: [
|
||||
{ required: true, message: t('views.chatLog.selectKnowledgePlaceholder'), trigger: 'change' },
|
||||
],
|
||||
document_id: [{ required: true, message: t('views.chatLog.documentPlaceholder'), trigger: 'change' }],
|
||||
document_id: [
|
||||
{ required: true, message: t('views.chatLog.documentPlaceholder'), trigger: 'change' },
|
||||
],
|
||||
})
|
||||
|
||||
const datasetList = ref<any[]>([])
|
||||
const documentList = ref<any[]>([])
|
||||
const optionLoading = ref(false)
|
||||
const paragraphList = ref<string[]>([])
|
||||
|
|
@ -99,36 +116,46 @@ const paragraphList = ref<string[]>([])
|
|||
watch(dialogVisible, (bool) => {
|
||||
if (!bool) {
|
||||
form.value = {
|
||||
dataset_id: '',
|
||||
knowledge_id: '',
|
||||
document_id: '',
|
||||
}
|
||||
datasetList.value = []
|
||||
documentList.value = []
|
||||
paragraphList.value = []
|
||||
formRef.value?.clearValidate()
|
||||
}
|
||||
})
|
||||
|
||||
function changeDataset(id: string) {
|
||||
const defaultProps = {
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
isLeaf: (data: any) => data.resource_type && data.resource_type !== 'folder',
|
||||
disabled: (data: any, node: any) => {
|
||||
return data.id === id
|
||||
},
|
||||
}
|
||||
|
||||
const loadTree = (node: any, resolve: any) => {
|
||||
console.log(node)
|
||||
if (node.isLeaf) return resolve([])
|
||||
const folder_id = node.level === 0 ? '' : node.data.id
|
||||
knowledge.asyncGetFolderKnowledge(folder_id, optionLoading).then((res: any) => {
|
||||
resolve(res.data)
|
||||
})
|
||||
}
|
||||
|
||||
function changeKnowledge(id: string) {
|
||||
form.value.document_id = ''
|
||||
getDocument(id)
|
||||
}
|
||||
|
||||
function getDocument(id: string) {
|
||||
document.asyncGetAllDocument(id, loading).then((res: any) => {
|
||||
document.asyncGetKnowledgeDocument(id, optionLoading).then((res: any) => {
|
||||
documentList.value = res.data?.filter((v: any) => v.id !== documentId)
|
||||
})
|
||||
}
|
||||
|
||||
function getDataset() {
|
||||
knowledge.asyncGetFolderKnowledge(loading).then((res: any) => {
|
||||
datasetList.value = res.data
|
||||
})
|
||||
}
|
||||
|
||||
const open = (list: any) => {
|
||||
paragraphList.value = list
|
||||
getDataset()
|
||||
formRef.value?.clearValidate()
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
|
@ -136,13 +163,16 @@ const submitForm = async (formEl: FormInstance | undefined) => {
|
|||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
const obj = {
|
||||
id_list: paragraphList.value,
|
||||
}
|
||||
paragraphApi
|
||||
.putMigrateMulParagraph(
|
||||
id,
|
||||
documentId,
|
||||
form.value.dataset_id,
|
||||
form.value.knowledge_id,
|
||||
form.value.document_id,
|
||||
paragraphList.value,
|
||||
obj,
|
||||
loading,
|
||||
)
|
||||
.then(() => {
|
||||
|
|
|
|||
|
|
@ -83,27 +83,34 @@
|
|||
ghostClass="ghost"
|
||||
>
|
||||
<template v-for="(item, index) in paragraphDetail" :key="item.id">
|
||||
<div :id="`m${item.id}`" style="display: flex; margin-bottom: 16px">
|
||||
<div :id="`m${item.id}`" class="flex mb-16">
|
||||
<!-- 批量操作 -->
|
||||
<div class="paragraph-card flex" v-if="isBatch === true">
|
||||
<div class="paragraph-card flex w-full" v-if="isBatch === true">
|
||||
<el-checkbox :value="item.id" />
|
||||
<ParagraphCard :data="item" class="mb-8 w-full" />
|
||||
<ParagraphCard
|
||||
:data="item"
|
||||
class="mb-8 w-full"
|
||||
@refresh="refresh"
|
||||
@refreshMigrateParagraph="refreshMigrateParagraph"
|
||||
:disabled="true"
|
||||
/>
|
||||
</div>
|
||||
<!-- 非批量操作 -->
|
||||
<div class="handle paragraph-card flex" :id="item.id" v-else>
|
||||
<div class="handle paragraph-card flex w-full" :id="item.id" v-else>
|
||||
<img
|
||||
src="@/assets/sort.svg"
|
||||
alt=""
|
||||
height="15"
|
||||
class="handle-img mr-8 mt-24 cursor"
|
||||
/>
|
||||
|
||||
<ParagraphCard
|
||||
:data="item"
|
||||
class="mb-8 w-full"
|
||||
@changeState="changeState"
|
||||
@deleteParagraph="deleteParagraph"
|
||||
/>
|
||||
</div>
|
||||
<ParagraphCard
|
||||
:data="item"
|
||||
class="mb-8 w-full"
|
||||
@changeState="changeState"
|
||||
@deleteParagraph="deleteParagraph"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</VueDraggable>
|
||||
|
|
@ -151,6 +158,7 @@ import { VueDraggable } from 'vue-draggable-plus'
|
|||
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||
import useStore from '@/stores'
|
||||
import { t } from '@/locales'
|
||||
import disable$ from 'dingtalk-jsapi/api/ui/pullToRefresh/disable'
|
||||
const { paragraph } = useStore()
|
||||
const route = useRoute()
|
||||
const {
|
||||
|
|
@ -192,7 +200,10 @@ function changeState(id: string) {
|
|||
paragraphDetail.value[index].is_active = !paragraphDetail.value[index].is_active
|
||||
}
|
||||
|
||||
function refreshMigrateParagraph() {
|
||||
function refreshMigrateParagraph(data: any) {
|
||||
if (data) {
|
||||
multipleSelection.value = data
|
||||
}
|
||||
paragraphDetail.value = paragraphDetail.value.filter(
|
||||
(v) => !multipleSelection.value.includes(v.id),
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue