/** * @Description: * @author cxg * @date 2020/07/23 */ <template> <div :id="eid" ref="scanFile" class="scan-file-com"> <iframe v-show="convertSuccess" frameborder="0" :src="pdfUrl" allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true" oallowfullscreen="true" msallowfullscreen="true" style="height:100%;flex:1;width:100%" /> <div v-show="!convertSuccess" class="full-info" > <div class="title"> <span v-show="code==='error'">{{ errorMessage }}</span> <span v-show="code==='loading'">努力加载中</span> <span v-show="code==='noFiles'">无浏览文件</span> <span v-show="code==='noMasterFile'">无合适主文件</span> <span v-show="code==='noCheckIn'">文件尚未检入</span> <div v-show="code==='converttings'"> <img class="wait-img" src="/images/waitting.gif"> <div>{{ `正在转换 请等待!!!!!${time}秒后 ` }}<el-button type="text" @click="refresh">刷新</el-button></div> </div> <span v-show="code==='convertError'">转换失败 <el-button type="text" @click="reconvert">再次转换</el-button><el-button type="text" @click="refresh">刷新</el-button></span> </div> </div> <div v-show="showOtherFiles" class="show-files-btn"> <el-button type="text" title="查看其他PDF" icon="el-icon-more" @click="drawer=true" /> </div> <transition name="slideFade"> <div v-if="drawer" transiton="slideFade" class="pop-fileList slideFade"> <div class="header"> <span class="title">文件列表</span> <el-button type="text" icon="el-icon-s-fold" @click="()=>{drawer=false}" /> </div> <ul class="files-list"> <li v-for="file in filesList" :key="file.id" :class="[fileId===file.fileId?'active':'']" :title="file.name" @click="showFile(file)"> {{ file.name }} </li> </ul> </div> </transition> </div> </template> <script> import { get, post } from '@/utils/http' export default { name: 'DxDocumentScanFile', componentName: '浏览', props: { basicData: { type: Object, required: true, default: () => {} }, modelName: { type: String, default: () => '' }, permissions: { type: [Object, Array], default: () => null }, cmpOptions: { type: Object, default: () => null } }, data() { return { convertSuccess: false, code: '', errorMessage: '', pdfUrl: '', time: 0, loadTime: 0, timer: null, fileId: '', taskId: '', taskStatus: '', converted: false, showOtherFiles: false, filesList: [], deactivated: false, drawer: false } }, computed: { eid() { return 'id_' + this.$utils.guid().replaceAll('-', '') }, contentType() { const defaultContentType = 'DOC_PDF_FILE,PROCESS_CONTENTROLE_PDF' return this.$utils._get(this.cmpOptions, 'contentType') || defaultContentType }, // 展示规则 dispalyRule() { return this.$utils._get(this.cmpOptions, 'dispalyRule') || null }, IntervalTime() { return this.$utils._get(this.cmpOptions, 'IntervalTime') || 15 }, noMainFile() { const noMainFile = this.$utils._get(this.cmpOptions, 'noMainFile') const filter = this.$utils._get(this.cmpOptions, 'linksFilter.filter[0].formItems') if (noMainFile) { return noMainFile } else if (filter) { const item = filter.formItems.find(r => r.attrName === 'noMainFile') if (item) { return item.attrInput === 'true' } } return false }, funKey() { return this.$utils._get(this.cmpOptions, 'funKey') || 'docConvert' } }, watch: { basicData: { immediate: true, deep: true, handler: function(val) { this.getFileId() } }, '$store.state.scanFile.reLoadFile': { handler: function(val) { if (val && this.basicData) { this.getFileId() } } } }, mounted() { this.$utils.setFullPanel(this.$el) }, deactivated() { this.deactivated = true this.timer && clearTimeout(this.timer) }, activated() { this.deactivated = false }, destroyed() { this.timer && clearTimeout(this.timer) }, methods: { showFile(file) { if (file && file.fileId) { this.getPdf(file) } else { this.convertSuccess = false } }, reconvert() { post(`/DxTaskMessage/reAction?taskId=${this.taskId}`).then(res => { this.refresh() }) }, refresh() { this.code = 'converttings' clearTimeout(this.timer) this.time = this.IntervalTime this.wait() }, getFileId() { this.fileId = '' this.showOtherFiles = false this.filesList = [] this.pdfUrl = '' this.convertSuccess = false if (!this.basicData || !this.basicData.id) { return } if (!this.modelName) { return } this.getDetailWithRecursion({ id: this.basicData.id, openProps: ['objFileLinks.target'], url: `/${this.modelName}/find/recursion` }).then(res => { const objFileLinks = this.$utils._get(res, 'items.content[0].objFileLinks') || [] this.filesList = this.filterFilesByRuleType(objFileLinks) if (this.filesList.length > 0) { this.showOtherFiles = this.filesList.length > 1 // 没有设置主文件 if (this.noMainFile) { return this.getPdf(this.filesList[0]) } const masterFile = this.filesList.find(file => file.contentType === 'DOC_PDF_FILE') if (!masterFile) { this.getConvertState() this.showOtherFiles = true const masterFile = this.filesList.find(file => file.contentType === 'MASTER_FILE') if (!masterFile) { this.filesList.unshift({ fileId: '', name: '主文件' }) } if (this.filesList[0] && this.filesList[0].fileId) { this.getPdf(this.filesList[0]) } else { this.convertSuccess = false } } else { this.getPdf(masterFile) } } else { this.code = 'noFiles' } }).catch(err => { this.code = 'error' this.errorMessage = err.mesage }) }, filterFile(list) { return list.filter(r => r.target && r.target.fileExtension === 'pdf' && (this.contentType.includes(r.contentType))) }, getDetailWithRecursion({ id, openProps = [], url = '' }) { const params = { 'openProps': [], 'pageFrom': 1, 'pageSize': 10, 'searchItems': { 'children': [], 'items': [ { 'fieldName': 'id', 'operator': 'EQ', 'value': parseInt(id) } ], 'operator': 'AND' } } params.openProps = this.$utils.getOpenPropsByLists(openProps) return post(url, params) }, getPdf(file) { // 原文件id换成linkId if (!file) { return } if (this.fileId === file.id) { return } this.fileId = file.id this.code = 'loading' this.convertSuccess = false get('/dfs/fileManager/preview', { objName: file.sourceIdType, objId: file.sourceId, linkId: file.id }).then(res => { this.convertSuccess = true if (res.items.fileBase64) { // this.pdfUrl = 'pdf/web/viewer.html?file=/test.pdf' this.pdfUrl = `pdf/web/viewer.html?eid=${this.eid}&file=${window.URL.createObjectURL(new Blob([this.base64ToUint8Array(res.items.fileBase64)]))}` this.$store.dispatch('scanFile/setReLoadFile', false) } }).catch(err => { this.code = 'error' this.errorMessage = err.message }) }, base64ToUint8Array(base64String) { const padding = '='.repeat((4 - base64String.length % 4) % 4) const base64 = (base64String + padding) .replace(/\-/g, '+') .replace(/_/g, '/') const rawData = window.atob(base64) const outputArray = new Uint8Array(rawData.length) for (var i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i) } return outputArray }, waitLoadPDF() { if (!this.loadTime) { return } this.loadTime-- setTimeout(() => { this.getFileId() }, this.IntervalTime * 1000) }, getConvertState() { // 状态已显示转换 if (this.converted) { this.waitLoadPDF() return } get(`/DxJobTask/getJobTaskInfo?funKey=${this.funKey}&pboClass=${this.basicData.dxClassname.split('.').slice(-1)[0]}&pboId=${this.basicData.id}`).then(res => { if (!res.items) { this.code = 'noMasterFile' this.timer && clearTimeout(this.timer) return } // 还在转换 if (res.items.taskStatus === 'START') { this.code = 'converttings' this.converted = false this.time = this.IntervalTime this.wait() return } this.timer && clearTimeout(this.timer) this.taskId = res.items.id // 转换成功 读取文件 if (res.items.taskStatus === 'FINISHED') { this.converted = true this.loadTime = 5 this.getFileId() return } // 转换失败 if (res.items.taskStatus === 'ERROR') { this.error() return } // 转换暂停 if (res.items.taskStatus === 'STOP') { this.error() return } }).catch((err) => { this.code = 'error' this.timer && clearTimeout(this.timer) this.errorMessage = err.mesage }) }, error() { this.code = 'convertError' }, wait() { this.timer && clearTimeout(this.timer) this.timer = setTimeout(() => { this.time-- if (this.deactivated) { return } else if (this.time === 0) { this.getConvertState() clearTimeout(this.timer) } else { this.wait() } }, 1000) }, // 通过“展示规则”和“查看文件类型”对文件进行过滤和排序 filterFilesByRuleType(files) { const contentTypeList = this.contentType.split(',').filter(c => !!c) if (!(files && files.length)) { return [] } // 1.对文件进行排序 files.sort((a, b) => { const val = this.$moment(a.modifyTime) - this.$moment(b.modifyTime) return !!(!isNaN(val) && val < 0) }) // 2.找出所有文件类型(组件上设置的文件类型及其之外的文件类型),先按照文件内容类型对文件进行归类 const allConTentTypes = [...contentTypeList.map(type => ({ type, files: [] }))] files.forEach(f => { const file = { ...f, fileId: f.target.id, name: f.target.originalFileName } const type = file.contentType if (type && contentTypeList.includes(type)) { const item = allConTentTypes.find(m => m.type === type) item && item.files.push(file) } }) // 3.按照规则返回文件 if (this.dispalyRule === 'oneTypeFiles') { let i = 0 while (i < contentTypeList.length) { const files = allConTentTypes[i].files if (files.length > 0) { return files } i++ } return [] } else { return allConTentTypes.map(m => m.files).flat() } } } } </script> <style lang='scss'> .scan-file-com{ height: 100%; .pop-fileList{ .header{ background-color:#F3F6F7; display: flex; justify-content: space-between; line-height: 40px; padding-left: 10px; padding-right: 10px; align-items: center; } .title{ font-size: 14px; } } } .scan-file-com{ width: 100%; height: calc(100% - 40px); position: relative; .slideFade{ position: absolute; height: calc(100% - 2px); width: calc(50% - 506px); min-width: 100px; top:0px; left:0px; z-index: 10; background-color: #fff; border: 1px solid #d8d8d8; .files-list{ padding: 20px 10px; margin: 0; li{ width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; list-style: none; &.active{ color:#409EFF ; } margin: 10px 0; cursor: pointer; } } .el-dialog__header{ background: linear-gradient( 90deg, #2F6FA4 0%, #4D84A3 64%, #54A781 100%); height: 60px; padding: 0px; padding-left: 10px; line-height: 60px; .el-dialog__title{ color: #282828; font-size: 14px; } } } .slideFade-enter { animation: slideFade-dialog-fade-in 0.5s ease; } .slideFade-leave { animation: slideFade-dialog-fade-out 0.5s ease forwards; } .slideFade-enter-active { animation: slideFade-dialog-fade-in 0.5s ease; } .slideFade-leave-active { animation: slideFade-dialog-fade-out 0.5s ease forwards; } @keyframes slideFade-dialog-fade-in { 0% { transform: translate3d(-100%, 0, 0);//修改这个可以控制,上下左右动画,例如:100%为从右到左 opacity: 1; } 100% { transform: translate3d(0, 0, 0); opacity: 1; } } @keyframes slideFade-dialog-fade-out { 0% { transform: translate3d(0, 0, 0); opacity: 1; } 100% { transform: translate3d(-100%, 0, 0); opacity: 1; } } .show-files-btn{ position: absolute; top: -38px; left: 50px; z-index: 1; } .full-info{ height: 100%; width: 100%; background-color: #F3F6F7 ; display: flex; justify-content: center; align-items: center; .wait-img{ width: 200px; } .title{ color: #666; font-weight: 700; text-align: center; } } } </style>