fix:1文件名过长抛出,2限制上传doc,3.修改创建索引调用方法.4.延迟解析失效时间

This commit is contained in:
wenjinbo 2025-09-19 16:35:07 +08:00
parent 73b332de51
commit c9fb5d8021
9 changed files with 113 additions and 31 deletions

View File

@ -24,8 +24,7 @@
:on-change="handleFileChange" :on-change="handleFileChange"
:file-list="[]" :file-list="[]"
:show-file-list="false" :show-file-list="false"
:limit="10" accept=".txt,.md,.markdown,.mdx,.pdf,.html,.htm,.xlsx,.xls,.docx,.csv,.vtt,.properties"
accept=".txt,.md,.markdown,.mdx,.pdf,.html,.htm,.xlsx,.xls,.doc,.docx,.csv,.vtt,.properties"
class="upload-area" class="upload-area"
:class="{ 'is-dragover': isDragOver }" :class="{ 'is-dragover': isDragOver }"
@drop="handleDrop" @drop="handleDrop"
@ -38,7 +37,7 @@
</el-icon> </el-icon>
<div class="upload-text"> <div class="upload-text">
<h4>拖拽文件到此处 <span class="link-text">点击选择</span></h4> <h4>拖拽文件到此处 <span class="link-text">点击选择</span></h4>
<p>支持 TXTMDPDFWordExcelHTMLCSV 等格式</p> <p>支持 TXTMDPDFDOCXExcelHTMLCSV 等格式不支持DOC格式</p>
<p>单个文件不超过 100MB最多可选择 10 个文件</p> <p>单个文件不超过 100MB最多可选择 10 个文件</p>
</div> </div>
</div> </div>
@ -330,7 +329,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, computed } from 'vue' import { ref, reactive, computed, nextTick } from 'vue'
import { ElMessage, ElNotification, ElLoading } from 'element-plus' import { ElMessage, ElNotification, ElLoading } from 'element-plus'
import type { UploadFile as ElUploadFile } from 'element-plus' import type { UploadFile as ElUploadFile } from 'element-plus'
import { import {
@ -373,6 +372,7 @@ const uploading = ref(false)
const uploadFiles = ref<ElUploadFile[]>([]) const uploadFiles = ref<ElUploadFile[]>([])
const isDragOver = ref(false) const isDragOver = ref(false)
const uploadRef = ref() const uploadRef = ref()
const isProcessingFileLimit = ref(false)
// //
const analysisMode = [ const analysisMode = [
@ -452,14 +452,55 @@ const getStep3Icon = () => {
// //
const handleFileChange = (file: ElUploadFile, fileList: ElUploadFile[]) => { const handleFileChange = (file: ElUploadFile, fileList: ElUploadFile[]) => {
//
if (isProcessingFileLimit.value) {
return
}
// //
if (file.size && file.size > 100 * 1024 * 1024) { if (file.size && file.size > 100 * 1024 * 1024) {
ElMessage.error('文件大小不能超过 100MB') ElMessage.error('文件大小不能超过 100MB')
return false return false
} }
// // 1010
uploadFiles.value = fileList if (fileList.length > 10) {
isProcessingFileLimit.value = true
const truncatedList = fileList.slice(0, 10)
const removedCount = fileList.length - 10
ElMessage.warning({
message: `已选择 ${fileList.length} 个文件,超出限制。系统已自动保留前 10 个文件,移除了 ${removedCount} 个文件。`,
duration: 4000,
showClose: true
})
//
uploadFiles.value = truncatedList
//
nextTick(() => {
if (uploadRef.value) {
uploadRef.value.clearFiles()
// 10
truncatedList.forEach(uploadFile => {
if (uploadFile.raw) {
uploadRef.value.handleStart(uploadFile.raw)
}
})
}
//
setTimeout(() => {
isProcessingFileLimit.value = false
}, 100)
})
} else {
//
uploadFiles.value = fileList
}
} }
const handleDrop = () => { const handleDrop = () => {
@ -579,7 +620,7 @@ const handleUpload = async () => {
await deleteDocument(parseInt(props.replaceFileId)) await deleteDocument(parseInt(props.replaceFileId))
deleteLoading.close() deleteLoading.close()
// // X
const uploadLoading = ElLoading.service({ const uploadLoading = ElLoading.service({
lock: true, lock: true,
text: '正在上传新文件...', text: '正在上传新文件...',

View File

@ -88,6 +88,7 @@
:header-row-style="{ height: '50px' }" :header-row-style="{ height: '50px' }"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
@row-dblclick="handleRowDoubleClick" @row-dblclick="handleRowDoubleClick"
@sort-change="handleSortChange"
> >
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column <el-table-column
@ -97,7 +98,7 @@
type="index" type="index"
:index="indexMethod" :index="indexMethod"
/> />
<el-table-column prop="fileName" :label="t('vabI18n.knowledge.document.table.fileName')" min-width="250"> <el-table-column prop="fileName" :label="t('vabI18n.knowledge.document.table.fileName')" min-width="250" sortable="custom" :sort-orders="['ascending', 'descending']">
<template #default="{ row }"> <template #default="{ row }">
<div class="file-name-cell"> <div class="file-name-cell">
<img <img
@ -132,8 +133,8 @@
<span v-else class="folder-status">--</span> <span v-else class="folder-status">--</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="createDate" :label="t('vabI18n.knowledge.document.table.createDate')" width="180" /> <el-table-column prop="createDate" :label="t('vabI18n.knowledge.document.table.createDate')" width="180" sortable="custom" :sort-orders="['ascending', 'descending']" />
<el-table-column prop="charCount" :label="t('vabI18n.knowledge.document.table.charCount')" width="120" align="right"> <el-table-column prop="charCount" :label="t('vabI18n.knowledge.document.table.charCount')" width="120" align="right" sortable="custom" :sort-orders="['ascending', 'descending']">
<template #default="{ row }"> <template #default="{ row }">
<span class="char-count" v-if="row.type === 'file'">{{ formatFileSize(row.charCount) }}</span> <span class="char-count" v-if="row.type === 'file'">{{ formatFileSize(row.charCount) }}</span>
<span v-else class="folder-indicator">--</span> <span v-else class="folder-indicator">--</span>
@ -243,7 +244,6 @@
@success="handleUploadSuccess" @success="handleUploadSuccess"
/> />
</el-dialog> </el-dialog>
<<<<<<< HEAD
<!-- 文件替换对话框 --> <!-- 文件替换对话框 -->
<el-dialog <el-dialog
@ -282,9 +282,6 @@
/> />
</el-dialog> </el-dialog>
=======
>>>>>>> 分段预览
<!-- 预览抽屉 --> <!-- 预览抽屉 -->
<el-drawer <el-drawer
@ -683,6 +680,12 @@ size: 20,
total: 0 total: 0
}) })
//
const sortConfig = reactive({
orderBy: 'name',
orderDirection: 'ASC'
})
// //
const fileList = ref<FileItem[]>([]) const fileList = ref<FileItem[]>([])
@ -1039,8 +1042,8 @@ try {
difyDatasetId: datasetId.value, difyDatasetId: datasetId.value,
parentId: currentParentId.value, // 使ID parentId: currentParentId.value, // 使ID
fileName: searchKeyword.value || undefined, fileName: searchKeyword.value || undefined,
orderBy: 'name', orderBy: sortConfig.orderBy,
orderDirection: 'ASC', orderDirection: sortConfig.orderDirection,
pageNo: pagination.current, pageNo: pagination.current,
pageSize: pagination.size pageSize: pagination.size
} }
@ -1194,6 +1197,25 @@ pagination.current = 1
fetchDocuments() fetchDocuments()
} }
//
const handleSortChange = (sortInfo: any) => {
if (sortInfo.prop && sortInfo.order) {
//
const fieldMapping: Record<string, string> = {
'fileName': 'name',
'createDate': 'created_at',
'charCount': 'size'
}
sortConfig.orderBy = fieldMapping[sortInfo.prop] || sortInfo.prop
sortConfig.orderDirection = sortInfo.order === 'ascending' ? 'ASC' : 'DESC'
//
pagination.current = 1
fetchDocuments()
}
}
// //
const handleOpenFolder = (row: FileItem) => { const handleOpenFolder = (row: FileItem) => {
// ID // ID

View File

@ -50,7 +50,11 @@ public class TDatasetFiles {
* 文件大小(字节)文件夹通常为0或子项总和 * 文件大小(字节)文件夹通常为0或子项总和
*/ */
private Long size; private Long size;
/**
* 字符数量
*/
// private String charCount;
//
/** /**
* 所有者用户ID * 所有者用户ID
*/ */

View File

@ -247,7 +247,7 @@ public class DeepAnalysisQueueService {
Map<Object, Object> taskInfo = redisTemplate.opsForHash().entries(taskInfoKey); Map<Object, Object> taskInfo = redisTemplate.opsForHash().entries(taskInfoKey);
Integer fileId = (Integer) taskInfo.get("fileId"); Integer fileId = (Integer) taskInfo.get("fileId");
if (fileId != null) { if (fileId != null) {
updateFileStatus(fileId, IndexingStatusEnum.ERROR.getCode()); updateFileStatus(fileId, IndexingStatusEnum.FAILED.getCode());
} }
} catch (Exception ex) { } catch (Exception ex) {
logger.error("更新文件状态失败: {}", ex.getMessage(), ex); logger.error("更新文件状态失败: {}", ex.getMessage(), ex);

View File

@ -162,13 +162,13 @@ public class DifyDatasetApiServiceImpl implements DifyDatasetApiService {
System.currentTimeMillis() - stepStartTime, originalFilename, fileExtension); System.currentTimeMillis() - stepStartTime, originalFilename, fileExtension);
// 2. 处理DOC文件转换 // 2. 处理DOC文件转换
if (documentConversionService.isDocFile(fileExtension)) { // if (documentConversionService.isDocFile(fileExtension)) {
stepStartTime = System.currentTimeMillis(); // stepStartTime = System.currentTimeMillis();
logger.info("检测到DOC文件开始转换: {}", originalFilename); // logger.info("检测到DOC文件开始转换: {}", originalFilename);
file = documentConversionService.convertDocToDocx(file, originalFilename); // file = documentConversionService.convertDocToDocx(file, originalFilename);
logger.info("DOC转换完成耗时: {} ms新文件名: {}", // logger.info("DOC转换完成耗时: {} ms新文件名: {}",
System.currentTimeMillis() - stepStartTime, file.getOriginalFilename()); // System.currentTimeMillis() - stepStartTime, file.getOriginalFilename());
} // }
// 5. 如果是深度解析提交到队列处理 // 5. 如果是深度解析提交到队列处理
@ -228,6 +228,8 @@ public class DifyDatasetApiServiceImpl implements DifyDatasetApiService {
// 7. 上传后处理 // 7. 上传后处理
stepStartTime = System.currentTimeMillis(); stepStartTime = System.currentTimeMillis();
Map<String, String> document = (Map<String, String>) res.getBody().get("document"); Map<String, String> document = (Map<String, String>) res.getBody().get("document");
long wordCount = Long.parseLong(document.get("word_count"));
//批次号 //批次号
String batch= (String) res.getBody().get("batch"); String batch= (String) res.getBody().get("batch");
String documentId = document.get("id"); String documentId = document.get("id");
@ -249,6 +251,7 @@ public class DifyDatasetApiServiceImpl implements DifyDatasetApiService {
String storagePath = difyUploadPath + "/" + getUUIDFilePath(documentId); String storagePath = difyUploadPath + "/" + getUUIDFilePath(documentId);
datasetFiles.setDifyStoragePath(storagePath); datasetFiles.setDifyStoragePath(storagePath);
datasetFiles.setSourceUrl(determineSourceUrl(sourceUrl, documentId)); datasetFiles.setSourceUrl(determineSourceUrl(sourceUrl, documentId));
// datasetFiles.setCharCount(String.valueOf(wordCount));
datasetFiles.setIsDeep(false); datasetFiles.setIsDeep(false);
datasetFiles.setIndexingStatus(IndexingStatusEnum.INDEXING.getCode()); datasetFiles.setIndexingStatus(IndexingStatusEnum.INDEXING.getCode());
TDatasetFiles savedFile = datasetFilesService.createFile(datasetFiles); TDatasetFiles savedFile = datasetFilesService.createFile(datasetFiles);
@ -268,6 +271,8 @@ public class DifyDatasetApiServiceImpl implements DifyDatasetApiService {
long totalTime = System.currentTimeMillis() - startTime; long totalTime = System.currentTimeMillis() - startTime;
logger.info("文档上传处理全部完成,总耗时: {} ms文件: {}", totalTime, originalFilename); logger.info("文档上传处理全部完成,总耗时: {} ms文件: {}", totalTime, originalFilename);
return res; return res;
} }

View File

@ -132,15 +132,22 @@ public class DatasetFilesServiceImpl implements DatasetFilesService {
if (!StringUtils.hasText(datasetFiles.getName())) { if (!StringUtils.hasText(datasetFiles.getName())) {
throw new IllegalArgumentException("文件/文件夹名称不能为空"); throw new IllegalArgumentException("文件/文件夹名称不能为空");
} }
if (StringUtils.hasText(datasetFiles.getName()) && datasetFiles.getName().length() > 100) {
throw new IllegalArgumentException("文件夹名称过长,需要小于100个字符");
}
if (!StringUtils.hasText(datasetFiles.getType())) { if (!StringUtils.hasText(datasetFiles.getType())) {
throw new IllegalArgumentException("类型不能为空"); throw new IllegalArgumentException("类型不能为空");
} }
if (!"file".equals(datasetFiles.getType()) && !"folder".equals(datasetFiles.getType())) { if (!"file".equals(datasetFiles.getType()) && !"folder".equals(datasetFiles.getType())) {
throw new IllegalArgumentException("类型必须是 file 或 folder"); throw new IllegalArgumentException("类型必须是 file 或 folder");
} }
// if (!StringUtils.hasText(datasetFiles.getDifyDatasetId())) { // if (!StringUtils.hasText(datasetFiles.getDifyDatasetId())) {
// throw new IllegalArgumentException("知识库ID不能为空"); // throw new IllegalArgumentException("知识库ID不能为空");
// } // }
if (datasetFiles.getOwnerId() == null) { if (datasetFiles.getOwnerId() == null) {
throw new IllegalArgumentException("所有者ID不能为空"); throw new IllegalArgumentException("所有者ID不能为空");
} }

View File

@ -113,6 +113,7 @@ public class EsTDatasetFilesServiceImpl implements EsTDatasetFilesService {
doc.getDifyStoragePath(), doc.getDifyStoragePath(),
doc.getSourceUrl(), doc.getSourceUrl(),
doc.getIsDeep(), doc.getIsDeep(),
true true
); );

View File

@ -8,6 +8,7 @@ import com.bjtds.brichat.service.DatasetFilesService;
import com.bjtds.brichat.service.EsKnowledgeService; import com.bjtds.brichat.service.EsKnowledgeService;
import com.bjtds.brichat.service.EsTDatasetFilesService; import com.bjtds.brichat.service.EsTDatasetFilesService;
import com.bjtds.brichat.service.IndexingTaskQueueService; import com.bjtds.brichat.service.IndexingTaskQueueService;
import com.bjtds.brichat.util.EsTDatasetFilesImporter;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
@ -37,7 +38,7 @@ public class IndexingStatusTaskService {
private DifyDatasetsDocMapper difyDatasetsDocMapper; private DifyDatasetsDocMapper difyDatasetsDocMapper;
@Resource @Resource
private EsTDatasetFilesService esTDatasetFilesService; private EsTDatasetFilesImporter esTDatasetFilesImporter;
/** /**
* 定时任务每1秒检查一次文档索引状态 * 定时任务每1秒检查一次文档索引状态
@ -101,7 +102,7 @@ public class IndexingStatusTaskService {
//添加索引到ES //添加索引到ES
esTDatasetFilesService.createIndex(task.getDocumentId()); esTDatasetFilesImporter.importDocumentId(task.getFileId());
//修改文件状态 //修改文件状态
TDatasetFiles file = datasetFilesService.getFileById(task.getFileId()); TDatasetFiles file = datasetFilesService.getFileById(task.getFileId());
if (file != null) { if (file != null) {

View File

@ -70,7 +70,7 @@ public class PdfConversionTaskService {
private static final String DEEP_ANALYSIS_PROCESSING = "deep_analysis:processing"; private static final String DEEP_ANALYSIS_PROCESSING = "deep_analysis:processing";
// PDF任务超时时间毫秒 // PDF任务超时时间毫秒
private static final long PDF_TASK_TIMEOUT_MS = 10 * 60 * 1000; // 10分钟 private static final long PDF_TASK_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1小时
/** /**
* 定时任务每3秒检查一次PDF转换任务状态 * 定时任务每3秒检查一次PDF转换任务状态
@ -208,9 +208,10 @@ public class PdfConversionTaskService {
String folderUrl = statusResponse.getFolderUrl(); String folderUrl = statusResponse.getFolderUrl();
String fileName = taskInfo.getName().split("\\.")[0] ; String originalName = taskInfo.getName();
String absolutePath = outputPath + fileName + "/" + fileName+".md"; int lastDotIndex = originalName.lastIndexOf('.');
String fileName = (lastDotIndex == -1) ? originalName : originalName.substring(0, lastDotIndex);
String absolutePath = outputPath + fileName + "/" + fileName + ".md";
logger.info("=== PDF转换任务完成 ==="); logger.info("=== PDF转换任务完成 ===");