ImportFile.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <template>
  2. <el-dialog
  3. :class="prefixCls"
  4. :visible.sync="modalIsShow"
  5. :title="title"
  6. top="10vh"
  7. width="500px"
  8. :close-on-click-modal="false"
  9. :close-on-press-escape="false"
  10. append-to-body
  11. @opened="visibleChange"
  12. >
  13. <div :class="[`${prefixCls}-footer`]" v-if="downloadUrl">
  14. 模板下载:
  15. <a :href="downloadUrl" :download="dfilename">{{ dfilename }}</a>
  16. </div>
  17. <div :class="[`${prefixCls}-footer`]" v-else-if="downloadHandle">
  18. 模板下载:
  19. <el-button type="text" @click="downloadHandle">{{ dfilename }}</el-button>
  20. </div>
  21. <slot></slot>
  22. <div :class="[`${prefixCls}-body`]">
  23. <el-upload
  24. drag
  25. :action="uploadUrl"
  26. :headers="headers"
  27. :max-size="maxSize"
  28. :format="format"
  29. :accept="accept"
  30. :data="uploadDataDict"
  31. :before-upload="handleBeforeUpload"
  32. :on-error="handleError"
  33. :on-success="handleSuccess"
  34. :http-request="upload"
  35. :disabled="disabled || loading"
  36. :auto-upload="autoUpload"
  37. :show-file-list="true"
  38. :file-list="fileList"
  39. :on-change="handleFileChange"
  40. :on-remove="handleFileRemove"
  41. ref="UploadComp"
  42. >
  43. <i class="el-icon-upload"></i><br />
  44. <em class="el-upload__text">点击或将文件拖拽到这里上传</em>
  45. <p
  46. slot="tip"
  47. :class="[
  48. `${prefixCls}-tips`,
  49. {
  50. 'cc-tips-success': res.success,
  51. 'cc-tips-error': !res.success
  52. }
  53. ]"
  54. v-if="res.message"
  55. >
  56. {{ res.message }}
  57. </p>
  58. </el-upload>
  59. </div>
  60. <div v-if="!autoUpload" slot="footer">
  61. <el-button
  62. type="primary"
  63. :disabled="loading || !canUpload"
  64. @click="submit"
  65. >确认</el-button
  66. >
  67. <el-button @click="cancel">取消</el-button>
  68. </div>
  69. </el-dialog>
  70. </template>
  71. <script>
  72. /**
  73. * auto-upload为false时,手动调用ElUpload.Submit时会触发before-upload-handle
  74. */
  75. import { fileMD5 } from "@/plugins/md5";
  76. import { $post } from "@/plugins/axios";
  77. const prefixCls = "cc-import-file";
  78. export default {
  79. name: "import-file",
  80. props: {
  81. title: {
  82. type: String,
  83. default: "文件上传"
  84. },
  85. downloadHandle: {
  86. type: Function
  87. },
  88. downloadUrl: {
  89. type: String,
  90. default: ""
  91. },
  92. downloadFilename: String,
  93. format: {
  94. type: Array,
  95. default() {
  96. return ["jpg", "jpeg", "png"];
  97. }
  98. },
  99. uploadUrl: {
  100. type: String,
  101. required: true
  102. },
  103. uploadData: {
  104. type: Object,
  105. default() {
  106. return {};
  107. }
  108. },
  109. maxSize: {
  110. type: Number,
  111. default: 20 * 1024 * 1024
  112. },
  113. addFilenameParam: {
  114. type: String,
  115. default: "filename"
  116. },
  117. autoUpload: {
  118. type: Boolean,
  119. default: true
  120. },
  121. disabled: { type: Boolean, default: false },
  122. beforeSubmitHandle: {
  123. type: Function,
  124. default: null
  125. }
  126. },
  127. data() {
  128. return {
  129. prefixCls,
  130. modalIsShow: false,
  131. headers: {
  132. md5: ""
  133. },
  134. selectFileName: "",
  135. loading: false,
  136. uploadDataDict: {},
  137. res: {
  138. success: true,
  139. message: ""
  140. },
  141. fileList: []
  142. };
  143. },
  144. computed: {
  145. dfilename() {
  146. return this.downloadFilename || this.downloadUrl.split("/").pop();
  147. },
  148. accept() {
  149. return this.format.map(el => `.${el}`).join();
  150. },
  151. canUpload() {
  152. return this.fileList.length > 0;
  153. }
  154. },
  155. methods: {
  156. visibleChange() {
  157. this.res = {
  158. success: true,
  159. message: ""
  160. };
  161. this.headers = { md5: "" };
  162. this.loading = false;
  163. this.uploadDataDict = {};
  164. this.$refs.UploadComp.clearFiles();
  165. },
  166. checkFileFormat(fileType) {
  167. const _file_format = fileType
  168. .split(".")
  169. .pop()
  170. .toLocaleLowerCase();
  171. return this.format.length
  172. ? this.format.some(item => item.toLocaleLowerCase() === _file_format)
  173. : true;
  174. },
  175. handleFileChange(file) {
  176. this.fileList = [file];
  177. },
  178. handleFileRemove(file, fileList) {
  179. this.fileList = fileList;
  180. },
  181. async handleBeforeUpload(file) {
  182. this.uploadDataDict = {
  183. ...this.uploadData
  184. };
  185. this.uploadDataDict[this.addFilenameParam] = file.name;
  186. if (file.size > this.maxSize) {
  187. this.handleExceededSize();
  188. return Promise.reject();
  189. }
  190. if (!this.checkFileFormat(file.name)) {
  191. this.handleFormatError();
  192. return Promise.reject();
  193. }
  194. const md5 = await fileMD5(file);
  195. this.headers["md5"] = md5;
  196. this.loading = true;
  197. return true;
  198. },
  199. upload(options) {
  200. let formData = new FormData();
  201. Object.entries(options.data).forEach(([k, v]) => {
  202. formData.append(k, v);
  203. });
  204. formData.append("file", options.file);
  205. this.$emit("uploading");
  206. return $post(options.action, formData, { headers: options.headers });
  207. },
  208. handleError(error) {
  209. this.loading = false;
  210. this.res = {
  211. success: false,
  212. message: error.message
  213. };
  214. this.$emit("upload-error", error);
  215. },
  216. handleSuccess(responseData) {
  217. this.loading = false;
  218. this.res = {
  219. success: true,
  220. message: "导入成功!"
  221. };
  222. this.cancel();
  223. this.$emit("upload-success", {
  224. data: responseData,
  225. filename: this.uploadDataDict[this.addFilenameParam]
  226. });
  227. },
  228. handleFormatError() {
  229. const content = "只支持文件格式为" + this.format.join("/");
  230. this.res = {
  231. success: false,
  232. message: content
  233. };
  234. this.$emit("valid-error", this.res);
  235. this.$refs.UploadComp.clearFiles();
  236. },
  237. handleExceededSize() {
  238. this.res = {
  239. success: false,
  240. message:
  241. "文件大小不能超过" + Math.floor(this.maxSize / (1024 * 1024)) + "M"
  242. };
  243. this.$emit("valid-error", this.res);
  244. this.$refs.UploadComp.clearFiles();
  245. },
  246. cancel() {
  247. this.modalIsShow = false;
  248. },
  249. open() {
  250. this.modalIsShow = true;
  251. },
  252. async submit() {
  253. if (this.beforeSubmitHandle) {
  254. let handleResult = true;
  255. await this.beforeSubmitHandle().catch(() => {
  256. handleResult = false;
  257. });
  258. if (!handleResult) return;
  259. }
  260. this.$refs.UploadComp.submit();
  261. }
  262. }
  263. };
  264. </script>