|
@@ -0,0 +1,407 @@
|
|
|
|
+<template>
|
|
|
|
+ <div class="more-img-uploade">
|
|
|
|
+ <draggable
|
|
|
|
+ :list="previewList"
|
|
|
|
+ tag="ul"
|
|
|
|
+ class="img-list"
|
|
|
|
+ v-bind="dragOptions"
|
|
|
|
+ draggable=".item"
|
|
|
|
+ @update="updateDrag"
|
|
|
|
+ >
|
|
|
|
+ <li v-for="(item, index) in previewList" :key="index" class="item">
|
|
|
|
+ <div class="el-upload-list el-upload-list--picture-card flex">
|
|
|
|
+ <auth-img v-if="!isPublic" :auth-src="item.thumbUrl" image-width="80px" image-height="80px"></auth-img>
|
|
|
|
+ <el-image v-if="isPublic" :src="item.thumbUrl" fit="contain" style="width: 80px;height: 80px;"></el-image>
|
|
|
|
+ <label class="el-upload-list__item-status-label"><i class="el-icon-upload-success el-icon-check"></i></label>
|
|
|
|
+ <span class="el-upload-list__item-actions">
|
|
|
|
+ <span class="el-upload-list__item-preview"><i class="el-icon-zoom-in" @click="handlePreview(item)"></i></span>
|
|
|
|
+ <span class="el-upload-list__item-delete"><i class="el-icon-delete" @click="handleDelete(item)"></i></span>
|
|
|
|
+ </span>
|
|
|
|
+ </div>
|
|
|
|
+ </li>
|
|
|
|
+ <el-upload
|
|
|
|
+ :action="fileSaveUrl"
|
|
|
|
+ list-type="picture-card"
|
|
|
|
+ :data="reqData"
|
|
|
|
+ :on-success="fileUploadSuccess"
|
|
|
|
+ :before-upload="handleBeforeUpload"
|
|
|
|
+ :limit="limit"
|
|
|
|
+ :on-error="handleUploadError"
|
|
|
|
+ :on-exceed="handleExceed"
|
|
|
|
+ name="file"
|
|
|
|
+ multiple
|
|
|
|
+ :on-remove="handleRemove"
|
|
|
|
+ :show-file-list="false"
|
|
|
|
+ :headers="headers"
|
|
|
|
+ :http-request="reqUploadImage"
|
|
|
|
+ :file-list="previewList"
|
|
|
|
+ :on-preview="handlePictureCardPreview"
|
|
|
|
+ :auto-upload="true"
|
|
|
|
+ :class="{hide: this.fileList.length >= this.limit}">
|
|
|
|
+ <i class="el-icon-plus"></i>
|
|
|
|
+
|
|
|
|
+ </el-upload>
|
|
|
|
+ </draggable>
|
|
|
|
+
|
|
|
|
+ <el-dialog :visible.sync="dialogVisible" title="预览" width="800" append-to-body>
|
|
|
|
+ <div style="display: block; max-width: 100%; margin: 0 auto;text-align: center;max-height: 435px;overflow: auto;">
|
|
|
|
+ <auth-img v-if="!isPublic && dialogVisible" :auth-src="dialogImageUrl" image-width="435px" ></auth-img>
|
|
|
|
+ <img v-if="isPublic" :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
|
|
|
|
+ </div>
|
|
|
|
+ </el-dialog>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+import draggable from "vuedraggable";
|
|
|
|
+import { getToken, getSign } from "@/utils/auth";
|
|
|
|
+import { randomStr20 } from "@/utils/util";
|
|
|
|
+import {
|
|
|
|
+ privateFileSaveUrl,
|
|
|
|
+ publicFileSaveUrl,
|
|
|
|
+ publicFileSaveAPI,
|
|
|
|
+ privateFileSaveAPI,
|
|
|
|
+ publicFileGetUrl,
|
|
|
|
+ privateFileGetUrl,
|
|
|
|
+} from "@/api/common";
|
|
|
|
+
|
|
|
|
+import AuthImg from "@/components/AuthImg/index.vue";
|
|
|
|
+import UploadImg from "@/components/UploadImg/index.vue";
|
|
|
|
+export default {
|
|
|
|
+ components: {
|
|
|
|
+ draggable,
|
|
|
|
+ AuthImg,
|
|
|
|
+ UploadImg
|
|
|
|
+ },
|
|
|
|
+ props: {
|
|
|
|
+ // 已经上传的文件url列表
|
|
|
|
+ value: [String, Object, Array],
|
|
|
|
+ // 图片数量限制
|
|
|
|
+ limit: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: 5,
|
|
|
|
+ },
|
|
|
|
+ // 大小限制(MB)
|
|
|
|
+ fileSize: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: 5,
|
|
|
|
+ },
|
|
|
|
+ // 文件类型, 例如['png', 'jpg', 'jpeg']
|
|
|
|
+ fileType: {
|
|
|
|
+ type: Array,
|
|
|
|
+ default: () => ["png", "jpg", "jpeg"],
|
|
|
|
+ },
|
|
|
|
+ // 是否显示提示
|
|
|
|
+ isShowTip: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: true
|
|
|
|
+ },
|
|
|
|
+ // 是否显示提示
|
|
|
|
+ isPublic: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: true
|
|
|
|
+ },
|
|
|
|
+ // 半高显示
|
|
|
|
+ low: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: false
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ dialogImageUrl: "",
|
|
|
|
+ dialogVisible: false,
|
|
|
|
+ hideUpload: false,
|
|
|
|
+ baseUrl: process.env.VUE_APP_BASE_API,
|
|
|
|
+ uploadImgUrl: this.isPublic ? publicFileSaveUrl : privateFileSaveUrl, // 上传的图片服务器地址
|
|
|
|
+ fileSaveUrl: '',
|
|
|
|
+ headers: {
|
|
|
|
+ Authorization: "Bearer " + getToken(),
|
|
|
|
+ },
|
|
|
|
+ fileList: [],
|
|
|
|
+ previewList: [],
|
|
|
|
+ reqData: {}
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ dialogImageUrl: "",
|
|
|
|
+ dialogVisible: false,
|
|
|
|
+ hideUpload: false,
|
|
|
|
+ baseUrl: process.env.VUE_APP_BASE_API,
|
|
|
|
+ uploadImgUrl: this.isPublic ? publicFileSaveUrl : privateFileSaveUrl, // 上传的图片服务器地址
|
|
|
|
+ fileSaveUrl: '',
|
|
|
|
+ headers: {
|
|
|
|
+ Authorization: "Bearer " + getToken(),
|
|
|
|
+ },
|
|
|
|
+ fileList: [],
|
|
|
|
+ previewList: [],
|
|
|
|
+ reqData: {}
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+ watch: {
|
|
|
|
+ value(val) {
|
|
|
|
+ if (val) {
|
|
|
|
+ this.initHandle()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ computed: {
|
|
|
|
+ // 拖拽属性
|
|
|
|
+ dragOptions() {
|
|
|
|
+ return {
|
|
|
|
+ animation: 200, // 动画时间
|
|
|
|
+ disabled: false, // false可拖拽,true不可拖拽
|
|
|
|
+ group: "description",
|
|
|
|
+ ghostClass: "ghost",
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ methods: {
|
|
|
|
+ // 拖拽完成
|
|
|
|
+ updateDrag(e){
|
|
|
|
+ this.fileList = this.previewList.map(item => {
|
|
|
|
+ return {
|
|
|
|
+ fileName: item.name
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ this.$emit("input", this.fileList);
|
|
|
|
+ this.$emit('change')
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ initHandle() {
|
|
|
|
+ if (this.value) {
|
|
|
|
+ // 首先将值转为数组
|
|
|
|
+ const list = Array.isArray(this.value) ? this.value : this.value.split(',')
|
|
|
|
+ // 然后将数组转为对象数组
|
|
|
|
+ this.previewList = []
|
|
|
|
+ this.fileList = list.map(item => {
|
|
|
|
+ var pitem = {
|
|
|
|
+ name: item.fileName,
|
|
|
|
+ url: (this.isPublic ? publicFileGetUrl : (this.baseUrl + privateFileGetUrl)) + item.fileName,
|
|
|
|
+ thumbUrl: (this.isPublic ? publicFileGetUrl : (this.baseUrl + privateFileGetUrl)) + item.fileName + "_s"
|
|
|
|
+ };
|
|
|
|
+ this.previewList.push(pitem)
|
|
|
|
+ return item;
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ this.previewList = []
|
|
|
|
+ this.fileList = []
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ handlePreview(item){
|
|
|
|
+ this.dialogVisible = true;
|
|
|
|
+ this.dialogImageUrl = item.url
|
|
|
|
+
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ handleDelete(item){
|
|
|
|
+ const findex = this.fileList.map(f => f.fileName).indexOf(item.name);
|
|
|
|
+ this.fileList.splice(findex, 1);
|
|
|
|
+ this.previewList.splice(findex, 1);
|
|
|
|
+ this.$emit("input", this.fileList);
|
|
|
|
+ this.$emit('change')
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 删除图片
|
|
|
|
+ handleRemove(file, fileList) {
|
|
|
|
+ const findex = this.fileList.map(f => f.name).indexOf(file.name);
|
|
|
|
+ this.fileList.splice(findex, 1);
|
|
|
|
+ this.previewList.splice(findex, 1);
|
|
|
|
+ this.$emit("input", this.fileList);
|
|
|
|
+ this.$emit('change')
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 上传图片
|
|
|
|
+ */
|
|
|
|
+ fileUploadSuccess(response, file, fileList) {
|
|
|
|
+ this.fileList.push({
|
|
|
|
+ fileName: response.fileName,
|
|
|
|
+ fileType: response.fileType
|
|
|
|
+ });
|
|
|
|
+ this.previewList.push({
|
|
|
|
+ name: response.fileName,
|
|
|
|
+ url: (this.isPublic ? publicFileGetUrl : (this.baseUrl + privateFileGetUrl)) + response.fileName,
|
|
|
|
+ fileType: response.fileType
|
|
|
|
+ });
|
|
|
|
+ this.$emit("input", this.fileList);
|
|
|
|
+ this.$emit('change')
|
|
|
|
+ this.loading.close();
|
|
|
|
+
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 上传前loading加载
|
|
|
|
+ handleBeforeUpload(file) {
|
|
|
|
+ let isImg = false;
|
|
|
|
+ if (this.fileType.length) {
|
|
|
|
+ let fileExtension = "";
|
|
|
|
+ if (file.name.lastIndexOf(".") > -1) {
|
|
|
|
+ fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
|
|
|
|
+ }
|
|
|
|
+ isImg = this.fileType.some(type => {
|
|
|
|
+ if (file.type.indexOf(type) > -1) return true;
|
|
|
|
+ if (fileExtension && fileExtension.indexOf(type) > -1) return true;
|
|
|
|
+ return false;
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ isImg = file.type.indexOf("image") > -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!isImg) {
|
|
|
|
+ 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.getHttpHeader()
|
|
|
|
+ this.loading = this.$loading({
|
|
|
|
+ lock: true,
|
|
|
|
+ text: "上传中",
|
|
|
|
+ background: "rgba(0, 0, 0, 0.7)",
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 自定义文件上传的实现
|
|
|
|
+ reqUploadImage(param) {
|
|
|
|
+ var data = this.reqData || {}
|
|
|
|
+ var params = {
|
|
|
|
+ file: param.file,
|
|
|
|
+ ...data
|
|
|
|
+ }
|
|
|
|
+ const request = this.isPublic ? publicFileSaveAPI : privateFileSaveAPI
|
|
|
|
+ request(params, this.headers).then(response => {
|
|
|
|
+ var res = {
|
|
|
|
+ fileName: response.data.fileName,
|
|
|
|
+ fileType: response.data.fileType
|
|
|
|
+ }
|
|
|
|
+ this.fileList.push({
|
|
|
|
+ fileName: response.data.fileName,
|
|
|
|
+ fileType: response.data.fileType
|
|
|
|
+ });
|
|
|
|
+ this.previewList.push({
|
|
|
|
+ name: response.data.fileName,
|
|
|
|
+ url: (this.isPublic ? publicFileGetUrl : (this.baseUrl + privateFileGetUrl)) + response.data.fileName,
|
|
|
|
+ fileType: response.fileType
|
|
|
|
+ });
|
|
|
|
+ this.$emit("input", this.fileList);
|
|
|
|
+ this.$emit('change')
|
|
|
|
+ this.loading.close();
|
|
|
|
+ // 但是我们上传成功了图片, fileList 里面的值却没有改变,还好有on-change指令可以使用
|
|
|
|
+ }).catch(response => {
|
|
|
|
+ param.onError()
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 请求头
|
|
|
|
+ getHttpHeader() {
|
|
|
|
+ let timestamp = parseInt(new Date().getTime()),
|
|
|
|
+ nonce = randomStr20();
|
|
|
|
+ var sign = getSign(this.reqData || {}, timestamp)
|
|
|
|
+ let url = this.uploadImgUrl + '?sign=' + sign + '&nonce=' + nonce;
|
|
|
|
+ this.fileSaveUrl = url
|
|
|
|
+ var headers = {
|
|
|
|
+ "Authorization": "Bearer " + getToken(),
|
|
|
|
+ "x-zz-timestamp": timestamp
|
|
|
|
+ }
|
|
|
|
+ this.headers = headers
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 文件个数超出
|
|
|
|
+ handleExceed() {
|
|
|
|
+ this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);
|
|
|
|
+ },
|
|
|
|
+ // 上传失败
|
|
|
|
+ handleUploadError() {
|
|
|
|
+ // this.$message({
|
|
|
|
+ // type: "error",
|
|
|
|
+ // message: "上传失败",
|
|
|
|
+ // });
|
|
|
|
+ this.loading.close();
|
|
|
|
+ },
|
|
|
|
+ // 预览
|
|
|
|
+ handlePictureCardPreview(file) {
|
|
|
|
+ this.dialogImageUrl = file.url;
|
|
|
|
+ this.dialogVisible = true;
|
|
|
|
+ },
|
|
|
|
+ // 对象转成指定字符串分隔
|
|
|
|
+ listToString(list, separator) {
|
|
|
|
+ let strs = "";
|
|
|
|
+ separator = separator || ",";
|
|
|
|
+ for (let i in list) {
|
|
|
|
+ strs += list[i].url.replace(this.baseUrl, "") + separator;
|
|
|
|
+ }
|
|
|
|
+ return strs != '' ? strs.substr(0, strs.length - 1) : '';
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
+.flex{
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+}
|
|
|
|
+// .el-upload--picture-card 控制加号部分
|
|
|
|
+::v-deep.hide .el-upload--picture-card {
|
|
|
|
+ display: none;
|
|
|
|
+}
|
|
|
|
+::v-deep .el-upload--picture-card{
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ width: 80px;
|
|
|
|
+ height: 80px;
|
|
|
|
+ line-height: 80px;
|
|
|
|
+}
|
|
|
|
+</style>
|
|
|
|
+<style scoped>
|
|
|
|
+.img-list {
|
|
|
|
+ width: 100%;
|
|
|
|
+ display: flex;
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
+ padding: 0;
|
|
|
|
+}
|
|
|
|
+.img-list li,
|
|
|
|
+.img-li {
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ width: 80px;
|
|
|
|
+ height: 80px;
|
|
|
|
+ margin: 0 10px 10px;
|
|
|
|
+ border: 1px dashed #d9d9d9;
|
|
|
|
+ border-radius: 6px;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ position: relative;
|
|
|
|
+ overflow: hidden;
|
|
|
|
+}
|
|
|
|
+.img-li {
|
|
|
|
+ float: left;
|
|
|
|
+}
|
|
|
|
+.img-list li img {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ object-fit: contain;
|
|
|
|
+ background: #000;
|
|
|
|
+}
|
|
|
|
+.upload-class {
|
|
|
|
+ font-size: 28px;
|
|
|
|
+ color: #8c939d;
|
|
|
|
+ text-align: center;
|
|
|
|
+ height: 120px;
|
|
|
|
+ width: 180px;
|
|
|
|
+ line-height: 120px;
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
+}
|
|
|
|
+</style>
|