| <template> | 
|   <div :id="uploadId" class="fm-uplaod-container"> | 
|     <div v-for="(item) in fileList" :key="item.key" :id="item.key" :style="{width: width+'px', height: height+'px'}" :class="{uploading: item.status=='uploading', 'is-success': item.status=='success'}" class="upload-file"> | 
|       <img :src="item.url" /> | 
|   | 
|       <el-progress v-if="item.status=='uploading'" :width="miniWidth*0.9" :percentage="item.percent" class="upload-progress" type="circle"></el-progress> | 
|   | 
|       <label v-if="item.status=='success'" class="item-status"> | 
|         <i class="el-icon-upload-success el-icon-check"></i> | 
|       </label> | 
|   | 
|       <div class="uplaod-action"> | 
|         <i :style="{'font-size': miniWidth/4+'px'}" class="el-icon-view" @click="handlePreviewFile(item.key)"></i> | 
|         <i :style="{'font-size': miniWidth/4+'px'}" class="el-icon-delete" @click="handleRemove(item.key)"></i> | 
|       </div> | 
|     </div> | 
|   | 
|     <div v-if="token" :style="{width: width+'px', height: height+'px'}" class="el-upload el-upload--picture-card"> | 
|       <i :style="{fontSize:miniWidth/4+'px',marginTop: (-miniWidth/8)+'px', marginLeft: (-miniWidth/8)+'px'}" class="el-icon-plus"></i> | 
|       <input ref="uploadInput" :style="{width: width+'px', height: height+'px'}" accept="image/* " multiple type="file" name="file" class="el-upload__input upload-input" @change="handleChange"> | 
|     </div> | 
|   </div> | 
| </template> | 
|   | 
| <script> | 
| import Viewer from "viewerjs"; | 
| require("viewerjs/dist/viewer.css"); | 
|   | 
| export default { | 
|   props: { | 
|     value: { | 
|       type: Array, | 
|       default: () => [] | 
|     }, | 
|     width: { | 
|       type: Number, | 
|       default: 100 | 
|     }, | 
|     height: { | 
|       type: Number, | 
|       default: 100 | 
|     }, | 
|     token: { | 
|       type: String, | 
|       default: "" | 
|     }, | 
|     domain: { | 
|       type: String, | 
|       default: "" | 
|     }, | 
|     multiple: { | 
|       type: Boolean, | 
|       default: true | 
|     }, | 
|     length: { | 
|       type: Number, | 
|       default: 9 | 
|     } | 
|   }, | 
|   data() { | 
|     return { | 
|       fileList: [], | 
|       viewer: null, | 
|       uploadId: "upload_" + new Date().getTime() | 
|     }; | 
|   }, | 
|   computed: { | 
|     miniWidth() { | 
|       if (this.width > this.height) { | 
|         return this.height; | 
|       } else { | 
|         return this.width; | 
|       } | 
|     } | 
|   }, | 
|   methods: { | 
|     handleChange() { | 
|       // console.log(this.$refs.uploadInput.files) | 
|       const files = this.$refs.uploadInput.files; | 
|   | 
|       for (let i = 0; i < files.length; i++) { | 
|         const file = files[i]; | 
|         const reader = new FileReader(); | 
|         const key = | 
|           new Date().getTime() + "_" + Math.ceil(Math.random() * 99999); | 
|   | 
|         reader.readAsDataURL(file); | 
|         reader.onload = () => { | 
|           this.fileList.push({ | 
|             key, | 
|             url: reader.result, | 
|             percent: 0, | 
|             status: "uploading" | 
|           }); | 
|   | 
|           this.$nextTick(() => { | 
|             this.uplaodAction(reader.result, file, key); | 
|           }); | 
|         }; | 
|       } | 
|   | 
|       this.$refs.uploadInput.value = []; | 
|     }, | 
|   | 
|     uplaodAction(res, file, key) { | 
|       const xhr = new XMLHttpRequest(); | 
|       const url = "http://upload-z2.qiniu.com/putb64/" + file.size; | 
|       xhr.open("POST", url, true); | 
|       xhr.setRequestHeader("Content-Type", "application/octet-stream"); | 
|       xhr.setRequestHeader("Authorization", "UpToken " + this.token); | 
|       xhr.send(res.split(",")[1]); | 
|       xhr.onreadystatechange = () => { | 
|         if (xhr.readyState === 4) { | 
|           const resData = JSON.parse(xhr.response); | 
|           if (resData) { | 
|             this.$set( | 
|               this.fileList, | 
|               this.fileList.findIndex(item => item.key === key), | 
|               { | 
|                 ...this.fileList[ | 
|                   this.fileList.findIndex(item => item.key === key) | 
|                 ], | 
|                 url: this.domain + resData.key, | 
|                 percent: 100 | 
|               } | 
|             ); | 
|             setTimeout(() => { | 
|               this.$set( | 
|                 this.fileList, | 
|                 this.fileList.findIndex(item => item.key === key), | 
|                 { | 
|                   ...this.fileList[ | 
|                     this.fileList.findIndex(item => item.key === key) | 
|                   ], | 
|                   status: "success" | 
|                 } | 
|               ); | 
|   | 
|               this.$emit("input", this.fileList); | 
|             }, 200); | 
|           } else { | 
|             this.$set( | 
|               this.fileList, | 
|               this.fileList.findIndex(item => item.key === key), | 
|               { | 
|                 ...this.fileList[ | 
|                   this.fileList.findIndex(item => item.key === key) | 
|                 ], | 
|                 status: "error" | 
|               } | 
|             ); | 
|             this.fileList.splice( | 
|               this.fileList.findIndex(item => item.key === key), | 
|               1 | 
|             ); | 
|           } | 
|         } | 
|       }; | 
|       xhr.onprogress = res => { | 
|         // console.log('progress', res) | 
|         if (res.total && res.loaded) { | 
|           this.$set( | 
|             this.fileList[this.fileList.findIndex(item => item.key === key)], | 
|             "percent", | 
|             (res.loaded / res.total) * 100 | 
|           ); | 
|         } | 
|       }; | 
|     }, | 
|   | 
|     handleRemove(key) { | 
|       this.fileList.splice( | 
|         this.fileList.findIndex(item => item.key === key), | 
|         1 | 
|       ); | 
|     }, | 
|   | 
|     handlePreviewFile(key) { | 
|       this.viewer && this.viewer.destroy(); | 
|       this.uploadId = "upload_" + new Date().getTime(); | 
|   | 
|       // console.log(this.viewer) | 
|       this.$nextTick(() => { | 
|         this.viewer = new Viewer(document.getElementById(this.uploadId)); | 
|         this.viewer.view(this.fileList.findIndex(item => item.key === key)); | 
|       }); | 
|     } | 
|   } | 
| }; | 
| </script> | 
|   | 
| <style lang="scss"> | 
| .fm-uplaod-container { | 
|   .upload-file { | 
|     margin: 0 10px 10px 0; | 
|     display: inline-flex; | 
|     justify-content: center; | 
|     align-items: center; | 
|     //  background: #fff; | 
|     overflow: hidden; | 
|     background-color: #fff; | 
|     border: 1px solid #c0ccda; | 
|     border-radius: 6px; | 
|     box-sizing: border-box; | 
|     position: relative; | 
|     vertical-align: top; | 
|   | 
|     &:hover { | 
|       .uplaod-action { | 
|         display: flex; | 
|       } | 
|     } | 
|   | 
|     .uplaod-action { | 
|       position: absolute; | 
|       top: 0; | 
|       bottom: 0; | 
|       left: 0; | 
|       right: 0; | 
|       background: rgba(0, 0, 0, 0.6); | 
|       display: none; | 
|       justify-content: center; | 
|       align-items: center; | 
|   | 
|       i { | 
|         color: #fff; | 
|         cursor: pointer; | 
|         margin: 0 5px; | 
|       } | 
|     } | 
|   | 
|     &.is-success { | 
|       .item-status { | 
|         position: absolute; | 
|         right: -15px; | 
|         top: -6px; | 
|         width: 40px; | 
|         height: 24px; | 
|         background: #13ce66; | 
|         text-align: center; | 
|         transform: rotate(45deg); | 
|         box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2); | 
|   | 
|         & > i { | 
|           font-size: 12px; | 
|           margin-top: 11px; | 
|           color: #fff; | 
|           transform: rotate(-45deg); | 
|         } | 
|       } | 
|     } | 
|   | 
|     &.uploading { | 
|       &:before { | 
|         display: block; | 
|         content: ""; | 
|         position: absolute; | 
|         top: 0; | 
|         left: 0; | 
|         right: 0; | 
|         bottom: 0; | 
|         background: rgba(0, 0, 0, 0.3); | 
|       } | 
|     } | 
|   | 
|     .upload-progress { | 
|       position: absolute; | 
|   | 
|       .el-progress__text { | 
|         color: #fff; | 
|         font-size: 16px !important; | 
|       } | 
|     } | 
|   | 
|     img { | 
|       max-width: 100%; | 
|       max-height: 100%; | 
|       vertical-align: middle; | 
|     } | 
|   } | 
|   | 
|   .el-upload--picture-card { | 
|     position: relative; | 
|     overflow: hidden; | 
|   | 
|     .el-icon-plus { | 
|       position: absolute; | 
|       top: 50%; | 
|       left: 50%; | 
|     } | 
|   } | 
|   | 
|   .upload-input { | 
|     position: absolute; | 
|     top: 0; | 
|     left: 0; | 
|     right: 0; | 
|     bottom: 0; | 
|     display: block; | 
|     opacity: 0; | 
|     cursor: pointer; | 
|   } | 
| } | 
| </style> |