index.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <template>
  2. <u-upload :name="name"
  3. :width="width" :height="height"
  4. :accept="accept" :fileList="fileList"
  5. :multiple="multiple" :maxCount="maxCount"
  6. @afterRead="afterRead" @delete="onDelete">
  7. <slot name="content" :data="fileList"></slot>
  8. <image
  9. v-if="customImg"
  10. src="@/static/discover/ic_upload.png"
  11. mode=""
  12. :style="{width: width + 'px', height: height + 'px'}"
  13. ></image>
  14. </u-upload>
  15. </template>
  16. <script>
  17. import { baseUrl } from '@/common/config.js';
  18. export default {
  19. name: "",
  20. props: {
  21. api: {
  22. type: String,
  23. default: '/common/upload'
  24. },
  25. name: {
  26. type: String,
  27. default: uni.$u.props.upload.name
  28. },
  29. accept: {
  30. type: String,
  31. default: 'image' // 默认接受图片
  32. },
  33. width: {
  34. type: [String, Number],
  35. default: uni.$u.props.upload.width
  36. },
  37. height: {
  38. type: [String, Number],
  39. default: uni.$u.props.upload.height
  40. },
  41. // 文件大小限制,单位为byte
  42. maxSize: {
  43. type: [String, Number],
  44. default: uni.$u.props.upload.maxSize
  45. },
  46. maxCount: {
  47. type: Number,
  48. default: 5
  49. },
  50. multiple: {
  51. type: Boolean,
  52. default: true
  53. },
  54. // 图片格式限制
  55. imageFormats: {
  56. type: Array,
  57. default: () => ['png', 'jpg', 'jpeg']
  58. },
  59. // 视频格式限制
  60. videoFormats: {
  61. type: Array,
  62. default: () => ['mp4', 'mov', 'mkv', 'wmv']
  63. },
  64. // 图片大小限制,单位为byte
  65. maxImageSize: {
  66. type: Number,
  67. default: 2 * 1024 * 1024 // 默认2MB
  68. },
  69. // 视频大小限制,单位为byte
  70. maxVideoSize: {
  71. type: Number,
  72. default: 50 * 1024 * 1024 // 默认50MB
  73. },
  74. customImg: {
  75. type: Boolean,
  76. default: false
  77. },
  78. fileList: {
  79. type: Array,
  80. default: []
  81. },
  82. },
  83. data() {
  84. return {
  85. //fileList: [],
  86. };
  87. },
  88. computed: {
  89. },
  90. mounted() {
  91. },
  92. beforeDestroy() {
  93. },
  94. methods: {
  95. // 上传后的处理函数
  96. async afterRead(event) {
  97. // 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
  98. let lists = [].concat(event.file);
  99. let fileListLen = this[`fileList`].length;
  100. // 验证文件格式和大小
  101. for (let i = 0; i < lists.length; i++) {
  102. const file = lists[i];
  103. const fileName = file.name.split('/').pop();
  104. const fileExtension = fileName.split('.').pop().toLowerCase();
  105. // 根据文件扩展名判断是图片还是视频(优先使用扩展名判断)
  106. const isImage = this.imageFormats.includes(fileExtension);
  107. const isVideo = this.videoFormats.includes(fileExtension);
  108. if (isImage) {
  109. // 图片验证
  110. if (file.size && file.size > this.maxImageSize) {
  111. const maxSizeMB = (this.maxImageSize / 1024 / 1024).toFixed(1);
  112. uni.$u.toast(`图片大小不能超过 ${maxSizeMB}MB`);
  113. return;
  114. }
  115. } else if (isVideo) {
  116. // 视频验证
  117. if (file.size && file.size > this.maxVideoSize) {
  118. const maxSizeMB = (this.maxVideoSize / 1024 / 1024).toFixed(1);
  119. uni.$u.toast(`视频大小不能超过 ${maxSizeMB}MB`);
  120. return;
  121. }
  122. } else {
  123. // 既不是图片也不是视频,检查是否有file.type
  124. if (file.type) {
  125. if (file.type.startsWith('image/')) {
  126. // 是图片但扩展名不在允许列表中
  127. uni.$u.toast(`图片格式仅限 ${this.imageFormats.join(', ')}`);
  128. return;
  129. } else if (file.type.startsWith('video/')) {
  130. // 是视频但扩展名不在允许列表中
  131. uni.$u.toast(`视频格式仅限 ${this.videoFormats.join(', ')}`);
  132. return;
  133. }
  134. }
  135. // 无法判断类型或类型不支持
  136. uni.$u.toast('不支持的文件格式');
  137. return;
  138. }
  139. }
  140. lists.map((item) => {
  141. this[`fileList`].push({
  142. ...item,
  143. status: "uploading",
  144. message: "上传中",
  145. });
  146. });
  147. // 无预览时,使用toast
  148. if (!this.$attrs.previewImage) {
  149. uni.showLoading({
  150. title: '上传中...'
  151. });
  152. }
  153. for (let i = 0; i < lists.length; i++) {
  154. const result = await this.uploadFilePromise(lists[i].url);
  155. let item = this[`fileList`][fileListLen];
  156. this[`fileList`].splice(
  157. fileListLen,
  158. 1,
  159. Object.assign(item, {
  160. status: "success",
  161. message: "",
  162. url: baseUrl + result,
  163. })
  164. );
  165. fileListLen++;
  166. // 无预览时,使用toast
  167. if (!this.$attrs.previewImage) {
  168. uni.hideLoading();
  169. uni.showToast({
  170. icon: 'none',
  171. title: result.message || '上传完成',
  172. duration: 2000
  173. });
  174. this.$emit('complete');
  175. }
  176. }
  177. this.$emit('fileList', this.fileList);
  178. },
  179. uploadFilePromise(url) {
  180. return new Promise((resolve, reject) => {
  181. uni.uploadFile({
  182. url: baseUrl + this.api,
  183. name: "file",
  184. header: {
  185. 'Authorization': `tf: ${uni.getStorageSync('access-token')}`
  186. },
  187. formData: {
  188. 'biz': 'temp',
  189. },
  190. filePath: url,
  191. success: (res) => {
  192. let data = JSON.parse(res.data);
  193. if (data.code === 200) {
  194. resolve(data.fileName);
  195. } else {
  196. uni.$u.toast('上传失败');
  197. reject();
  198. }
  199. },
  200. });
  201. });
  202. },
  203. onDelete(event) {
  204. uni.showModal({
  205. title: '提示',
  206. content: '确定要删除?',
  207. cancelText: '取消',
  208. confirmText: '确定',
  209. success: res => {
  210. if (res.confirm) {
  211. this[`fileList`].splice(event.index, 1);
  212. this.$emit('fileList', this.fileList);
  213. }
  214. }
  215. })
  216. },
  217. }
  218. }
  219. </script>
  220. <style lang="scss" scoped></style>