<template>
<el-form-item :label="label" prop="coverUrl">
<el-image
v-if="ruleCoverUrl"
class="uploadImgwh"
:src="ruleCoverUrl"
@click="clickImgUpdata"
/>
<div v-else class="updataCourseImage uploadImgwh">
<el-button @click="clickImgUpdata">上传封面图片</el-button>
</div>
<!-- 上传课程封面弹框 -->
<el-dialog
title="上传课程封面"
v-loading="loading"
:element-loading-text="'正在上传中...' + per + '%'"
:close-on-press-escape="false"
:close-on-click-modal="false"
append-to-body
:visible.sync="dialogImg"
width="50%"
>
<div class="updataimg">
<div>
<div class="cropper-content" v-if="coverUrl">
<div class="cropper" style="text-align:center">
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.outputSize"
:outputType="option.outputType"
:info="option.info"
:canScale="option.canScale"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:fixedBox="option.fixedBox"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:centerBox="option.centerBox"
:infoTrue="option.infoTrue"
:full="option.full"
:enlarge="option.enlarge"
:mode="option.mode"
@realTime='realTime'
>
</vueCropper>
</div>
</div>
<div
v-else
class="updataCourseImage uploadImgwh"
>
<span>暂无封面图片</span>
</div>
</div>
<div>
<div style="width: 222px;height: 138px; padding: 0 0 30px 30px;">
<img :src='previewImg' alt="请上传后再预览" class='previewImg' style="display: inline-block; width: 192px; height: 108px; border: 1px dashed #87cefa;">
</div>
<div class="updataimg_right">
<h3>封面预览</h3>
<p>注意:</p>
<p>封面不允许涉及政治色彩和色情;</p>
<p>支持jpg/gif/png格式,2M以内;</p>
<p>建议最佳封面尺寸比例:16 : 9</p>
<el-button
size="mini"
type="primary"
@click="uploadFile"
style="margin-right: 30px"
>上传</el-button
>
<input
v-show="false"
ref="fileRef"
accept=".png, .jpg, .jpeg, .webp, .gif"
type="file"
@change="beforeAvatarUpload($event)"
/>
<el-button size="mini" @click="clearImg">清空</el-button>
</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="clearBtn">取 消</el-button>
<el-button type="primary" @click="addCoverUrl">保 存</el-button>
</span>
</el-dialog>
</el-form-item>
</template>
<script>
import { _api_stsTokenUpdata } from "@/api/oss/oss.js";
import { VueCropper } from 'vue-cropper'
export default {
components: { VueCropper },
props: {
ruleCoverUrl: String,
label: String,
},
data() {
return {
// loading
loading: false,
// 弹出框
dialogImg: false,
// 弹出框内图
coverUrl: undefined,
// 进度
per: 0,
// 上传点
abortCheckpoint: undefined,
option: {
img: 'https://cmp-uploadfile.oss-cn-beijing.aliyuncs.com/52785f074330e.jpg', // 裁剪图片的地址 url 地址, base64, blob, 给个默认,防止报错
outputSize: 0.5, // 裁剪生成图片的质量
outputType: 'png', // 裁剪生成图片的格式 jpeg, png, webp
info: true, // 裁剪框的大小信息
canScale: true, // 图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 256, // 默认生成截图框宽度
autoCropHeight: 144, // 默认生成截图框高度
fixedBox: false, // 固定截图框大小 不允许改变
fixed: true, // 是否开启截图框宽高固定比例
fixedNumber: [16, 9], // 截图框的宽高比例 [ 宽度 , 高度 ]
canMove: true, // 上传图片是否可以移动
canMoveBox: true, // 截图框能否拖动
original: false, // 上传图片按照原始比例渲染
centerBox: true, // 截图框是否被限制在图片里面
infoTrue: true, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
full: false, // 是否输出原图比例的截图
enlarge: '2', // 图片根据截图框输出比例倍数
mode: 'contain' // 图片默认渲染方式 contain , cover, 100px, 100% auto
},
success: () => {}, // 回调方法
previewImg: null, // 预览后的图片
resImg:null,
}
},
methods: {
//获取图片预览
realTime (data) {
const that = this
this.$refs.cropper.getCropBlob(data => {
console.log(data)
// 这里data数据为Blob类型,blobToDataURI方法转换成base64
this.blobToDataURI(data, function(res) {
that.previewImg = res
})
})
},
// 课程封面的点击事件
clickImgUpdata() {
this.dialogImg = true;
this.coverUrl = this.ruleCoverUrl;
},
// 上传代理
uploadFile() {
this.$refs.fileRef.dispatchEvent(new MouseEvent("click"));
},
// base64转化为Blob/file对象
convertBase64ToBlob(imageEditorBase64) {
var base64Arr = imageEditorBase64.split(",");
var imgtype = "";
var base64String = "";
if (base64Arr.length > 1) {
//如果是图片base64,去掉头信息
base64String = base64Arr[1];
imgtype = base64Arr[0].substring(
base64Arr[0].indexOf(":") + 1,
base64Arr[0].indexOf(";")
);
}
// 将base64解码
var bytes = atob(base64String);
//var bytes = base64;
var bytesCode = new ArrayBuffer(bytes.length);
// 转换为类型化数组
var byteArray = new Uint8Array(bytesCode);
// 将base64转换为ascii码
for (var i = 0; i < bytes.length; i++) {
byteArray[i] = bytes.charCodeAt(i);
}
// 生成Blob对象(文件对象)
let blob = new Blob([bytesCode], { type: imgtype });
let filename = new Date().getTime() + '';
//生成file文件对象
var file = new File([blob], filename, {type: imgtype, lastModified: Date.now()});
return file
},
// 图片上传保存
addCoverUrl() {
console.log(this.previewImg)
if(!this.previewImg){
return this.$message.warning('未上传文件,请上传文件后再进行保存!')
}
let file = this.convertBase64ToBlob(this.previewImg)
this.OSS(file)
},
// 清空图片列表
clearImg() {
this.coverUrl = "";
this.previewImg = ''
},
// 关闭上传图片弹框
clearBtn() {
this.clearImg();
this.dialogImg = false;
},
// 上传
async beforeAvatarUpload(e) {
// 获取到第一张图片
const file = e.target.files[0];
let regImage = ["image/jpg", "image/jpeg", "image/png", "image/gif"];
if (regImage.indexOf(file.type) == -1) {
this.$message.error("请上传图片!!!");
return;
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error("上传的封面图片大小不能超过 2MB!");
return;
}
const aBlob = new Blob(e.target.files)
let that = this
this.blobToDataURI(aBlob, function(res) {
that.coverUrl = res
that.option.img = res
})
},
blobToDataURI(blob, callback) {
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function (e) {
callback(e.target.result);
}
},
async OSS(file){
this.loading = true;
const filename = file.name;
// 获取STS token
let credentials = await _api_stsTokenUpdata();
// 创建对象
this.ossClient = new OSS({
region: "oss-cn-beijing",
accessKeyId: credentials.data.accessKeyId,
accessKeySecret: credentials.data.accessKeySecret,
stsToken: credentials.data.securityToken,
bucket: credentials.data.bucketName,
secure: true,
});
this.ossClient
.multipartUpload(filename, file, {
parallel: 1,
partSize: 1024 * 1024,
progress: (p, cpt, res) => {
// 获取上传进度。
this.abortCheckpoint = cpt;
console.log(p * 100);
this.per = Math.floor(p * 100);
},
})
.then((result) => {
console.log(result)
let index = result.res.requestUrls[0].lastIndexOf("?")
if(index == -1){
this.coverUrl = result.res.requestUrls[0]
// this.option.img = this.coverUrl
}else{
this.coverUrl = result.res.requestUrls[0].substr(0,index)
// this.option.img = this.coverUrl
}
this.$emit("giveruleCoverUrl", this.coverUrl)
// e.target.value = ''
this.dialogImg = false
this.loading = false;
})
.catch(function (err) {
console.log(err);
this.loading = false;
});
},
},
};
</script>
<style lang="scss" scoped>
.updataimg {
display: flex;
.updataimg_right {
padding: 30px;
h3 {
font-weight: bolder;
font-size: 16px;
}
p {
margin: 0;
font-size: 12px;
}
}
}
// 上传课程封面
.updataCourseImage {
display: flex;
justify-content: center;
align-items: center;
border: 1px dashed #87cefa;
background-color: #fcfdfd;
}
.uploadImgwh{
width: 512px;
height: 288px;
}
.real_info_class {
.el-checkbox__input .el-checkbox__inner {
border-radius: 0;
}
}
.file-image {
width: 320px;
height: 320px;
font-size: 14px;
border: 1px solid #cccccc;
margin: 15px 0;
}
/* 截图 */
/* .cropper-content {} */
.cropper {
width: 512px;
height: 288px;
}
</style>
学习如逆水行舟,不进则退。