Merge branch '分段预览'

# Conflicts:
#	chat-client/src/views/datasets/components/DocumentList.vue
This commit is contained in:
wenjinbo 2025-09-18 18:09:59 +08:00
commit 73b332de51
7 changed files with 417 additions and 197 deletions

View File

@ -0,0 +1,9 @@
import request from '@/utils/request'
export function getSegmentList(params: { datasetId: string; documentId: string }) {
return request({
url: '/brichat-service/documentSegment/selectSegments',
method: 'get',
params,
})
}

View File

@ -243,6 +243,7 @@
@success="handleUploadSuccess"
/>
</el-dialog>
<<<<<<< HEAD
<!-- 文件替换对话框 -->
<el-dialog
@ -281,16 +282,42 @@
/>
</el-dialog>
=======
>>>>>>> 分段预览
<!-- 预览抽屉 -->
<el-drawer
v-model="previewDrawerVisible"
:title="t('vabI18n.knowledge.document.preview.title')"
:direction="'rtl'"
size="60%"
size="80%"
class="preview-drawer"
:close-on-click-modal="false"
@close="handleClose"
>
<div v-loading="previewLoading">
<div v-loading="previewLoading" class="drawer-content-container" style="display: flex; height: 100%;">
<!-- 左侧分段数据容器 -->
<div class="segment-list-container" style="width: 30%; border-right: 1px solid #ebeef5; overflow-y: auto; padding: 10px;">
<h3>分段数据</h3>
<el-form v-if="segmentList.length > 0">
<el-form-item
v-for="(segment) in segmentList"
:key="segment.id"
style="cursor: pointer; margin-bottom: 5px;"
>
<span>分段{{segment.position}}</span>
<h4>{{segment.content}}</h4>
</el-form-item>
</el-form>
<div v-else>
暂无分段数据
</div>
</div>
<!-- 右侧原预览内容 -->
<div class="preview-content-container" style="flex: 1; padding: 10px; overflow-y: auto;">
<!-- TXT 文件预览 -->
<div v-if="previewFileType === 'txt'" class="text-preview-container">
<pre class="text-preview">{{ previewTextContent }}</pre>
@ -324,8 +351,10 @@
@error="errorHandler"
/>
</div>
</div>
</el-drawer>
<!-- 重命名对话框 -->
<el-dialog
v-model="renameDialogVisible"
@ -456,7 +485,8 @@
import { useRoute, useRouter } from 'vue-router'
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import VueOfficePdf from '@vue-office/pdf'
import { getDatasetDocPage, uploadDocument, deleteDocument, downloadDocument, previewDocumentUrl, renameDocument, createFolder, CreateFolderReq } from '@/api/dataset'
import { getDatasetDocPage, uploadDocument, deleteDocument, downloadDocument, previewDocumentUrl, renameDocument, createFolder, CreateFolderReq} from '@/api/dataset'
import {getSegmentList} from "@/api/Segment"
import DocUpload from './DocUpload.vue'
//VueOfficeDocx
import VueOfficeDocx from '@vue-office/docx'
@ -467,6 +497,7 @@ import VueOfficeExcel from '@vue-office/excel'
//
import '@vue-office/excel/lib/index.css'
import VueOfficePptx from '@vue-office/pptx'
// markdown
@ -539,7 +570,7 @@ folderName: [
{ pattern: /^[^<>:"/\\|?*]+$/, message: t('vabI18n.knowledge.document.createFolderDialog.rules.namePattern', '文件夹名称不能包含特殊字符'), trigger: 'blur' }
]
}
const segmentList= ref([])
//
const contextMenuVisible = ref(false)
const contextMenuPosition = reactive({
@ -559,7 +590,10 @@ name: string;
const handleClose = () => {
uploadDialogVisible.value = false
segmentList.value = []
}
//
@ -686,6 +720,10 @@ try {
}
)
const handleClose = () => {
previewDrawerVisible.value = false,
segmentList.value = []
}
const loading = ElLoading.service({
lock: true,
text: t('vabI18n.knowledge.document.messages.deleteing'),
@ -917,7 +955,6 @@ const handlePreview = async (row: FileItem) => {
previewDrawerVisible.value = true
previewLoading.value = true
console.log("row",row)
previewFileType.value = row.fileType;
try {
@ -935,6 +972,13 @@ const handlePreview = async (row: FileItem) => {
breaks: true,
gfm: true
})
const resp = await getSegmentList({
datasetId:datasetId.value,
documentId: row.difyDocId
})
if (resp.data?.length) {
segmentList.value = resp.data
}
previewMarkdownContent.value = marked.parse(content) as string
}
@ -2317,4 +2361,82 @@ transform: scale(0.9) translateY(-5px);
gap: 4px;
}
}
.segment-list-container {
width: 30%;
border-right: 1px solid #ebeef5;
overflow-y: auto;
padding: 16px;
background: #f9fafc;
display: flex;
flex-direction: column;
gap: 12px;
h3 {
margin-bottom: 12px;
font-size: 16px;
font-weight: 600;
color: #303133;
}
.el-form-item {
cursor: pointer;
padding: 16px; //
border-radius: 8px;
background: white;
transition: all 0.2s ease;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
min-height: 100px; //
display: flex;
flex-direction: column;
justify-content: center; //
&:hover {
background: #f0f4ff;
transform: translateX(2px);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
}
span {
font-size: 14px;
font-weight: 500;
color: #606266;
margin-top: 4px;
word-break: break-word; //
}
h4 {
font-family: "Microsoft YaHei", "微软雅黑", sans-serif; //
font-size: 14px;
font-weight: 600;
color: #4a4a4a;
margin: 0;
line-height: 1.6;
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-word;
}
}
.empty-state {
text-align: center;
color: #909399;
font-size: 14px;
margin-top: 20px;
}
}
/* 右侧预览内容保持原有样式 */
.preview-content-container {
flex: 1;
padding: 10px;
overflow-y: auto;
background: #ffffff;
border-radius: 0 8px 8px 0;
}
</style>

View File

@ -0,0 +1,29 @@
package com.bjtds.brichat.controller;
import com.bjtds.brichat.entity.dto.SegmentDto;
import com.bjtds.brichat.service.dify.DocumentSegmentService;
import com.bjtds.brichat.util.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.C;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.Comparator;
import java.util.List;
@RestController
@Slf4j
@CrossOrigin(value = "*", maxAge = 3600)
@RequestMapping("/documentSegment")
public class DocumentSegmentController {
@Autowired
private DocumentSegmentService documentSegmentService;
@GetMapping("/selectSegments")
public ResultUtils SelectSegments(@RequestParam("documentId") String documentId, @RequestParam("datasetId") String datasetId) {
List<SegmentDto> segments = documentSegmentService.SelectSegments(documentId, datasetId);
segments.sort(Comparator.comparing(SegmentDto::getPosition));
return ResultUtils.success(segments);
}
}

View File

@ -0,0 +1,13 @@
package com.bjtds.brichat.mapper.postgresql;
import com.bjtds.brichat.entity.dto.SegmentDto;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface DifyDocumentSegmentMapper {
List<SegmentDto> SelectSegmentsByDocumentIdAndDatasetId(String documentId, String datasetId);
}

View File

@ -0,0 +1,10 @@
package com.bjtds.brichat.service.dify;
import com.bjtds.brichat.entity.dto.SegmentDto;
import java.util.List;
public interface DocumentSegmentService {
List<SegmentDto> SelectSegments(String documentId, String datasetId);
}

View File

@ -0,0 +1,22 @@
package com.bjtds.brichat.service.dify.impl;
import com.bjtds.brichat.entity.dto.SegmentDto;
import com.bjtds.brichat.mapper.postgresql.DifyDocumentSegmentMapper;
import com.bjtds.brichat.service.dify.DocumentSegmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
@Service
public class DocumentSegmentServiceImpl implements DocumentSegmentService {
@Autowired
private DifyDocumentSegmentMapper difyDocumentSegmentMapper;
@Override
public List<SegmentDto> SelectSegments(String documentId, String datasetId) {
return difyDocumentSegmentMapper.SelectSegmentsByDocumentIdAndDatasetId(documentId, datasetId);
}
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjtds.brichat.mapper.postgresql.DifyDocumentSegmentMapper">
<select id="SelectSegmentsByDocumentIdAndDatasetId" resultType="com.bjtds.brichat.entity.dto.SegmentDto">
select *
from document_segments
where
<if test="documentId != null">
document_id = CAST(#{documentId} as uuid) and
</if>
<if test="datasetId != null">
dataset_id = CAST(#{datasetId} as uuid)
</if>
</select>
</mapper>