fs-upload.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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
  5. type="icon-close"
  6. size="20px"
  7. colorType="danger"
  8. class="fs-file-del"
  9. @click="handleDel(index)">
  10. </fs-icon>
  11. <fs-avatar
  12. v-if="mediaType === 'image'"
  13. :src="formatPath(item)"
  14. :shape="shape"
  15. :size="size"
  16. :width="width"
  17. :height="height"
  18. radius
  19. @click="handlePreview(formatPath(item))">
  20. </fs-avatar>
  21. <video v-else :src="formatPath(item)" controls class="fs-file-video"></video>
  22. </view>
  23. <view class="fs-file-box" @click="upload" v-if="modelValue.length < count">
  24. <slot>
  25. <fs-avatar
  26. :shape="shape"
  27. :size="size"
  28. :width="width"
  29. :height="height"
  30. radius
  31. bgColor="#EBEFF5"
  32. >
  33. <fs-icon type="icon-plus" size="50px"></fs-icon>
  34. </fs-avatar>
  35. </slot>
  36. </view>
  37. </view>
  38. </template>
  39. <script setup>
  40. import utils from '@/utils/utils'
  41. import config from '@/utils/config'
  42. const props = defineProps({
  43. action: String,
  44. name: {
  45. type: String,
  46. default: 'file'
  47. },
  48. header: {
  49. type: Object,
  50. default: () => {}
  51. },
  52. count: {
  53. type: Number,
  54. default: 1
  55. },
  56. chooseData: {
  57. type: Object,
  58. default: () => {}
  59. },
  60. modelValue: {
  61. type: Array,
  62. default: () => []
  63. },
  64. mediaType: {
  65. type: String,
  66. default: 'image',
  67. validator(value) {
  68. return ['image', 'video'].includes(value)
  69. }
  70. },
  71. shape: {
  72. type: String,
  73. default: 'square',
  74. validator(value) {
  75. return ['square', 'circle'].includes(value)
  76. }
  77. },
  78. size: {
  79. type: String,
  80. default: '150rpx'
  81. },
  82. width: {
  83. type: String,
  84. default: '150rpx'
  85. },
  86. height: {
  87. type: String,
  88. default: '150rpx'
  89. },
  90. formData: {
  91. type: Object,
  92. default() {
  93. return {}
  94. }
  95. },
  96. pathKey: {
  97. type: String,
  98. default: 'filePath'
  99. },
  100. cloudUpload: Boolean
  101. })
  102. const emit = defineEmits(['update:modelValue'])
  103. const handlePreview = current => {
  104. uni.previewImage({
  105. current,
  106. urls: props.modelValue.map(item => formatPath(item))
  107. })
  108. }
  109. const upload = async () => {
  110. let methods = ''
  111. if (props.mediaType === 'image') {
  112. methods = 'chooseAndUploadImage'
  113. } else {
  114. methods = 'chooseAndUploadVideo'
  115. }
  116. utils[methods](
  117. {
  118. count: props.count,
  119. ...props.chooseData
  120. },
  121. {
  122. url: props.action,
  123. name: props.name,
  124. header: props.header,
  125. formData: props.formData
  126. },
  127. props.cloudUpload
  128. ).then(res => {
  129. const fileList = [...props.modelValue, ...res]
  130. fileList.length > props.count && fileList.splice(props.count)
  131. console.log(fileList);
  132. emit('update:modelValue', fileList)
  133. })
  134. }
  135. const handleDel = index => {
  136. props.modelValue.splice(index, 1)
  137. emit('update:modelValue',props.modelValue)
  138. }
  139. const formatPath = item => {
  140. const path = props.pathKey ? item[props.pathKey] : item
  141. return utils.isHttp(path) ? path : config.baseUrl + path
  142. }
  143. </script>
  144. <style lang="scss" scoped>
  145. .fs-file{
  146. &-list{
  147. display: flex;
  148. flex-wrap: wrap;
  149. padding-top: var(--gutter);
  150. }
  151. &-box{
  152. position: relative;
  153. margin-bottom: var(--gutter);
  154. margin-left: var(--gutter);
  155. }
  156. &-video{
  157. width: 300rpx;
  158. height: 200rpx;
  159. }
  160. &-del{
  161. position: absolute;
  162. top: 0;
  163. right: 0;
  164. transform: translate(50%, -50%);
  165. font-size: 22px;
  166. color: var(--sub);
  167. z-index: 10;
  168. }
  169. }
  170. </style>