2025/5/21 分段批量新增 导入 导出 功能

[new feat]  分段批量新增 导入 导出 功能
This commit is contained in:
陈昱达
2025-05-21 11:09:39 +08:00
parent 66fcfd7614
commit c93ad5a836
6 changed files with 394 additions and 40 deletions

View File

@@ -266,7 +266,8 @@ export function datasetQuerySegments(data) {
return request({
url: getUrl(`/datasetDocumentEx/querySegments`),
method: 'get',
params: data
params: data,
noLoading: true
})
}
@@ -446,3 +447,24 @@ export function segmentCreate(data) {
data
})
}
// 分段模板
export function segmentTemplate(model) {
// model 分别时 qa general
return getUrl(`/template/download/${model}`)
}
// 导入分段
export function importSegment(data) {
return request({
url: getUrl(`/datasetDocumentEx/segment/batchImport`),
method: 'post',
data
})
}
// 导出分段
export function exportSegment(data) {
return getUrl(
`/datasetDocumentEx/segment/export?documentId=${data.documentId}`
)
}

View File

@@ -7,3 +7,16 @@
cursor: pointer;
color: $--color-primary;
}
//
//.el-button {
// &.el-dropdown__caret-button {
// padding-left: 5px;
// padding-right: 5px;
// }
//}
.el-dropdown {
& .el-dropdown__caret-button {
padding-left: 5px;
padding-right: 5px;
}
}

View File

@@ -0,0 +1,160 @@
<template>
<div class="container batchAdd-container">
<!-- 文件上传区域 -->
<div
@click.stop="createFile"
@dragover.prevent="handleDragOver"
@dragleave.prevent="handleDragLeave"
@drop.prevent="handleDrop"
class="upload-container"
:class="{ 'drag-over': isDragOver }"
>
<el-empty v-if="fileList.length === 0">
<template #image>
<img :src="uploadPng" alt="" style="width: 50px;height: 50px;" />
</template>
<template #description>
<div class="flex flex-direction-c">
<span class="upload-tip">点击或将文件拖拽到这里上传</span>
</div>
</template>
</el-empty>
<div v-else @click.stop="">
<div
class="file-preview-container align-items-c justify-content-b mh20"
v-for="item in fileList"
>
<div class="flex align-items-c fs12">
<img
:src="uploadPng"
alt="CSV Icon"
style="width: 25px;height: 30px"
/>
<span class="file-name fs12 ml20 fw500">{{ item.name }}</span>
</div>
<div>
<el-button type="primary" size="medium" @click.stop="removeFile(0)"
>移除</el-button
>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import uploadPng from '@/assets/images/konwledge/upload.png'
export default {
name: 'batchAddSegment',
data() {
return {
uploadPng,
fileList: [], // 文件列表
isDragOver: false
}
},
watch: {
fileList: {
handler(newValue, oldValue) {
if (newValue.length > 0) {
this.$emit('getFileList', newValue)
} else {
this.$emit('getFileList', [])
}
}
}
},
methods: {
// 生成filed
createFile() {
let input = document.createElement('input')
input.type = 'file'
input.accept = '.xlsx,.doc,.docx,.pdf,.txt'
input.onchange = e => {
const newFiles = Array.from(e.target.files)
if (this.fileList.length + newFiles.length > 1) {
this.$message.error('最多只能上传1个文件')
return
}
this.fileList = [...this.fileList, ...newFiles]
}
input.click()
},
// 新增:移除文件
removeFile(index) {
this.fileList.splice(index, 1)
},
handleDragOver() {
this.isDragOver = true
},
handleDragLeave() {
this.isDragOver = false
},
handleDrop(event) {
this.isDragOver = false
const files = event.dataTransfer.files
if (this.fileList.length + files.length > 1) {
this.$message.error('最多只能上传1个文件')
return
}
this.fileList = [...this.fileList, ...Array.from(files)]
}
}
}
</script>
<style scoped lang="scss">
.file-preview-container {
display: flex;
align-items: center;
//background-color: #f5f5f5; // 灰色背景
padding: 15px 10px;
border-radius: 4px;
}
.file-name {
margin-left: 10px;
color: #333;
}
.upload-container {
border-radius: 6px;
border-style: dashed;
border-width: 1px;
border-color: #d9d9d9;
text-align: center;
&:hover {
border-color: var(--color-primary);
}
&.drag-over {
border-color: var(--color-primary);
background-color: #ecf5ff;
}
}
.upload-tip {
font-family: PingFangSC, PingFang SC;
font-weight: 500;
font-size: 14px;
color: #5f5e68;
font-style: normal;
}
.upload-tip-field {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 13px;
color: #b1b5c7;
font-style: normal;
}
</style>

View File

@@ -269,6 +269,13 @@ import SearchSetting from '@/views/knowledge/detail/components/SearchSetting/Ind
import { displayStatus } from '@/assets/js/utils/utilOptions'
export default {
name: 'index',
// 父子组件共享
provide() {
return {
viewDocumentDetail: row => this.viewDocumentDetail(row)
}
},
data() {
return {
displayStatus,
@@ -456,24 +463,36 @@ export default {
},
// 查看文档详情
viewDocumentDetail(row) {
// 调用查询分段信息接口
datasetQuerySegments({ documentId: row.id }).then(res => {
if (res) {
this.descriptions = {
dataset: {
knowledgeName: this.knowledgeName,
segmentedMode: this.segmentedMode,
knowledgeImage: this.knowledgeImage
},
...row,
...res.content.content
}
this.drawer = true
// 调用datasetDocumentEx接口获取分词规则和词频规则
this.getDocumentExInfo(row.id)
this.descriptions = {
...row,
dataset: {
knowledgeName: this.knowledgeName,
segmentedMode: this.segmentedMode,
knowledgeImage: this.knowledgeImage
}
})
}
this.drawer = true
this.getDocumentExInfo(row.id)
// // 调用查询分段信息接口
// datasetQuerySegments({ documentId: row.id }).then(res => {
// if (res) {
// // this.descriptions = JSON.parse(
// // JSON.stringify({
// // dataset: {
// // knowledgeName: this.knowledgeName,
// // segmentedMode: this.segmentedMode,
// // knowledgeImage: this.knowledgeImage
// // },
// // ...row,
// // ...res.content.content
// // })
// // )
// this.drawer = true
//
// // 调用datasetDocumentEx接口获取分词规则和词频规则
// this.getDocumentExInfo(row.id)
// }
// })
},
jumpToUpload(params) {

View File

@@ -142,7 +142,7 @@
class="el-card review"
>
<div class="title flex align-items-c" style="gap: 10px">
<el-dropdown @command="command">
<el-dropdown @command="command" trigger="click">
<span class="el-dropdown-link">
{{
documentDetail.length > 0

View File

@@ -1,21 +1,42 @@
<script>
import { datasetQuerySegments, getPdfUrl, queryTask } from '@/api/generatedApi'
import {
datasetQuerySegments,
importSegment,
queryTask,
segmentTemplate,
exportSegment
} from '@/api/generatedApi'
import TextModel from '@/views/knowledge/detail/components/documentDetail/TextModel.vue'
import QAModel from '@/views/knowledge/detail/components/documentDetail/QAModel.vue'
import RenderFile from '@/components/RenderFile/Index.vue'
import MetadataOperator from '@/views/knowledge/detail/components/metaData/MetadataOperator.vue'
import AddSegment from '@/views/knowledge/detail/components/documentDetail/addSegment.vue'
import BatchAddSegment from '@/views/knowledge/detail/components/documentDetail/batchAddSegment.vue'
import { Form } from 'element-ui'
export default {
name: 'index',
components: { MetadataOperator, QAModel, TextModel, RenderFile, AddSegment },
components: {
MetadataOperator,
QAModel,
TextModel,
RenderFile,
AddSegment,
BatchAddSegment
},
data() {
return {
searchText: '',
batchAddSegmentDialog: false,
iframeSrc: window.location.origin,
newForm: {},
descriptions: null,
addSegmentDialog: false
addSegmentDialog: false,
batchSegmentList: []
}
},
inject: ['viewDocumentDetail'],
props: {
noEdit: {
type: Boolean,
@@ -76,23 +97,64 @@ export default {
}
},
methods: {
// 新增分段
addSegment() {
this.addSegmentDialog = true
},
importSegmentToKnowledge() {
let form = new FormData()
form.append('documentId', this.form.id)
if (this.batchSegmentList.length === 0) {
this.$message.error('请先选择文件')
return
}
toSplit() {
this.$router.push({
path: '/knowledge/detail/create',
query: {
documentId: this.form.id,
datasetId: this.form.datasetId,
activeLevel: 1
this.batchSegmentList.map(item => {
form.append('file', item)
})
importSegment(form).then(res => {
if (res) {
this.$message.success('导入成功')
this.batchAddSegmentDialog = false
this.batchSegmentList = []
this._getSplitResultPreview()
}
})
},
getPdfUrl,
getFileList(list) {
this.batchSegmentList = list
},
downLoadSegmentTemplate() {
let model = null
switch (this.newForm.segmentedMode) {
case 0:
model = 'general'
break
case 1:
model = 'qa'
break
default:
model = 'general'
return ''
}
window.open(segmentTemplate(model))
},
command(type) {
switch (type) {
case 'newAdd':
// 批量新增
this.batchAddSegmentDialog = true
break
case 'exportSeg':
// 导出分段
window.open(exportSegment({ documentId: this.form.id }))
break
}
},
// 新增分段
addSegment() {
this._getSplitResultPreview()
// this.addSegmentDialog = true
},
_getTaskDetail() {
queryTask({ id: this.form.id }).then(res => {
const { content } = res.content
@@ -100,6 +162,9 @@ export default {
})
},
_getSplitResultPreview() {
if (this.descriptions && this.descriptions.data) {
this.descriptions.data = []
}
datasetQuerySegments({ documentId: this.form.id }).then(res => {
this.descriptions = res.content.content
})
@@ -169,14 +234,31 @@ export default {
</div>
<div class="card-body">
<div :class="!noEdit ? 'mt10' : 'mt40'">
<el-button
class="line-button"
size="medium"
<div class="flex align-items-c mt10" style="gap:20px">
<el-dropdown
trigger="click"
v-if="!noEdit"
split-button
size="medium"
type="primary"
@click="addSegment"
>新增分段</el-button
class="line-button"
@command="command"
>
新增分段
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="newAdd">批量新增</el-dropdown-item>
<el-dropdown-item command="exportSeg">分段导出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-input
style="width: 50vh;"
size="small"
disabled
placeholder="分段搜索"
v-model="searchText"
></el-input>
</div>
<el-row :gutter="20" class="mt10">
<!-- 左侧表单内容和知识内容 -->
@@ -189,18 +271,24 @@ export default {
>
<!-- 知识内容 -->
<div class="content-card el-card ">
<div class="knowledge-content" v-if="descriptions">
<div
class="knowledge-content"
v-if="descriptions"
v-loading="descriptions.data && descriptions.data.length <= 0"
>
<text-model
:noEdit="noEdit"
v-if="descriptions.doc_form === 'text_model'"
:descriptions="descriptions"
:parentForm="form"
:key="descriptions.data.length"
/>
<q-a-model
:noEdit="noEdit"
v-else-if="descriptions.doc_form === 'qa_model'"
:descriptions="descriptions"
:parentForm="form"
:key="descriptions.data.length"
/>
</div>
<div v-else class="p20 flex align-items-c">
@@ -247,10 +335,51 @@ export default {
@close="addSegmentDialog = false"
></add-segment>
</el-drawer>
<r-dialog
title="批量新增"
:visible.sync="batchAddSegmentDialog"
append-to-body
width="40%"
destroy-on-close
>
<template slot="title">
<div class="flex align-items-c">
<div>批量新增</div>
<el-button
size="mini"
type="text"
class="ml20"
icon="el-icon-download"
@click="downLoadSegmentTemplate"
>下载模板</el-button
>
</div>
</template>
<batch-add-segment
:document-id="form.id"
@close="batchAddSegmentDialog = false"
@getFileList="getFileList"
></batch-add-segment>
<div slot="footer">
<el-button @click="batchAddSegmentDialog = false" size="medium"
>取消</el-button
>
<el-button
size="medium"
type="primary"
:disabled="batchSegmentList.length < 1"
@click="importSegmentToKnowledge"
>导入</el-button
>
</div>
</r-dialog>
</div>
</template>
<style lang="scss" scoped>
@import '@/assets/sass/renderSass/theme.scss';
.form-container {
background: #fff;
padding: 5px;
@@ -290,4 +419,15 @@ export default {
.clearfix:after {
clear: both;
}
::v-deep .line-button {
background: $--color-primary-button-gradient;
overflow: hidden;
border-radius: 8px;
& .el-button-group {
& .el-button {
background: unset;
border: unset;
}
}
}
</style>