Browse Source

预归档库优化

master
xuhuajiao 3 months ago
parent
commit
ebfa01ba13
  1. 63
      src/views/collectReorganizi/collectionLibrary/file/index.vue
  2. 63
      src/views/collectReorganizi/collectionLibrary/module/uploadFile/index.vue
  3. 666
      src/views/collectReorganizi/collectionLibrary/module/uploadOriginal/bigUpload22.vue
  4. 645
      src/views/components/category/preUpload4 -数组.vue
  5. 85
      src/views/prearchiveLibrary/file/index.vue
  6. 3
      src/views/prearchiveLibrary/index.vue
  7. 63
      src/views/prearchiveLibrary/module/detail.vue

63
src/views/collectReorganizi/collectionLibrary/file/index.vue

@ -52,32 +52,8 @@
<!-- @click="showCoverPreview(scope.row)" -->
<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-if="scope.row.file_type === 'ofd'">
<i class="fileIcon icon-ofd" />
</div>
<div v-else>
<i class="fileIcon icon-other" />
<div :class="getFileIconClass(scope.row.file_type)">
<i class="fileIcon" :class="getFileIconClass(scope.row.file_type)" />
</div>
</template>
</el-table-column>
@ -180,6 +156,41 @@ export default {
mounted() {
},
methods: {
getFileIconClass(fileType) {
if (!fileType) return 'icon-other'
const lowerFileType = fileType.toLowerCase()
switch (lowerFileType) {
case 'jpg':
case 'jpeg':
case 'png':
case 'bmp':
case 'gif':
return 'icon-image'
case 'xlsx':
case 'xls':
return 'icon-excel'
case 'docx':
case 'doc':
return 'icon-word'
case 'pdf':
return 'icon-pdf'
case 'ppt':
case 'pptx':
return 'icon-ppt'
case 'zip':
case 'rar':
return 'icon-zip'
case 'txt':
return 'icon-txt'
case 'ofd':
return 'icon-ofd'
//
default:
return 'icon-other'
}
},
getFileSize(fileSize) {
const fileSizeInKB = (fileSize / 1024).toFixed(2) + ' KB'
const fileSizeInB = fileSize + 'B'

63
src/views/collectReorganizi/collectionLibrary/module/uploadFile/index.vue

@ -36,32 +36,8 @@
</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-if="scope.row.file_type === 'ofd'">
<i class="fileIcon icon-ofd" />
</div>
<div v-else>
<i class="fileIcon icon-other" />
<div :class="getFileIconClass(scope.row.file_type)">
<i class="fileIcon" :class="getFileIconClass(scope.row.file_type)" />
</div>
</template>
</el-table-column>
@ -188,6 +164,41 @@ export default {
},
methods: {
getFileIconClass(fileType) {
if (!fileType) return 'icon-other'
const lowerFileType = fileType.toLowerCase()
switch (lowerFileType) {
case 'jpg':
case 'jpeg':
case 'png':
case 'bmp':
case 'gif':
return 'icon-image'
case 'xlsx':
case 'xls':
return 'icon-excel'
case 'docx':
case 'doc':
return 'icon-word'
case 'pdf':
return 'icon-pdf'
case 'ppt':
case 'pptx':
return 'icon-ppt'
case 'zip':
case 'rar':
return 'icon-zip'
case 'txt':
return 'icon-txt'
case 'ofd':
return 'icon-ofd'
//
default:
return 'icon-other'
}
},
getFileSize(fileSize) {
const fileSizeInKB = (fileSize / 1024).toFixed(2) + ' KB'
const fileSizeInB = fileSize + 'B'

666
src/views/collectReorganizi/collectionLibrary/module/uploadOriginal/bigUpload22.vue

@ -0,0 +1,666 @@
<template>
<div>
<!--上传组件-->
<el-dialog class="big-file" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="uploadBigVisible" :before-close="handleCloseDialog">
<template #title>
{{ uploadTitle }}
<span style="color: red;font-size: 12px; ">单个文件不可超过10GB</span>
</template>
<div class="setting-dialog">
<div class="uploader-big">
<uploader
ref="uploader"
:key="uploaderKey"
:auto-start="false"
:options="options"
:file-status-text="statusText"
@file-success="fileSuccess"
@files-added="filesAdded"
@file-error="onFileError"
@file-removed="filesRemove"
>
<uploader-unsupport />
<uploader-drop>
<p>{{ !isCatalogUpload ? '将文件拖到此处,或点击上传(可多文件上传)' : "将ZIP包拖到此处, 或点击上传(只可单文件上传)" }}</p>
<uploader-btn :attrs="attrs">
<slot>
<i class="iconfont icon-tianjiawenjian upload-icon" />
</slot>
</uploader-btn>
<div class="el-upload__tip">上传限制文件大小最大10GB/</div>
</uploader-drop>
<!-- <uploader-files /> -->
<uploader-list>
<!--通过slot-scope绑定文件实例-->
<div slot-scope="props" class="set-file">
<div v-for="(file,i) in props.fileList" :key="i">
<uploader-file
:list="true"
:file="file"
:class=" file.fileType.substring(0, file.fileType.indexOf('/')) === 'image' ? 'icon-image' : `icon-`+file.name.substring(
file.name.lastIndexOf('.') + 1,
file.name.length
)"
/>
</div>
</div>
</uploader-list>
</uploader>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="handleCloseDialog">取消</el-button>
<el-button :loading="btnLoading" type="primary" @click="handleUploadConfirm">保存</el-button>
</div>
</div>
</el-dialog>
<!-- 判断是否有重复上传的文件 -->
<el-dialog class="collectUpload-dialog" title="文件上传" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="repeatFileVisible">
<div class="setting-dialog">
<p style="color:#f00;margin-bottom: 20px;display:block">提示以下所选文件在当前档案文件列表已存在</p>
<div v-for="item in repeatFileData" :key="item.name" class="file-list" style="margin-bottom: 10px;">
<i class="iconfont icon-xiaowenjian" />
{{ item.name }}
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleRepeatFile(0)">直接上传</el-button>
<el-button style="width: 85px;" type="primary" @click="handleRepeatFile(1)">去重后上传</el-button>
<el-button type="text" @click="repeatFileVisible = false">取消</el-button>
</div>
</el-dialog>
<!-- 目录上传报错 -->
<el-dialog class="catalog-dialog" title="目录上传-失败列表" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="catalogErrorVisible">
<div class="setting-dialog">
<div style="margin-bottom: 20px; display:flex; justify-content: flex-start;">
<p style="margin-right: 20px;">总条数 <span style=" font-weight: bold;">{{ resultCatalog && resultCatalog.mountFile.total }} </span> </p>
<p style="margin-right: 20px;">成功 <span style="color:#1AAE93; font-weight: bold;">{{ resultCatalog && resultCatalog.mountFile.successNum }} </span> </p>
<p>失败 <span style="color:#f00; font-weight: bold; ">{{ resultCatalog && resultCatalog.mountFile.failNum }}</span> </p>
</div>
<el-table class="archives-table" :data="catalogInfoData" style="min-width: 100%" height="calc(100vh - 676px)">
<el-table-column type="expand">
<template #default="{ row }">
<el-row style="padding-left: 20px;">
<el-col :span="24" style="line-height: 30px;">
<div v-for="(file, index) in row.children" :key="index"><i class="iconfont icon-xiaowenjian" />{{ file }}</div>
</el-col>
</el-row>
</template>
</el-table-column>
<el-table-column prop="archives" label="档案/电子原文" />
<el-table-column prop="description" label="失败原因" />
</el-table>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="catalogErrorVisible = false">确定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { FetchInitFileCategoryView } from '@/api/collect/collect'
import { mapGetters } from 'vuex'
import axios from 'axios'
import SparkMD5 from 'spark-md5'
import { getToken } from '@/utils/auth'
import { getCurrentTime } from '@/utils/index'
import { catalogUpload } from '@/utils/upload'
// https://juejin.cn/post/7040817922540830728
export default {
props: {
selectedCategory: {
type: Object,
default: function() {
return {}
}
},
arcId: {
type: String,
default: function() {
return ''
}
}
},
data() {
return {
isCatalogUpload: false,
uploadTitle: '文件上传',
btnLoading: false,
uploadBigVisible: false,
skip: false,
options: {
target: null,
//
testChunks: true, //
singleFile: false, //
uploadMethod: 'post', // 使 HTTP , POST
parseTimeRemaining: function(timeRemaining, parsedTimeRemaining) {
return parsedTimeRemaining
.replace(/\syears?/, '年')
.replace(/\days?/, '天')
.replace(/\shours?/, '小时')
.replace(/\sminutes?/, '分钟')
.replace(/\sseconds?/, '秒')
},
//
checkChunkUploadedByResponse: (chunk, message) => {
const result = JSON.parse(message)
if (result.data.skipUpload) {
this.skip = true
return true
}
return (result.data.uploaded || []).indexOf(chunk.offset + 1) >= 0
},
headers: {
'Authorization': getToken()
},
processParams: (params, file, chunk) => {
params.fileMd5 = chunk.file.uniqueIdentifier
params.chunkIndex = chunk.offset
return params
}
},
attrs: {
accept: '',
multiple: true
},
//
statusText: {
success: '上传成功',
error: '上传出错了',
uploading: '上传中...',
paused: '暂停中...',
waiting: '等待中...',
cmd5: '计算文件MD5中...'
},
fileList: [],
nowDate: null,
submitted: false,
//
repeatFileVisible: false,
repeatFileData: [],
originFileData: [],
uploaderKey: 0,
resultCatalog: {
mountFile: {},
failArchives: []
},
catalogErrorVisible: false,
catalogInfoData: []
}
},
computed: {
...mapGetters([
'baseApi'
])
},
mounted() {
this.options.target = this.baseApi + '/api/collect/chunk'
},
methods: {
opened() {
this.$nextTick(() => {
if (!this.isCatalogUpload) {
this.uploadTitle = '文件上传'
this.attrs = { accept: '', multiple: true }
this.options.singleFile = false
} else {
this.uploadTitle = '原文目录上传'
this.attrs = { accept: '.zip', multiple: false }
this.options.singleFile = true
}
this.uploaderKey++
console.log('this.isCatalogUpload', this.isCatalogUpload)
this.uploadBigVisible = true
})
},
updateUploadOptions(uploadType) {
console.log('uploadType', uploadType)
if (uploadType === 1) {
this.isCatalogUpload = false
this.uploadTitle = '文件上传'
this.attrs = { accept: '' }
this.options.singleFile = false
} else {
this.isCatalogUpload = true
this.uploadTitle = '原文目录上传'
this.attrs = { accept: '.zip' }
this.options.singleFile = true
}
console.log('this.attrs.accept', this.attrs.accept)
this.uploaderKey++
this.uploadBigVisible = true
},
//
getFileList() {
const params = {
'categoryId': this.selectedCategory.id,
'archivesId': this.arcId
}
return FetchInitFileCategoryView(params).then(data => {
this.originFileData = data.returnlist
})
},
fileSuccess(rootFile, file, response, chunk) {
this.chunkOffset = []
const result = JSON.parse(response)
console.log('result', result)
this.fileList.push(file)
if (result.code === 200 && this.fileList.length !== 0) {
this.submitted = true
} else {
this.submitted = false
}
if (this.skip) {
this.skip = false
}
},
filesRemove(file, index) {
const uploaderInstance = this.$refs.uploader.uploader
const temp = uploaderInstance.fileList.findIndex(e => e.uniqueIdentifier === file.uniqueIdentifier)
if (temp > -1) {
uploaderInstance.fileList[temp].cancel() //
}
this.fileList = this.fileList.filter(f => f.uniqueIdentifier !== file.uniqueIdentifier)
},
handleUploadConfirm() {
if (this.$refs.uploader.fileList.length === 0) {
this.$message({ message: '请选择要上传的文件!', type: 'error', offset: 8 })
return false
}
this.nowDate = getCurrentTime()
const jsonArrayToSend = []
console.log('this.$refs.uploader.fileList', this.$refs.uploader.fileList)
// 使 Promise.all
Promise.all(this.$refs.uploader.fileList.map(async(item) => {
const json = {}
const jsonArray = []
const jsonString = {}
if (item.file.type.substring(0, item.file.type.indexOf('/')) === 'image') {
const fileBase64 = await this.getBase64(item.file)
const imgRes = await this.getImgPx(fileBase64)
item.file.px = imgRes.width + 'px*' + imgRes.height + 'px'
} else {
item.file.px = ''
}
jsonString.file_name = item.file.name
jsonString.file_size = item.file.size
jsonString.file_type = item.file.name.substring(item.name.lastIndexOf('.') + 1, item.file.name.length)
json.last_modified = item.file.lastModified
jsonString.file_path = ''
jsonString.sequence = null
jsonString.archive_id = this.arcId
jsonString.file_dpi = item.file.px
jsonString.file_thumbnail = ''
jsonString.create_time = this.nowDate
jsonString.id = null
jsonArray.push(jsonString)
json.categoryId = this.selectedCategory.id
json.archivesId = this.arcId
json.identifier = item.uniqueIdentifier
json.filename = item.name
json.totalChunks = item.chunks.length - 1
json.totalSize = item.size
json.fileJsonString = JSON.stringify(jsonArray)
jsonArrayToSend.push(json)
})).then(() => {
console.log('jsonArrayToSend', jsonArrayToSend)
if (this.$refs.uploader.fileList.every(item => item.completed) && this.submitted) {
this.btnLoading = true
this.submitted = false
axios.post(this.baseApi + '/api/collect/merge', jsonArrayToSend, {
headers: {
'Authorization': getToken()
}
}).then((res) => {
console.log('merge', res.data.data)
if (res.data.code === 200) {
if (this.isCatalogUpload && res.data.data.length === 1 && res.data.data[0] !== '') {
//
catalogUpload(this.baseApi + '/api/collect/catalogUpload',
res.data.data[0],
this.selectedCategory.fondsId
).then(res => {
if (res.data.code === 200) {
this.resultCatalog = res.data.data
if (this.resultCatalog.mountFile.total === this.resultCatalog.mountFile.successNum) {
this.$message({ message: '目录上传操作成功', type: 'success', offset: 8 })
} else if (this.resultCatalog.mountFile.total === this.resultCatalog.mountFile.failNum) {
this.catalogErrorVisible = true
} else {
this.catalogErrorVisible = true
}
this.catalogInfoData = []
this.resultCatalog.failArchives.forEach(item => {
const parts = item.split(':')
if (parts.length === 2) {
const field = parts[0]
let fileStr = parts[1]
//
fileStr = fileStr.replace(/\[|\]/g, '')
//
const fileArray = fileStr.split(',').map(file => file.trim())
// field
const match = field.match(/^([\w-·]+)(.*)$/)
let archives = ''
let description = ''
if (match) {
archives = match[1]
description = match[2]
}
this.catalogInfoData.push({
archives,
description,
children: fileArray
})
}
})
console.log('catalogInfoData', this.catalogInfoData)
this.$emit('close-dialog')
} else {
console.log('result1', res.data)
console.log('result2', res.data.message)
this.$message({ message: res.data.message, type: 'error', offset: 8 })
}
this.handleCloseDialog()
})
} else {
this.$message({ message: '所有文件上传成功', type: 'success', offset: 8 })
this.$emit('close-dialog')
this.handleCloseDialog()
}
} else {
this.$message({ message: '部分或全部文件上传失败', type: 'error', offset: 8 })
this.handleCloseDialog()
}
})
} else {
this.submitted = false
this.$message({ message: '请耐心等待文件上传完成后再保存!', type: 'error', offset: 8 })
}
})
},
onFileError(rootFile, file, message, chunk) {
this.$message({ message: `上传出错:${file.name} - ${message}`, type: 'error', offset: 8 })
},
handleRepeatFileCancel() {
this.repeatFileVisible = false
this.repeatFileData = []
this.originFileData = []
const uploaderInstance = this.$refs.uploader.uploader
uploaderInstance.fileList.forEach(file => file.cancel())
},
handleRepeatFile(type) {
if (type === 0) {
//
this.fileList.forEach(file => this.computeMD5(file))
} else {
//
const nonRepeatFileData = this.fileList.filter(file => !this.repeatFileData.some(repeatFile => repeatFile.name === file.name))
if (nonRepeatFileData.length === 0) {
this.$message({ message: '当前所选文件去重后无可上传的文件', type: 'error', offset: 8 })
this.handleRepeatFileCancel()
this.handleCloseDialog()
} else {
//
const uploaderInstance = this.$refs.uploader
uploaderInstance.fileList = uploaderInstance.fileList.filter(file => nonRepeatFileData.some(nonRepeatFile => nonRepeatFile.uniqueIdentifier === file.uniqueIdentifier))
this.$refs.uploader.files = this.$refs.uploader.files.filter(file => nonRepeatFileData.some(nonRepeatFile => nonRepeatFile.uniqueIdentifier === file.uniqueIdentifier))
nonRepeatFileData.forEach(file => this.computeMD5(file))
}
}
this.repeatFileVisible = false
},
async filesAdded(file, fileList, event) {
if (!this.isCatalogUpload) {
//
await this.getFileList()
file.forEach((e) => {
this.fileList.push(e)
const existingFileNames = this.originFileData.map(file => file.file_name)
this.repeatFileData = this.fileList.filter(file => existingFileNames.includes(file.name))
console.log('filteredFileList', this.repeatFileData)
if (this.repeatFileData.length === 0) {
this.computeMD5(e)
} else {
this.repeatFileVisible = true
}
})
} else {
file.forEach((e) => {
this.fileList.push(e)
this.computeMD5(e)
})
}
},
computeMD5(file) {
const maxMessage = '上传文件大小不能超过 10GB!'
const maxSize = 10 * 1024 * 1024 * 1024
if (file && file.size > maxSize) {
this.$message.warning(maxMessage)
return false
}
const fileReader = new FileReader()
const time = new Date().getTime()
const blobSlice =
File.prototype.slice ||
File.prototype.mozSlice ||
File.prototype.webkitSlice
let currentChunk = 0
//
const chunkSize = 10 * 1024 * 1024
const chunks = Math.ceil(file.size / chunkSize)
const spark = new SparkMD5.ArrayBuffer()
// "MD5"
file.cmd5 = true
file.pause()
// loadNext
const loadNext = () => {
const start = currentChunk * chunkSize
const end = start + chunkSize >= file.size ? file.size : start + chunkSize
fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end))
}
loadNext()
fileReader.onload = (e) => {
spark.append(e.target.result)
if (currentChunk < chunks) {
currentChunk++
loadNext()
// MD5
console.log(
`${currentChunk}分片解析完成, 开始第${
currentChunk + 1
} / ${chunks}分片解析`
)
} else {
const md5 = spark.end()
console.log(
`MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${
file.size
} 用时${new Date().getTime() - time} ms`
)
console.log('md5', md5)
spark.destroy() //
file.uniqueIdentifier = md5 // md5
file.cmd5 = false // md5
file.resume() //
}
}
fileReader.onerror = function() {
this.error(`文件${file.name}读取出错,请检查该文件`)
file.cancel()
}
},
// 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 })
}
})
},
handleCloseDialog(done) {
this.btnLoading = false
this.uploadBigVisible = false
const uploaderInstance = this.$refs.uploader.uploader
console.log('uploaderInstance.fileList', uploaderInstance.fileList)
uploaderInstance.fileList.forEach(file => file.cancel())
uploaderInstance.fileList = []
uploaderInstance.files = []
this.fileList = []
this.$refs.uploader.files = []
this.$refs.uploader.fileList = []
// isCatalogUpload attrs
this.isCatalogUpload = false
this.attrs = { accept: '', multiple: true }
this.uploaderKey++
}
}
}
</script>
<style lang="scss" scoped>
.uploader-big{
width: 100%;
.uploader{
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
text-align: center;
margin-bottom: 8px;
.uploader-drop{
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
height: 180px;
// padding: 20px 0;
border: none;
.uploader-btn{
// width: 120px;
margin: 20px 0 20px 0;
padding: 0;
border: none;
i{
font-size: 32px;
color: #1F55EB;
}
&:hover{
background-color: transparent;
}
}
.el-upload__tip{
font-size: 12px;
color: #A6ADB6;
}
}
}
.upload-big-button{
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
margin: 10px 0 5px 0;
}
}
.uploader-file[status="success"] .uploader-file-remove {
display:block
}
::v-deep .uploader-list{
max-height: 344px;
overflow-y: scroll;
.uploader-file-size{
text-align: right !important;
}
.uploader-file-icon:before{
content: "";
}
.uploader-file-name{
text-align: left !important;
}
.uploader-file{
.uploader-file-icon:before{
background: url("~@/assets/images/fileIcon/attachment.png") no-repeat;
background-size: 100% 100%;
}
&.icon-image{
.uploader-file-icon:before{
background: url("~@/assets/images/fileIcon/image.png") no-repeat;
background-size: 100% 100%;
}
}
&.icon-excel,&.icon-xlsx,&.icon-xls{
.uploader-file-icon:before{
background: url("~@/assets/images/fileIcon/excel.png") no-repeat;
background-size: 100% 100%;
}
}
&.icon-pdf{
.uploader-file-icon:before{
background: url("~@/assets/images/fileIcon/pdf.png") no-repeat;
background-size: 100% 100%;
}
}
&.icon-ppt, &.icon-pptx{
.uploader-file-icon:before{
background: url("~@/assets/images/fileIcon/ppt.png") no-repeat;
background-size: 100% 100%;
}
}
&.icon-word,&.icon-docx,&.icon-doc{
.uploader-file-icon:before{
background: url("~@/assets/images/fileIcon/word.png") no-repeat;
background-size: 100% 100%;
}
}
&.icon-zip,&.icon-rar{
.uploader-file-icon:before{
background: url("~@/assets/images/fileIcon/zip.png") no-repeat;
background-size: 100% 100%;
}
}
&.icon-txt{
.uploader-file-icon:before{
background: url("~@/assets/images/fileIcon/txt.png") no-repeat;
background-size: 100% 100%;
}
}
&.icon-ofd{
.uploader-file-icon:before{
background: url("~@/assets/images/fileIcon/OFD.png") no-repeat;
background-size: 100% 100%;
}
}
}
}
</style>

645
src/views/components/category/preUpload4 -数组.vue

@ -1,645 +0,0 @@
<template>
<div class="upload-container">
<!-- 多文件选择框添加multiple属性 -->
<input type="file" multiple @change="handleFileSelect">
<!-- 遍历展示每个文件的上传状态 -->
<div v-for="(fileItem, index) in fileList" :key="index" class="file-item">
<div class="file-name">{{ fileItem.file.name }}</div>
<!-- 上传进度条 -->
<div v-if="fileItem.uploading" class="progress-wrapper">
<div class="progress-bar" :style="{ width: fileItem.progress + '%' }" />
<span class="progress-text">上传进度: {{ fileItem.progress }}%</span>
</div>
<!-- 合并中状态 -->
<div v-if="fileItem.merging" class="merge-loading">
<span>合并中...</span>
</div>
<!-- 验签中状态 -->
<div v-if="fileItem.verifying" class="verify-loading">
<span>验签中...</span>
</div>
<!-- 上传错误信息 -->
<p v-if="fileItem.errorMsg" class="error">{{ fileItem.errorMsg }}</p>
<!-- 上传成功+验签结果 -->
<div v-if="fileItem.successMsg" class="success-section">
<p class="success">{{ fileItem.successMsg }}</p>
<!-- 验签成功 -->
<p v-if="fileItem.verifySuccess" class="verify-success"> 验签成功</p>
<!-- 验签失败 -->
<p v-if="fileItem.verifyError" class="verify-error"> 验签失败: {{ fileItem.verifyError }}</p>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import SparkMD5 from 'spark-md5'
import { getToken } from '@/utils/auth'
// getCurrentTime
const getCurrentTime = () => {
return new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
}
export default {
name: 'MinioMultiChunkUpload',
props: {
selectedDocument: {
type: Object,
default: () => ({})
},
arcId: {
type: String,
default: ''
},
selectedCategory: {
type: Object,
default: () => ({})
},
isBatchMount: {
type: String,
default: ''
}
},
data() {
return {
fileList: [], //
CHUNK_SIZE: 5 * 1024 * 1024, // (5MB)
totalMergeStartTime: null, //
totalMergeEndTime: null, //
baseApi: '', //
allChunksUploaded: false //
}
},
methods: {
/**
* 工具方法格式化时间戳为易读的本地时间带毫秒
* @param {number} timestamp - 时间戳
* @returns {string} 格式化后的时间字符串
*/
formatTime(timestamp) {
if (!timestamp) return '无'
return new Date(timestamp).toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
millisecond: '3-digit'
})
},
/**
* 工具方法计算两个时间戳的差值并格式化
* @param {number} start - 开始时间戳
* @param {number} end - 结束时间戳
* @returns {string} 格式化的耗时字符串
*/
getTimeDiff(start, end) {
if (!start || !end) return '0ms'
const diff = end - start
if (diff < 1000) return `${diff}ms`
if (diff < 60000) return `${(diff / 1000).toFixed(2)}s`
return `${(diff / 60000).toFixed(2)}min`
},
/**
* 工具方法获取图片分辨率
* @param {string} base64 - 图片base64编码
* @returns {Promise<{width: number, height: number}>} 图片宽高
*/
getImgPx(base64) {
return new Promise((resolve) => {
const img = new Image()
img.onload = () => {
resolve({ width: img.width, height: img.height })
}
img.src = base64
})
},
/**
* 工具方法将文件转为base64
* @param {File} file - 文件对象
* @returns {Promise<string>} base64编码
*/
getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result)
reader.onerror = (err) => reject(err)
})
},
/**
* 工具方法显示提示信息可替换为项目的Message组件
* @param {string} msg - 提示内容
* @param {string} type - 类型success/error
*/
showMessage(msg, type) {
if (type === 'error') {
console.error(msg)
} else {
console.log(msg)
}
// ElementUI/NaiveUI
// this.$message[type](msg)
},
/**
* 重置上传状态
*/
resetUploadState() {
this.allChunksUploaded = false
//
},
/**
* 多文件选择处理函数
* @param {Event} e - 选择文件的事件对象
*/
async handleFileSelect(e) {
const selectedFiles = Array.from(e.target.files) //
if (selectedFiles.length === 0) return
//
const newFileList = selectedFiles.map(file => ({
file, //
uploading: false, //
merging: false, //
progress: 0, //
errorMsg: '', // /
successMsg: '', //
verifying: false, //
verifySuccess: false, //
verifyError: '', //
md5: '', // MD5
//
md5StartTime: null, // MD5
md5EndTime: null, // MD5
chunkUploadStartTime: null, //
chunkUploadEndTime: null, //
mergeStartTime: null, //
mergeEndTime: null, //
verifyStartTime: null, //
verifyEndTime: null //
}))
this.fileList = [...this.fileList, ...newFileList]
//
for (const fileItem of newFileList) {
await this.uploadFileChunks(fileItem)
}
//
this.allChunksUploaded = true
this.handleUploadConfirm()
},
/**
* 单个文件的分片上传流程仅上传分片不立即合并
* @param {Object} fileItem - 文件状态对象
*/
async uploadFileChunks(fileItem) {
const file = fileItem.file
fileItem.uploading = true
fileItem.progress = 0
fileItem.errorMsg = ''
fileItem.successMsg = ''
try {
// 1. MD5
const fileMd5 = await this.calculateFileMd5(file, fileItem)
fileItem.md5 = fileMd5 // MD5
console.log(`${file.name}】文件MD5:`, fileMd5)
// 2.
const totalChunks = Math.ceil(file.size / this.CHUNK_SIZE)
console.log(`${file.name}】总分片数:`, totalChunks)
// 3.
fileItem.chunkUploadStartTime = new Date().getTime()
console.log(`${file.name}】分片上传开始时间:${this.formatTime(fileItem.chunkUploadStartTime)}`)
const uploadedChunks = []
for (let i = 0; i < totalChunks; i++) {
//
const checkResult = await this.checkChunkExists(fileMd5, i)
if (!checkResult.exists) {
//
await this.uploadSingleChunk(file, fileMd5, i)
}
uploadedChunks.push(i)
fileItem.progress = Math.round((uploadedChunks.length / totalChunks) * 100)
}
//
fileItem.chunkUploadEndTime = new Date().getTime()
console.log(`${file.name}】分片上传结束时间:${this.formatTime(fileItem.chunkUploadEndTime)},耗时:${this.getTimeDiff(fileItem.chunkUploadStartTime, fileItem.chunkUploadEndTime)}`)
fileItem.progress = 100 // 100%
} catch (err) {
//
const fileName = file.name
if (fileItem.chunkUploadStartTime && !fileItem.chunkUploadEndTime) {
fileItem.chunkUploadEndTime = new Date().getTime()
console.log(`${fileName}】分片上传异常结束时间:${this.formatTime(fileItem.chunkUploadEndTime)},耗时:${this.getTimeDiff(fileItem.chunkUploadStartTime, fileItem.chunkUploadEndTime)}`)
}
fileItem.errorMsg = '分片上传失败: ' + (err.message || '未知错误')
console.error(`${fileName}】分片上传流程异常:`, err.message)
this.allChunksUploaded = false //
} finally {
fileItem.uploading = false
}
},
/**
* 计算文件MD5用于分片唯一标识
* @param {File} file - 待上传的文件
* @param {Object} fileItem - 文件状态对象
* @returns {Promise<string>} 文件的MD5值
*/
calculateFileMd5(file, fileItem) {
return new Promise((resolve, reject) => {
// MD5
fileItem.md5StartTime = new Date().getTime()
console.log(`${file.name}】MD5计算开始时间:${this.formatTime(fileItem.md5StartTime)}`)
const spark = new SparkMD5.ArrayBuffer()
const fileReader = new FileReader()
const chunkSize = 2 * 1024 * 1024 // MD5
let offset = 0
const loadNextChunk = () => {
const blob = file.slice(offset, offset + chunkSize)
fileReader.readAsArrayBuffer(blob)
}
fileReader.onload = (e) => {
spark.append(e.target.result)
offset += chunkSize
if (offset < file.size) {
loadNextChunk()
} else {
// MD5
fileItem.md5EndTime = new Date().getTime()
console.log(`${file.name}】MD5计算结束时间:${this.formatTime(fileItem.md5EndTime)},耗时:${this.getTimeDiff(fileItem.md5StartTime, fileItem.md5EndTime)}`)
resolve(spark.end())
}
}
fileReader.onerror = (err) => {
reject(err)
}
loadNextChunk()
})
},
/**
* 校验所有分片是否存在合并前的二次校验
* @param {string} fileMd5 - 文件MD5
* @param {number} totalChunks - 总分片数
* @returns {Promise<boolean>} 所有分片是否都存在
*/
async checkAllChunksExist(fileMd5, totalChunks) {
for (let i = 0; i < totalChunks; i++) {
const result = await this.checkChunkExists(fileMd5, i)
if (!result.exists) {
console.warn(`${fileMd5}】分片${i}未上传`)
return false
}
}
return true
},
/**
* 检查分片是否已存在断点续传核心
* @param {string} fileMd5 - 文件MD5
* @param {number} chunkIndex - 分片索引
* @returns {Promise<Object>} 分片存在状态
*/
async checkChunkExists(fileMd5, chunkIndex) {
const response = await axios.get('/api/minioUpload/chunk', {
params: {
fileMd5,
chunkIndex
},
headers: { 'Authorization': getToken() }
})
if (response.data.code !== 200) {
throw new Error('检查分片失败: ' + response.data.msg)
}
return response.data.data
},
/**
* 上传单个分片
* @param {File} file - 待上传的文件
* @param {string} fileMd5 - 文件MD5
* @param {number} chunkIndex - 分片索引
*/
async uploadSingleChunk(file, fileMd5, chunkIndex) {
//
const start = chunkIndex * this.CHUNK_SIZE
const end = Math.min(start + this.CHUNK_SIZE, file.size)
const chunkBlob = file.slice(start, end)
// FormData
const formData = new FormData()
formData.append('file', chunkBlob, `${fileMd5}_${chunkIndex}`)
formData.append('fileMd5', fileMd5)
formData.append('chunkIndex', chunkIndex)
const response = await axios.post('/api/minioUpload/chunk', formData, {
headers: {
'Content-Type': 'multipart/form-data',
'Authorization': getToken()
}
})
if (response.data.code !== 200) {
throw new Error(`分片${chunkIndex}上传失败: ` + response.data.msg)
}
},
/**
* 所有文件分片上传完成后自动执行批量合并核心改造方法
*/
async handleUploadConfirm() {
if (this.fileList.length === 0 || !this.allChunksUploaded) {
this.showMessage('没有可处理的文件或分片上传未完成!', 'error')
return
}
//
const validFiles = this.fileList.filter(item => !item.errorMsg && item.progress === 100)
if (validFiles.length === 0) {
this.showMessage('无有效分片上传完成的文件!', 'error')
return
}
//
this.totalMergeStartTime = new Date().getTime()
console.log(`【整体合并】所有文件分片上传完成,开始合并,合并开始时间:${this.formatTime(this.totalMergeStartTime)}`)
const nowDate = getCurrentTime()
const jsonArrayToSend = []
//
validFiles.forEach(fileItem => {
fileItem.merging = true
fileItem.mergeStartTime = new Date().getTime()
console.log(`【文件${fileItem.file.name}】合并开始时间:${this.formatTime(fileItem.mergeStartTime)}`)
})
try {
//
const processFiles = validFiles.map(async(fileItem) => {
const file = fileItem.file
const json = {}
const jsonArray = []
const jsonString = {}
//
if (file.type.startsWith('image')) {
const fileBase64 = await this.getBase64(file)
const imgRes = await this.getImgPx(fileBase64)
jsonString.file_dpi = `${imgRes.width}px*${imgRes.height}px`
} else {
jsonString.file_dpi = ''
}
// handleUploadConfirm
jsonString.file_name = file.name
jsonString.file_size = file.size
jsonString.file_type = file.name.split('.').pop() || ''
json.last_modified = file.lastModified
jsonString.file_path = ''
jsonString.sequence = null
jsonString.archive_id = this.arcId
jsonString.create_time = nowDate
jsonString.id = null
jsonString.file_thumbnail = ''
jsonArray.push(jsonString)
//
if (this.isBatchMount === 'true') {
json.categoryId = this.selectedCategory.id
} else {
json.documentId = this.selectedDocument.id
}
//
const totalChunks = Math.ceil(file.size / this.CHUNK_SIZE)
//
const chunksExist = await this.checkAllChunksExist(fileItem.md5, totalChunks)
if (!chunksExist) {
throw new Error(`${file.name}】部分分片未上传完成,无法合并`)
}
json.archivesId = this.arcId
json.identifier = fileItem.md5
json.filename = file.name
json.totalChunks = totalChunks
json.totalSize = file.size
json.fileJsonString = JSON.stringify(jsonArray)
jsonArrayToSend.push(json)
return json
})
//
const jsonArray = await Promise.all(processFiles)
// /api/minioUpload/merge
const response = await axios.post('/api/minioUpload/merge', jsonArray, {
headers: {
'Authorization': getToken(),
'Content-Type': 'application/json' // JSON
}
})
//
this.totalMergeEndTime = new Date().getTime()
const totalMergeDuration = this.getTimeDiff(this.totalMergeStartTime, this.totalMergeEndTime)
if (response.data.code === 200) {
this.showMessage('所有文件合并成功', 'success')
//
validFiles.forEach((fileItem, index) => {
fileItem.mergeEndTime = new Date().getTime()
const mergeDuration = this.getTimeDiff(fileItem.mergeStartTime, fileItem.mergeEndTime)
console.log(`【文件${fileItem.file.name}】合并结束时间:${this.formatTime(fileItem.mergeEndTime)},合并耗时:${mergeDuration}`)
//
const mergeResult = response.data.data[index] || {}
fileItem.successMsg = '上传成功! 路径: ' + (mergeResult.filePath || '未知路径')
fileItem.merging = false
//
this.verifySignature(fileItem, mergeResult)
})
console.log(`【整体合并】所有文件合并完成,合并结束时间:${this.formatTime(this.totalMergeEndTime)},整体合并耗时:${totalMergeDuration}`)
this.$emit('onUploadSuccess', response.data.data, validFiles.map(f => f.file.name), jsonArrayToSend)
} else {
throw new Error(response.data.msg || '合并失败')
}
} catch (err) {
//
this.totalMergeEndTime = new Date().getTime()
const totalMergeDuration = this.getTimeDiff(this.totalMergeStartTime, this.totalMergeEndTime)
console.log(`【整体合并】合并失败,失败时间:${this.formatTime(this.totalMergeEndTime)},合并耗时:${totalMergeDuration},异常信息:`, err)
this.showMessage(`合并失败: ${err.message}`, 'error')
//
validFiles.forEach(fileItem => {
fileItem.merging = false
fileItem.errorMsg = fileItem.errorMsg || `合并失败: ${err.message}`
})
this.$emit('onUploadError', err)
} finally {
this.resetUploadState()
}
},
/**
* 调用验签接口验证签名
* @param {Object} fileItem - 文件状态对象
* @param {Object} mergeResult - 合并成功后的返回数据
*/
async verifySignature(fileItem, mergeResult) {
const file = fileItem.file
const verifyParams = {
certFingerprint: mergeResult.certFingerprint,
filePath: mergeResult.filePath,
signature: mergeResult.signature,
timestamp: mergeResult.timestamp
}
console.log(`${file.name}】验签参数:`, verifyParams)
fileItem.verifying = true
try {
const response = await axios.post(
'/api/minioUpload/verify-signature',
null,
{
params: verifyParams,
headers: { 'Authorization': getToken() }
}
)
console.log(`${file.name}】验签接口响应:`, response.data)
if (response.data.code === 200) { //
fileItem.verifySuccess = true
} else {
fileItem.verifyError = response.data.error || '验签失败,原因未知'
}
} catch (err) {
fileItem.verifyError = `请求异常: ${err.message || '网络错误'}`
console.error(`${file.name}】验签请求异常:`, err)
} finally {
//
fileItem.verifyEndTime = new Date().getTime()
fileItem.verifying = false
//
const totalTime = this.getTimeDiff(fileItem.md5StartTime, fileItem.verifyEndTime)
console.log(`${file.name}】上传+合并+验签全流程总耗时:${totalTime}`)
}
}
}
}
</script>
<style scoped>
.upload-container {
max-width: 800px;
margin: 20px auto;
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 8px;
}
/* 单个文件项样式 */
.file-item {
margin-top: 20px;
padding: 15px;
border: 1px solid #f0f0f0;
border-radius: 6px;
}
.file-name {
font-weight: 500;
margin-bottom: 10px;
color: #333;
}
/* 进度条容器 */
.progress-wrapper {
display: flex;
flex-direction: column;
gap: 5px;
}
.progress-bar {
height: 20px;
background-color: #42b983;
transition: width 0.3s ease;
border-radius: 10px;
}
.progress-text {
font-size: 14px;
color: #666;
}
/* 合并中状态 */
.merge-loading {
margin: 10px 0;
color: #1890ff;
font-size: 14px;
}
/* 验签中状态 */
.verify-loading {
margin: 10px 0;
color: #42b983;
font-size: 14px;
}
/* 上传和验签提示样式 */
.success-section {
display: flex;
flex-direction: column;
gap: 5px;
}
.success {
color: #00C851;
margin: 0;
font-size: 14px;
}
.error {
color: #ff4444;
margin: 10px 0 0 0;
font-size: 14px;
}
.verify-success {
color: #00C851;
font-size: 14px;
margin: 0;
}
.verify-error {
color: #ff4444;
font-size: 14px;
margin: 0;
}
</style>

85
src/views/prearchiveLibrary/file/index.vue

@ -87,32 +87,8 @@
</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-if="scope.row.file_type === 'ofd'">
<i class="fileIcon icon-ofd" />
</div>
<div v-else>
<i class="fileIcon icon-other" />
<div :class="getFileIconClass(scope.row.file_type)">
<i class="fileIcon" :class="getFileIconClass(scope.row.file_type)" />
</div>
</template>
</el-table-column>
@ -149,6 +125,8 @@ import { header, form } from '@crud/crud'
import { mapGetters } from 'vuex'
import { downloadFile } from '@/utils/index'
import { FetchFileListByDocumentId } from '@/api/prearchiveLibrary/prearchiveLibrary'
import { getToken } from '@/utils/auth'
export default {
name: 'File',
components: { },
@ -196,6 +174,41 @@ export default {
mounted() {
},
methods: {
getFileIconClass(fileType) {
if (!fileType) return 'icon-other'
const lowerFileType = fileType.toLowerCase()
switch (lowerFileType) {
case 'jpg':
case 'jpeg':
case 'png':
case 'bmp':
case 'gif':
return 'icon-image'
case 'xlsx':
case 'xls':
return 'icon-excel'
case 'docx':
case 'doc':
return 'icon-word'
case 'pdf':
return 'icon-pdf'
case 'ppt':
case 'pptx':
return 'icon-ppt'
case 'zip':
case 'rar':
return 'icon-zip'
case 'txt':
return 'icon-txt'
case 'ofd':
return 'icon-ofd'
//
default:
return 'icon-other'
}
},
getFileSize(fileSize) {
const fileSizeInKB = (fileSize / 1024).toFixed(2) + ' KB'
const fileSizeInB = fileSize + 'B'
@ -271,28 +284,32 @@ export default {
done()
},
toPreview(row) {
console.log('row', row)
console.log('selectedCategory', row)
console.log('this.parentInfo', this.parentInfo)
const routeData = this.$router.resolve({
path: '/preview',
query: {
'archiveNo': this.parentInfo.maintitle
}})
window.open(routeData.href, '_blank')
localStorage.setItem('documentId', JSON.stringify(this.selectedCategory.id))
localStorage.setItem('fileParentInfo', JSON.stringify(this.parentInfo))
localStorage.setItem('fileTables', JSON.stringify(this.fileData))
localStorage.setItem('fileCurrent', JSON.stringify(row))
},
//
downloadFile(row) {
const url = this.baseApi + '/downloadFile' + row.file_path
fetch(url).then(res => res.blob()).then(blob => {
// filePath
// bucketType 1 2
const url = this.baseApi + '/api/minioUpload/getFile?filePath=' + row.file_path + '&bucketType=1'
const fetchOptions = {
method: 'GET',
headers: {
'Authorization': getToken()
}
}
fetch(url, fetchOptions).then(res => res.blob()).then(blob => {
downloadFile(blob, row.file_name.split('.')[0], row.file_type)
}).catch(() => {
this.$message({ message: '下载文件失败!', type: 'error', offset: 8 })
this.$message({ message: '下载文件失败', type: 'error', offset: 8 })
})
}
}

3
src/views/prearchiveLibrary/index.vue

@ -148,8 +148,6 @@
</div>
<!-- @close-dialog="closeDialog" -->
<!-- <UploadOriginal ref="uploadOriginalRef" :selected-category="selectedCategory" :arc-id="arcId" /> -->
<!-- 大文件上传 -->
<!-- <BigUpload ref="uploadBigRef" :is-document-page="true" :selected-category="selectedDocument" :arc-id="arcId" /> -->
<!-- <el-dialog class="preview-dialog" :modal-append-to-body="false" :close-on-click-modal="false" append-to-body :before-close="closeDialog" :visible="fileOneVisible" title="单文件上传">
<span class="dialog-right-top" />
@ -185,7 +183,6 @@ import batchFile from './module/batchFile'
import moveFile from './module/moveFile'
import detail from './module/detail'
// import PreUpload from '@/views/components/category/preUpload'
// import BigUpload from './module/bigUpload'
import File from './file/index'
import { exportFile } from '@/utils/index'

63
src/views/prearchiveLibrary/module/detail.vue

@ -44,32 +44,8 @@
</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-if="scope.row.file_type === 'ofd'">
<i class="fileIcon icon-ofd" />
</div>
<div v-else>
<i class="fileIcon icon-other" />
<div :class="getFileIconClass(scope.row.file_type)">
<i class="fileIcon" :class="getFileIconClass(scope.row.file_type)" />
</div>
</template>
</el-table-column>
@ -151,6 +127,41 @@ export default {
mounted() {
},
methods: {
getFileIconClass(fileType) {
if (!fileType) return 'icon-other'
const lowerFileType = fileType.toLowerCase()
switch (lowerFileType) {
case 'jpg':
case 'jpeg':
case 'png':
case 'bmp':
case 'gif':
return 'icon-image'
case 'xlsx':
case 'xls':
return 'icon-excel'
case 'docx':
case 'doc':
return 'icon-word'
case 'pdf':
return 'icon-pdf'
case 'ppt':
case 'pptx':
return 'icon-ppt'
case 'zip':
case 'rar':
return 'icon-zip'
case 'txt':
return 'icon-txt'
case 'ofd':
return 'icon-ofd'
//
default:
return 'icon-other'
}
},
downloadFile(row) {
// filePath
// bucketType 1 2

Loading…
Cancel
Save