|
|
@ -138,26 +138,46 @@ |
|
|
|
</div> |
|
|
|
|
|
|
|
<!--新增 / 编辑 表单组件--> |
|
|
|
<el-dialog class="preview-dialog" :modal-append-to-body="false" :close-on-click-modal="false" append-to-body :before-close="handleClose" :visible="formVisible" :title="formTitle"> |
|
|
|
<el-dialog :class="isAiAutoCategory ? 'preview-dialog ai-preview-dialog' :'preview-dialog'" :modal-append-to-body="false" :close-on-click-modal="false" append-to-body :before-close="handleClose" :visible="formVisible" :title="formTitle"> |
|
|
|
<span class="dialog-right-top" /> |
|
|
|
<span class="dialog-left-bottom" /> |
|
|
|
<div class="setting-dialog"> |
|
|
|
<!-- form @emitTableList="getTableList" --> |
|
|
|
<PreviewForm |
|
|
|
v-if="formPreviewData.length" |
|
|
|
ref="previewForm" |
|
|
|
:is-has-code="true" |
|
|
|
:is-disabled="false" |
|
|
|
:form-preview-data.sync="formPreviewData" |
|
|
|
:selected-category="selectedCategory" |
|
|
|
:arc-id="arcId" |
|
|
|
:is-des-form-type="isDesFormType" |
|
|
|
:is-title-type="isTitleType" |
|
|
|
:collect-level="collectLevel" |
|
|
|
:category-menu="categoryMenu" |
|
|
|
@close-dialog="closeDialog" |
|
|
|
/> |
|
|
|
<div style="display: flex; justify-content: flex-start;"> |
|
|
|
<PreviewForm |
|
|
|
v-if="formPreviewData.length" |
|
|
|
ref="previewForm" |
|
|
|
:is-has-code="true" |
|
|
|
:is-disabled="false" |
|
|
|
:form-preview-data.sync="formPreviewData" |
|
|
|
:selected-category="selectedCategory" |
|
|
|
:arc-id="arcId" |
|
|
|
:is-des-form-type="isDesFormType" |
|
|
|
:is-title-type="isTitleType" |
|
|
|
:collect-level="collectLevel" |
|
|
|
:category-menu="categoryMenu" |
|
|
|
@close-dialog="closeDialog" |
|
|
|
/> |
|
|
|
<div v-if="isAiAutoCategory" style="flex: 1; margin-left: 10px; "> |
|
|
|
<!-- AI辅助著录内容 --> |
|
|
|
<div style="display: flex; justify-content: flex-start;"> |
|
|
|
<div class="upload-btn"> |
|
|
|
<input id="upFile" type="file" name="upFile" multiple @change="changeAiFile($event)"> |
|
|
|
<el-button :loading="aiLoading" size="small" type="primary"><i :class="['iconfont', aiLoading ? 'icon-huoqu' : 'icon-shangchuan']" />{{ aiLoading ? 'AI辅助著录识别中' : '选择文件' }}</el-button> |
|
|
|
</div> |
|
|
|
<div style="flex: 1; margin-left: 10px; line-height: 34px; height: 106px; overflow: hidden; overflow-y: scroll;"> |
|
|
|
<div v-for="item in fileList" :key="item.name" class="file-list"> |
|
|
|
<i class="iconfont icon-xiaowenjian" /> |
|
|
|
{{ item.name }} |
|
|
|
<i class="el-icon-close" @click="deleteFile(item)" /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<pre v-if="aiJsonData" ref="typingContainer" v-highlightjs="displayedText">{{ displayedText }}</pre> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div slot="footer" class="dialog-footer" style="margin-top: 85px !important;"> |
|
|
|
<el-button type="primary" style="width: 84px;" @click="handleAiCategory">AI辅助著录</el-button> |
|
|
|
<el-button type="primary" @click="handlerArchivesSubmit">保存</el-button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
@ -244,6 +264,7 @@ import QuickPaper from './quickPaper/index' |
|
|
|
import PackingBox from './packingBox/index' |
|
|
|
import ArchivesFilling from './archivesFilling/index' |
|
|
|
import qs from 'qs' |
|
|
|
// getCurrentTime |
|
|
|
import { downloadFile, exportFile } from '@/utils/index' |
|
|
|
import { mapGetters } from 'vuex' |
|
|
|
|
|
|
@ -299,7 +320,14 @@ export default { |
|
|
|
quickPaper: false, |
|
|
|
quickPaperArcId: [], |
|
|
|
totalSumAll: 0, |
|
|
|
categoryMenu: [] |
|
|
|
categoryMenu: [], |
|
|
|
isAiAutoCategory: false, |
|
|
|
aiLoading: false, |
|
|
|
fileList: [], |
|
|
|
aiJsonData: null, |
|
|
|
displayedText: '', |
|
|
|
typingInterval: null, |
|
|
|
typingFinished: false |
|
|
|
} |
|
|
|
}, |
|
|
|
computed: { |
|
|
@ -1232,6 +1260,197 @@ export default { |
|
|
|
setTimeout(() => { |
|
|
|
this.handleSearch(this.collectLevel) |
|
|
|
}) |
|
|
|
}, |
|
|
|
handleAiCategory() { |
|
|
|
this.isAiAutoCategory = !this.isAiAutoCategory |
|
|
|
if (!this.isAiAutoCategory) { |
|
|
|
this.fileList = [] |
|
|
|
} |
|
|
|
}, |
|
|
|
async changeAiFile(e) { |
|
|
|
// 替换文件时清空 aiJsonData |
|
|
|
this.aiJsonData = null |
|
|
|
this.displayedText = '' |
|
|
|
this.typingFinished = false |
|
|
|
if (this.typingInterval) { |
|
|
|
clearInterval(this.typingInterval) |
|
|
|
} |
|
|
|
|
|
|
|
const selectedFiles = Array.from(e.target.files) |
|
|
|
const imageFiles = selectedFiles.filter(file => file.type.startsWith('image/')) |
|
|
|
const nonImageFiles = selectedFiles.filter(file => !file.type.startsWith('image/')) |
|
|
|
|
|
|
|
// 不允许同时选择图片和非图片文件 |
|
|
|
if (imageFiles.length > 0 && nonImageFiles.length > 0) { |
|
|
|
this.$message.error('不能同时选择图片和其他类型文件,请重新选择') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
const existingImageFiles = this.fileList.filter(item => item.formatType === 'image') |
|
|
|
const existingNonImageFiles = this.fileList.filter(item => item.formatType !== 'image') |
|
|
|
|
|
|
|
if (imageFiles.length > 0) { |
|
|
|
if (existingImageFiles.length > 0) { |
|
|
|
if (existingImageFiles.length + imageFiles.length > 3) { |
|
|
|
// 若加入新图片会超过 3 张,清空已有图片 |
|
|
|
this.fileList = this.fileList.filter(item => item.formatType !== 'image') |
|
|
|
} |
|
|
|
} else if (existingNonImageFiles.length > 0) { |
|
|
|
// 若已有非图片文件,清空已有非图片文件 |
|
|
|
this.fileList = this.fileList.filter(item => item.formatType === 'image') |
|
|
|
} |
|
|
|
|
|
|
|
// 检查图片文件数量 |
|
|
|
if (imageFiles.length > 3) { |
|
|
|
this.$message.error('图片文件最多只能选择 3 个,请重新选择') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
for (const file of imageFiles) { |
|
|
|
// 检查文件是否已存在 |
|
|
|
if (this.fileList.some(item => item.name === file.name)) { |
|
|
|
this.$message.warning(`文件 ${file.name} 已存在,请勿重复上传`) |
|
|
|
continue |
|
|
|
} |
|
|
|
|
|
|
|
const fileInfo = { |
|
|
|
file: file, |
|
|
|
size: file.size, |
|
|
|
formatType: file.type.substring(0, file.type.indexOf('/')), |
|
|
|
name: file.name, |
|
|
|
postfix: file.name.substring( |
|
|
|
file.name.lastIndexOf('.') + 1, |
|
|
|
file.name.length |
|
|
|
), |
|
|
|
px: '' |
|
|
|
} |
|
|
|
|
|
|
|
const fileBase64 = await this.getBase64(file) |
|
|
|
const res = await this.getImgPx(fileBase64) |
|
|
|
fileInfo.px = res.width + 'px*' + res.height + 'px' |
|
|
|
|
|
|
|
this.fileList.push(fileInfo) |
|
|
|
this.uploadSave() |
|
|
|
} |
|
|
|
} else if (nonImageFiles.length > 0) { |
|
|
|
if (existingNonImageFiles.length > 0) { |
|
|
|
// 若已有非图片文件,直接替换 |
|
|
|
this.fileList = this.fileList.filter(item => item.formatType === 'image') |
|
|
|
} else if (existingImageFiles.length > 0) { |
|
|
|
// 若已有图片文件,清空已有图片文件 |
|
|
|
this.fileList = this.fileList.filter(item => item.formatType !== 'image') |
|
|
|
} |
|
|
|
|
|
|
|
// 检查非图片文件数量 |
|
|
|
if (nonImageFiles.length > 1) { |
|
|
|
this.$message.error('非图片文件最多只能选择 1 个,请重新选择') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
for (const file of nonImageFiles) { |
|
|
|
// 检查文件是否已存在 |
|
|
|
if (this.fileList.some(item => item.name === file.name)) { |
|
|
|
this.$message.warning(`文件 ${file.name} 已存在,请勿重复上传`) |
|
|
|
continue |
|
|
|
} |
|
|
|
|
|
|
|
const fileInfo = { |
|
|
|
file: file, |
|
|
|
size: file.size, |
|
|
|
formatType: file.type.substring(0, file.type.indexOf('/')), |
|
|
|
name: file.name, |
|
|
|
postfix: file.name.substring( |
|
|
|
file.name.lastIndexOf('.') + 1, |
|
|
|
file.name.length |
|
|
|
), |
|
|
|
px: '' |
|
|
|
} |
|
|
|
|
|
|
|
this.fileList.push(fileInfo) |
|
|
|
this.uploadSave() |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
uploadSave() { |
|
|
|
this.aiLoading = true |
|
|
|
this.aiJsonData = null |
|
|
|
// this.$refs.previewForm.addOrUpdateForm = {} |
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
const json = `{ |
|
|
|
"fonds_no": "A001", |
|
|
|
"archival_category_code": "WSWJ", |
|
|
|
"archive_ctg_no": "SCGL", |
|
|
|
"archive_year": "2024", |
|
|
|
"retention": "永久", |
|
|
|
"item_no": "0005", |
|
|
|
"archive_no": "A001-WSWJ·SCGL-2024-Y-0005", |
|
|
|
"maintitle": "Windows下如何创建FTP文件夹", |
|
|
|
"keyword": "", |
|
|
|
"doc_no": "武汉飞天[2024]0005", |
|
|
|
"is_entity": 1, |
|
|
|
"id": "6C91AAD1F6D9940469F8B0" |
|
|
|
}` |
|
|
|
|
|
|
|
this.aiJsonData = json |
|
|
|
this.startTypingEffect() |
|
|
|
}, 3000) |
|
|
|
}, |
|
|
|
startTypingEffect() { |
|
|
|
const lines = this.aiJsonData.split('\n') |
|
|
|
let currentLineIndex = 0 |
|
|
|
this.displayedText = '' |
|
|
|
this.typingFinished = false |
|
|
|
|
|
|
|
this.typingInterval = setInterval(() => { |
|
|
|
if (currentLineIndex < lines.length) { |
|
|
|
this.displayedText += lines[currentLineIndex] + '\n' |
|
|
|
currentLineIndex++ |
|
|
|
} else { |
|
|
|
clearInterval(this.typingInterval) |
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
this.typingFinished = true |
|
|
|
this.$refs.previewForm.archivesType = 'add' |
|
|
|
this.$refs.previewForm.addOrUpdateForm = JSON.parse(this.aiJsonData) |
|
|
|
}, 1000) |
|
|
|
} |
|
|
|
|
|
|
|
// 滚动条始终保持在底部 |
|
|
|
const container = this.$refs.typingContainer |
|
|
|
if (container) { |
|
|
|
container.scrollTop = container.scrollHeight |
|
|
|
} |
|
|
|
this.aiLoading = false |
|
|
|
}, 200) |
|
|
|
}, |
|
|
|
deleteFile(item) { |
|
|
|
const index = this.fileList.indexOf(item) |
|
|
|
if (index !== -1) { |
|
|
|
this.fileList.splice(index, 1) |
|
|
|
} |
|
|
|
}, |
|
|
|
// 将上传的图片转为base64 |
|
|
|
getBase64(file) { |
|
|
|
const reader = new FileReader() |
|
|
|
reader.readAsDataURL(file) |
|
|
|
return new Promise((resolve) => { |
|
|
|
reader.onload = () => { |
|
|
|
resolve(reader.result) |
|
|
|
} |
|
|
|
}) |
|
|
|
}, |
|
|
|
// 获取图片的分辨率 |
|
|
|
getImgPx(img) { |
|
|
|
const image = new Image() |
|
|
|
image.src = img |
|
|
|
return new Promise((resolve) => { |
|
|
|
image.onload = () => { |
|
|
|
const width = image.width |
|
|
|
const height = image.height |
|
|
|
resolve({ width, height }) |
|
|
|
} |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -1268,4 +1487,25 @@ export default { |
|
|
|
::v-deep.vue-treeselect--has-value .vue-treeselect__single-value{ |
|
|
|
font-size: 14px; |
|
|
|
} |
|
|
|
.ai-preview-dialog{ |
|
|
|
::v-deep .el-dialog{ |
|
|
|
width: 1300px !important; |
|
|
|
.preview-content{ |
|
|
|
width: 728px !important; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
pre { |
|
|
|
background-color: #f4f4f4; |
|
|
|
padding: 10px; |
|
|
|
border: 1px solid #ccc; |
|
|
|
border-radius: 4px; |
|
|
|
white-space: pre-wrap; |
|
|
|
word-wrap: break-word; |
|
|
|
height: calc(100vh - 430px); |
|
|
|
overflow: hidden; |
|
|
|
overflow-y: auto; |
|
|
|
} |
|
|
|
|
|
|
|
</style> |