uploadFile.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <!--
  2. * @Description: 对上传文件组件进行封装
  3. * @Author: kcz
  4. * @Date: 2020-03-17 12:53:50
  5. * @LastEditors: kcz
  6. * @LastEditTime: 2021-05-05 12:12:30
  7. -->
  8. <template>
  9. <div :style="{ width: record.options.width }">
  10. <a-upload
  11. v-if="!record.options.drag"
  12. :disabled="record.options.disabled || parentDisabled"
  13. :name="config.uploadFileName || record.options.fileName"
  14. :headers="config.uploadFileHeaders || record.options.headers"
  15. :data="config.uploadFileData || optionsData"
  16. :action="config.uploadFile || record.options.action"
  17. :multiple="record.options.multiple"
  18. :fileList="fileList"
  19. @preview="handlePreview"
  20. @change="handleChange"
  21. :remove="remove"
  22. :beforeUpload="beforeUpload"
  23. >
  24. <a-button
  25. v-if="fileList.length < record.options.limit"
  26. :disabled="record.options.disabled || parentDisabled"
  27. >
  28. <a-icon type="upload" /> {{ record.options.placeholder }}
  29. </a-button>
  30. </a-upload>
  31. <a-upload-dragger
  32. v-else
  33. :class="{ 'hide-upload-drag': !(fileList.length < record.options.limit) }"
  34. :disabled="record.options.disabled || parentDisabled"
  35. :name="config.uploadFileName || record.options.fileName"
  36. :headers="config.uploadFileHeaders || record.options.headers"
  37. :data="config.uploadFileData || optionsData"
  38. :action="config.uploadFile || record.options.action"
  39. :multiple="record.options.multiple"
  40. :fileList="fileList"
  41. @preview="handlePreview"
  42. @change="handleChange"
  43. :remove="remove"
  44. :beforeUpload="beforeUpload"
  45. >
  46. <p class="ant-upload-drag-icon">
  47. <a-icon type="cloud-upload" />
  48. </p>
  49. <p class="ant-upload-text">单击或拖动文件到此区域</p>
  50. </a-upload-dragger>
  51. </div>
  52. </template>
  53. <script>
  54. /*
  55. * author kcz
  56. * date 2019-12-31
  57. * description 上传文件组件
  58. */
  59. export default {
  60. name: "KUploadFile",
  61. // eslint-disable-next-line vue/require-prop-types
  62. props: ["record", "value", "config", "parentDisabled", "dynamicData"],
  63. data() {
  64. return {
  65. fileList: []
  66. };
  67. },
  68. watch: {
  69. value: {
  70. // value 需要深度监听及默认先执行handler函数
  71. handler(val) {
  72. if (val) {
  73. this.setFileList();
  74. }
  75. },
  76. immediate: true,
  77. deep: true
  78. }
  79. },
  80. computed: {
  81. optionsData() {
  82. try {
  83. return JSON.parse(this.record.options.data);
  84. } catch (err) {
  85. console.error(err);
  86. return {};
  87. }
  88. }
  89. },
  90. methods: {
  91. setFileList() {
  92. // 当传入value改变时,fileList也要改变
  93. // 如果传入的值为字符串,则转成json
  94. if (typeof this.value === "string") {
  95. this.fileList = JSON.parse(this.value);
  96. // 将转好的json覆盖组件默认值的字符串
  97. this.handleSelectChange();
  98. } else {
  99. this.fileList = this.value;
  100. }
  101. },
  102. handleSelectChange() {
  103. setTimeout(() => {
  104. const arr = this.fileList.map(item => {
  105. if (typeof item.response !== "undefined") {
  106. const res = item.response;
  107. return {
  108. type: "file",
  109. name: item.name,
  110. status: item.status,
  111. uid: res.data.fileId || Date.now(),
  112. url: res.data.url || ""
  113. };
  114. } else {
  115. return {
  116. type: "file",
  117. name: item.name,
  118. status: item.status,
  119. uid: item.uid,
  120. url: item.url || ""
  121. };
  122. }
  123. });
  124. this.$emit("change", arr);
  125. this.$emit("input", arr);
  126. }, 10);
  127. },
  128. handlePreview(file) {
  129. // 下载文件
  130. const downloadWay = this.record.options.downloadWay;
  131. const dynamicFun = this.record.options.dynamicFun;
  132. if (downloadWay === "a") {
  133. // 使用a标签下载
  134. const a = document.createElement("a");
  135. a.href = file.url || file.thumbUrl;
  136. a.download = file.name;
  137. a.click();
  138. } else if (downloadWay === "ajax") {
  139. // 使用ajax获取文件blob,并保持到本地
  140. this.getBlob(file.url || file.thumbUrl).then(blob => {
  141. this.saveAs(blob, file.name);
  142. });
  143. } else if (downloadWay === "dynamic") {
  144. // 触发动态函数
  145. this.dynamicData[dynamicFun](file);
  146. }
  147. },
  148. /**
  149. * 获取 blob
  150. * url 目标文件地址
  151. */
  152. getBlob(url) {
  153. return new Promise(resolve => {
  154. const xhr = new XMLHttpRequest();
  155. xhr.open("GET", url, true);
  156. xhr.responseType = "blob";
  157. xhr.onload = () => {
  158. if (xhr.status === 200) {
  159. resolve(xhr.response);
  160. }
  161. };
  162. xhr.send();
  163. });
  164. },
  165. /**
  166. * 保存 blob
  167. * filename 想要保存的文件名称
  168. */
  169. saveAs(blob, filename) {
  170. if (window.navigator.msSaveOrOpenBlob) {
  171. navigator.msSaveBlob(blob, filename);
  172. } else {
  173. const link = document.createElement("a");
  174. const body = document.querySelector("body");
  175. link.href = window.URL.createObjectURL(blob);
  176. link.download = filename;
  177. // fix Firefox
  178. link.style.display = "none";
  179. body.appendChild(link);
  180. link.click();
  181. body.removeChild(link);
  182. window.URL.revokeObjectURL(link.href);
  183. }
  184. },
  185. remove() {
  186. this.handleSelectChange();
  187. },
  188. beforeUpload(e, files) {
  189. if (files.length + this.fileList.length > this.record.options.limit) {
  190. this.$message.warning(`最大上传数量为${this.record.options.limit}`);
  191. files.splice(this.record.options.limit - this.fileList.length);
  192. }
  193. },
  194. handleChange(info) {
  195. this.fileList = info.fileList;
  196. if (info.file.status === "done") {
  197. const res = info.file.response;
  198. if (res.code === 0) {
  199. this.handleSelectChange();
  200. } else {
  201. this.fileList.pop();
  202. this.$message.error(`文件上传失败`);
  203. }
  204. } else if (info.file.status === "error") {
  205. this.$message.error(`文件上传失败`);
  206. }
  207. }
  208. }
  209. };
  210. </script>