FileUpload.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <template>
  2. <el-upload
  3. class="file-upload"
  4. :action="uploadUrl"
  5. :on-success="onSuccess"
  6. :on-remove="onRemove"
  7. :headers="headers"
  8. :file-list="fileList"
  9. :limit="filesLimit"
  10. :on-exceed="onExceed"
  11. :on-preview="onPreview"
  12. ref="upload"
  13. >
  14. <el-button type="primary" size="mini" slot="trigger">
  15. 点击上传
  16. </el-button>
  17. <div class="file-list-item" slot="file" slot-scope="{ file }">
  18. <div class="file-name">
  19. <i class="status-icon el-icon-warning-outline danger" v-if="file.status === 'fail'"></i>
  20. <i class="status-icon el-icon-circle-check success" v-else-if="file.status === 'success'"></i>
  21. <i class="status-icon el-icon-loading" v-else></i>
  22. {{ file.name }}
  23. <i class="opt">
  24. <i class="opt-icon el-icon-search" v-if="file.status === 'success'" @click="preview(file)"></i>
  25. <i class="opt-icon el-icon-download" v-if="file.status === 'success'" @click="download(file)"></i>
  26. <i class="opt-icon el-icon-delete" @click="removeFile(file)"></i>
  27. </i>
  28. </div>
  29. <el-progress
  30. v-if="file.status === 'uploading'"
  31. :percentage="file.percentage"
  32. :show-text="false"
  33. :stroke-width="2"
  34. class="upload-progress"
  35. ></el-progress>
  36. </div>
  37. <el-image style="width:0;height:0;" :src="previewUrl" :preview-src-list="[previewUrl]" ref="preview">
  38. </el-image>
  39. </el-upload>
  40. </template>
  41. <script>
  42. import resolveUrl from 'resolve-url';
  43. import axios from 'axios';
  44. export default {
  45. name: 'FileUpload',
  46. props: {
  47. single: {
  48. type: Boolean,
  49. default() {
  50. return false;
  51. }
  52. },
  53. limit: {
  54. type: Number,
  55. default() {
  56. return 10000;
  57. }
  58. },
  59. value: {}
  60. },
  61. data() {
  62. return {
  63. fileList: [],
  64. watchValue: true,
  65. uploadUrl: '',
  66. previewUrl: null
  67. };
  68. },
  69. computed: {
  70. headers() {
  71. return {
  72. Authorization: 'Bearer ' + localStorage.getItem('token')
  73. };
  74. },
  75. filesLimit() {
  76. if (this.single) {
  77. return 1;
  78. }
  79. return this.limit;
  80. },
  81. disabled() {
  82. return this.fileList.length >= this.limit;
  83. }
  84. },
  85. created() {
  86. this.uploadUrl = resolveUrl(this.$baseUrl, 'upload/file');
  87. this.update(this.value);
  88. },
  89. methods: {
  90. onSuccess(res, file, fileList) {
  91. file.url = res;
  92. this.fileList = fileList;
  93. },
  94. onRemove(file, fileList) {
  95. this.fileList = fileList;
  96. },
  97. update(value) {
  98. if (this.filesLimit === 1) {
  99. this.fileList = value ? [{ name: value.split('/').pop(), url: value }] : [];
  100. } else {
  101. if (!value) {
  102. this.fileList = [];
  103. } else {
  104. this.fileList = value.map(i => {
  105. return { name: i.split('/').pop(), url: i };
  106. });
  107. }
  108. }
  109. },
  110. onExceed(files, fileList) {
  111. console.log(files, fileList);
  112. this.$message.error(`最多上传${this.filesLimit}个文件`);
  113. },
  114. onPreview(file) {
  115. console.log(file);
  116. },
  117. removeFile(file) {
  118. if (file.status === 'uploading') {
  119. this.$refs.upload.abort(file);
  120. } else if (file.status === 'success') {
  121. let index = this.fileList.findIndex(i => i.url === file.url);
  122. if (index > -1) {
  123. this.fileList.splice(index, 1);
  124. }
  125. }
  126. },
  127. download(file) {
  128. window.open(file.url, '_blank');
  129. },
  130. preview(file) {
  131. this.previewUrl = file.url;
  132. this.$nextTick(() => {
  133. this.$refs.preview.clickHandler();
  134. });
  135. },
  136. isImage(file) {
  137. return /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(file.url);
  138. }
  139. },
  140. watch: {
  141. value(oldValue, value) {
  142. if (!this.watchValue) return;
  143. console.log('watch::');
  144. this.update(value);
  145. },
  146. fileList(fileList) {
  147. this.watchValue = false;
  148. if (this.filesLimit === 1) {
  149. this.$emit('input', fileList[0] ? fileList[0].url : null);
  150. } else {
  151. this.$emit(
  152. 'input',
  153. fileList.map(i => i.url)
  154. );
  155. }
  156. this.$nextTick(() => {
  157. this.watchValue = true;
  158. });
  159. }
  160. }
  161. };
  162. </script>
  163. <style lang="less" scoped>
  164. .file-list-item {
  165. line-height: 1.8;
  166. margin-top: 5px;
  167. cursor: pointer;
  168. .file-name {
  169. padding: 0 90px 0 20px;
  170. }
  171. .upload-progress {
  172. margin-top: 2px;
  173. position: absolute;
  174. bottom: 0;
  175. left: 20px;
  176. right: 0;
  177. width: auto;
  178. }
  179. .danger {
  180. color: #f56c6c;
  181. }
  182. .success {
  183. color: #67c23a;
  184. }
  185. .status-icon {
  186. position: absolute;
  187. left: 0;
  188. top: 0;
  189. line-height: inherit;
  190. }
  191. .opt {
  192. position: absolute;
  193. right: 0;
  194. top: 0;
  195. line-height: inherit;
  196. .opt-icon {
  197. margin-left: 15px;
  198. transition: color 0.3s;
  199. &:hover {
  200. color: #409eff;
  201. }
  202. }
  203. }
  204. }
  205. </style>