custom-upload.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <template>
  2. <view class="custom_upload mtb20">
  3. <slot>
  4. <view class="choose_box">
  5. <slot name="list">
  6. <view class="images_box" :style="imageBoxStyle" v-for="(item,index) in images"
  7. v-if="images[0]!==''&&images.length>0" :key="index">
  8. <u-transition show mode="fade-right">
  9. <u-image showLoading lazyLoad @click="previewImage(index,images)" :src="item" width="100%"
  10. :height="imageBoxStyle.height?imageBoxStyle.height:'188rpx'" radius="17rpx" />
  11. <view class="close_icon centerV" @click="images.splice(index,1)">
  12. <u-icon name="close" color="#fff" size="22rpx" bold></u-icon>
  13. </view>
  14. </u-transition>
  15. </view>
  16. </slot>
  17. <view class="upload_box centerV" :style="imageBoxStyle" @click="props.readonly?null:showPopup=true">
  18. <slot name="upload-image">
  19. <u-image showLoading lazyLoad :src="config.getResource('icons/upload.png')" width="59rpx" height="59rpx"
  20. radius="17rpx" />
  21. </slot>
  22. </view>
  23. </view>
  24. </slot>
  25. <u-popup :show="showPopup" @close="close" closeOnClickOverlay round="20rpx" :safeAreaInsetBottom="true" closeable>
  26. <view class="upload_content column">
  27. <text class="bold center mb20">{{title}}</text>
  28. <view class="mt20">
  29. <u-button shape="circle" text="拍照" @click="uploadImg({sourceType:['camera']})"
  30. :custom-style="{marginRight:'10rpx',height:'96rpx',border: '2rpx solid #1f1f1f',color:'#1f1f1f'}"></u-button>
  31. <u-button shape="circle" color="#1f1f1f" type="primary" text="相册" @click="uploadImg({sourceType:['album']})"
  32. :custom-style="{height:'96rpx',marginTop:'24rpx'}"></u-button>
  33. </view>
  34. </view>
  35. </u-popup>
  36. <modal-popup ref="showModal" />
  37. </view>
  38. </template>
  39. <script setup>
  40. import {
  41. ref,
  42. watchEffect
  43. } from "vue";
  44. import fileUpload from '@/utils/request/upload/upload';
  45. import config from "@/core/config";
  46. import {
  47. doUploadsReady
  48. } from "@/api/upload.js"
  49. import {
  50. showToast,
  51. previewImage
  52. } from "@/core/app";
  53. const props = defineProps({
  54. value: {
  55. type: [String, Array],
  56. default: ''
  57. },
  58. show: {
  59. type: Boolean,
  60. default: false
  61. },
  62. title: {
  63. type: String,
  64. default: '上传图片'
  65. },
  66. options: {
  67. type: Object,
  68. default: {}
  69. },
  70. maxLength: {
  71. type: Number,
  72. default: 1
  73. },
  74. uploadType: {
  75. type: String,
  76. default: 'list'
  77. },
  78. imageBoxStyle: {
  79. type: Object,
  80. default: {}
  81. },
  82. readonly: {
  83. type: Boolean,
  84. default: false
  85. }
  86. })
  87. const emits = defineEmits(['update:value', 'update:show', 'close'])
  88. // 图片列表
  89. const images = ref([])
  90. const showPopup = ref(props.show)
  91. watchEffect(() => {
  92. images.value = props.value ? props.value.split(',') : props.value.split('')
  93. showPopup.value = props.show
  94. })
  95. // 关闭popup
  96. const close = () => {
  97. showPopup.value = false
  98. emits('update:show', false)
  99. emits('close', false)
  100. }
  101. // 上传头像
  102. const uploadImg = async (options = {}) => {
  103. if (props.uploadType == 'list') {
  104. if (images.value.length >= props.maxLength) return showToast(
  105. `只能上传${props.maxLength}张`)
  106. }
  107. // #ifdef APP
  108. empowerCameraAlbum(options.sourceType[0])
  109. // #endif
  110. const fupload = new fileUpload({});
  111. const data1 = await fupload.ossImagUpload({
  112. ...options,
  113. ...props.options
  114. })
  115. for (let item of data1) {
  116. const result = await doUploadsReady(item);
  117. if (result) {
  118. const {
  119. data
  120. } = result;
  121. uni.uploadFile({
  122. url: data.host,
  123. filePath: item.path,
  124. name: 'file',
  125. formData: {
  126. key: data.key,
  127. policy: data.policy,
  128. OSSAccessKeyId: data.ossAccessKeyId,
  129. signature: data.signature,
  130. },
  131. success: async (res) => {
  132. if (res.statusCode === 200) {
  133. if (props.uploadType == 'list') {
  134. if (images.value.length >= props.maxLength) return showToast(
  135. `只能上传${props.maxLength}张`)
  136. }
  137. if (props.uploadType == 'list') {
  138. images.value.push(JSON.parse(res.data).data.filePath)
  139. } else {
  140. images.value = JSON.parse(res.data).data.filePath
  141. }
  142. emits('update:value', typeof images.value == 'string' ? images.value : images.value.join(','))
  143. close()
  144. }
  145. },
  146. fail: err => {}
  147. });
  148. }
  149. }
  150. }
  151. // 权限检查
  152. const showModal = ref(null)
  153. const empowerCameraAlbum = (permissionType, cameraMsg = "申请相机,存储写入权限为了拍照和使用图片上传头像", albumMsg =
  154. "申请相册读取权限,为了选择相册图片上传头像") => {
  155. let permissionID = []
  156. let authorizedType = null
  157. if (permissionType === 'camera') {
  158. authorizedType = 'cameraAuthorized'
  159. permissionID = ['android.permission.CAMERA', 'android.permission.WRITE_EXTERNAL_STORAGE']
  160. } else {
  161. authorizedType = 'albumAuthorized'
  162. permissionID = ['android.permission.READ_EXTERNAL_STORAGE']
  163. }
  164. if (uni.getAppAuthorizeSetting()[authorizedType] !== 'authorized') {
  165. showModal.value.open({
  166. content: permissionType == 'camera' ? cameraMsg : albumMsg,
  167. popType: 'popup'
  168. })
  169. }
  170. }
  171. // 方法暴露
  172. defineExpose({
  173. uploadImg,
  174. empowerCameraAlbum,
  175. showPopup
  176. })
  177. </script>
  178. <style lang="scss">
  179. .custom_upload {
  180. width: 100%;
  181. .upload_content {
  182. padding: 25rpx;
  183. margin-bottom: 100rpx;
  184. }
  185. .choose_box {
  186. width: 100%;
  187. display: grid;
  188. grid-template-columns: 1fr 1fr 1fr;
  189. grid-row-gap: 20rpx;
  190. grid-column-gap: 30rpx;
  191. .images_box,
  192. .upload_box {
  193. width: 100%;
  194. height: 188rpx;
  195. border-radius: 17rpx;
  196. }
  197. .images_box {
  198. position: relative;
  199. animation: zoom 1s;
  200. }
  201. .close_icon {
  202. position: absolute;
  203. top: -15rpx;
  204. right: -10rpx;
  205. width: 35rpx;
  206. height: 35rpx;
  207. background: rgba(0, 0, 0, .5);
  208. border-radius: 50%;
  209. }
  210. .upload_box {
  211. background: #F6F6F6;
  212. }
  213. }
  214. }
  215. </style>