Commit b8f538a9 authored by 刘怀志's avatar 刘怀志

上传图片功能修改

parent 20b37ad5
...@@ -58,3 +58,11 @@ export function refreshCache() { ...@@ -58,3 +58,11 @@ export function refreshCache() {
method: 'delete' method: 'delete'
}) })
} }
export function uploadCommon(data) {
return request({
headers: { 'Content-Type': 'multipart/form-data' },
url: '/common/upload',
method: 'post',
data
})
}
<template> <template>
<div class="component-upload-image"> <div class="component-upload-image">
<ImageCropperModal
:visible="cropperVisible"
:url="file"
:auto-crop-width="autoCropWidth"
:auto-crop-height="autoCropHeight"
@cancel="cropperVisible = false"
@confirm="onConfirm"
/>
<el-upload <el-upload
ref="imageUpload" ref="imageUpload"
:action="uploadImgUrl" multiple
action
list-type="picture-card" list-type="picture-card"
:on-success="handleUploadSuccess" :on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload" :before-upload="handleBeforeUpload"
:limit="1" :limit="limit"
:on-error="handleUploadError" :on-error="handleUploadError"
:on-exceed="handleExceed" :on-exceed="handleExceed"
:on-remove="handleDelete" :on-remove="handleDelete"
:show-file-list="true" :show-file-list="true"
:headers="headers" :headers="headers"
:file-list="fileList" :file-list="fileList"
:auto-upload="false"
:on-change="changeUpload"
:on-preview="handlePictureCardPreview" :on-preview="handlePictureCardPreview"
:class="{hide: fileList.length >= limit :class="{hide: fileList.length >= limit
|| $refs.imageUpload && $refs.imageUpload.uploadFiles.length >= limit || $refs.imageUpload && $refs.imageUpload.uploadFiles.length >= limit
|| number >= limit}" || number >= limit}"
> >
<i class="el-icon-plus" /> <i slot="default" class="el-icon-plus" />
<div slot="file" slot-scope="{file}" class="customer-upload-area">
<el-image :ref="file.url" class="el-upload-list__item-thumbnail customer-upload-error" :src="file.url" :preview-src-list="[file.url]">
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline" />
<div>加载失败</div>
</div>
</el-image>
<label class="el-upload-list__item-status-label">
<i class="el-icon-upload-success el-icon-check" />
</label>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in" />
</span>
<span
class="el-upload-list__item-delete"
@click="handleDelete(file)"
>
<i class="el-icon-delete" />
</span>
</span>
</div>
</el-upload> </el-upload>
<!-- 上传提示 --> <!-- 上传提示 -->
...@@ -45,9 +81,15 @@ ...@@ -45,9 +81,15 @@
</template> </template>
<script> <script>
import ImageCropperModal from '@/components/imageCropper/index'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { uploadCommon } from '@/api/system/config'
export default { export default {
components: {
ImageCropperModal
},
props: { props: {
value: [String, Object, Array], value: [String, Object, Array],
// 图片数量限制 // 图片数量限制
...@@ -58,7 +100,7 @@ export default { ...@@ -58,7 +100,7 @@ export default {
// 大小限制(MB) // 大小限制(MB)
fileSize: { fileSize: {
type: Number, type: Number,
default: 4 default: 5
}, },
// 文件类型, 例如['png', 'jpg', 'jpeg'] // 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: { fileType: {
...@@ -73,6 +115,14 @@ export default { ...@@ -73,6 +115,14 @@ export default {
}, },
data() { data() {
return { return {
queryParams: {
companyImgUrl: ''
},
autoCropWidth: '400', // 要裁剪的宽
autoCropHeight: '400', // 要裁剪的高
file: '',
fileName: '', // 存放文件名
cropperVisible: false, // 控制弹窗打开关闭
number: 0, number: 0,
uploadList: [], uploadList: [],
dialogImageUrl: '', dialogImageUrl: '',
...@@ -96,15 +146,16 @@ export default { ...@@ -96,15 +146,16 @@ export default {
value: { value: {
handler(val) { handler(val) {
if (val) { if (val) {
console.log('kkkkkkkkkkkkkkkkkk', this.baseUrl)
// 首先将值转为数组 // 首先将值转为数组
const list = Array.isArray(val) ? val : this.value.split(',') const list = Array.isArray(val) ? val : this.value.split(',')
// 然后将数组转为对象数组 // 然后将数组转为对象数组
this.fileList = list.map(item => { this.fileList = list.map(item => {
if (typeof item === 'string') { if (typeof item === 'string') {
if (item.indexOf(this.baseUrl) === -1) { if (item.indexOf(this.baseUrl) === -1) {
item = { name: this.baseUrl + item, url: encodeURI(this.baseUrl + item) } item = { name: this.baseUrl + item, url: this.baseUrl + item }
} else { } else {
item = { name: item, url: encodeURI(item) } item = { name: item, url: item }
} }
} }
return item return item
...@@ -119,8 +170,73 @@ export default { ...@@ -119,8 +170,73 @@ export default {
} }
}, },
methods: { methods: {
// 文件状态改变时
changeUpload(file) {
var img = file.name.substring(file.name.lastIndexOf('.') + 1)
const suffix = img === 'jpg' || img === 'png' || img === 'jpeg'
if (!suffix) {
this.$message.error('只能上传图片!')
return false
}
// URL.createObjectURL的参数只能是blob或者file类型
// 第一种方法用FileReader,URL.createObjectURL接收blob类型
const reader = new FileReader()
reader.onload = () => {
// 把Array Buffer转化为blob 如果是base64不需要
this.file = typeof reader.result === 'object' ? window.URL.createObjectURL(new Blob([reader.result]))
: reader.result
}
// 转化为base64
this.cropperVisible = true
reader.readAsArrayBuffer(file.raw)
// 第二种方法,URL.createObjectURL接收file类型
// this.$nextTick(() => {
// this.file = URL.createObjectURL(file.raw)
// this.cropperVisible = true
// })
this.fileName = file.name
},
// 点击剪裁弹框的确定按钮
async onConfirm(blob) {
// 这里的new FormData()指,以文件的方式传给后端(FormData的数据)
const form = new FormData()
// new File()的第一个参数是一个字符串数组,数组中的每一个元素对应着文件中一行的内容
// 第二个参数就是文件名字符串
// 第三个参数可以设定一些文件的属性,比如文件的MIME,最后更新时间等
const file = new File([blob], this.fileName, { type: blob.type, lastModified: Date.now() })
file.uid = Date.now()
form.append('file', file)
// 如果想在这里打印查看form的值,会发现它是空对象
// 解决办法,需要用form.get('键')的方法获取值
// console.log(form.get('file'))
// 这里调用接口,获取后端返给的图片地址
this.number++
uploadCommon(form).then(res => {
this.cropperVisible = false
if (res.code === 200) {
this.uploadList.push({ name: res.fileName, url: res.fileName })
this.uploadedSuccessfully()
} else {
this.number--
// this.$modal.closeLoading()
this.$modal.msgError(res.msg)
this.$refs.imageUpload.handleRemove(file)
this.uploadedSuccessfully()
}
}).catch(err => {
this.handleUploadError(err)
})
},
// 上传前loading加载 // 上传前loading加载
handleBeforeUpload(file) { handleBeforeUpload(file) {
console.log('图片file---,', file.name)
const nameTest = /^[^%;]*$/
if (!nameTest.test(file.name)) {
this.$modal.msgError('不能含有%;等特殊字符')
return false
}
let isImg = false let isImg = false
if (this.fileType.length) { if (this.fileType.length) {
let fileExtension = '' let fileExtension = ''
...@@ -137,13 +253,13 @@ export default { ...@@ -137,13 +253,13 @@ export default {
} }
if (!isImg) { if (!isImg) {
this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join('/')}图片格式文件`) this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join('/')}图片格式文件!`)
return false return false
} }
if (this.fileSize) { if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize const isLt = file.size / 1024 / 1024 < this.fileSize
if (!isLt) { if (!isLt) {
this.$modal.msgError(`上传图片大小不能超过 ${this.fileSize} MB`) this.$modal.msgError(`上传图片大小不能超过 ${this.fileSize} MB!`)
return false return false
} }
} }
...@@ -152,7 +268,7 @@ export default { ...@@ -152,7 +268,7 @@ export default {
}, },
// 文件个数超出 // 文件个数超出
handleExceed() { handleExceed() {
this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个`) this.$modal.msgError(`上传文件数量不能超过 ${this.limit}!`)
}, },
// 上传成功回调 // 上传成功回调
handleUploadSuccess(res, file) { handleUploadSuccess(res, file) {
...@@ -161,7 +277,7 @@ export default { ...@@ -161,7 +277,7 @@ export default {
this.uploadedSuccessfully() this.uploadedSuccessfully()
} else { } else {
this.number-- this.number--
this.$modal.closeLoading() // this.$modal.closeLoading()
this.$modal.msgError(res.msg) this.$modal.msgError(res.msg)
this.$refs.imageUpload.handleRemove(file) this.$refs.imageUpload.handleRemove(file)
this.uploadedSuccessfully() this.uploadedSuccessfully()
...@@ -178,22 +294,22 @@ export default { ...@@ -178,22 +294,22 @@ export default {
// 上传失败 // 上传失败
handleUploadError() { handleUploadError() {
this.$modal.msgError('上传图片失败,请重试') this.$modal.msgError('上传图片失败,请重试')
this.$modal.closeLoading() // this.$modal.closeLoading()
}, },
// 上传结束处理 // 上传结束处理
uploadedSuccessfully() { uploadedSuccessfully() {
console.log('uploadedSuccessfully', this.number, this.uploadList.length)
if (this.number > 0 && this.uploadList.length === this.number) { if (this.number > 0 && this.uploadList.length === this.number) {
this.fileList = this.fileList.concat(this.uploadList) this.fileList = this.fileList.concat(this.uploadList)
this.uploadList = [] this.uploadList = []
this.number = 0 this.number = 0
this.$emit('input', this.listToString(this.fileList)) this.$emit('input', this.listToString(this.fileList))
this.$modal.closeLoading() // this.$modal.closeLoading()
} }
}, },
// 预览 // 预览
handlePictureCardPreview(file) { handlePictureCardPreview(file) {
this.dialogImageUrl = file.url this.$refs[file.url].clickHandler()
this.dialogVisible = true
}, },
// 对象转成指定字符串分隔 // 对象转成指定字符串分隔
listToString(list, separator) { listToString(list, separator) {
...@@ -210,16 +326,29 @@ export default { ...@@ -210,16 +326,29 @@ export default {
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.customer-upload-area{
width: 100%;
height: 100%;
.customer-upload-error{
width: 100%;
height: 100%;
color: #DB4747;
display: flex;
justify-content: center;
align-items: center;
align-content: center;
text-align: center;
font-size: 12px;
.el-icon-picture-outline{
font-size: 18px;
}
}
}
// .el-upload--picture-card 控制加号部分 // .el-upload--picture-card 控制加号部分
::v-deep.hide .el-upload--picture-card { ::v-deep.hide .el-upload--picture-card {
display: none; display: none;
} }
::v-deep .el-upload-list--picture-card {
line-height: 0;
}
::v-deep .el-upload-list__item {
margin: 0 0.5rem 0 0 !important;
}
// 去掉动画效果 // 去掉动画效果
::v-deep .el-list-enter-active, ::v-deep .el-list-enter-active,
::v-deep .el-list-leave-active { ::v-deep .el-list-leave-active {
...@@ -230,9 +359,11 @@ export default { ...@@ -230,9 +359,11 @@ export default {
opacity: 0; opacity: 0;
transform: translateY(0); transform: translateY(0);
} }
::v-deep .el-upload:focus { ::v-deep .el-upload-list--picture-card {
border-color: #5FB54B !important; line-height: 0;
color: #5FB54B !important; }
::v-deep .el-upload-list__item {
margin: 0 0.5rem 0 0 !important;
} }
</style> </style>
<template>
<div class="image-cropper-modal">
<el-dialog
:visible="visible"
:append-to-body="true"
:close-on-click-modal="false"
title="裁剪图片"
width="700px"
class="image-cropper-dialog"
@close="visible = false"
>
<vue-cropper
ref="imageCropper"
:img="url"
:auto-crop-width="autoCropWidth"
:auto-crop-height="autoCropHeight"
:auto-crop="true"
:fixed="false"
:fixed-number="[1, 1]"
:fixed-box="true"
:output-size="1"
output-type="png"
/>
<template #footer>
<span class="dialog-footer">
<el-button class="common-btn cancel" @click="onCancel">取 消</el-button>
<el-button class="common-btn confirm" type="primary" @click="onConfirm">确 定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
import { VueCropper } from 'vue-cropper'
export default {
name: 'ImageCropperModal',
components: {
VueCropper
},
props: {
visible: {
type: Boolean,
default: false
},
url: {
type: String,
default: ''
},
autoCropWidth: {
type: String,
default: `${100 * 4}`
},
autoCropHeight: {
type: String,
default: `${100 * 4}`
}
},
methods: {
onCancel() {
this.$emit('cancel')
},
onConfirm() {
this.$refs.imageCropper.getCropBlob((blob) => {
this.$emit('confirm', blob)
})
}
}
}
</script>
<style lang="scss" scoped>
.image-cropper-dialog {
.vue-cropper {
height: 500px;
}
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment