fs-upload.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <template>
  2. <view class="fs-file-list">
  3. <view v-for="(item, index) in modelValue" :key="index" class="fs-file-box">
  4. <fs-icon type="icon-close" size="20px" colorType="danger" class="fs-file-del" @click="handleDel(index)"></fs-icon>
  5. <fs-avatar
  6. v-if="mediaType === 'image'"
  7. :src="formatPath(item)"
  8. :shape="shape"
  9. :size="size"
  10. :width="width"
  11. :height="height"
  12. radius
  13. @click="handlePreview(formatPath(item))"
  14. ></fs-avatar>
  15. <video v-else :src="formatPath(item)" controls class="fs-file-video"></video>
  16. </view>
  17. <view class="fs-file-box" @click="upload" v-if="modelValue.length < count">
  18. <slot>
  19. <fs-avatar :shape="shape" :size="size" :width="width" :height="height" radius bgColor="#EBEFF5">
  20. <fs-icon type="icon-plus" size="50px"></fs-icon>
  21. </fs-avatar>
  22. </slot>
  23. </view>
  24. </view>
  25. </template>
  26. <script>
  27. /**
  28. * 上传组件
  29. * @description 上传组件
  30. * @property {String} action 上传地址
  31. * @property {String} name 文件对应的key,开发者在服务器端通过这个key可以获取到文件二进制内容
  32. * @property {Object} HTTP 请求 Header, header 中不能设置 Referer
  33. * @property {String} mediaType = [image | video] 媒体类型
  34. * @property {Number} count 最多上传数量
  35. * @property {String} shape 上传框形状
  36. * @property {String} size 上传框大小
  37. * @property {String} width 上传框宽度(优先级高于size)
  38. * @property {String} height 上传框高度(优先级高于size)
  39. * @property {String} height 上传框高度(优先级高于size)
  40. * @property {String} height 上传框高度(优先级高于size)
  41. * @property {Object} chooseDatachooseImage/chooseVideo参数
  42. * @property {Object} formData 上传数据
  43. * @property {String} pathKey 接口返回的图片路径的key(如果没有可设置成空)
  44. * @property {String} cloudUpload 是否云上传(需配置云服务空间)
  45. */
  46. export default {
  47. name: 'fs-upload'
  48. }
  49. </script>
  50. <script setup>
  51. import utils from '@/utils/utils'
  52. import config from '@/utils/config'
  53. const props = defineProps({
  54. action: String,
  55. name: {
  56. type: String,
  57. default: 'file'
  58. },
  59. header: {
  60. type: Object,
  61. default: () => {}
  62. },
  63. count: {
  64. type: Number,
  65. default: 1
  66. },
  67. chooseData: {
  68. type: Object,
  69. default: () => {}
  70. },
  71. modelValue: {
  72. type: Array,
  73. default: () => []
  74. },
  75. mediaType: {
  76. type: String,
  77. default: 'image',
  78. validator(value) {
  79. return ['image', 'video'].includes(value)
  80. }
  81. },
  82. shape: {
  83. type: String,
  84. default: 'square',
  85. validator(value) {
  86. return ['square', 'circle'].includes(value)
  87. }
  88. },
  89. size: {
  90. type: String,
  91. default: '150rpx'
  92. },
  93. width: {
  94. type: String,
  95. default: '150rpx'
  96. },
  97. height: {
  98. type: String,
  99. default: '150rpx'
  100. },
  101. formData: {
  102. type: Object,
  103. default() {
  104. return {}
  105. }
  106. },
  107. pathKey: {
  108. type: String,
  109. default: 'filePath'
  110. },
  111. cloudUpload: Boolean
  112. })
  113. const emit = defineEmits(['update:modelValue'])
  114. const handlePreview = current => {
  115. uni.previewImage({
  116. current,
  117. urls: props.modelValue.map(item => formatPath(item))
  118. })
  119. }
  120. const upload = async () => {
  121. let methods = ''
  122. if (props.mediaType === 'image') {
  123. methods = 'chooseAndUploadImage'
  124. } else {
  125. methods = 'chooseAndUploadVideo'
  126. }
  127. utils[methods](
  128. {
  129. count: props.count,
  130. ...props.chooseData
  131. },
  132. {
  133. url: props.action,
  134. name: props.name,
  135. header: props.header,
  136. formData: props.formData
  137. },
  138. props.cloudUpload
  139. ).then(res => {
  140. const fileList = [...props.modelValue, ...res]
  141. fileList.length > props.count && fileList.splice(props.count)
  142. console.log(fileList)
  143. emit('update:modelValue', fileList)
  144. })
  145. }
  146. const handleDel = index => {
  147. props.modelValue.splice(index, 1)
  148. emit('update:modelValue', props.modelValue)
  149. }
  150. const formatPath = item => {
  151. const path = props.pathKey ? item[props.pathKey] : item
  152. return utils.isHttp(path) ? path : config.baseUrl + path
  153. }
  154. </script>
  155. <style lang="scss" scoped>
  156. .fs-file {
  157. &-list {
  158. display: flex;
  159. flex-wrap: wrap;
  160. padding-top: var(--gutter);
  161. }
  162. &-box {
  163. position: relative;
  164. margin-bottom: var(--gutter);
  165. margin-left: var(--gutter);
  166. }
  167. &-video {
  168. width: 300rpx;
  169. height: 200rpx;
  170. }
  171. &-del {
  172. position: absolute;
  173. top: 0;
  174. right: 0;
  175. transform: translate(50%, -50%);
  176. font-size: 22px;
  177. color: var(--sub);
  178. z-index: 10;
  179. }
  180. }
  181. </style>