| | |
| | | <el-upload |
| | | ref="upload" |
| | | class="upload-input" |
| | | :class="{hide: uploadDisabled || !isShowUpload}" |
| | | :accept="accept" |
| | | :action="uploadAction" |
| | | :before-upload="handleBeforeUpload" |
| | | :data="data" |
| | | :disabled="uploading" |
| | | :drag="false" |
| | | :limit="limit" |
| | | list-type="text" |
| | | :multiple="multiple" |
| | | :name="name" |
| | | :on-change="handleChange" |
| | | :on-error="handleUploadError" |
| | | :auto-upload="true" |
| | | :before-upload="handleBeforeUpload" |
| | | :http-request="checkedFile" |
| | | :before-remove="removeFile" |
| | | :on-exceed="handleExceed" |
| | | :on-success="handleUploadSuccess" |
| | | :on-progress="onUploadProgress" |
| | | :show-file-list="false" |
| | | :file-list="fileList" |
| | | v-if="!image && !crop" |
| | | |
| | | > |
| | | <el-button class="upload-btn" size="mini" type="primary" icon="el-icon-upload" |
| | | v-show="!uploadDisabled && isShowUpload">{{ buttonText }} |
| | | <!-- <el-upload--> |
| | | <!-- ref="upload"--> |
| | | <!-- class="upload-input"--> |
| | | <!-- :class="{hide: uploadDisabled || !isShowUpload}"--> |
| | | <!-- :accept="accept"--> |
| | | <!-- :action="uploadAction"--> |
| | | <!-- :before-upload="handleBeforeUpload"--> |
| | | <!-- :data="data"--> |
| | | <!-- :disabled="uploading"--> |
| | | <!-- :drag="false"--> |
| | | <!-- :limit="limit"--> |
| | | <!-- list-type="text"--> |
| | | <!-- :multiple="multiple"--> |
| | | <!-- :name="name"--> |
| | | <!-- :on-change="handleChange"--> |
| | | <!-- :on-error="handleUploadError"--> |
| | | <!-- :on-exceed="handleExceed"--> |
| | | <!-- :on-success="handleUploadSuccess"--> |
| | | <!-- :on-progress="onUploadProgress"--> |
| | | <!-- :show-file-list="false"--> |
| | | <!-- :file-list="fileList"--> |
| | | <!-- v-if="!image && !crop"--> |
| | | <!-- :auto-upload="true"--> |
| | | <!-- :http-request="checkedFile"--> |
| | | <!-- :before-remove="removeFile"--> |
| | | <!-- >--> |
| | | <div style="display:inline-block;width:600px;text-align: center" v-if="onlyUploadFile" class="el-upload__tip"> |
| | | {{computerFileName}} |
| | | </div> |
| | | <el-button slot="trigger" v-if="onlyUploadFile" size="small" type="primary">选取文件</el-button> |
| | | <el-button type="primary" v-if="onlyUploadFile" size="small" style="margin-left:20px" @click="myCheckedFile">提 交 |
| | | </el-button> |
| | | <el-button class="upload-btn" size="mini" type="primary" icon="el-icon-upload" |
| | | v-show="!uploadDisabled && isShowUpload && !onlyUploadFile">{{ buttonText }} |
| | | </el-button> |
| | | |
| | | <div slot="tip" class="el-upload__tip" v-show="!uploadDisabled && isShowUpload && tip">{{ tip }}</div> |
| | | </el-upload> |
| | | |
| | | <br/> |
| | | <div v-show="progressFlag"> |
| | | <el-progress :text-inside="true" :stroke-width="30" :percentage="progressPercent" :format="format"></el-progress> |
| | | <el-progress :text-inside="true" :stroke-width="30" :percentage="progressPercent" :format="format"></el-progress> |
| | | </div> |
| | | |
| | | </div> |
| | | |
| | | <ul class="el-upload-list el-upload-list--text" v-if="!image && !crop && showFileList"> |
| | | <ul class="el-upload-list el-upload-list--text" v-if="!image && !crop && !onlyUploadFile"> |
| | | <li tabindex="0" class="el-upload-list__item is-success" v-for="(file, index) in uploadList" :key="file.id"> |
| | | <a class="el-upload-list__item-name" :href="file.url" target="_blank"><i |
| | | class="el-icon-document"></i>{{ file.name }}</a> |
| | |
| | | :limit="limit" |
| | | :list-type="drag ? 'picture' : 'picture-card'" |
| | | :multiple="multiple" |
| | | :name="name" |
| | | :on-change="handleChange" |
| | | :on-error="handleUploadError" |
| | | :on-exceed="handleExceed" |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import Cookies from 'js-cookie' |
| | | import Cropper from 'vue-image-crop-upload' |
| | | import EleGallery from '../../vue-ele-gallery' |
| | | import Cookies from 'js-cookie' |
| | | import Cropper from 'vue-image-crop-upload' |
| | | import EleGallery from '../../vue-ele-gallery' |
| | | import SparkMD5 from "spark-md5"; |
| | | import axios from "axios"; |
| | | import {getUUID} from "../../../utils"; |
| | | |
| | | export default { |
| | | name: 'ZtUploader', |
| | | props: { |
| | | // 值 |
| | | value: { |
| | | type: [Object, Array], |
| | | default() { |
| | | return this.multiple ? [] : null |
| | | } |
| | | }, |
| | | action: { |
| | | type: String, |
| | | default: '/sys/oss/upload' |
| | | }, |
| | | // 是否为图片 |
| | | image: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 是否剪裁 |
| | | crop: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 裁剪高度 |
| | | cropHeight: { |
| | | type: Number |
| | | }, |
| | | // 裁剪宽度 |
| | | cropWidth: { |
| | | type: Number |
| | | }, |
| | | // 是否启用拖拽上传 |
| | | drag: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 是否支持多选文件 |
| | | multiple: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 图片显示大小 |
| | | size: { |
| | | type: Number, |
| | | default: 100 |
| | | }, |
| | | // 大小限制(MB) |
| | | fileSize: { |
| | | type: Number |
| | | }, |
| | | // 文件类型, 例如['png', 'jpg', 'jpeg'] |
| | | fileType: { |
| | | type: Array, |
| | | default: () => [] |
| | | }, |
| | | // 缩略图后缀, 例如七牛云缩略图样式 (?imageView2/1/w/20/h/20) |
| | | thumbSuffix: { |
| | | type: String, |
| | | default: '' |
| | | }, |
| | | // 是否显示提示 |
| | | isShowTip: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | // 弹窗标题 |
| | | title: String, |
| | | // 图片懒加载 |
| | | lazy: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 文件个数显示 |
| | | limit: { |
| | | type: Number, |
| | | default: 10 |
| | | }, |
| | | // 上传时附带的额外参数 |
| | | data: Object, |
| | | // 上传的文件字段名 |
| | | name: { |
| | | type: String, |
| | | default: 'file' |
| | | }, |
| | | // 接受上传的文件类型(thumbnail-mode 模式下此参数无效) |
| | | accept: String, |
| | | buttonText: { |
| | | type: String, |
| | | default: '上传' |
| | | }, |
| | | tip: String, |
| | | showFileList: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | disabled: { |
| | | type: Boolean, |
| | | default: false |
| | | } |
| | | }, |
| | | components: { |
| | | Cropper, |
| | | EleGallery |
| | | }, |
| | | inject: { |
| | | elForm: { |
| | | default: '' |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | progressPercent: 0, |
| | | uploadAction: `${window.SITE_CONFIG['apiURL']}${this.action}?token=${Cookies.get('token')}`, |
| | | cropData: {}, |
| | | isShowCrop: false, |
| | | uploading: false, |
| | | fileList: this.getUploadList(this.value), |
| | | uploadList: this.getUploadList(this.value), |
| | | progressFlag:false |
| | | } |
| | | }, |
| | | computed: { |
| | | // 是否显示提示 |
| | | showTip() { |
| | | return this.isShowTip && (this.fileType.length || this.fileSize) |
| | | }, |
| | | galleryValues() { |
| | | let urls = [] |
| | | if (this.value) { |
| | | if (this.multiple) { |
| | | this.value.forEach(v => urls.push({ |
| | | src: v.url, |
| | | title: v.name |
| | | })) |
| | | } else { |
| | | urls.push({ |
| | | src: this.value.url, |
| | | title: this.value.name |
| | | }) |
| | | export default { |
| | | name: 'ZtUploader', |
| | | props: { |
| | | // 值 |
| | | value: { |
| | | type: [Object, Array], |
| | | default() { |
| | | return this.multiple ? [] : null |
| | | } |
| | | }, |
| | | dataForm: Object, |
| | | action: { |
| | | type: String, |
| | | default: '/sys/oss/uploadNew' |
| | | }, |
| | | // 是否为图片 |
| | | showFileList: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | onlyUploadFile: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 是否为图片 |
| | | image: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 是否剪裁 |
| | | crop: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 裁剪高度 |
| | | cropHeight: { |
| | | type: Number |
| | | }, |
| | | // 裁剪宽度 |
| | | cropWidth: { |
| | | type: Number |
| | | }, |
| | | // 是否启用拖拽上传 |
| | | drag: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 是否支持多选文件 |
| | | multiple: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 图片显示大小 |
| | | size: { |
| | | type: Number, |
| | | default: 100 |
| | | }, |
| | | // 大小限制(MB) |
| | | fileSize: { |
| | | type: Number |
| | | }, |
| | | // 文件类型, 例如['png', 'jpg', 'jpeg'] |
| | | fileType: { |
| | | type: Array, |
| | | default: () => [] |
| | | }, |
| | | // 缩略图后缀, 例如七牛云缩略图样式 (?imageView2/1/w/20/h/20) |
| | | thumbSuffix: { |
| | | type: String, |
| | | default: '' |
| | | }, |
| | | // 是否显示提示 |
| | | isShowTip: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | // 弹窗标题 |
| | | title: String, |
| | | // 图片懒加载 |
| | | lazy: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 文件个数显示 |
| | | limit: { |
| | | type: Number, |
| | | default: 10 |
| | | }, |
| | | // 上传时附带的额外参数 |
| | | data: Object, |
| | | // 上传的文件字段名 |
| | | name: { |
| | | type: String, |
| | | default: 'file' |
| | | }, |
| | | // 接受上传的文件类型(thumbnail-mode 模式下此参数无效) |
| | | accept: String, |
| | | buttonText: { |
| | | type: String, |
| | | default: '上传' |
| | | }, |
| | | tip: String, |
| | | disabled: { |
| | | type: Boolean, |
| | | default: false |
| | | } |
| | | return urls |
| | | }, |
| | | isShowUpload() { // 是否显示上传按钮 |
| | | if (this.multiple) { |
| | | return this.uploadList.length < this.limit |
| | | components: { |
| | | Cropper, |
| | | EleGallery |
| | | }, |
| | | inject: { |
| | | elForm: { |
| | | default: '' |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | isUpload: false, |
| | | maxSize: 50 * 1024 * 1024 * 1024, // 上传最大文件限制 最小单位是b |
| | | multiUploadSize: 10 * 1024 * 1024, // 大于这个大小的文件使用分块上传(后端可以支持断点续传) 100mb |
| | | eachSize: 10 * 1024 * 1024, // 每块文件大小 100mb |
| | | requestCancelQueue: [], // 请求方法队列(调用取消上传 |
| | | // 每上传一块的进度 |
| | | eachProgress: 0, |
| | | // 总共有多少块。断点续传使用 |
| | | chunksKeep: 0, |
| | | // 切割后的文件数组 |
| | | fileChunksKeep: [], |
| | | // 这个文件,断点续传 |
| | | fileKeep: null, |
| | | // 断点续传,文件md5 |
| | | fileMd5Keep: "", |
| | | progressPercent: 0, |
| | | uploadAction: `${window.SITE_CONFIG['apiURL']}/sys/oss/upload_chunk?token=${Cookies.get('token')}`, |
| | | uploadCheckAction: `${window.SITE_CONFIG['apiURL']}/sys/oss/upload_success?token=${Cookies.get('token')}`, |
| | | uploadProcessAction: `${window.SITE_CONFIG['apiURL']}${this.action}?token=${Cookies.get('token')}`, |
| | | cropData: {}, |
| | | isShowCrop: false, |
| | | uploading: false, |
| | | fileList: this.getUploadList(this.value), |
| | | uploadList: this.getUploadList(this.value), |
| | | progressFlag: false |
| | | } |
| | | }, |
| | | created() { |
| | | if (this.onlyUploadFile) { |
| | | this.fileList = [{id: '1', name: '', url: ''}] |
| | | } else { |
| | | return this.uploadList.length === 0 |
| | | this.fileList = [] |
| | | } |
| | | }, |
| | | uploadDisabled() { |
| | | return this.disabled || (this.elForm || {}).disabled |
| | | }, |
| | | successFiles() { |
| | | return this.uploadList.filter((file) => file.status === 'success') |
| | | }, |
| | | isShowGrllery() { |
| | | return this.galleryValues.length > 0 |
| | | } |
| | | }, |
| | | watch: { |
| | | value(val, oldval) { |
| | | if (this.uploadList !== val) { |
| | | this.uploadList = this.getUploadList(val) |
| | | this.fileList = this.getUploadList(val) |
| | | console.log(this.fileList,'this.fileList this.fileList') |
| | | this.$emit('getUploaderImg',this.fileList) |
| | | } |
| | | }, |
| | | isShowCrop(value) { |
| | | if (value === false) { |
| | | this.cropData = {} |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | format(percentage) { |
| | | return percentage === 100 ? '后台正在处理' : `${percentage}%`; |
| | | }, |
| | | // 获取已上传的文件列表 |
| | | getUploadList(val) { |
| | | if (val) { |
| | | // console.log(val, 'getUploadList val') |
| | | if (!this.multiple) { // 单选 |
| | | return [val] |
| | | } else { |
| | | // console.log([...val], 'getUploadList [...val]') |
| | | return [...val] |
| | | computed: { |
| | | // 是否显示提示 |
| | | showTip() { |
| | | return this.isShowTip && (this.fileType.length || this.fileSize) |
| | | }, |
| | | computerFileName(computerFileName) { |
| | | let fileName = 'aaaa' |
| | | if (this.fileList.length > 0) { |
| | | fileName = this.fileList[0].name |
| | | } |
| | | } else { |
| | | return [] |
| | | } |
| | | }, |
| | | onUploadProgress(event, file, fileList) { |
| | | this.progressFlag = true |
| | | let per = Number( |
| | | ((event.loaded / event.total) * 100).toFixed(2) |
| | | ) |
| | | this.progressPercent = per > 100 ? 100 : per |
| | | }, |
| | | handleSetFileSet(fileName, fileType, fileSize) { |
| | | const uid = this.cropData.uid || new Date().getTime() |
| | | this.cropData = { |
| | | name: fileName, |
| | | percentage: 0, |
| | | size: fileSize, |
| | | type: fileType, |
| | | status: 'ready', |
| | | uid: uid |
| | | } |
| | | }, |
| | | handleCropSuccess(b64Data) { |
| | | this.cropData.url = b64Data |
| | | }, |
| | | handleCropUploadError(status) { |
| | | this.$message.error('上传失败, 请重试') |
| | | this.$emit('error', status) |
| | | }, |
| | | handleCropUploadSuccess(response) { |
| | | this.cropData.status = 'success' |
| | | this.cropData.percentage = 100 |
| | | this.cropData.response = response |
| | | const file = Object.assign({}, this.cropData) |
| | | this.handleUploadSuccess(response, file) |
| | | }, |
| | | // 上传前校检格式和大小 |
| | | handleBeforeUpload(file) { |
| | | let isAccept = true |
| | | if (this.fileType.length) { // 文件类型(后缀)一致 |
| | | let fileExtension = '' |
| | | if (file.name.lastIndexOf('.') > -1) { |
| | | fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1) |
| | | } |
| | | isAccept = this.fileType.some((type) => { |
| | | if (file.type.indexOf(type) > -1) return true |
| | | if (fileExtension && fileExtension.indexOf(type) > -1) return true |
| | | return false |
| | | }) |
| | | } |
| | | if (!isAccept) { |
| | | this.$message.error(`文件格式不正确, 请上传${this.fileType.join('/')}格式文件!`) |
| | | return false |
| | | } |
| | | if (this.fileSize) { |
| | | const isLt = file.size / 1024 / 1024 < this.fileSize |
| | | if (!isLt) { |
| | | this.$message.error(`上传大小不能超过 ${this.fileSize} MB!`) |
| | | return false |
| | | } |
| | | } |
| | | this.uploading = true |
| | | return true |
| | | }, |
| | | handleChange() { |
| | | this.uploading = false |
| | | /*const config = { |
| | | onUploadProgress: (progressEvent) => { |
| | | this.progressPercent = Number( |
| | | ((progressEvent.loaded / progressEvent.total) * 90).toFixed(2) |
| | | ) |
| | | } |
| | | } |
| | | //this.progressFlag = true; |
| | | let form = new FormData(); |
| | | form.append("file", params.file); |
| | | this.$http.post( this.uploadAction,form,config ).then((res) => { |
| | | this.progressPercent = 100; |
| | | })*/ |
| | | }, |
| | | // 文件个数超出 |
| | | handleExceed() { |
| | | this.$message.error(`最多上传${this.limit}个`) |
| | | }, |
| | | // 上传失败 |
| | | handleUploadError(err) { |
| | | this.uploading = false |
| | | this.$message.error('上传失败, 请重试') |
| | | this.$emit('error', err) |
| | | }, |
| | | // 上传成功回调 |
| | | handleUploadSuccess(response, file) { |
| | | console.log(response, file,'response, file') |
| | | if (response.code === 0) { |
| | | this.progressPercent = 100 |
| | | this.uploading = false |
| | | // this.$message.success('上传成功') |
| | | if (this.multiple) { |
| | | this.uploadList.push(response.data) |
| | | this.$emit('input', this.uploadList) |
| | | } else { |
| | | this.$emit('input', response.data) |
| | | } |
| | | this.progressFlag = false |
| | | this.progressPercent = 0 |
| | | } |
| | | }, |
| | | async handleRemove(index) { |
| | | let file = this.uploadList[index] |
| | | if (file.status === 1) { // 证书文件,直接从列表删除,不保存数据库 |
| | | this.handRemoveAndSetValue(index) |
| | | } else { |
| | | if (await this.$tip.confirm(this.$t('prompt.info', {'handle': this.$t('delete')}))) { |
| | | let res = await this.$http.delete('/sys/oss', {'data': [file.id]}) |
| | | if (res.success) { |
| | | await this.$tip.success() |
| | | this.handRemoveAndSetValue(index) |
| | | return fileName |
| | | }, |
| | | galleryValues() { |
| | | let urls = [] |
| | | if (this.value) { |
| | | if (this.multiple) { |
| | | this.value.forEach(v => urls.push({ |
| | | src: v.url, |
| | | title: v.name |
| | | })) |
| | | } else { |
| | | urls.push({ |
| | | src: this.value.url, |
| | | title: this.value.name |
| | | }) |
| | | } |
| | | } |
| | | return urls |
| | | }, |
| | | isShowUpload() { // 是否显示上传按钮 |
| | | if (this.multiple) { |
| | | return this.uploadList.length < this.limit |
| | | } else { |
| | | return this.uploadList.length === 0 || this.onlyUploadFile |
| | | } |
| | | }, |
| | | uploadDisabled() { |
| | | return this.disabled || (this.elForm || {}).disabled |
| | | }, |
| | | successFiles() { |
| | | return this.uploadList.filter((file) => file.status === 'success') |
| | | }, |
| | | isShowGrllery() { |
| | | return this.galleryValues.length > 0 |
| | | } |
| | | }, |
| | | handRemoveAndSetValue(index) { |
| | | if (this.multiple) { |
| | | this.uploadList.splice(index, 1) |
| | | this.$refs.upload.uploadFiles.splice(index, 1) |
| | | this.$emit('input', this.uploadList || []) |
| | | } else { |
| | | this.$emit('input', null) |
| | | watch: { |
| | | // eslint-disable-next-line no-unused-vars |
| | | value(val, oldval) { |
| | | if (this.uploadList !== val) { |
| | | this.uploadList = this.getUploadList(val) |
| | | this.fileList = this.getUploadList(val) |
| | | if (this.fileList.length>0){ |
| | | console.log(this.fileList[0].status, 'val.files[0].status23') |
| | | // alert('2222'+this.fileList[0].status) |
| | | } |
| | | } |
| | | }, |
| | | isShowCrop(value) { |
| | | if (value === false) { |
| | | this.cropData = {} |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | format(percentage) { |
| | | return percentage === 100 ? '后台正在处理' : percentage === 99 ? '正在进行文件校验' : `已上传${percentage}%`; |
| | | }, |
| | | // 获取已上传的文件列表 |
| | | getUploadList(val) { |
| | | if (val) { |
| | | if (val.length > 0) { |
| | | if (!this.multiple) { // 单选 |
| | | console.log(val, 'getUploadList val') |
| | | return val |
| | | } else { |
| | | console.log([...val], 'getUploadList [...val]') |
| | | return [...val] |
| | | } |
| | | } else { |
| | | return [] |
| | | } |
| | | } |
| | | }, |
| | | // eslint-disable-next-line no-unused-vars |
| | | onUploadProgress(event, file, fileList) { |
| | | this.progressFlag = true |
| | | /*let per = Number( |
| | | ((event.loaded / event.total) * 100).toFixed(2) |
| | | ) |
| | | this.progressPercent = per > 100 ? 100 : per*/ |
| | | }, |
| | | handleSetFileSet(fileName, fileType, fileSize) { |
| | | const uid = this.cropData.uid || new Date().getTime() |
| | | this.cropData = { |
| | | name: fileName, |
| | | percentage: 0, |
| | | size: fileSize, |
| | | type: fileType, |
| | | status: 'ready', |
| | | uid: uid |
| | | } |
| | | }, |
| | | handleCropSuccess(b64Data) { |
| | | this.cropData.url = b64Data |
| | | }, |
| | | handleCropUploadError(status) { |
| | | this.$message.error('上传失败, 请重试') |
| | | this.$emit('error', status) |
| | | }, |
| | | handleCropUploadSuccess(response) { |
| | | console.log(response, 'handleCropUploadSuccess response') |
| | | this.cropData.status = 'success' |
| | | this.cropData.percentage = 100 |
| | | this.cropData.response = response |
| | | const file = Object.assign({}, this.cropData) |
| | | this.handleUploadSuccess(response, file) |
| | | }, |
| | | // 上传前校检格式和大小 |
| | | handleBeforeUpload(file) { |
| | | let isAccept = true |
| | | if (this.fileType.length) { // 文件类型(后缀)一致 |
| | | let fileExtension = '' |
| | | if (file.name.lastIndexOf('.') > -1) { |
| | | fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1) |
| | | } |
| | | isAccept = this.fileType.some((type) => { |
| | | if (file.type.indexOf(type) > -1) return true |
| | | if (fileExtension && fileExtension.indexOf(type) > -1) return true |
| | | return false |
| | | }) |
| | | } |
| | | if (!isAccept) { |
| | | this.$message.error(`文件格式不正确, 请上传${this.fileType.join('/')}格式文件!`) |
| | | return false |
| | | } |
| | | if (this.fileSize) { |
| | | const isLt = file.size / 1024 / 1024 < this.fileSize |
| | | if (!isLt) { |
| | | this.$message.error(`上传大小不能超过 ${this.fileSize} MB!`) |
| | | return false |
| | | } |
| | | } |
| | | if (this.dataForm) { |
| | | // eslint-disable-next-line vue/no-mutating-props |
| | | this.dataForm.hasUploadFinsh = 50 |
| | | } |
| | | this.uploading = true |
| | | return true |
| | | }, |
| | | async handleChange() { |
| | | this.uploading = false |
| | | /*const config = { |
| | | onUploadProgress: (progressEvent) => { |
| | | this.progressPercent = Number( |
| | | ((progressEvent.loaded / progressEvent.total) * 90).toFixed(2) |
| | | ) |
| | | } |
| | | } |
| | | //this.progressFlag = true; |
| | | let form = new FormData(); |
| | | form.append("file", params.file); |
| | | this.$http.post( this.uploadAction,form,config ).then((res) => { |
| | | this.progressPercent = 100; |
| | | })*/ |
| | | }, |
| | | // 文件个数超出 |
| | | handleExceed(files, fileList) { |
| | | if (this.onlyUploadFile) { |
| | | this.$set(fileList[0], 'raw', files[0]) |
| | | this.$set(fileList[0], 'name', files[0].name) |
| | | /* this.$refs.upload.clearFiles() |
| | | this.$refs.upload.handleStart(files[0])*/ |
| | | } |
| | | //this.$message.error(`最多上传${this.limit}个`) |
| | | }, |
| | | // 上传失败 |
| | | handleUploadError(err) { |
| | | this.uploading = false |
| | | this.$message.error('上传失败, 请重试') |
| | | this.$emit('error', err) |
| | | }, |
| | | // 上传成功回调 |
| | | // eslint-disable-next-line no-unused-vars |
| | | handleUploadSuccess(response, file) { |
| | | console.log(response, 'handleUploadSuccess response') |
| | | if (response.code === 0) { |
| | | this.progressPercent = 100 |
| | | this.uploading = false |
| | | // this.$message.success('上传成功') |
| | | if (this.multiple) { |
| | | this.uploadList.push(response.data) |
| | | this.$emit('input', this.uploadList) |
| | | } else { |
| | | this.$emit('input', response.data) |
| | | } |
| | | this.progressFlag = false |
| | | this.progressPercent = 0 |
| | | } |
| | | }, |
| | | async handleRemove(index) { |
| | | let file = this.uploadList[index] |
| | | if (file.status === 1) { // 证书文件,直接从列表删除,不保存数据库 |
| | | this.handRemoveAndSetValue(index) |
| | | } else { |
| | | if (await this.$tip.confirm(this.$t('prompt.info', {'handle': this.$t('delete')}))) { |
| | | let res = await this.$http.delete('/sys/oss', {'data': [file.id]}) |
| | | if (res.success) { |
| | | await this.$tip.success() |
| | | this.handRemoveAndSetValue(index) |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | handRemoveAndSetValue(index) { |
| | | console.log(index, 'handRemoveAndSetValue') |
| | | if (this.multiple) { |
| | | this.uploadList.splice(index, 1) |
| | | this.$refs.upload.uploadFiles.splice(index, 1) |
| | | this.$emit('input', this.uploadList || []) |
| | | } else { |
| | | this.$emit('input', null) |
| | | } |
| | | }, |
| | | nullFunction(param) { |
| | | }, |
| | | //开始分片上传myCheckedFile |
| | | async myCheckedFile() { |
| | | if (!this.handleBeforeUpload(this.fileList[0].raw)) |
| | | return |
| | | let options = { |
| | | file: this.fileList[0].raw, |
| | | onProgress: function (val) { |
| | | }, |
| | | onSuccess: function (val) { |
| | | }, |
| | | onError: function (val) { |
| | | } |
| | | } |
| | | await this.checkedFile(options) |
| | | }, |
| | | async checkedFile(options) { |
| | | if (!this.isUpload) { |
| | | this.isUpload = true; |
| | | } else { |
| | | return this.$message({ |
| | | message: `当前文件正在上传`, |
| | | type: "warning" |
| | | }); |
| | | } |
| | | this.progressFlag = true |
| | | const { |
| | | maxSize, |
| | | multiUploadSize, |
| | | getSize, |
| | | splitUpload, |
| | | singleUpload |
| | | } = this; // 解构赋值 |
| | | const {file, onProgress, onSuccess, onError} = options; // 解构赋值 |
| | | |
| | | file.uid = getUUID().toString() |
| | | if (file.size > maxSize) { |
| | | return this.$message({ |
| | | message: `您选择的文件大于${getSize(maxSize)}`, |
| | | type: "error" |
| | | }); |
| | | } |
| | | this.fileKeep = file; |
| | | const uploadFunc = |
| | | file.size > multiUploadSize ? splitUpload : singleUpload; // 选择上传方式 |
| | | try { |
| | | await uploadFunc(file, onProgress); |
| | | onSuccess(); |
| | | } catch (e) { |
| | | console.error(e); |
| | | this.$message({ |
| | | message: e.message, |
| | | type: "error" |
| | | }); |
| | | this.progressFlag = false; |
| | | this.progressPercent = 0; |
| | | onError(); |
| | | } |
| | | }, |
| | | // 格式化文件大小显示文字 |
| | | getSize(size) { |
| | | return size > 1024 |
| | | ? size / 1024 > 1024 |
| | | ? size / (1024 * 1024) > 1024 |
| | | ? (size / (1024 * 1024 * 1024)).toFixed(2) + "GB" |
| | | : (size / (1024 * 1024)).toFixed(2) + "MB" |
| | | : (size / 1024).toFixed(2) + "KB" |
| | | : size.toFixed(2) + "B"; |
| | | }, |
| | | // 单文件直接上传 |
| | | async singleUpload(file, onProgress) { |
| | | await this.postFile( |
| | | {file, uid: file.uid, fileName: file.fileName, chunk: 0}, |
| | | onProgress |
| | | ); |
| | | const reader = new FileReader(); |
| | | |
| | | reader.readAsArrayBuffer(file); |
| | | console.log(file, 'singleUpload file'); |
| | | let hashMd5 = ""; |
| | | console.log(hashMd5); |
| | | const that = this; |
| | | |
| | | function getHash(cb) { |
| | | console.log(cb, "进入单个上传的getHash"); |
| | | console.log("进入单个上传的getHash"); |
| | | reader.onload = function (e) { |
| | | console.log("进入单个上传的getHash的函数2"); |
| | | console.log(hashMd5); |
| | | console.log(this); |
| | | // console.log(e) |
| | | const hash = SparkMD5.ArrayBuffer.hash(e.target.result, false); |
| | | console.log(e.target.result, 'e.target.result'); |
| | | console.log(hash, 'hash'); |
| | | that.hashMd5 = hash; |
| | | console.log(that.hashMd5, 'hashMd5'); |
| | | that.fileMd5Keep = hash; |
| | | cb(hash); |
| | | }; |
| | | } |
| | | |
| | | await getHash(function (hash) { |
| | | console.log(hash, 'getHash(function (hash) hash'); |
| | | console.log(that, 'getHash(function (hash) that'); |
| | | // 请求接口 |
| | | that.validateFile({ |
| | | name: file.name, |
| | | uid: file.uid, |
| | | md5: hash, |
| | | chunks: 1, |
| | | filter_type: "user_data_file" |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | // 大文件分块上传 |
| | | splitUpload(file, onProgress) { |
| | | console.log(file, 'splitUpload(file'); |
| | | // eslint-disable-next-line no-async-promise-executor |
| | | return new Promise(async (resolve, reject) => { |
| | | try { |
| | | const {eachSize} = this; |
| | | const chunks = Math.ceil(file.size / eachSize); |
| | | this.chunksKeep = chunks; |
| | | const fileChunks = await this.splitFile(file, eachSize, chunks); |
| | | this.fileChunksKeep = fileChunks; |
| | | //判断每上传一个文件,进度条涨多少,保留两位小数 |
| | | this.eachProgress = 100 / chunks; |
| | | this.progressFlag = true; |
| | | let currentChunk = 0; |
| | | let percent = 0; |
| | | for (let i = 0; i < fileChunks.length; i++) { |
| | | // 服务端检测已经上传到第currentChunk块了,那就直接跳到第currentChunk块,实现断点续传 |
| | | // 此时需要判断进度条 |
| | | if (Number(currentChunk) === i) { |
| | | // 每块上传完后则返回需要提交的下一块的index |
| | | await this.postFile( |
| | | { |
| | | chunked: true, |
| | | chunk: i, |
| | | chunks, |
| | | eachSize, |
| | | fileName: file.name, |
| | | fullSize: file.size, |
| | | uid: file.uid, |
| | | file: fileChunks[i] |
| | | }, |
| | | onProgress |
| | | ); |
| | | currentChunk++; |
| | | |
| | | // 上传完一块后,进度条增加 |
| | | percent = percent + this.eachProgress; |
| | | // 不能超过100 |
| | | this.progressPercent = percent > 100 ? 99 : Math.floor(percent); |
| | | } |
| | | } |
| | | const spark = new SparkMD5.ArrayBuffer(); |
| | | let currentChunkMd5 = 0; |
| | | const that = this; |
| | | const reader = new FileReader(); |
| | | reader.onload = async function (e) { |
| | | spark.append(e.target.result); |
| | | currentChunkMd5++; |
| | | |
| | | if (currentChunkMd5 < chunks) { |
| | | await loadNext(); |
| | | } else { |
| | | // console.log(spark.end()); |
| | | const hashMd5111 = spark.end(); |
| | | that.fileMd5Keep = hashMd5111; |
| | | // 在这里请求接口 |
| | | await that.validateFile({ |
| | | name: file.name, |
| | | uid: file.uid, |
| | | md5: hashMd5111, |
| | | chunks: fileChunks.length, |
| | | filter_type: "git_secret_file" |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | // eslint-disable-next-line no-inner-declarations |
| | | async function loadNext() { |
| | | const start = currentChunkMd5 * eachSize; |
| | | const end = |
| | | start + eachSize >= file.size ? file.size : start + eachSize; |
| | | await reader.readAsArrayBuffer(file.slice(start, end)); |
| | | } |
| | | |
| | | await loadNext(); |
| | | resolve(); |
| | | } catch (error) { |
| | | reject(error); |
| | | } |
| | | }); |
| | | }, |
| | | // 断点续传 |
| | | againSplitUpload(file, array) { |
| | | console.log("file,array"); |
| | | console.log(file); |
| | | console.log(array); |
| | | // eslint-disable-next-line no-async-promise-executor |
| | | return new Promise(async (resolve, reject) => { |
| | | try { |
| | | // eslint-disable-next-line no-unused-vars |
| | | const {eachSize, fileKeep} = this; |
| | | const chunks = this.chunksKeep; |
| | | const fileChunks = this.fileChunksKeep; |
| | | this.progressFlag = true; |
| | | // let currentChunk = 0; |
| | | for (let i = 0; i < array.length; i++) { |
| | | // 服务端检测已经上传到第currentChunk块了,那就直接跳到第currentChunk块,实现断点续传 |
| | | // 此时需要判断进度条 |
| | | // 每块上传完后则返回需要提交的下一块的index |
| | | await this.postFile({ |
| | | chunked: true, |
| | | chunk: array[i], |
| | | chunks, |
| | | name: file.name, |
| | | fullSize: fileKeep.size, |
| | | uid: file.uid, |
| | | file: fileChunks[array[i]] |
| | | }); |
| | | // currentChunk++ |
| | | |
| | | // 上传完一块后,进度条增加 |
| | | this.progressPercent += this.eachProgress; |
| | | // 不能超过100 |
| | | this.progressPercent = this.progressPercent > 100 ? 100 : this.progressPercent; |
| | | } |
| | | let fileMd5KeepTwo = this.fileMd5Keep; |
| | | |
| | | const isValidate = await this.validateFile({ |
| | | name: file.name, |
| | | uid: file.uid, |
| | | md5: fileMd5KeepTwo, |
| | | chunks: fileChunks.length, |
| | | filter_type: "git_secret_file" |
| | | }); |
| | | if (!isValidate) { |
| | | throw new Error("文件校验异常"); |
| | | } |
| | | // 关闭进度条 |
| | | this.progressFlag = false; |
| | | // 重置进度条 |
| | | this.progressPercent = 0; |
| | | resolve(); |
| | | } catch (e) { |
| | | reject(e); |
| | | } |
| | | }); |
| | | }, |
| | | // 文件分块,利用Array.prototype.slice方法 |
| | | splitFile(file, eachSize, chunks) { |
| | | return new Promise((resolve, reject) => { |
| | | try { |
| | | setTimeout(() => { |
| | | const fileChunk = []; |
| | | for (let chunk = 0; chunks > 0; chunks--) { |
| | | fileChunk.push(file.slice(chunk, chunk + eachSize)); |
| | | chunk += eachSize; |
| | | } |
| | | resolve(fileChunk); |
| | | }, 0); |
| | | } catch (e) { |
| | | console.error(e); |
| | | reject(new Error("文件切块发生错误")); |
| | | } |
| | | }); |
| | | }, |
| | | removeFile(file) { |
| | | this.requestCancelQueue[file.uid](); |
| | | delete this.requestCancelQueue[file.uid]; |
| | | return true; |
| | | }, |
| | | // 提交文件方法,将参数转换为FormData, 然后通过axios发起请求 |
| | | postFile(param, onProgress) { |
| | | const formData = new FormData(); |
| | | formData.append("file", param.file); // 改了 |
| | | formData.append("fileName", param.fileName); // 改了 |
| | | formData.append("uid", param.uid); |
| | | formData.append("chunk", param.chunk); |
| | | formData.append("filter_type", "git_secret_file"); |
| | | formData.append("chunks", param.chunks); |
| | | const {requestCancelQueue} = this; |
| | | const config = { |
| | | cancelToken: new axios.CancelToken(function executor(cancel) { |
| | | if (requestCancelQueue[param.uid]) { |
| | | requestCancelQueue[param.uid](); |
| | | delete requestCancelQueue[param.uid]; |
| | | } |
| | | requestCancelQueue[param.uid] = cancel; |
| | | }), |
| | | onUploadProgress: e => { |
| | | if (param.chunked) { |
| | | e.percent = Number( |
| | | ( |
| | | ((param.chunk * (param.eachSize - 1) + e.loaded) / |
| | | param.fullSize) * |
| | | 100 |
| | | ).toFixed(2) |
| | | ); |
| | | } else { |
| | | e.percent = Number(((e.loaded / e.total) * 100).toFixed(2)); |
| | | } |
| | | onProgress(e) |
| | | } |
| | | } |
| | | //return axios.post('sys/oss/upload_chunk/', formData, config).then(rs => rs.data) |
| | | return this.$http({ |
| | | url: "/sys/oss/upload_chunk/", |
| | | method: "POST", |
| | | data: formData |
| | | }).then(rs => rs.data |
| | | ); |
| | | }, |
| | | // 文件校验方法 |
| | | validateFile(file) { |
| | | //return axios.post('sys/oss/upload_success/', file).then(rs => rs.data) |
| | | return this.$http({ |
| | | url: "/sys/oss/upload_success/", |
| | | method: "POST", |
| | | data: file |
| | | }).then(res => { |
| | | console.log(res, "validateFile res") |
| | | if (res && !res.data) { |
| | | this.againSplitUpload(file, res.data.error_file) |
| | | this.$message({ |
| | | message: "有文件上传失败,正在重新上传", |
| | | type: "warning" |
| | | }); |
| | | } else if (res && res.data) { |
| | | this.progressPercent = 100 |
| | | if (!this.onlyUploadFile) { |
| | | this.$http({ |
| | | url: this.action, |
| | | method: "POST", |
| | | data: file |
| | | }).then(res => { |
| | | console.log(res, '后台处理 res1') |
| | | let aa = res.data.status |
| | | console.log(aa, 'res.data.status') |
| | | |
| | | if (this.multiple) { |
| | | this.uploadList.push(res.data) |
| | | this.$emit('input', this.uploadList) |
| | | } else { |
| | | this.$emit('input', res.data) |
| | | } |
| | | this.uploading = false |
| | | this.progressFlag = false |
| | | this.progressPercent = 0 |
| | | this.isUpload = false |
| | | }) |
| | | } else { |
| | | console.log(file.uid, 'file.uid') |
| | | this.$emit('recall', file.uid) |
| | | this.uploading = false |
| | | this.progressFlag = false |
| | | this.progressPercent = 0 |
| | | this.isUpload = false |
| | | } |
| | | } else if (res && res.status == 40008) { |
| | | this.$message.error(res.message); |
| | | this.progressFlag = false; |
| | | this.progressPercent = 0; |
| | | } |
| | | }) |
| | | } |
| | | }, |
| | | mounted() { |
| | | // 插入到body中, 避免弹出层被遮盖 |
| | | if (this.crop && this.$refs.cropper) { |
| | | document.body.appendChild(this.$refs.cropper.$el) |
| | | } |
| | | } |
| | | }, |
| | | mounted() { |
| | | // 插入到body中, 避免弹出层被遮盖 |
| | | if (this.crop && this.$refs.cropper) { |
| | | document.body.appendChild(this.$refs.cropper.$el) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | .zt-upload { |
| | | line-height: 1; |
| | | } |
| | | .zt-upload { |
| | | line-height: 1; |
| | | } |
| | | |
| | | .zt .upload-input .upload-btn { |
| | | padding: 8px 12px; |
| | | } |
| | | .zt .upload-input .upload-btn { |
| | | padding: 8px 12px; |
| | | } |
| | | |
| | | .zt .upload-input.hide { |
| | | height: 0px; |
| | | } |
| | | .zt .upload-input.hide { |
| | | height: 0px; |
| | | } |
| | | |
| | | .zt-upload .el-loading-spinner { |
| | | line-height: 1; |
| | | } |
| | | .zt-upload .el-loading-spinner { |
| | | line-height: 1; |
| | | } |
| | | |
| | | .zt-upload .el-icon-plus { |
| | | vertical-align: middle; |
| | | } |
| | | .zt-upload .el-icon-plus { |
| | | vertical-align: middle; |
| | | } |
| | | |
| | | .zt-upload .el-upload--picture-card { |
| | | width: auto; |
| | | height: auto; |
| | | background: none; |
| | | line-height: inherit; |
| | | } |
| | | .zt-upload .el-upload--picture-card { |
| | | width: auto; |
| | | height: auto; |
| | | background: none; |
| | | line-height: inherit; |
| | | } |
| | | |
| | | /* 裁剪 */ |
| | | .vue-image-crop-upload.zt-upload-image--cropper { |
| | | z-index: 99; |
| | | } |
| | | /* 裁剪 */ |
| | | .vue-image-crop-upload.zt-upload-image--cropper { |
| | | z-index: 99; |
| | | } |
| | | |
| | | .zt-upload-image--cropper .vicp-drop-area { |
| | | background-color: #fbfdff !important; |
| | | } |
| | | .zt-upload-image--cropper .vicp-drop-area { |
| | | background-color: #fbfdff !important; |
| | | } |
| | | |
| | | .zt-upload-image--cropper .vicp-icon1-arrow { |
| | | border-bottom-color: #909399 !important; |
| | | } |
| | | .zt-upload-image--cropper .vicp-icon1-arrow { |
| | | border-bottom-color: #909399 !important; |
| | | } |
| | | |
| | | .zt-upload-image--cropper .vicp-icon1-body { |
| | | background-color: #909399 !important; |
| | | } |
| | | .zt-upload-image--cropper .vicp-icon1-body { |
| | | background-color: #909399 !important; |
| | | } |
| | | |
| | | .zt-upload-image--cropper .vicp-icon1-bottom { |
| | | border-color: #909399 !important; |
| | | } |
| | | .zt-upload-image--cropper .vicp-icon1-bottom { |
| | | border-color: #909399 !important; |
| | | } |
| | | </style> |