image-upload.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. <template>
  2. <div>
  3. <el-upload
  4. class="uploader"
  5. :action="oss_url"
  6. :data="dataObj"
  7. :multiple="multiple"
  8. name="file"
  9. :accept="accept"
  10. :show-file-list="false"
  11. :on-success="uploadSuccess"
  12. :before-upload="beforeUpload"
  13. />
  14. <div class="images">
  15. <div v-for="(item, index) in fileList" :key="index" class="item">
  16. <div v-if="item.url" class="img" @mouseover="item.hover = true;" @mouseout="item.hover = false;">
  17. <el-image v-if="checkFileType(item.url) == 'image'" ref="img" :src="imageURL + item.url" :preview-src-list="previewImages" style="width: 120px; height: 120px" fit="cover" />
  18. <el-image v-else ref="img" :src="imageURL + item.url" style="width: 120px; height: 120px" fit="cover">
  19. <div slot="error" class="image-slot">
  20. <img v-if="checkFileType(item.url) == 'word'" class="file" src="@/assets/common/word.png">
  21. <img v-if="checkFileType(item.url) == 'excel'" class="file" src="@/assets/common/excel.png">
  22. <img v-if="checkFileType(item.url) == 'ppt'" class="file" src="@/assets/common/ppt.png">
  23. <img v-if="checkFileType(item.url) == 'pdf'" class="file" src="@/assets/common/pdf.png">
  24. </div>
  25. </el-image>
  26. <div v-show="item.hover" class="mask">
  27. <i v-if="checkFileType(item.url) == 'image'" class="el-icon-zoom-in" @click="previewImage(item.url)" />
  28. <i class="el-icon-upload2" @click="uploadImage(item.url)" />
  29. <i class="el-icon-delete" @click="deleteImage(item.url)" />
  30. </div>
  31. </div>
  32. </div>
  33. <div v-if="multiple || (!multiple && fileList.length < 1)" class="add" @click="uploadImage()"><i class="el-icon-plus" /></div>
  34. </div>
  35. </div>
  36. </template>
  37. <script>
  38. import { getOssConfig } from '@/api/common'
  39. import { findElem } from '@/utils/util'
  40. export default {
  41. name: 'FileUpload',
  42. props: {
  43. // 接受上传的文件列表
  44. fileList: Array,
  45. // 接受上传的文件类型
  46. fileType: {
  47. type: Array,
  48. default: () => ['image', 'word', 'excel', 'ppt', 'pdf']
  49. },
  50. // 是否支持多选文件
  51. multiple: {
  52. type: Boolean,
  53. default: false
  54. },
  55. startRestricting: {
  56. type: Boolean,
  57. default: false
  58. },
  59. restrictFilename: {
  60. type: Array,
  61. default:()=>{
  62. return []
  63. }
  64. }
  65. },
  66. data() {
  67. return {
  68. imageURL: this.$imageUrl,
  69. oss_url: '',
  70. dataObj: {},
  71. uploadImageUrl: '',
  72. waitUploadList: []
  73. }
  74. },
  75. computed: {
  76. isShowFileList: {
  77. get: function() {
  78. if (this.fileList.length > 0 && this.fileList[0].url) {
  79. return true
  80. } else {
  81. return false
  82. }
  83. },
  84. set: function(newValue) {}
  85. },
  86. accept() {
  87. const imageList = ['.jpg', '.jpeg', '.png']
  88. const videoList = ['.mp4']
  89. const wordList = ['.doc', '.docx', '.dot', '.wps', '.wpt']
  90. const excelList = ['.xls', '.xlsx', '.xlt', '.et', '.ett']
  91. const pptList = ['.ppt', '.pptx', '.dps', '.dpt', '.pot', '.pps']
  92. const pdfList = ['.pdf']
  93. let whiteList = []
  94. this.fileType.includes('image') && (whiteList = whiteList.concat(imageList))
  95. this.fileType.includes('video') && (whiteList = whiteList.concat(videoList))
  96. this.fileType.includes('word') && (whiteList = whiteList.concat(wordList))
  97. this.fileType.includes('excel') && (whiteList = whiteList.concat(excelList))
  98. this.fileType.includes('ppt') && (whiteList = whiteList.concat(pptList))
  99. this.fileType.includes('pdf') && (whiteList = whiteList.concat(pdfList))
  100. return whiteList.join(',')
  101. },
  102. previewImages() {
  103. const fileList = []
  104. if (this.fileList && this.fileList.length > 0) {
  105. this.fileList.forEach(item => {
  106. if (this.checkFileType(item.url) == 'image') {
  107. fileList.push(this.imageURL + item.url)
  108. }
  109. })
  110. }
  111. return fileList
  112. }
  113. },
  114. created() {
  115. getOssConfig().then(res => {
  116. this.oss_url = res.data.host
  117. })
  118. },
  119. methods: {
  120. getUUID() {
  121. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
  122. return (c === 'x' ? (Math.random() * 16) | 0 : 'r&0x3' | '0x8').toString(16)
  123. })
  124. },
  125. createName(name) {
  126. const date = Date.now()
  127. const uuid = this.getUUID()
  128. const fileSuffix = name.substring(name.lastIndexOf('.') + 1)
  129. return `${date}${uuid}.${fileSuffix}`
  130. },
  131. // 检查文件类型
  132. checkFileType(url) {
  133. if (!url) return ''
  134. const fileSuffix = url.substring(url.lastIndexOf('.') + 1)
  135. if (['jpg', 'jpeg', 'png'].includes(fileSuffix)) {
  136. return 'image'
  137. } else if (['doc', 'docx', 'dot', 'wps', 'wpt'].includes(fileSuffix)) {
  138. return 'word'
  139. } else if (['xls', 'xlsx', 'xlt', 'et', 'ett'].includes(fileSuffix)) {
  140. return 'excel'
  141. } else if (['ppt', 'pptx', 'dps', 'dpt', 'pot', 'pps'].includes(fileSuffix)) {
  142. return 'ppt'
  143. } else if (['pdf'].includes(fileSuffix)) {
  144. return 'pdf'
  145. } else {
  146. return ''
  147. }
  148. },
  149. // 获取oss配置
  150. async getOssConfig(fileName) {
  151. const result = await new Promise((resolve, reject) => {
  152. getOssConfig().then(res => {
  153. const fileKey = this.createName(fileName)
  154. res.data.name = fileName
  155. res.data.key = res.data.dir + fileKey
  156. resolve(res.data)
  157. }).catch(res => {
  158. resolve({})
  159. })
  160. })
  161. return result
  162. },
  163. // 预览图片
  164. previewImage(url) {
  165. const index = findElem(this.fileList, 'url', url)
  166. this.$refs.img[index].showViewer = true
  167. },
  168. // 删除图片
  169. deleteImage(url) {
  170. const index = findElem(this.fileList, 'url', url)
  171. this.fileList.splice(index, 1)
  172. },
  173. // 点击上传
  174. uploadImage(url) {
  175. this.uploadImageUrl = url
  176. document.querySelector('.uploader input').click()
  177. },
  178. // 上传文件之前
  179. async beforeUpload(file) {
  180. const loading = this.$loading({
  181. lock: true,
  182. text: 'Loading',
  183. spinner: 'el-icon-loading',
  184. background: 'rgba(0, 0, 0, 0.7)'
  185. })
  186. this.$emit('handleIsFileName', file.name)
  187. this.dataObj = await this.getOssConfig(file.name)
  188. this.waitUploadList.push(this.dataObj)
  189. if (this.startRestricting) {
  190. if (!this.restrictFilename.includes(file.name.split('.')[0])) {
  191. this.$errorMsg('请根据固定文件名称上传:' + this.restrictFilename.join())
  192. loading.close()
  193. return Promise.reject()
  194. }
  195. }
  196. },
  197. // 文件上传成功
  198. uploadSuccess(res, file) {
  199. const loading = this.$loading({
  200. lock: true,
  201. text: 'Loading',
  202. spinner: 'el-icon-loading',
  203. background: 'rgba(0, 0, 0, 0.7)'
  204. })
  205. if (this.uploadImageUrl) {
  206. const index = findElem(this.fileList, 'url', this.uploadImageUrl)
  207. this.$set(this.fileList, index, {
  208. name: this.dataObj.name,
  209. url: this.dataObj.key,
  210. hover: false
  211. })
  212. this.waitUploadList = []
  213. } else {
  214. const index = findElem(this.waitUploadList, 'name', file.name)
  215. if (this.startRestricting) {
  216. if (this.fileList.length) {
  217. this.fileList.forEach(k => {
  218. if (k.name.split('.')[0] === file.name.split('.')[0]) {
  219. k.name = this.waitUploadList[index].name
  220. k.url = this.waitUploadList[index].key
  221. k.hover = false
  222. this.waitUploadList.splice(index, 1)
  223. this.showFileList = true
  224. loading.close()
  225. }
  226. })
  227. return false
  228. }
  229. }
  230. this.fileList.push({
  231. name: this.waitUploadList[index].name,
  232. url: this.waitUploadList[index].key,
  233. hover: false
  234. })
  235. this.waitUploadList.splice(index, 1)
  236. }
  237. this.showFileList = true
  238. loading.close()
  239. }
  240. }
  241. }
  242. </script>
  243. <style scoped lang="scss">
  244. .images {
  245. display: flex;
  246. flex-wrap: wrap;
  247. .item {
  248. margin-right: 20px;
  249. .img {
  250. width: 120px;
  251. height: 120px;
  252. border-radius: 5px;
  253. overflow: hidden;
  254. position: relative;
  255. border: 1px dashed #eaeaea;
  256. display: flex;
  257. .el-image {
  258. display: block;
  259. }
  260. .file {
  261. width: 120px;
  262. height: 120px;
  263. display: block;
  264. padding: 30px;
  265. }
  266. .mask {
  267. position: absolute;
  268. left: 0;
  269. top: 0;
  270. width: 120px;
  271. height: 120px;
  272. background: rgba($color: #000000, $alpha: 0.3);
  273. display: flex;
  274. align-items: center;
  275. justify-content: center;
  276. i {
  277. font-size: 20px;
  278. color: #ffffff;
  279. cursor: pointer;
  280. margin: 0 8px;
  281. }
  282. }
  283. }
  284. }
  285. .add {
  286. width: 120px;
  287. height: 120px;
  288. border: 1px dashed #eaeaea;
  289. border-radius: 5px;
  290. cursor: pointer;
  291. display: flex;
  292. align-items: center;
  293. justify-content: center;
  294. i {
  295. font-size: 30px;
  296. color: #999;
  297. }
  298. }
  299. }
  300. .uploader {
  301. height: 0;
  302. }
  303. </style>