Merge branch 'main' of github.com:maxkb-dev/maxkb

This commit is contained in:
shaohuzhang1 2024-01-19 16:08:06 +08:00
commit 33a6347227
5 changed files with 204 additions and 100 deletions

View File

@ -103,22 +103,24 @@ const putDocument: (dataset_id: string, document_id: string, data: any) => Promi
* *
* @param dataset_id, document_id, * @param dataset_id, document_id,
*/ */
const delDocument: (dataset_id: string, document_id: string) => Promise<Result<boolean>> = ( const delDocument: (
dataset_id, dataset_id: string,
document_id document_id: string,
) => { loading?: Ref<boolean>
return del(`${prefix}/${dataset_id}/document/${document_id}`) ) => Promise<Result<boolean>> = (dataset_id, document_id, loading) => {
return del(`${prefix}/${dataset_id}/document/${document_id}`, loading)
}
/**
*
* @param dataset_id,
*/
const delMulDocument: (
dataset_id: string,
data: any,
loading?: Ref<boolean>
) => Promise<Result<boolean>> = (dataset_id, data, loading) => {
return del(`${prefix}/${dataset_id}/document/_bach`, undefined, { id_list: data }, loading)
} }
// /**
// * 批量删除文档
// * @param 参数 dataset_id, document_id,
// */
// const delDocument: (dataset_id: string, document_id: string) => Promise<Result<boolean>> = (
// dataset_id,
// document_id
// ) => {
// return del(`${prefix}/${dataset_id}/document/${document_id}`)
// }
/** /**
* *
* @param dataset_id * @param dataset_id
@ -152,6 +154,37 @@ const putDocumentRefresh: (
) )
} }
/**
*
* @param dataset_id,
*/
const delMulSyncDocument: (
dataset_id: string,
data: any,
loading?: Ref<boolean>
) => Promise<Result<boolean>> = (dataset_id, data, loading) => {
return put(`${prefix}/${dataset_id}/document/_bach`, { id_list: data }, undefined, loading)
}
/**
* Web站点文档
* @param
* {
"source_url_list": [
"string"
],
"selector": "string"
}
}
*/
const postWebDocument: (
dataset_id: string,
data: any,
loading?: Ref<boolean>
) => Promise<Result<any>> = (dataset_id, data, loading) => {
return post(`${prefix}/${dataset_id}/document/web`, data, undefined, loading)
}
export default { export default {
postSplitDocument, postSplitDocument,
getDocument, getDocument,
@ -159,7 +192,10 @@ export default {
postDocument, postDocument,
putDocument, putDocument,
delDocument, delDocument,
delMulDocument,
getDocumentDetail, getDocumentDetail,
listSplitPattern, listSplitPattern,
putDocumentRefresh putDocumentRefresh,
delMulSyncDocument,
postWebDocument
} }

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.5 2H21.5C22.0523 2 22.5 2.44772 22.5 3V17C22.5 17.5523 22.0523 18 21.5 18H2.5C1.94772 18 1.5 17.5523 1.5 17V3C1.5 2.44772 1.94772 2 2.5 2ZM3.5 14V16H20.5V14H3.5Z" fill="white"/>
<path d="M6.5 20H17.5C17.7761 20 18 20.2239 18 20.5V21.5C18 21.7761 17.7761 22 17.5 22H6.5C6.22386 22 6 21.7761 6 21.5V20.5C6 20.2239 6.22386 20 6.5 20Z" fill="#D8D8D8"/>
</svg>

After

Width:  |  Height:  |  Size: 464 B

View File

@ -17,7 +17,6 @@
class="paragraph-source-card cursor mb-8" class="paragraph-source-card cursor mb-8"
:class="item.is_active ? '' : 'disabled'" :class="item.is_active ? '' : 'disabled'"
:showIcon="false" :showIcon="false"
@click="editParagraph(item)"
> >
<template #icon> <template #icon>
<AppAvatar :name="index + 1 + ''" class="mr-12 avatar-light" :size="22" /> <AppAvatar :name="index + 1 + ''" class="mr-12 avatar-light" :size="22" />
@ -45,13 +44,11 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-scrollbar> </el-scrollbar>
<ParagraphDialog ref="ParagraphDialogRef" title="分段详情" @refresh="refresh" />
</el-dialog> </el-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch, nextTick } from 'vue' import { ref, watch, nextTick } from 'vue'
import ParagraphDialog from '@/views/paragraph/component/ParagraphDialog.vue' import { cloneDeep } from 'lodash'
const emit = defineEmits(['refresh']) const emit = defineEmits(['refresh'])
const ParagraphDialogRef = ref() const ParagraphDialogRef = ref()
@ -64,21 +61,14 @@ watch(dialogVisible, (bool) => {
} }
}) })
const open = (data: any) => { const open = (data: any, id?: string) => {
detail.value = data detail.value = cloneDeep(data)
detail.value.paragraph_list = id
? detail.value.paragraph_list.filter((v) => v.dataset_id === id)
: detail.value.paragraph_list
dialogVisible.value = true dialogVisible.value = true
} }
function editParagraph(row: any) {
ParagraphDialogRef.value.open(row)
}
function refresh(data: any) {
if (data) {
const index = detail.value.paragraph_list.findIndex((v) => v.id === data.id)
detail.value.paragraph_list.splice(index, 1, data)
}
}
defineExpose({ open }) defineExpose({ open })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,29 +1,36 @@
<template> <template>
<el-dialog <el-dialog
title="同步知识库" title="导入文档"
v-model="dialogVisible" v-model="dialogVisible"
width="600px"
:close-on-click-modal="false" :close-on-click-modal="false"
:close-on-press-escape="false" :close-on-press-escape="false"
:destroy-on-close="true" :destroy-on-close="true"
> >
<p class="mb-8">同步方式</p> <el-form
<el-radio-group v-model="method" class="card__radio"> label-position="top"
<el-card shadow="never" class="mb-16" :class="method === 'replace' ? 'active' : ''"> ref="webFormRef"
<el-radio label="replace" size="large"> :rules="rules"
<p class="mb-4">替换同步</p> :model="form"
<el-text type="info">重新获取 Web 站点文档覆盖替换本地知识库中的文档</el-text> require-asterisk-position="right"
</el-radio> >
</el-card> <el-form-item label="文档地址" prop="source_url" v-if="isImport">
<el-input
<el-card shadow="never" class="mb-16" :class="method === 'complete' ? 'active' : ''"> v-model="form.source_url"
<el-radio label="complete" size="large"> placeholder="请输入文档地址,一行一个,地址不正确文档会导入失败。"
<p class="mb-4">整体同步</p> :rows="10"
<el-text type="info">先删除本地知识库所有文档重新获取 Web 站点文档</el-text> type="textarea"
</el-radio> />
</el-card> </el-form-item>
</el-radio-group> <el-form-item v-else label="文档地址" prop="source_url">
<p class="danger">注意所有同步都会删除已有数据重新获取新数据请谨慎操作</p> <el-input v-model="form.source_url" placeholder="请输入文档地址" />
</el-form-item>
<el-form-item label="选择器">
<el-input
v-model="form.selector"
placeholder="默认为 body可输入 .classname/#idname/tagname"
/>
</el-form-item>
</el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> 取消 </el-button> <el-button @click.prevent="dialogVisible = false"> 取消 </el-button>
@ -33,56 +40,61 @@
</el-dialog> </el-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from 'vue' import { ref, reactive, watch } from 'vue'
import { useRoute } from 'vue-router'
import documentApi from '@/api/document'
import { MsgSuccess } from '@/utils/message' import { MsgSuccess } from '@/utils/message'
import useStore from '@/stores' const route = useRoute()
const { dataset } = useStore() const {
params: { id }
} = route as any
const emit = defineEmits(['refresh']) const emit = defineEmits(['refresh'])
const loading = ref<boolean>(false) const loading = ref<boolean>(false)
const method = ref('replace') const isImport = ref<boolean>(false)
const datasetId = ref('') const form = ref<any>({
source_url: '',
selector: ''
})
const rules = reactive({
source_url: [{ required: true, message: '请输入 Web 根地址', trigger: 'blur' }]
})
const dialogVisible = ref<boolean>(false) const dialogVisible = ref<boolean>(false)
watch(dialogVisible, (bool) => { watch(dialogVisible, (bool) => {
if (!bool) { if (!bool) {
method.value = 'replace' form.value = {
source_url: '',
selector: ''
}
isImport.value = false
} }
}) })
const open = (id: string) => { const open = (row: any) => {
datasetId.value = id if (row) {
isImport.value = false
} else {
isImport.value = true
}
dialogVisible.value = true dialogVisible.value = true
} }
const submit = () => { const submit = () => {
dataset.asyncSyncDateset(datasetId.value, method.value, loading).then((res: any) => { const obj = {
// MsgSuccess('') source_url_list: form.value.source_url.split('\n'),
emit('refresh', res.data) selector: form.value.selector
}
documentApi.postWebDocument(id, obj, loading).then((res: any) => {
MsgSuccess('导入成功')
emit('refresh')
dialogVisible.value = false dialogVisible.value = false
}) })
} }
defineExpose({ open }) defineExpose({ open })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped></style>
.select-provider {
font-size: 16px;
color: rgba(100, 106, 115, 1);
font-weight: 400;
line-height: 24px;
cursor: pointer;
&:hover {
color: var(--el-color-primary);
}
}
.active-breadcrumb {
font-size: 16px;
color: rgba(31, 35, 41, 1);
font-weight: 500;
line-height: 24px;
}
</style>

View File

@ -10,9 +10,18 @@
@click="router.push({ path: '/dataset/upload', query: { id: id } })" @click="router.push({ path: '/dataset/upload', query: { id: id } })"
>上传文档</el-button >上传文档</el-button
> >
<el-button v-if="datasetDetail.type === '1'" type="primary">导入文档</el-button> <el-button v-if="datasetDetail.type === '1'" type="primary" @click="importDoc"
<!-- <el-button v-if="datasetDetail.type === '1'">批量同步</el-button> --> >导入文档</el-button
<el-button :disabled="multipleSelection.length === 0">批量删除</el-button> >
<el-button
@click="syncMulDocument"
:disabled="multipleSelection.length === 0"
v-if="datasetDetail.type === '1'"
>批量同步</el-button
>
<el-button @click="deleteMulDocument" :disabled="multipleSelection.length === 0"
>批量删除</el-button
>
</div> </div>
<el-input <el-input
@ -119,12 +128,14 @@
</el-tooltip> </el-tooltip>
<span @click.stop> <span @click.stop>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<span class="el-dropdown-link cursor"> <el-button text>
<el-icon><MoreFilled /></el-icon> <el-icon><MoreFilled /></el-icon>
</span> </el-button>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item icon="Setting">设置</el-dropdown-item> <el-dropdown-item icon="Setting" @click="settingDoc(row)"
>设置</el-dropdown-item
>
<el-dropdown-item icon="Delete" @click.stop="deleteDocument(row)" <el-dropdown-item icon="Delete" @click.stop="deleteDocument(row)"
>删除</el-dropdown-item >删除</el-dropdown-item
> >
@ -137,6 +148,7 @@
</el-table-column> </el-table-column>
</app-table> </app-table>
</div> </div>
<ImportDocumentDialog ref="ImportDocumentDialogRef" :title="title" @refresh="refresh" />
</div> </div>
</LayoutContainer> </LayoutContainer>
</template> </template>
@ -145,6 +157,7 @@ import { ref, onMounted, reactive, onBeforeUnmount } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { ElTable } from 'element-plus' import { ElTable } from 'element-plus'
import documentApi from '@/api/document' import documentApi from '@/api/document'
import ImportDocumentDialog from './component/ImportDocumentDialog.vue'
import { numberFormat } from '@/utils/utils' import { numberFormat } from '@/utils/utils'
import { datetimeFormat } from '@/utils/time' import { datetimeFormat } from '@/utils/time'
import { MsgSuccess, MsgConfirm } from '@/utils/message' import { MsgSuccess, MsgConfirm } from '@/utils/message'
@ -169,8 +182,19 @@ const paginationConfig = reactive({
total: 0 total: 0
}) })
const ImportDocumentDialogRef = ref()
const multipleTableRef = ref<InstanceType<typeof ElTable>>() const multipleTableRef = ref<InstanceType<typeof ElTable>>()
const multipleSelection = ref<any[]>([]) const multipleSelection = ref<any[]>([])
const title = ref('')
function importDoc() {
title.value = '导入文档'
ImportDocumentDialogRef.value.open()
}
function settingDoc(row: any) {
title.value = '设置'
ImportDocumentDialogRef.value.open(row)
}
const handleSelectionChange = (val: any[]) => { const handleSelectionChange = (val: any[]) => {
multipleSelection.value = val multipleSelection.value = val
@ -199,9 +223,22 @@ const closeInterval = () => {
} }
} }
function refreshDocument(row: any) { function refreshDocument(row: any) {
documentApi.putDocumentRefresh(row.dataset_id, row.id).then((res) => { if (row.type === '1') {
getList() MsgConfirm(`确认同步文档?`, `同步将删除已有数据重新获取新数据,请谨慎操作。`, {
}) confirmButtonText: '同步',
confirmButtonClass: 'danger'
})
.then(() => {
documentApi.putDocumentRefresh(row.dataset_id, row.id).then((res) => {
getList()
})
})
.catch(() => {})
} else {
documentApi.putDocumentRefresh(row.dataset_id, row.id).then((res) => {
getList()
})
}
} }
function rowClickHandle(row: any) { function rowClickHandle(row: any) {
@ -225,6 +262,32 @@ function creatQuickHandle(val: string) {
}) })
} }
function syncMulDocument() {
const arr: string[] = []
multipleSelection.value.map((v) => {
if (v) {
arr.push(v.id)
}
})
documentApi.delMulSyncDocument(id, arr, loading).then(() => {
MsgSuccess('批量同步成功')
getList()
})
}
function deleteMulDocument() {
const arr: string[] = []
multipleSelection.value.map((v) => {
if (v) {
arr.push(v.id)
}
})
documentApi.delMulDocument(id, arr, loading).then(() => {
MsgSuccess('批量删除成功')
getList()
})
}
function deleteDocument(row: any) { function deleteDocument(row: any) {
MsgConfirm( MsgConfirm(
`是否删除文档:${row.name} ?`, `是否删除文档:${row.name} ?`,
@ -235,16 +298,10 @@ function deleteDocument(row: any) {
} }
) )
.then(() => { .then(() => {
loading.value = true documentApi.delDocument(id, row.id, loading).then(() => {
documentApi MsgSuccess('删除成功')
.delDocument(id, row.id) getList()
.then(() => { })
MsgSuccess('删除成功')
getList()
})
.catch(() => {
loading.value = false
})
}) })
.catch(() => {}) .catch(() => {})
} }
@ -314,6 +371,11 @@ function getDetail() {
}) })
} }
function refresh() {
paginationConfig.current_page = 1
getList()
}
onMounted(() => { onMounted(() => {
getDetail() getDetail()
getList() getList()