file.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <template>
  2. <div class="sc-upload-file">
  3. <el-upload
  4. :disabled="disabled"
  5. :auto-upload="autoUpload"
  6. :action="action"
  7. :name="name"
  8. :data="data"
  9. :http-request="request"
  10. v-model:file-list="defaultFileList"
  11. :show-file-list="showFileList"
  12. :drag="drag"
  13. :accept="accept"
  14. :multiple="multiple"
  15. :limit="limit"
  16. :before-upload="before"
  17. :on-success="success"
  18. :on-error="error"
  19. :on-preview="handlePreview"
  20. :on-exceed="handleExceed">
  21. <slot>
  22. <el-button type="primary" :disabled="disabled">{{btnTxt?btnTxt:'Click to upload'}}</el-button>
  23. </slot>
  24. <template #tip>
  25. <div v-if="tip" class="el-upload__tip">{{tip}}</div>
  26. </template>
  27. </el-upload>
  28. <span style="display:none!important"><el-input v-model="value"></el-input></span>
  29. </div>
  30. </template>
  31. <script>
  32. import config from "@/config/upload"
  33. export default {
  34. props: {
  35. modelValue: { type: [String, Array], default: "" },
  36. tip: { type: String, default: "" },
  37. btnTxt: { type: String, default: "" },
  38. action: { type: String, default: "" },
  39. apiObj: { type: Object, default: () => {} },
  40. name: { type: String, default: config.filename },
  41. data: { type: Object, default: () => {} },
  42. accept: { type: String, default: "" },
  43. maxSize: { type: Number, default: config.maxSizeFile },
  44. limit: { type: Number, default: 0 },
  45. autoUpload: { type: Boolean, default: true },
  46. showFileList: { type: Boolean, default: true },
  47. drag: { type: Boolean, default: false },
  48. multiple: { type: Boolean, default: true },
  49. disabled: { type: Boolean, default: false },
  50. onSuccess: { type: Function, default: () => { return true } }
  51. },
  52. data() {
  53. return {
  54. value: "",
  55. defaultFileList: []
  56. }
  57. },
  58. watch:{
  59. modelValue(val){
  60. if(Array.isArray(val)){
  61. if (JSON.stringify(val) != JSON.stringify(this.formatArr(this.defaultFileList))) {
  62. this.defaultFileList = val
  63. this.value = val
  64. }
  65. }else{
  66. if (val != this.toStr(this.defaultFileList)) {
  67. this.defaultFileList = this.toArr(val)
  68. this.value = val
  69. }
  70. }
  71. },
  72. defaultFileList: {
  73. handler(val){
  74. this.$emit('update:modelValue', Array.isArray(this.modelValue) ? this.formatArr(val) : this.toStr(val))
  75. this.value = this.toStr(val)
  76. },
  77. deep: true
  78. }
  79. },
  80. mounted() {
  81. this.defaultFileList = Array.isArray(this.modelValue) ? this.modelValue : this.toArr(this.modelValue)
  82. this.value = this.modelValue
  83. },
  84. methods: {
  85. //默认值转换为数组
  86. toArr(str){
  87. var _arr = []
  88. var arr = str.split(",")
  89. arr.forEach(item => {
  90. if(item){
  91. var urlArr = item.split('/');
  92. var fileName = urlArr[urlArr.length - 1]
  93. _arr.push({
  94. name: fileName,
  95. url: item
  96. })
  97. }
  98. })
  99. return _arr
  100. },
  101. //数组转换为原始值
  102. toStr(arr){
  103. return arr.map(v => v.url).join(",")
  104. },
  105. //格式化数组值
  106. formatArr(arr){
  107. var _arr = []
  108. arr.forEach(item => {
  109. if(item){
  110. _arr.push({
  111. name: item.name,
  112. url: item.url
  113. })
  114. }
  115. })
  116. return _arr
  117. },
  118. before(file){
  119. const maxSize = file.size / 1024 / 1024 < this.maxSize;
  120. if (!maxSize) {
  121. this.$message.warning(`上传文件大小不能超过 ${this.maxSize}MB!`);
  122. return false;
  123. }
  124. },
  125. success(res, file){
  126. var os = this.onSuccess(res, file)
  127. if(os!=undefined && os==false){
  128. return false
  129. }
  130. var response = config.parseData(res)
  131. file.name = response.fileName
  132. file.url = response.src
  133. },
  134. error(err){
  135. this.$notify.error({
  136. title: '上传文件未成功',
  137. message: err
  138. })
  139. },
  140. beforeRemove(uploadFile){
  141. return this.$confirm(`是否移除 ${uploadFile.name} ?`, '提示', {
  142. type: 'warning',
  143. }).then(() => {
  144. return true
  145. }).catch(() => {
  146. return false
  147. })
  148. },
  149. handleExceed(){
  150. this.$message.warning(`当前设置最多上传 ${this.limit} 个文件,请移除后上传!`)
  151. },
  152. handlePreview(uploadFile){
  153. window.open(uploadFile.url)
  154. },
  155. request(param){
  156. var apiObj = config.apiObjFile;
  157. if(this.apiObj){
  158. apiObj = this.apiObj;
  159. }
  160. const data = new FormData();
  161. data.append(param.filename, param.file);
  162. for (const key in param.data) {
  163. data.append(key, param.data[key]);
  164. }
  165. apiObj.post(data, {
  166. onUploadProgress: e => {
  167. const complete = parseInt(((e.loaded / e.total) * 100) | 0, 10)
  168. param.onProgress({percent: complete})
  169. }
  170. }).then(res => {
  171. var response = config.parseData(res);
  172. if(response.code == config.successCode){
  173. param.onSuccess(res)
  174. }else{
  175. param.onError(res.msg || "未知错误")
  176. }
  177. }).catch(err => {
  178. param.onError(err)
  179. })
  180. }
  181. }
  182. }
  183. </script>
  184. <style scoped>
  185. .el-form-item.is-error .sc-upload-file:deep(.el-upload-dragger) {border-color: var(--el-color-danger);}
  186. .sc-upload-file {width: 100%;}
  187. .sc-upload-file:deep(.el-upload-list__item) {transition: none !important;}
  188. </style>