fs-upload.vue 3.0 KB

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