9 changed files with 1299 additions and 667 deletions
-
12src/api/collect/collect.js
-
14src/assets/styles/yxk-admin.scss
-
25src/views/AIAssistant/AICataloging/history/index.vue
-
664src/views/AIAssistant/AICataloging/index copy.vue
-
646src/views/AIAssistant/AICataloging/index.vue
-
387src/views/AIAssistant/AICataloging/running/index.vue
-
93src/views/AIAssistant/AICataloging/running/module/detail.vue
-
77src/views/collectReorganizi/collectionLibrary/module/collectHeader.vue
-
40src/views/components/echarts/graph.vue
@ -0,0 +1,25 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<Running ref="running" :is-histroy="true" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import Running from '../running/index' |
||||
|
|
||||
|
export default { |
||||
|
name: 'History', |
||||
|
components: { Running }, |
||||
|
data() { |
||||
|
return { |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
}, |
||||
|
methods: { |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
</style> |
||||
@ -0,0 +1,664 @@ |
|||||
|
<template> |
||||
|
<div class="app-container category-container" style="height: calc(100vh - 140px);"> |
||||
|
<!-- 门类列表 --> |
||||
|
<div class="container-main"> |
||||
|
<div class="elect-cont-left"> |
||||
|
<div class="container-left"> |
||||
|
<span class="right-top-line" /> |
||||
|
<span class="left-bottom-line" /> |
||||
|
<!--门类树状结构--> |
||||
|
<div class="tree-scroll"> |
||||
|
<el-scrollbar style="height: calc(100vh - 230px);"> |
||||
|
<el-tree ref="categroyTree" v-loading="crud.loading" class="arc-tree arc-tree-01" :data="crud.data" :props="defaultProps" node-key="id" :expand-on-click-node="false" highlight-current @node-click="handleNodeClick"> |
||||
|
<span slot-scope="{ node, data }" class="custom-tree-node"> |
||||
|
<el-tooltip :content="node.label" placement="left" :enterable="false" effect="dark"> |
||||
|
<span v-if="data.isType === 0"> |
||||
|
{{ data.label }} |
||||
|
</span> |
||||
|
<span v-if="data.isType === 1" class="iconFolder tree-text"> |
||||
|
{{ data.label }} |
||||
|
</span> |
||||
|
<span v-if="data.isType === 2" class="iconArch tree-text"> |
||||
|
{{ data.label }} |
||||
|
</span> |
||||
|
<span v-if="data.isType === 3" class="iconFile tree-text"> |
||||
|
{{ data.label }} |
||||
|
</span> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
</el-tree> |
||||
|
</el-scrollbar> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 门类管理tab --> |
||||
|
<div class="elect-cont-right"> |
||||
|
<div v-if="selectedCategory.isType === 2" class="container-right"> |
||||
|
<span class="right-top-line" /> |
||||
|
<span class="left-bottom-line" /> |
||||
|
<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> |
||||
|
<!-- margin-left: 10px; line-height: 34px; height: 106px; overflow: hidden; overflow-y: scroll; --> |
||||
|
<div style="flex: 1; font-size: 12px; display: flex; line-height: 34px; "> |
||||
|
<div v-for="item in fileList" :key="item.name" class="file-list" style="margin-left: 10px;"> |
||||
|
<i class="iconfont icon-xiaowenjian" style="font-size: 14px;" /> |
||||
|
{{ item.name }} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="ai-category-main"> |
||||
|
<div class="ai-des-left"> |
||||
|
<div class="des-title"> |
||||
|
<p>著录项</p> |
||||
|
</div> |
||||
|
<div class="ai-des-form"> |
||||
|
<PreviewForm |
||||
|
ref="previewForm" |
||||
|
:is-has-code="true" |
||||
|
:is-disabled="false" |
||||
|
:form-preview-data.sync="formPreviewData" |
||||
|
:selected-category="selectedCategory" |
||||
|
:is-des-form-type="isDesFormType" |
||||
|
:collect-level="collectLevel" |
||||
|
:category-menu="categoryMenu" |
||||
|
:is-ai-category="true" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="ai-des-right"> |
||||
|
<div class="des-title"> |
||||
|
<p>AI识别数据</p> |
||||
|
</div> |
||||
|
<div class="ai-des-json"> |
||||
|
<pre v-if="aiJsonData" ref="typingContainer" v-highlightjs="displayedText">{{ displayedText }}</pre> |
||||
|
</div> |
||||
|
<div v-if="typingFinished" style="text-align: right;"> |
||||
|
<el-button @click="saveAiData">保存</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script> |
||||
|
import crudCategory from '@/api/system/category/category' |
||||
|
import CRUD, { presenter, header } from '@crud/crud' |
||||
|
import PreviewForm from '@/views/components/category/PreviewForm' |
||||
|
import { FetchInitCategoryInputFieldByPid, FetchCategoryMenu } from '@/api/system/category/category' |
||||
|
import { FetchAIResultZhulu } from '@/api/collect/collect' |
||||
|
import { getCurrentTime } from '@/utils/index' |
||||
|
import { archivesUpload } from '@/utils/upload' |
||||
|
import { mapGetters } from 'vuex' |
||||
|
|
||||
|
export default { |
||||
|
name: 'AICataloging', |
||||
|
components: { PreviewForm }, |
||||
|
cruds() { |
||||
|
return [ |
||||
|
CRUD({ |
||||
|
title: 'AI辅助著录', url: 'api/category/fondMenu', |
||||
|
crudMethod: { ...crudCategory }, |
||||
|
optShow: { |
||||
|
add: false, |
||||
|
edit: false, |
||||
|
del: false, |
||||
|
download: false, |
||||
|
group: false |
||||
|
} |
||||
|
}) |
||||
|
] |
||||
|
}, |
||||
|
mixins: [presenter(), header()], |
||||
|
provide() { |
||||
|
return { |
||||
|
parentsData: this |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
defaultProps: { |
||||
|
children: 'children', |
||||
|
label: 'label' |
||||
|
}, |
||||
|
selectedCategory: {}, |
||||
|
formPreviewData: [], |
||||
|
isDesFormType: 'arcives', |
||||
|
collectLevel: 3, |
||||
|
categoryMenu: [], |
||||
|
nowDate: '', // 当前时间 |
||||
|
aiLoading: false, |
||||
|
fileList: [], |
||||
|
aiJsonData: null, |
||||
|
displayedText: '', |
||||
|
typingInterval: null, |
||||
|
typingFinished: false, |
||||
|
currentLineIndex: 0 |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
...mapGetters([ |
||||
|
'baseApi' |
||||
|
]) |
||||
|
}, |
||||
|
mounted() { |
||||
|
this.getCategoryDataTree() |
||||
|
}, |
||||
|
methods: { |
||||
|
getCategoryDataTree() { |
||||
|
FetchCategoryMenu().then(res => { |
||||
|
this.categoryMenu = res |
||||
|
}) |
||||
|
}, |
||||
|
filterData(data) { |
||||
|
return data.filter(node => { |
||||
|
if (node.children && node.children.length > 0) { |
||||
|
node.children = this.filterData(node.children) // 递归处理子节点 |
||||
|
} |
||||
|
return node.isType !== 3 // 过滤掉isType为3的节点 |
||||
|
}) |
||||
|
}, |
||||
|
// 逆归实现 获取指定元素 |
||||
|
findNode(tree, func) { |
||||
|
for (const node of tree) { |
||||
|
if (func(node)) return node |
||||
|
if (node.children) { |
||||
|
const res = this.findNode(node.children, func) |
||||
|
if (res) return res |
||||
|
} |
||||
|
} |
||||
|
return null |
||||
|
}, |
||||
|
// 根据父级展开全部子级 |
||||
|
expandAllChildren(node, targetElement) { |
||||
|
node.expanded = true |
||||
|
// 递归展开当前节点的每个子节点 |
||||
|
if (node.childNodes && node.childNodes.length > 0) { |
||||
|
for (let i = 0; i < node.childNodes.length; i++) { |
||||
|
if (node.childNodes[i].data.id === targetElement.id) { |
||||
|
this.$refs.categroyTree.setCurrentKey(node.childNodes[i]) |
||||
|
} |
||||
|
this.expandAllChildren(node.childNodes[i], targetElement) |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
// 转换函数,将原始数据转换为el-tree所需格式 |
||||
|
transformData(rawData) { |
||||
|
return rawData.map(item => { |
||||
|
return { |
||||
|
label: item.fondName, |
||||
|
isType: 0, |
||||
|
id: item.fondsId, |
||||
|
fondsNo: item.fondsNo, |
||||
|
children: item.categoryList.map(category => { |
||||
|
return { |
||||
|
label: category.cnName, |
||||
|
cnName: category.cnName, |
||||
|
id: category.id, |
||||
|
arrangeType: category.arrangeType, |
||||
|
isType: category.isType, |
||||
|
fondsId: item.fondsId, |
||||
|
fondName: item.fondName, |
||||
|
fondsNo: item.fondsNo, |
||||
|
children: this.transformChildren(category.children, item.fondsId, item.fondName, item.fondsNo) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
}, |
||||
|
// 递归函数,用于处理数据的子节点 |
||||
|
transformChildren(children, fondsId, fondName, fondsNo) { |
||||
|
return children.map(child => { |
||||
|
return { |
||||
|
label: child.cnName, |
||||
|
cnName: child.cnName, |
||||
|
id: child.id, |
||||
|
isType: child.isType, |
||||
|
pid: child.pid, |
||||
|
code: child.code, |
||||
|
arrangeType: child.arrangeType, |
||||
|
fondsId: fondsId, |
||||
|
fondName: fondName, |
||||
|
fondsNo: fondsNo, |
||||
|
children: child.children.length ? this.transformChildren(child.children, fondsId, fondName, fondsNo) : [] |
||||
|
} |
||||
|
}) |
||||
|
}, |
||||
|
// 找顶级节点 |
||||
|
findTopLevelNode(data, fondsId) { |
||||
|
for (let i = 0; i < data.length; i++) { |
||||
|
if (data[i].id === fondsId) { |
||||
|
return data[i] |
||||
|
} |
||||
|
} |
||||
|
return null |
||||
|
}, |
||||
|
[CRUD.HOOK.afterRefresh]() { |
||||
|
this.crud.data = this.filterData(this.transformData(this.crud.data)) |
||||
|
this.$nextTick(() => { |
||||
|
let currentKey |
||||
|
if (localStorage.getItem('currentArchivesKey') !== null) { |
||||
|
currentKey = JSON.parse(localStorage.getItem('currentArchivesKey')) |
||||
|
// 删除门类节点后 |
||||
|
if (this.$refs.categroyTree.getCurrentKey(currentKey.id) == null) { |
||||
|
localStorage.removeItem('currentArchivesKey') |
||||
|
} |
||||
|
this.topLevelNode = this.findTopLevelNode(this.crud.data, currentKey.fondsId) |
||||
|
// 如果找到了顶级节点,则从该节点开始递归查找指定元素 |
||||
|
if (this.topLevelNode) { |
||||
|
if (currentKey) { |
||||
|
// 展开顶级节点的子节点 |
||||
|
if (currentKey.isType === 1) { |
||||
|
currentKey = this.findNode(this.crud.data[0].children, (node) => { |
||||
|
return node.isType !== 1 |
||||
|
}) |
||||
|
} |
||||
|
this.expandAllChildren(this.$refs.categroyTree.getNode(this.topLevelNode), currentKey) |
||||
|
} else { |
||||
|
this.defaultSetting(currentKey) |
||||
|
} |
||||
|
} else { |
||||
|
this.defaultSetting(currentKey) |
||||
|
} |
||||
|
} else { |
||||
|
this.defaultSetting(currentKey) |
||||
|
} |
||||
|
if (currentKey && currentKey.id) { |
||||
|
this.$nextTick(() => { |
||||
|
// 选中节点的门类详情 |
||||
|
this.handleNodeClick(currentKey) |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
}, |
||||
|
defaultSetting(currentKey) { |
||||
|
if (this.crud.data[0].isType === 0) { |
||||
|
currentKey = this.findNode(this.crud.data[0].children, (node) => { |
||||
|
return node.isType !== 1 |
||||
|
}) |
||||
|
this.expandAllChildren(this.$refs.categroyTree.getNode(this.crud.data[0]), currentKey) |
||||
|
} else { |
||||
|
currentKey = this.crud.data[0] |
||||
|
this.expandAllChildren(this.$refs.categroyTree.getNode(this.crud.data[0]), currentKey) |
||||
|
} |
||||
|
}, |
||||
|
// 选中门类后,设置门类详情数据 |
||||
|
handleNodeClick(val) { |
||||
|
if (val) { |
||||
|
localStorage.setItem('currentArchivesKey', JSON.stringify(val)) |
||||
|
this.selectedCategory = val |
||||
|
this.$nextTick(() => { |
||||
|
this.getFormInfo() |
||||
|
}) |
||||
|
} |
||||
|
}, |
||||
|
getFormInfo() { |
||||
|
// console.log('this.selectedCategory.arrangeType', this.selectedCategory.arrangeType) |
||||
|
// if (this.selectedCategory.arrangeType === 1) { |
||||
|
// this.collectLevel = 3 |
||||
|
// } else if (this.selectedCategory.arrangeType === 2) { |
||||
|
// this.collectLevel = 2 |
||||
|
// } else { |
||||
|
// this.collectLevel = 1 |
||||
|
// } |
||||
|
const params = { |
||||
|
'categoryId': this.selectedCategory.id, |
||||
|
'categoryLevel': this.collectLevel |
||||
|
} |
||||
|
FetchInitCategoryInputFieldByPid(params).then(data => { |
||||
|
this.formPreviewData = data |
||||
|
console.log('formPreviewData', this.formPreviewData) |
||||
|
this.isDesFormType = 'arcives' |
||||
|
this.$nextTick(() => { |
||||
|
this.$refs.previewForm.archivesType = 'add' |
||||
|
this.$refs.previewForm.FetchNoFormatField(this.selectedCategory.id) |
||||
|
}) |
||||
|
}) |
||||
|
}, |
||||
|
// 选择附件 |
||||
|
async changeAiFile(e) { |
||||
|
// 替换文件时清空 aiJsonData |
||||
|
this.aiJsonData = null |
||||
|
this.currentLineIndex = 0 |
||||
|
this.displayedText = '' |
||||
|
this.typingFinished = false |
||||
|
this.typingInterval = null |
||||
|
// 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 |
||||
|
// } |
||||
|
if (existingNonImageFiles.length > 0) { |
||||
|
// 若已有非图片文件,清空已有非图片文件 |
||||
|
this.fileList = this.fileList.filter(item => item.formatType === 'image') |
||||
|
} |
||||
|
|
||||
|
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.FetchAiFileUplaod(this.fileList) |
||||
|
} 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.FetchAiFileUplaod(this.fileList) |
||||
|
} |
||||
|
}, |
||||
|
FetchAiFileUplaod(files) { |
||||
|
this.aiLoading = true |
||||
|
this.nowDate = getCurrentTime() |
||||
|
const promiseArray = files.map(async(item, index) => { |
||||
|
const json = {} |
||||
|
json.file_name = item.name |
||||
|
json.file_size = item.size |
||||
|
json.file_type = item.postfix |
||||
|
json.file_path = '' |
||||
|
json.archive_id = this.arcId |
||||
|
json.file_dpi = item.px |
||||
|
json.file_thumbnail = '' |
||||
|
json.create_time = this.nowDate |
||||
|
json.id = null |
||||
|
json.last_modified = item.file.lastModified |
||||
|
return json |
||||
|
}) |
||||
|
console.log('promiseArray', promiseArray) |
||||
|
const fileDefault = files.map(item => item.file) |
||||
|
|
||||
|
Promise.all(promiseArray) |
||||
|
.then((arrayUpload) => { |
||||
|
archivesUpload(this.baseApi + '/api/collect/uploadAssistEnterFiles', |
||||
|
fileDefault, |
||||
|
this.selectedCategory.id, |
||||
|
this.arcId, |
||||
|
JSON.stringify(arrayUpload) |
||||
|
).then(res => { |
||||
|
if (res.data.data !== null) { |
||||
|
const params = { |
||||
|
'code': res.data.data.code, |
||||
|
'id': res.data.data.id |
||||
|
} |
||||
|
const fetchAiZhuluResult = () => { |
||||
|
// 检查是否应该继续请求 |
||||
|
if (!this.shouldContinueFetching) return |
||||
|
|
||||
|
FetchAIResultZhulu(params).then((res) => { |
||||
|
const data = JSON.parse(res) |
||||
|
console.log('data', data) |
||||
|
if (data.result !== null && data.status === 'success') { |
||||
|
this.$message({ message: '解析著录附件成功', type: 'success', offset: 8 }) |
||||
|
this.aiJsonData = data.result |
||||
|
this.startTypingEffect() |
||||
|
} else { |
||||
|
setTimeout(fetchAiZhuluResult, 3000) |
||||
|
} |
||||
|
}).catch(err => { |
||||
|
console.log(err) |
||||
|
}) |
||||
|
} |
||||
|
fetchAiZhuluResult() |
||||
|
} else { |
||||
|
this.$message({ message: '著录附件传输失败', type: 'error', offset: 8 }) |
||||
|
} |
||||
|
}) |
||||
|
}) |
||||
|
.catch((error) => { |
||||
|
console.error(error) |
||||
|
}) |
||||
|
}, |
||||
|
startTypingEffect() { |
||||
|
const lines = this.aiJsonData.split('\n') |
||||
|
this.currentLineIndex = 0 |
||||
|
this.displayedText = '' |
||||
|
this.typingFinished = false |
||||
|
|
||||
|
this.typingInterval = setInterval(() => { |
||||
|
if (this.currentLineIndex < lines.length) { |
||||
|
this.displayedText += lines[this.currentLineIndex] + '\n' |
||||
|
this.currentLineIndex++ |
||||
|
} else { |
||||
|
clearInterval(this.typingInterval) |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
this.typingFinished = true |
||||
|
if (this.aiJsonData) { |
||||
|
// this.$refs.previewForm.archivesType = 'add' |
||||
|
this.$refs.previewForm.addOrUpdateForm = JSON.parse(this.aiJsonData) |
||||
|
this.aiLoading = false |
||||
|
} |
||||
|
}, 1000) |
||||
|
} |
||||
|
|
||||
|
// 滚动条始终保持在底部 |
||||
|
const container = this.$refs.typingContainer |
||||
|
if (container) { |
||||
|
container.scrollTop = container.scrollHeight |
||||
|
} |
||||
|
}, 200) |
||||
|
}, |
||||
|
saveAiData() { |
||||
|
this.$router.push({ path: '/collectReorganizi/collectionLibrary' }) |
||||
|
}, |
||||
|
// 将上传的图片转为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 }) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
@import "~@/assets/styles/mixin.scss"; |
||||
|
@import "~@/assets/styles/variables.scss"; |
||||
|
.category-container { |
||||
|
.elect-cont-left{ |
||||
|
width: 296px !important; |
||||
|
} |
||||
|
} |
||||
|
.openSidebar .category-container .elect-cont-right{ |
||||
|
width: calc(100vw - 614px) !important; |
||||
|
} |
||||
|
.hideSidebar .category-container .elect-cont-right { |
||||
|
width: calc(100vw - 412px) !important; |
||||
|
} |
||||
|
.tree-scroll{ |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
.ai-category-main{ |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
margin-top: 10px; |
||||
|
|
||||
|
.ai-des-left{ |
||||
|
width: 740px; |
||||
|
margin-right: 20px; |
||||
|
} |
||||
|
.ai-des-right{ |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.ai-des-form{ |
||||
|
height: calc(100vh - 262px); |
||||
|
overflow-y: auto; |
||||
|
padding-right: 10px; |
||||
|
} |
||||
|
|
||||
|
.ai-des-json{ |
||||
|
height: calc(100vh - 300px); |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.prearch-upload{ |
||||
|
margin-right: 0 !important; |
||||
|
::v-deep .el-form-item__label{ |
||||
|
position: relative; |
||||
|
&::before{ |
||||
|
position: absolute; |
||||
|
top: -2px; |
||||
|
right: 70px; |
||||
|
content: "*"; |
||||
|
font-size: 10px; |
||||
|
color: #ff4949; |
||||
|
font-style: normal; |
||||
|
} |
||||
|
} |
||||
|
::v-deep .el-form-item__content{ |
||||
|
position: relative; |
||||
|
width: 540px !important; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
.input-style{ |
||||
|
width: 500px; |
||||
|
height: 34px; |
||||
|
line-height: 34px; |
||||
|
padding: 0 20px; |
||||
|
border: 1px solid #e6e8ed; |
||||
|
border-radius: 3px; |
||||
|
// &.error-box{ |
||||
|
// border-color: #ed4a41; |
||||
|
// } |
||||
|
} |
||||
|
// .error-tip{ |
||||
|
// position: absolute; |
||||
|
// left: 0; |
||||
|
// bottom: -26px; |
||||
|
// font-size: 12px; |
||||
|
// color: #ff4949; |
||||
|
// } |
||||
|
.upload-btn{ |
||||
|
position: relative; |
||||
|
width:96px; |
||||
|
margin-right: 0 !important; |
||||
|
margin-left: 10px; |
||||
|
overflow: initial !important; |
||||
|
#upFile{ |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
// opacity: 0; |
||||
|
width: 84px; |
||||
|
height: 34px; |
||||
|
} |
||||
|
.el-button{ |
||||
|
margin-top: -2px; |
||||
|
font-weight: bold; |
||||
|
border-color: #0348f3; |
||||
|
color: #0348f3; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
pre { |
||||
|
background-color: #f4f4f4; |
||||
|
padding: 10px; |
||||
|
border: 1px solid #ccc; |
||||
|
border-radius: 4px; |
||||
|
white-space: pre-wrap; |
||||
|
word-wrap: break-word; |
||||
|
height: calc(100vh - 300px); |
||||
|
overflow-y: auto; |
||||
|
} |
||||
|
</style> |
||||
@ -1,645 +1,55 @@ |
|||||
<template> |
<template> |
||||
<div class="app-container category-container" style="height: calc(100vh - 140px);"> |
|
||||
<!-- 门类列表 --> |
|
||||
<div class="container-main"> |
|
||||
<div class="elect-cont-left"> |
|
||||
<div class="container-left"> |
|
||||
|
<div class="app-container tab-container"> |
||||
|
<div class="tab-content"> |
||||
<span class="right-top-line" /> |
<span class="right-top-line" /> |
||||
<span class="left-bottom-line" /> |
<span class="left-bottom-line" /> |
||||
<!--门类树状结构--> |
|
||||
<div class="tree-scroll"> |
|
||||
<el-scrollbar style="height: calc(100vh - 230px);"> |
|
||||
<el-tree ref="categroyTree" v-loading="crud.loading" class="arc-tree arc-tree-01" :data="crud.data" :props="defaultProps" node-key="id" :expand-on-click-node="false" highlight-current @node-click="handleNodeClick"> |
|
||||
<span slot-scope="{ node, data }" class="custom-tree-node"> |
|
||||
<el-tooltip :content="node.label" placement="left" :enterable="false" effect="dark"> |
|
||||
<span v-if="data.isType === 0"> |
|
||||
{{ data.label }} |
|
||||
</span> |
|
||||
<span v-if="data.isType === 1" class="iconFolder tree-text"> |
|
||||
{{ data.label }} |
|
||||
</span> |
|
||||
<span v-if="data.isType === 2" class="iconArch tree-text"> |
|
||||
{{ data.label }} |
|
||||
</span> |
|
||||
<span v-if="data.isType === 3" class="iconFile tree-text"> |
|
||||
{{ data.label }} |
|
||||
</span> |
|
||||
</el-tooltip> |
|
||||
</span> |
|
||||
</el-tree> |
|
||||
</el-scrollbar> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
<!-- 门类管理tab --> |
|
||||
<div class="elect-cont-right"> |
|
||||
<div v-if="selectedCategory.isType === 2" class="container-right"> |
|
||||
<span class="right-top-line" /> |
|
||||
<span class="left-bottom-line" /> |
|
||||
<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> |
|
||||
<!-- margin-left: 10px; line-height: 34px; height: 106px; overflow: hidden; overflow-y: scroll; --> |
|
||||
<div style="flex: 1; font-size: 12px; display: flex; line-height: 34px; "> |
|
||||
<div v-for="item in fileList" :key="item.name" class="file-list" style="margin-left: 10px;"> |
|
||||
<i class="iconfont icon-xiaowenjian" style="font-size: 14px;" /> |
|
||||
{{ item.name }} |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="ai-category-main"> |
|
||||
<div class="ai-des-left"> |
|
||||
<div class="des-title"> |
|
||||
<p>著录项</p> |
|
||||
</div> |
|
||||
<div class="ai-des-form"> |
|
||||
<PreviewForm |
|
||||
ref="previewForm" |
|
||||
:is-has-code="true" |
|
||||
:is-disabled="false" |
|
||||
:form-preview-data.sync="formPreviewData" |
|
||||
:selected-category="selectedCategory" |
|
||||
:is-des-form-type="isDesFormType" |
|
||||
:collect-level="collectLevel" |
|
||||
:category-menu="categoryMenu" |
|
||||
:is-ai-category="true" |
|
||||
/> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="ai-des-right"> |
|
||||
<div class="des-title"> |
|
||||
<p>AI识别数据</p> |
|
||||
</div> |
|
||||
<div class="ai-des-json"> |
|
||||
<pre v-if="aiJsonData" ref="typingContainer" v-highlightjs="displayedText">{{ displayedText }}</pre> |
|
||||
</div> |
|
||||
<div v-if="typingFinished" style="text-align: right;"> |
|
||||
<el-button @click="saveAiData">保存</el-button> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
<span class="right-bottom-line" /> |
||||
|
<ul class="tab-nav"> |
||||
|
<li :class="{ 'active-tab-nav': activeIndex == 0 }" @click="changeActiveTab(0)">处理中<i /></li> |
||||
|
<li :class="{ 'active-tab-nav': activeIndex == 1 }" @click="changeActiveTab(1)">已完成<i /></li> |
||||
|
<!-- 最右侧装饰img --> |
||||
|
<span class="tab-right-img" /> |
||||
|
</ul> |
||||
|
<component :is="comName" /> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
import crudCategory from '@/api/system/category/category' |
|
||||
import CRUD, { presenter, header } from '@crud/crud' |
|
||||
import PreviewForm from '@/views/components/category/PreviewForm' |
|
||||
import { FetchInitCategoryInputFieldByPid, FetchCategoryMenu } from '@/api/system/category/category' |
|
||||
import { getCurrentTime } from '@/utils/index' |
|
||||
import { archivesUpload } from '@/utils/upload' |
|
||||
import { mapGetters } from 'vuex' |
|
||||
|
import running from './running/index' |
||||
|
import history from './history/index' |
||||
|
|
||||
export default { |
export default { |
||||
name: 'AICataloging', |
name: 'AICataloging', |
||||
components: { PreviewForm }, |
|
||||
cruds() { |
|
||||
return [ |
|
||||
CRUD({ |
|
||||
title: 'AI辅助著录', url: 'api/category/fondMenu', |
|
||||
crudMethod: { ...crudCategory }, |
|
||||
optShow: { |
|
||||
add: false, |
|
||||
edit: false, |
|
||||
del: false, |
|
||||
download: false, |
|
||||
group: false |
|
||||
} |
|
||||
}) |
|
||||
] |
|
||||
}, |
|
||||
mixins: [presenter(), header()], |
|
||||
provide() { |
|
||||
return { |
|
||||
parentsData: this |
|
||||
} |
|
||||
}, |
|
||||
|
components: { running, history }, |
||||
data() { |
data() { |
||||
return { |
return { |
||||
defaultProps: { |
|
||||
children: 'children', |
|
||||
label: 'label' |
|
||||
}, |
|
||||
selectedCategory: {}, |
|
||||
formPreviewData: [], |
|
||||
isDesFormType: 'arcives', |
|
||||
collectLevel: 3, |
|
||||
categoryMenu: [], |
|
||||
nowDate: '', // 当前时间 |
|
||||
aiLoading: false, |
|
||||
fileList: [], |
|
||||
aiJsonData: null, |
|
||||
displayedText: '', |
|
||||
typingInterval: null, |
|
||||
typingFinished: false, |
|
||||
currentLineIndex: 0 |
|
||||
|
activeIndex: 0 |
||||
} |
} |
||||
}, |
}, |
||||
computed: { |
computed: { |
||||
...mapGetters([ |
|
||||
'baseApi' |
|
||||
]) |
|
||||
}, |
|
||||
mounted() { |
|
||||
this.getCategoryDataTree() |
|
||||
}, |
|
||||
methods: { |
|
||||
getCategoryDataTree() { |
|
||||
FetchCategoryMenu().then(res => { |
|
||||
this.categoryMenu = res |
|
||||
}) |
|
||||
}, |
|
||||
filterData(data) { |
|
||||
return data.filter(node => { |
|
||||
if (node.children && node.children.length > 0) { |
|
||||
node.children = this.filterData(node.children) // 递归处理子节点 |
|
||||
} |
|
||||
return node.isType !== 3 // 过滤掉isType为3的节点 |
|
||||
}) |
|
||||
}, |
|
||||
// 逆归实现 获取指定元素 |
|
||||
findNode(tree, func) { |
|
||||
for (const node of tree) { |
|
||||
if (func(node)) return node |
|
||||
if (node.children) { |
|
||||
const res = this.findNode(node.children, func) |
|
||||
if (res) return res |
|
||||
} |
|
||||
} |
|
||||
return null |
|
||||
}, |
|
||||
// 根据父级展开全部子级 |
|
||||
expandAllChildren(node, targetElement) { |
|
||||
node.expanded = true |
|
||||
// 递归展开当前节点的每个子节点 |
|
||||
if (node.childNodes && node.childNodes.length > 0) { |
|
||||
for (let i = 0; i < node.childNodes.length; i++) { |
|
||||
if (node.childNodes[i].data.id === targetElement.id) { |
|
||||
this.$refs.categroyTree.setCurrentKey(node.childNodes[i]) |
|
||||
} |
|
||||
this.expandAllChildren(node.childNodes[i], targetElement) |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
// 转换函数,将原始数据转换为el-tree所需格式 |
|
||||
transformData(rawData) { |
|
||||
return rawData.map(item => { |
|
||||
return { |
|
||||
label: item.fondName, |
|
||||
isType: 0, |
|
||||
id: item.fondsId, |
|
||||
fondsNo: item.fondsNo, |
|
||||
children: item.categoryList.map(category => { |
|
||||
return { |
|
||||
label: category.cnName, |
|
||||
cnName: category.cnName, |
|
||||
id: category.id, |
|
||||
arrangeType: category.arrangeType, |
|
||||
isType: category.isType, |
|
||||
fondsId: item.fondsId, |
|
||||
fondName: item.fondName, |
|
||||
fondsNo: item.fondsNo, |
|
||||
children: this.transformChildren(category.children, item.fondsId, item.fondName, item.fondsNo) |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
// 递归函数,用于处理数据的子节点 |
|
||||
transformChildren(children, fondsId, fondName, fondsNo) { |
|
||||
return children.map(child => { |
|
||||
return { |
|
||||
label: child.cnName, |
|
||||
cnName: child.cnName, |
|
||||
id: child.id, |
|
||||
isType: child.isType, |
|
||||
pid: child.pid, |
|
||||
code: child.code, |
|
||||
arrangeType: child.arrangeType, |
|
||||
fondsId: fondsId, |
|
||||
fondName: fondName, |
|
||||
fondsNo: fondsNo, |
|
||||
children: child.children.length ? this.transformChildren(child.children, fondsId, fondName, fondsNo) : [] |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
// 找顶级节点 |
|
||||
findTopLevelNode(data, fondsId) { |
|
||||
for (let i = 0; i < data.length; i++) { |
|
||||
if (data[i].id === fondsId) { |
|
||||
return data[i] |
|
||||
} |
|
||||
} |
|
||||
return null |
|
||||
}, |
|
||||
[CRUD.HOOK.afterRefresh]() { |
|
||||
this.crud.data = this.filterData(this.transformData(this.crud.data)) |
|
||||
this.$nextTick(() => { |
|
||||
let currentKey |
|
||||
if (localStorage.getItem('currentArchivesKey') !== null) { |
|
||||
currentKey = JSON.parse(localStorage.getItem('currentArchivesKey')) |
|
||||
// 删除门类节点后 |
|
||||
if (this.$refs.categroyTree.getCurrentKey(currentKey.id) == null) { |
|
||||
localStorage.removeItem('currentArchivesKey') |
|
||||
} |
|
||||
this.topLevelNode = this.findTopLevelNode(this.crud.data, currentKey.fondsId) |
|
||||
// 如果找到了顶级节点,则从该节点开始递归查找指定元素 |
|
||||
if (this.topLevelNode) { |
|
||||
if (currentKey) { |
|
||||
// 展开顶级节点的子节点 |
|
||||
if (currentKey.isType === 1) { |
|
||||
currentKey = this.findNode(this.crud.data[0].children, (node) => { |
|
||||
return node.isType !== 1 |
|
||||
}) |
|
||||
} |
|
||||
this.expandAllChildren(this.$refs.categroyTree.getNode(this.topLevelNode), currentKey) |
|
||||
} else { |
|
||||
this.defaultSetting(currentKey) |
|
||||
} |
|
||||
} else { |
|
||||
this.defaultSetting(currentKey) |
|
||||
} |
|
||||
} else { |
|
||||
this.defaultSetting(currentKey) |
|
||||
} |
|
||||
if (currentKey && currentKey.id) { |
|
||||
this.$nextTick(() => { |
|
||||
// 选中节点的门类详情 |
|
||||
this.handleNodeClick(currentKey) |
|
||||
}) |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
defaultSetting(currentKey) { |
|
||||
if (this.crud.data[0].isType === 0) { |
|
||||
currentKey = this.findNode(this.crud.data[0].children, (node) => { |
|
||||
return node.isType !== 1 |
|
||||
}) |
|
||||
this.expandAllChildren(this.$refs.categroyTree.getNode(this.crud.data[0]), currentKey) |
|
||||
} else { |
|
||||
currentKey = this.crud.data[0] |
|
||||
this.expandAllChildren(this.$refs.categroyTree.getNode(this.crud.data[0]), currentKey) |
|
||||
} |
|
||||
}, |
|
||||
// 选中门类后,设置门类详情数据 |
|
||||
handleNodeClick(val) { |
|
||||
if (val) { |
|
||||
localStorage.setItem('currentArchivesKey', JSON.stringify(val)) |
|
||||
this.selectedCategory = val |
|
||||
this.$nextTick(() => { |
|
||||
this.getFormInfo() |
|
||||
}) |
|
||||
} |
|
||||
}, |
|
||||
getFormInfo() { |
|
||||
// console.log('this.selectedCategory.arrangeType', this.selectedCategory.arrangeType) |
|
||||
// if (this.selectedCategory.arrangeType === 1) { |
|
||||
// this.collectLevel = 3 |
|
||||
// } else if (this.selectedCategory.arrangeType === 2) { |
|
||||
// this.collectLevel = 2 |
|
||||
// } else { |
|
||||
// this.collectLevel = 1 |
|
||||
// } |
|
||||
const params = { |
|
||||
'categoryId': this.selectedCategory.id, |
|
||||
'categoryLevel': this.collectLevel |
|
||||
|
comName: function() { |
||||
|
if (this.activeIndex === 0) { |
||||
|
return 'running' |
||||
|
} else if (this.activeIndex === 1) { |
||||
|
return 'history' |
||||
} |
} |
||||
FetchInitCategoryInputFieldByPid(params).then(data => { |
|
||||
this.formPreviewData = data |
|
||||
console.log('formPreviewData', this.formPreviewData) |
|
||||
this.isDesFormType = 'arcives' |
|
||||
this.$nextTick(() => { |
|
||||
this.$refs.previewForm.archivesType = 'add' |
|
||||
this.$refs.previewForm.FetchNoFormatField(this.selectedCategory.id) |
|
||||
}) |
|
||||
}) |
|
||||
}, |
|
||||
// 选择附件 |
|
||||
async changeAiFile(e) { |
|
||||
// 替换文件时清空 aiJsonData |
|
||||
this.aiJsonData = null |
|
||||
this.currentLineIndex = 0 |
|
||||
this.displayedText = '' |
|
||||
this.typingFinished = false |
|
||||
this.typingInterval = null |
|
||||
// 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) |
|
||||
|
return 'running' |
||||
} |
} |
||||
this.FetchAiFileUplaod(this.fileList) |
|
||||
} 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.FetchAiFileUplaod(this.fileList) |
|
||||
} |
|
||||
}, |
|
||||
FetchAiFileUplaod(files) { |
|
||||
this.nowDate = getCurrentTime() |
|
||||
const promiseArray = files.map(async(item, index) => { |
|
||||
const json = {} |
|
||||
json.file_name = item.name |
|
||||
json.file_size = item.size |
|
||||
json.file_type = item.postfix |
|
||||
// json.file_path = this.filePath[index].path |
|
||||
json.file_path = '' |
|
||||
json.archive_id = this.arcId |
|
||||
json.file_dpi = item.px |
|
||||
json.file_thumbnail = '' |
|
||||
json.create_time = this.nowDate |
|
||||
json.id = null |
|
||||
json.last_modified = item.file.lastModified |
|
||||
// json.digital_summary = null |
|
||||
// json.public_key = null |
|
||||
// json.private_key = null |
|
||||
return json |
|
||||
}) |
|
||||
console.log('promiseArray', promiseArray) |
|
||||
// 原始得上传文件二进制 |
|
||||
const fileDefault = files.map(item => item.file) |
|
||||
|
|
||||
Promise.all(promiseArray) |
|
||||
.then((arrayUpload) => { |
|
||||
// 上传附件 |
|
||||
archivesUpload(this.baseApi + '/api/collect/uploadAssistEnterFiles', |
|
||||
fileDefault, |
|
||||
this.selectedCategory.id, |
|
||||
this.arcId, |
|
||||
JSON.stringify(arrayUpload) |
|
||||
).then(res => { |
|
||||
if (res.data.code === 200) { |
|
||||
this.$message({ message: res.data.data, type: 'success', offset: 8 }) |
|
||||
// this.aiJsonData = res.data; |
|
||||
// this.startTypingEffect(); |
|
||||
} else { |
|
||||
this.$message({ message: '上传附件失败', type: 'error', offset: 8 }) |
|
||||
} |
|
||||
// this.handleClose() |
|
||||
}) |
|
||||
}) |
|
||||
.catch((error) => { |
|
||||
console.error(error) |
|
||||
}) |
|
||||
}, |
}, |
||||
startTypingEffect() { |
|
||||
const lines = this.aiJsonData.split('\n') |
|
||||
this.currentLineIndex = 0 |
|
||||
this.displayedText = '' |
|
||||
this.typingFinished = false |
|
||||
|
|
||||
this.typingInterval = setInterval(() => { |
|
||||
if (this.currentLineIndex < lines.length) { |
|
||||
this.displayedText += lines[this.currentLineIndex] + '\n' |
|
||||
this.currentLineIndex++ |
|
||||
} else { |
|
||||
clearInterval(this.typingInterval) |
|
||||
|
|
||||
setTimeout(() => { |
|
||||
this.typingFinished = true |
|
||||
if (this.aiJsonData) { |
|
||||
// this.$refs.previewForm.archivesType = 'add' |
|
||||
this.$refs.previewForm.addOrUpdateForm = JSON.parse(this.aiJsonData) |
|
||||
this.aiLoading = false |
|
||||
} |
|
||||
}, 1000) |
|
||||
} |
|
||||
|
|
||||
// 滚动条始终保持在底部 |
|
||||
const container = this.$refs.typingContainer |
|
||||
if (container) { |
|
||||
container.scrollTop = container.scrollHeight |
|
||||
} |
|
||||
}, 200) |
|
||||
}, |
|
||||
saveAiData() { |
|
||||
this.$router.push({ path: '/collectReorganizi/collectionLibrary' }) |
|
||||
}, |
|
||||
// 将上传的图片转为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 }) |
|
||||
} |
|
||||
}) |
|
||||
|
methods: { |
||||
|
changeActiveTab(data) { |
||||
|
this.activeIndex = data |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
</script> |
</script> |
||||
|
|
||||
<style lang="scss" scoped> |
<style lang="scss" scoped> |
||||
@import "~@/assets/styles/mixin.scss"; |
|
||||
@import "~@/assets/styles/variables.scss"; |
|
||||
.category-container { |
|
||||
.elect-cont-left{ |
|
||||
width: 296px !important; |
|
||||
} |
|
||||
} |
|
||||
.openSidebar .category-container .elect-cont-right{ |
|
||||
width: calc(100vw - 614px) !important; |
|
||||
} |
|
||||
.hideSidebar .category-container .elect-cont-right { |
|
||||
width: calc(100vw - 412px) !important; |
|
||||
} |
|
||||
.tree-scroll{ |
|
||||
font-size: 14px; |
|
||||
} |
|
||||
.ai-category-main{ |
|
||||
display: flex; |
|
||||
justify-content: flex-start; |
|
||||
margin-top: 10px; |
|
||||
|
|
||||
.ai-des-left{ |
|
||||
width: 740px; |
|
||||
margin-right: 20px; |
|
||||
} |
|
||||
.ai-des-right{ |
|
||||
flex: 1; |
|
||||
} |
|
||||
|
|
||||
.ai-des-form{ |
|
||||
height: calc(100vh - 262px); |
|
||||
overflow-y: auto; |
|
||||
padding-right: 10px; |
|
||||
} |
|
||||
|
|
||||
.ai-des-json{ |
|
||||
height: calc(100vh - 300px); |
|
||||
margin-bottom: 10px; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.prearch-upload{ |
|
||||
margin-right: 0 !important; |
|
||||
::v-deep .el-form-item__label{ |
|
||||
position: relative; |
|
||||
&::before{ |
|
||||
position: absolute; |
|
||||
top: -2px; |
|
||||
right: 70px; |
|
||||
content: "*"; |
|
||||
font-size: 10px; |
|
||||
color: #ff4949; |
|
||||
font-style: normal; |
|
||||
} |
|
||||
} |
|
||||
::v-deep .el-form-item__content{ |
|
||||
position: relative; |
|
||||
width: 540px !important; |
|
||||
display: flex; |
|
||||
justify-content: space-between; |
|
||||
.input-style{ |
|
||||
width: 500px; |
|
||||
height: 34px; |
|
||||
line-height: 34px; |
|
||||
padding: 0 20px; |
|
||||
border: 1px solid #e6e8ed; |
|
||||
border-radius: 3px; |
|
||||
// &.error-box{ |
|
||||
// border-color: #ed4a41; |
|
||||
// } |
|
||||
} |
|
||||
// .error-tip{ |
|
||||
// position: absolute; |
|
||||
// left: 0; |
|
||||
// bottom: -26px; |
|
||||
// font-size: 12px; |
|
||||
// color: #ff4949; |
|
||||
// } |
|
||||
.upload-btn{ |
|
||||
position: relative; |
|
||||
width:96px; |
|
||||
margin-right: 0 !important; |
|
||||
margin-left: 10px; |
|
||||
overflow: initial !important; |
|
||||
#upFile{ |
|
||||
position: absolute; |
|
||||
left: 0; |
|
||||
top: 0; |
|
||||
// opacity: 0; |
|
||||
width: 84px; |
|
||||
height: 34px; |
|
||||
} |
|
||||
.el-button{ |
|
||||
margin-top: -2px; |
|
||||
font-weight: bold; |
|
||||
border-color: #0348f3; |
|
||||
color: #0348f3; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
[data-theme=dark] .tab-content{ |
||||
|
height: calc(100vh - 200px) !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 - 300px); |
|
||||
overflow-y: auto; |
|
||||
|
[data-theme=light] .tab-content{ |
||||
|
height: calc(100vh - 179px); |
||||
} |
} |
||||
</style> |
</style> |
||||
@ -0,0 +1,387 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<!--工具栏--> |
||||
|
<div class="head-container" style="text-align: right;"> |
||||
|
<el-button v-if="!isHistroy" size="mini" @click="uploadVisible=true"> |
||||
|
<i class="iconfont icon-shangchuan" /> |
||||
|
AI著录文件上传 |
||||
|
</el-button> |
||||
|
</div> |
||||
|
<!--表格渲染--> |
||||
|
<el-table |
||||
|
ref="table" |
||||
|
v-loading="crud.loading" |
||||
|
:data="crud.data" |
||||
|
row-key="id" |
||||
|
@select="crud.selectChange" |
||||
|
@select-all="crud.selectAllChange" |
||||
|
@cell-dblclick="tableDoubleClick" |
||||
|
@selection-change="crud.selectionChangeHandler" |
||||
|
> |
||||
|
<el-table-column label="文件id" prop="id" /> |
||||
|
<!-- <el-table-column label="结束时间" prop="endTime" align="center" min-width="160"> |
||||
|
<template slot-scope="scope"> |
||||
|
<div v-if="scope.row.endTime">{{ scope.row.endTime | parseTime }}</div> |
||||
|
<div v-else>-</div> |
||||
|
</template> |
||||
|
</el-table-column> --> |
||||
|
<el-table-column label="解析状态" prop="status" align="center" width="140"> |
||||
|
<template slot-scope="scope"> |
||||
|
<div v-if="!isHistroy"> |
||||
|
<span class="row-state soon-state">解析中</span> |
||||
|
<!-- <span class="row-state end-state">解析完成</span> --> |
||||
|
</div> |
||||
|
<div v-else> |
||||
|
<span v-if="scope.row.endTime" class="row-state end-state">已处理</span> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="操作" prop="status" align="center" width="140"> |
||||
|
<!-- slot-scope="scope" --> |
||||
|
<template> |
||||
|
<!-- v-if="scope.row.status === 1" --> |
||||
|
<el-button size="mini" class="check-btn" style="padding: 5px;"> |
||||
|
<i class="iconfont icon-tianjiawenjian" /> |
||||
|
新增档案 |
||||
|
</el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
<!--分页组件--> |
||||
|
<pagination v-if="crud.data.length!==0" /> |
||||
|
<Detail ref="aiCatalogingFile" :is-histroy="isHistroy" /> |
||||
|
|
||||
|
<el-dialog class="fileUpload-dialog" title="文件上传" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="uploadVisible"> |
||||
|
<div class="setting-dialog"> |
||||
|
<div class="upload-container"> |
||||
|
<i v-if="fileList.length === 0" class="iconfont icon-tianjiawenjian upload-icon" /> |
||||
|
<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 class="upload-input"> |
||||
|
<input ref="fileInput" type="file" multiple @change="changeAiFile"> |
||||
|
<div class="upload-zip"><i class="iconfont icon-shangchuan2" />点击上传</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="text" @click="uploadVisible = false">取消</el-button> |
||||
|
<el-button :loading="aiLoading" type="primary" @click="handleUploadConfirm">保存</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
|
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import CRUD, { presenter, header, crud } from '@crud/crud' |
||||
|
import pagination from '@crud/Pagination' |
||||
|
import Detail from './module/detail' |
||||
|
|
||||
|
import { archivesUpload } from '@/utils/upload' |
||||
|
import { getCurrentTime } from '@/utils/index' |
||||
|
import { mapGetters } from 'vuex' |
||||
|
import { FetchAIResultZhulu } from '@/api/collect/collect' |
||||
|
|
||||
|
export default { |
||||
|
name: 'Running', |
||||
|
components: { pagination, Detail }, |
||||
|
cruds() { |
||||
|
return CRUD({ title: '处理中', url: 'api/flowable/getFlowList', crudMethod: {}, |
||||
|
optShow: { |
||||
|
add: false, |
||||
|
edit: false, |
||||
|
del: false, |
||||
|
reset: false, |
||||
|
download: false, |
||||
|
group: false |
||||
|
}}) |
||||
|
}, |
||||
|
mixins: [presenter(), header(), crud()], |
||||
|
|
||||
|
props: { |
||||
|
isHistroy: { |
||||
|
type: Boolean, |
||||
|
default: false |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
aiLoading: false, |
||||
|
permission: {}, |
||||
|
uploadVisible: false, |
||||
|
nowDate: '', |
||||
|
fileList: [], |
||||
|
aiJsonData: null, |
||||
|
displayedText: '', |
||||
|
typingInterval: null, |
||||
|
typingFinished: false, |
||||
|
currentLineIndex: 0, |
||||
|
shouldContinueFetching: true |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
...mapGetters([ |
||||
|
'baseApi' |
||||
|
]) |
||||
|
}, |
||||
|
mounted() { |
||||
|
}, |
||||
|
methods: { |
||||
|
[CRUD.HOOK.beforeRefresh]() { |
||||
|
if (this.isHistroy) { |
||||
|
this.crud.query.isEnd = true |
||||
|
} else { |
||||
|
this.crud.query.isEnd = false |
||||
|
} |
||||
|
}, |
||||
|
// table - 双击查看详情 |
||||
|
tableDoubleClick(row) { |
||||
|
this.$refs.aiCatalogingFile.detailVisible = true |
||||
|
this.$refs.aiCatalogingFile.getFileList() |
||||
|
}, |
||||
|
async changeAiFile(e) { |
||||
|
// 替换文件时清空 aiJsonData |
||||
|
this.aiJsonData = null |
||||
|
this.currentLineIndex = 0 |
||||
|
this.displayedText = '' |
||||
|
this.typingFinished = false |
||||
|
this.typingInterval = null |
||||
|
// 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 |
||||
|
// } |
||||
|
if (existingNonImageFiles.length > 0) { |
||||
|
// 若已有非图片文件,清空已有非图片文件 |
||||
|
this.fileList = this.fileList.filter(item => item.formatType === 'image') |
||||
|
} |
||||
|
|
||||
|
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.FetchAiFileUplaod(this.fileList) |
||||
|
} 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) |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
handleUploadConfirm() { |
||||
|
this.FetchAiFileUplaod(this.fileList) |
||||
|
}, |
||||
|
FetchAiFileUplaod(files) { |
||||
|
this.aiLoading = true |
||||
|
this.nowDate = getCurrentTime() |
||||
|
const promiseArray = files.map(async(item, index) => { |
||||
|
const json = {} |
||||
|
json.file_name = item.name |
||||
|
json.file_size = item.size |
||||
|
json.file_type = item.postfix |
||||
|
json.file_path = '' |
||||
|
json.archive_id = null |
||||
|
json.file_dpi = item.px |
||||
|
json.file_thumbnail = '' |
||||
|
json.create_time = this.nowDate |
||||
|
json.id = null |
||||
|
json.last_modified = item.file.lastModified |
||||
|
return json |
||||
|
}) |
||||
|
console.log('promiseArray', promiseArray) |
||||
|
const fileDefault = files.map(item => item.file) |
||||
|
// this.selectedCategory.id, |
||||
|
// this.arcId, |
||||
|
Promise.all(promiseArray) |
||||
|
.then((arrayUpload) => { |
||||
|
archivesUpload(this.baseApi + '/api/collect/uploadAssistEnterFiles', |
||||
|
fileDefault, |
||||
|
JSON.stringify(arrayUpload) |
||||
|
).then(res => { |
||||
|
if (res.data.data !== null) { |
||||
|
const params = { |
||||
|
'code': res.data.data.code, |
||||
|
'id': res.data.data.id |
||||
|
} |
||||
|
const fetchAiZhuluResult = () => { |
||||
|
// 检查是否应该继续请求 |
||||
|
if (!this.shouldContinueFetching) return |
||||
|
|
||||
|
FetchAIResultZhulu(params).then((res) => { |
||||
|
const data = JSON.parse(res) |
||||
|
console.log('data', data) |
||||
|
if (data.result !== null && data.status === 'success') { |
||||
|
this.$message({ message: '解析著录附件成功', type: 'success', offset: 8 }) |
||||
|
this.aiJsonData = data.result |
||||
|
this.startTypingEffect() |
||||
|
} else { |
||||
|
setTimeout(fetchAiZhuluResult, 3000) |
||||
|
} |
||||
|
}).catch(err => { |
||||
|
console.log(err) |
||||
|
}) |
||||
|
} |
||||
|
fetchAiZhuluResult() |
||||
|
} else { |
||||
|
this.$message({ message: '著录附件传输失败', type: 'error', offset: 8 }) |
||||
|
} |
||||
|
}) |
||||
|
}) |
||||
|
.catch((error) => { |
||||
|
console.error(error) |
||||
|
}) |
||||
|
}, |
||||
|
startTypingEffect() { |
||||
|
const lines = this.aiJsonData.split('\n') |
||||
|
this.currentLineIndex = 0 |
||||
|
this.displayedText = '' |
||||
|
this.typingFinished = false |
||||
|
|
||||
|
this.typingInterval = setInterval(() => { |
||||
|
if (this.currentLineIndex < lines.length) { |
||||
|
this.displayedText += lines[this.currentLineIndex] + '\n' |
||||
|
this.currentLineIndex++ |
||||
|
} else { |
||||
|
clearInterval(this.typingInterval) |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
this.typingFinished = true |
||||
|
if (this.aiJsonData) { |
||||
|
// this.$refs.previewForm.archivesType = 'add' |
||||
|
// this.$refs.previewForm.addOrUpdateForm = JSON.parse(this.aiJsonData) |
||||
|
this.aiLoading = false |
||||
|
} |
||||
|
}, 1000) |
||||
|
} |
||||
|
|
||||
|
// 滚动条始终保持在底部 |
||||
|
const container = this.$refs.typingContainer |
||||
|
if (container) { |
||||
|
container.scrollTop = container.scrollHeight |
||||
|
} |
||||
|
}, 200) |
||||
|
}, |
||||
|
// 附件旁边的X |
||||
|
deleteFile(file) { |
||||
|
const index = this.fileList.indexOf(file) |
||||
|
this.fileList.splice(index, 1) |
||||
|
if (this.fileList.length !== 0) { |
||||
|
// archivesUpload(this.baseApi + '/api/collect/uploadFiles', this.fileList, this.selectedCategory.id).then(res => { |
||||
|
// if (res.data.code === 200) { |
||||
|
// this.filePath = res.data.data |
||||
|
// } |
||||
|
// }) |
||||
|
} else { |
||||
|
this.$message({ message: '已清空所有要上传的附件', offset: 8 }) |
||||
|
} |
||||
|
}, |
||||
|
// 将上传的图片转为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 }) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
</style> |
||||
@ -0,0 +1,93 @@ |
|||||
|
<template> |
||||
|
<el-dialog class="detail-dialog" :visible.sync="detailVisible" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body title="AI著录文件"> |
||||
|
<div class="setting-dialog"> |
||||
|
<el-table |
||||
|
ref="table" |
||||
|
:data="tableData" |
||||
|
style="min-width: 100%" |
||||
|
height="calc(100vh - 382px)" |
||||
|
> |
||||
|
<el-table-column type="selection" width="55" align="center" /> |
||||
|
<el-table-column type="index" label="序号" width="55" align="center" /> |
||||
|
<el-table-column prop="file_name" label="文件名称" show-overflow-tooltip min-width="140" /> |
||||
|
<el-table-column prop="file_type" label="格式" min-width="60" align="center" /> |
||||
|
<el-table-column prop="file_size" label="大小" min-width="85" align="center"> |
||||
|
<template slot-scope="scope"> |
||||
|
{{ getFileSize(scope.row.file_size) }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<!-- <el-table-column prop="file_dpi" label="分辨率" min-width="120" align="center"> |
||||
|
<template slot-scope="scope"> |
||||
|
<div v-if="!scope.row.file_dpi || scope.row.file_dpi === 'null'"> - </div> |
||||
|
<div v-else> {{ scope.row.file_dpi }} </div> |
||||
|
</template> |
||||
|
</el-table-column> --> |
||||
|
<el-table-column prop="file_thumbnail" label="缩略图" min-width="60" align="center"> |
||||
|
<template slot-scope="scope"> |
||||
|
<div v-if="scope.row.file_type === 'jpg' || scope.row.file_type === 'jpeg' || scope.row.file_type === 'png' || scope.row.file_type === 'bmp'|| scope.row.file_type === 'gif'"> |
||||
|
<i class="fileIcon icon-image" /> |
||||
|
</div> |
||||
|
<div v-else-if="scope.row.file_type === 'xlsx' || scope.row.file_type === 'xls'"> |
||||
|
<i class="fileIcon icon-excel" /> |
||||
|
</div> |
||||
|
<div v-else-if="scope.row.file_type === 'docx' || scope.row.file_type === 'doc'"> |
||||
|
<i class="fileIcon icon-word" /> |
||||
|
</div> |
||||
|
<div v-else-if="scope.row.file_type === 'pdf'"> |
||||
|
<i class="fileIcon icon-pdf" /> |
||||
|
</div> |
||||
|
<div v-else-if="scope.row.file_type === 'ppt' || scope.row.file_type === 'pptx'"> |
||||
|
<i class="fileIcon icon-ppt" /> |
||||
|
</div> |
||||
|
<div v-else-if="scope.row.file_type === 'zip' || scope.row.file_type === 'rar'"> |
||||
|
<i class="fileIcon icon-zip" /> |
||||
|
</div> |
||||
|
<div v-else-if="scope.row.file_type === 'txt'"> |
||||
|
<i class="fileIcon icon-txt" /> |
||||
|
</div> |
||||
|
<div v-else> |
||||
|
<i class="fileIcon icon-other" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="create_time" label="创建时间" min-width="130" align="center" /> |
||||
|
</el-table> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" @click="detailVisible=false">确定</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: 'Detail', |
||||
|
components: { |
||||
|
}, |
||||
|
props: { |
||||
|
isHistroy: { |
||||
|
type: Boolean, |
||||
|
default: false |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
tableData: [], |
||||
|
detailVisible: false |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
}, |
||||
|
mounted() { |
||||
|
|
||||
|
}, |
||||
|
methods: { |
||||
|
getFileList() { |
||||
|
console.log('附件列表') |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang='scss' scoped> |
||||
|
</style> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue