Browse Source

AI辅助著录/知识图谱样式修改

master
xuhuajiao 4 months ago
parent
commit
a07d8a7b13
  1. 12
      src/api/collect/collect.js
  2. 14
      src/assets/styles/yxk-admin.scss
  3. 25
      src/views/AIAssistant/AICataloging/history/index.vue
  4. 664
      src/views/AIAssistant/AICataloging/index copy.vue
  5. 646
      src/views/AIAssistant/AICataloging/index.vue
  6. 387
      src/views/AIAssistant/AICataloging/running/index.vue
  7. 93
      src/views/AIAssistant/AICataloging/running/module/detail.vue
  8. 77
      src/views/collectReorganizi/collectionLibrary/module/collectHeader.vue
  9. 40
      src/views/components/echarts/graph.vue

12
src/api/collect/collect.js

@ -313,6 +313,15 @@ export function FetchInitExternalReceptionDetailsList(params) {
})
}
// AI著录 - 得到AI返回结果
export function FetchAIResultZhulu(params) {
return request({
url: 'api/collect/getAIResultZhulu',
method: 'get',
params
})
}
export default {
collectAdd,
collectEdit,
@ -344,5 +353,6 @@ export default {
FetchRestoreArchives,
FetchBusinessFlowTitle,
FetchBecomeDocument,
FetchInitExternalReceptionDetailsList
FetchInitExternalReceptionDetailsList,
FetchAIResultZhulu
}

14
src/assets/styles/yxk-admin.scss

@ -2084,3 +2084,17 @@ input[type ='number'] {
}
}
}
.check-btn{
color: #fff !important;
background-color: #0348f3;
}
.el-button.check-btn:hover,
.el-button.check-btn:focus,
.el-button--info.check-btn.is-plain:hover,
.el-button--info.check-btn.is-plain:focus{
color: #fff !important;
background-color: #0348f3 !important;
}

25
src/views/AIAssistant/AICataloging/history/index.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>

664
src/views/AIAssistant/AICataloging/index copy.vue

@ -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 // isType3
})
},
//
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>

646
src/views/AIAssistant/AICataloging/index.vue

@ -1,645 +1,55 @@
<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="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>
</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 { 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 {
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() {
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: {
...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 // isType3
})
},
//
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>
<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>

387
src/views/AIAssistant/AICataloging/running/index.vue

@ -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>

93
src/views/AIAssistant/AICataloging/running/module/detail.vue

@ -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>

77
src/views/collectReorganizi/collectionLibrary/module/collectHeader.vue

@ -178,7 +178,7 @@
</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 v-if="(isTitleType === 3 && selectedCategory.arrangeType === 1) || isTitleType === 4 || isTitleType === 6 || (isTitleType === 3 && activeIndex === 1)" type="primary" style="width: 84px;" @click="handleAiCategory">AI辅助著录</el-button>
<el-button type="primary" @click="handlerArchivesSubmit">保存</el-button>
</div>
</div>
@ -246,7 +246,7 @@
import CRUD, { crud } from '@crud/crud'
import { collectionLibraryCrud } from '../mixins/index'
import { FetchInitCategoryInputFieldByPid, FetchCategoryMenu } from '@/api/system/category/category'
import { FetchDetailsById, collectDel, FetchRemoveArchivesSingle, FetchDeleteArchivesFile, FetchUpdateArchivesNo, FetchDisbandArchives, FetchReturnReDocument, FetchCompleteDelArchives, FetchRestoreArchives } from '@/api/collect/collect'
import { FetchDetailsById, collectDel, FetchRemoveArchivesSingle, FetchDeleteArchivesFile, FetchUpdateArchivesNo, FetchDisbandArchives, FetchReturnReDocument, FetchCompleteDelArchives, FetchRestoreArchives, FetchAIResultZhulu } from '@/api/collect/collect'
import { FetchArchivesClassTree } from '@/api/system/archivesClass'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
@ -330,7 +330,8 @@ export default {
displayedText: '',
typingInterval: null,
typingFinished: false,
currentLineIndex: 0
currentLineIndex: 0,
shouldContinueFetching: true
}
},
computed: {
@ -569,6 +570,7 @@ export default {
},
//
handleClose(done) {
this.shouldContinueFetching = false
this.formVisible = false
this.quickPaper = false
@ -581,6 +583,7 @@ export default {
clearInterval(this.typingInterval)
}
this.fileList = []
this.aiLoading = false
done()
},
//
@ -1305,22 +1308,26 @@ export default {
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) {
// 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')
}
//
if (imageFiles.length > 3) {
this.$message.error('图片文件最多只能选择 3 个,请重新选择')
return
}
for (const file of imageFiles) {
//
if (this.fileList.some(item => item.name === file.name)) {
@ -1386,13 +1393,13 @@ export default {
}
},
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 = this.filePath[index].path
json.file_path = ''
json.archive_id = this.arcId
json.file_dpi = item.px
@ -1400,32 +1407,46 @@ export default {
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();
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 })
this.$message({ message: '著录附件传输失败', type: 'error', offset: 8 })
}
// this.handleClose()
})
})
.catch((error) => {
@ -1449,7 +1470,7 @@ export default {
this.typingFinished = true
if (this.aiJsonData) {
// this.$refs.previewForm.archivesType = 'add'
this.$refs.previewForm.addOrUpdateForm = JSON.parse(this.aiJsonData)
// this.$refs.previewForm.addOrUpdateForm = JSON.parse(this.aiJsonData)
this.aiLoading = false
}
}, 1000)

40
src/views/components/echarts/graph.vue

@ -33,19 +33,12 @@
import { getGraphData } from '../../../neo4j.js'
import RelationGraph from 'relation-graph'
const graph_json_data = {
'nodes': [
],
'lines': [
]
}
export default {
name: 'Demo',
components: { RelationGraph },
data() {
return {
allData: graph_json_data,
allData: { 'nodes': [], 'lines': [] },
isShowCodePanel: false,
isShowNodeTipsPanel: false,
nodeMenuPanelPosition: { x: 0, y: 0 },
@ -67,7 +60,7 @@ export default {
defaultLineColor: 'rgba(0,0,0,0.5)',
defaultNodeBorderWidth: 0,
defaultNodeBorderColor: 'transpanret',
defaultNodeFontColor: '#000',
defaultNodeFontColor: '#fff',
defaultFocusRootNode: false
},
isLoading: false,
@ -81,6 +74,8 @@ export default {
// const graphInstance = this.$refs.graphRef.getInstance();
// await graphInstance.zoomToFit();
}, 3000)
this.allData.nodes = []
this.allData.lines = []
const query = "MATCH path = (target:Archives {id: '0047B3542CE88B895E41DE'})-[rels:HAS_KEYWORD*1..4]-(related:Archives) WHERE target <> related UNWIND relationships(path) AS r WITH startNode(r) AS n, r, endNode(r) AS m, length(path)/2 AS depth RETURN DISTINCT n, r, m;"
this.fetchData(query)
},
@ -93,16 +88,29 @@ export default {
this.errorMessage = ''
try {
const { nodes, edges } = await getGraphData(query)
const colors = ['rgb(225,151,102)', 'rgb(194,159,87)', 'rgb(253,183,112)', 'rgb(127,181,123)', 'rgb(224,178,159)', 'rgb(196,149,72)', 'rgb(255,162,24)', 'rgb(189,237,229)']
const typeColorMap = {}
// ArchivesCategoryCategoryClassFondsKeywordsRetentionSecrecyPeriodSecurityClass
const newNodes = nodes.map(item => {
const newItem = { ...item, id: String(item.id) }
if (item.type) {
if (!typeColorMap[item.type]) {
typeColorMap[item.type] = colors[Object.keys(typeColorMap).length % colors.length]
const typeToColorMap = {
Archives: '#0348F3',
Category: '#14C9C9',
CategoryClass: '#F8B722',
Fonds: '#722ED1',
Keywords: '#F4647B',
Retention: '#018BFF',
SecrecyPeriod: '#FEBD98',
SecurityClass: '#B1EBDF'
}
newItem.color = typeColorMap[item.type]
newItem.borderColor = typeColorMap[item.type]
const defaultColor = '#000000' //
if (typeToColorMap[item.type]) {
newItem.color = typeToColorMap[item.type]
newItem.borderColor = typeToColorMap[item.type]
} else {
newItem.color = defaultColor
newItem.borderColor = defaultColor
}
return newItem
})

Loading…
Cancel
Save