阅行客电子档案
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

369 lines
12 KiB

<template>
<!--上传组件-->
<el-dialog class="big-file" title="大文件上传" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="uploadBigVisible">
<div class="setting-dialog">
<div class="uploader-big">
<uploader
ref="uploader"
: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>将文件拖到此处或点击上传</p>
<uploader-btn single>
<slot>
<i class="iconfont icon-tianjiawenjian upload-icon" />
</slot>
</uploader-btn>
<div class="el-upload__tip">上传限制文件大小最大10GB/</div>
<!-- <uploader-btn :attrs="attrs">选择图片</uploader-btn>
<uploader-btn :directory="true">选择文件夹</uploader-btn> -->
</uploader-drop>
<uploader-files />
<!-- <ul class="file-list">
<li
v-for="file in fileList"
:key="file.id"
class="file-item"
:class="`file-${file.id}`"
>
<uploader-file
ref="files"
:class="'file_' + file.id"
:file="file"
:list="true"
/>
</li>
</ul> -->
</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>
</template>
<script>
import { mapGetters } from 'vuex'
import axios from 'axios'
import SparkMD5 from 'spark-md5'
import { getToken } from '@/utils/auth'
import { getCurrentTime } from '@/utils/index'
// https://juejin.cn/post/7040817922540830728
export default {
props: {
selectedCategory: {
type: Object,
default: function() {
return {}
}
},
arcId: {
type: String,
default: function() {
return ''
}
}
},
data() {
return {
btnLoading: false,
uploadBigVisible: false,
skip: false,
options: {
target: '/api/collect/upload',
// 开启服务端分片校验功能
testChunks: true, // 是否分片
singleFile: true, // 单文件上传
uploadMethod: 'post', // 真正上传的时候使用的 HTTP 方法,默认 POST
allowDuplicateUploads: false, // 上传过得文件不可以再上传
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()
}
},
attrs: {
accept: 'image/*'
},
// 修改上传状态
statusText: {
success: '上传成功',
error: '上传出错了',
uploading: '上传中...',
paused: '暂停中...',
waiting: '等待中...',
cmd5: '计算文件MD5中...'
},
fileList: [],
nowDate: null,
submitted: false
}
},
computed: {
...mapGetters([
'baseApi'
])
},
methods: {
fileSuccess(rootFile, file, response, chunk) {
this.chunkOffset = []
const result = JSON.parse(response)
console.log('result', result)
// 是否需要合并
// if (result.data.needMerge && !this.skip) {
// } else {
// console.log('上传成功,不需要合并')
// }
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) {
this.fileList = []
const uploaderInstance = this.$refs.uploader.uploader
const temp = uploaderInstance.fileList.findIndex(e => e.uniqueIdentifier === file.uniqueIdentifier)
if (temp > -1) {
uploaderInstance.fileList[temp].cancel() // 这句代码是删除所选上传文件的关键
}
},
handleUploadConfirm() {
if (this.$refs.uploader.fileList.length === 0) {
this.$message.error('请选择要上传的文件!')
return false
}
this.nowDate = getCurrentTime()
this.$refs.uploader.fileList.map(async(item, index) => {
const json = {}
const jsonArray = []
const jsonString = {}
if (item.file.type.substring(0, item.file.type.indexOf('/')) === 'image') {
const fileBase64 = await this.getBase64(item)
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)
// jsonString.file_path = res.data.data
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
// chunk.offset
json.totalChunks = item.chunks.length - 1
json.totalSize = item.size
json.fileJsonString = JSON.stringify(jsonArray)
if (item.completed && this.submitted) {
this.btnLoading = true
this.submitted = false
axios.post(this.baseApi + '/api/collect/merge', json, { headers: {
'Authorization': getToken()
}}).then((res) => {
console.log(res)
if (res.data.code === 200 && res.data.data !== '') {
this.$message.success('上传成功')
} else {
this.$message.error('上传失败')
}
this.$emit('close-dialog')
this.uploadBigVisible = false
this.fileList = []
this.btnLoading = false
this.$refs.uploader.files = []
this.$refs.uploader.fileList = []
this.$refs.uploader.uploader.fileList = []
this.$refs.uploader.uploader.files = []
})
} else {
this.submitted = false
this.$message.error('请耐心等待文件上传完成后再保存!')
}
})
},
onFileError(rootFile, file, message, chunk) {
this.$message.error('上传出错:' + message)
},
filesAdded(file, fileList, event) {
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()
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`
)
spark.destroy() // 释放缓存
file.uniqueIdentifier = md5 // 将文件md5赋值给文件唯一标识
file.cmd5 = false // 取消计算md5状态
file.resume() // 开始上传
}
}
fileReader.onerror = function() {
this.error(`文件${file.name}读取出错,请检查该文件`)
file.cancel()
}
function loadNext() {
const start = currentChunk * chunkSize
const end = start + chunkSize >= file.size ? file.size : start + chunkSize
fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end))
}
},
// 将上传的图片转为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.uploadBigVisible = false
this.fileList = []
}
}
}
</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
}
</style>