UploadProgressPopup.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <template>
  2. <popup :show="show" round :close-on-click-overlay="false" class="upload-progress-popup"
  3. @update:show="emit('update:show', $event)">
  4. <slot name="header"></slot>
  5. <div class="upload-box" v-loading="loading" element-loading-:text="t('上传中...')">
  6. <div class="box-header">
  7. <div class="upload-title">
  8. <span>{{ t('上传照片') }}</span>
  9. <span v-if="!uploadRequired" class="optional">{{ t('(可选)') }}</span>
  10. </div>
  11. <div class="ai-btn">{{ t('AI 智能分析') }}</div>
  12. </div>
  13. <upload ref="uploadRef" :maxCount="10" :initImgArr="displayImgArr" :before-read="beforeReadUpload"
  14. :after-read="afterReadUpload">
  15. </upload>
  16. <!-- <div class="upload-result">{{ t('AI识别结果:该病为该病为该病为该病为病为该病为病为该病为') }}</div> -->
  17. </div>
  18. <slot name="footer"></slot>
  19. <div class="upload-action-btns">
  20. <div class="cancel-btn" @click="emit('cancel')">{{ t('取消') }}</div>
  21. <div class="confirm-btn" @click="handleConfirm">{{ confirmText }}</div>
  22. </div>
  23. </popup>
  24. </template>
  25. <script setup>
  26. import { useI18n } from "@/i18n";
  27. const { t } = useI18n();
  28. import { ref, computed, watch } from 'vue';
  29. import { Popup } from 'vant';
  30. import { ElMessage } from 'element-plus';
  31. import upload from '@/components/upload.vue';
  32. import UploadFile from "@/utils/upliadFile";
  33. import { getFileExt } from "@/utils/util";
  34. import {base_img_url2} from '@/api/config';
  35. const props = defineProps({
  36. show: {
  37. type: Boolean,
  38. default: false,
  39. },
  40. popupImageUploadLoading: {
  41. type: Boolean,
  42. default: false,
  43. },
  44. initImgArr: {
  45. type: Array,
  46. default: () => [],
  47. },
  48. confirmText: {
  49. type: String,
  50. default: '确认信息',
  51. },
  52. /** 是否必传图片,默认必传 */
  53. uploadRequired: {
  54. type: Boolean,
  55. default: true,
  56. },
  57. });
  58. const emit = defineEmits(['update:show', 'cancel', 'confirm', 'reset']);
  59. const uploadRef = ref(null);
  60. const popupInnerImgArr = ref([]);
  61. const popupInnerLoading = ref(false);
  62. const uploadFileObj = new UploadFile();
  63. const miniUserId = localStorage.getItem("MINI_USER_ID");
  64. const loading = computed(() => props.popupImageUploadLoading || popupInnerLoading.value);
  65. /** 弹窗内上传优先展示,否则回显父组件传入的 initImgArr */
  66. const displayImgArr = computed(() =>
  67. popupInnerImgArr.value.length ? popupInnerImgArr.value : props.initImgArr,
  68. );
  69. function getConfirmImgArr() {
  70. if (popupInnerImgArr.value.length) {
  71. return [...popupInnerImgArr.value.map(item => base_img_url2 + item)];
  72. }
  73. return [...(props.initImgArr || [])];
  74. }
  75. const beforeReadUpload = () => {
  76. popupInnerLoading.value = false;
  77. return true;
  78. };
  79. const afterReadUpload = async (data) => {
  80. if (!Array.isArray(data)) {
  81. data = [data];
  82. }
  83. popupInnerLoading.value = true;
  84. try {
  85. for (const file of data) {
  86. const fileVal = file.file;
  87. file.status = "uploading";
  88. file.message = "上传中...";
  89. const ext = getFileExt(fileVal.name);
  90. const key = `birdseye-look-mini/${miniUserId}/${new Date().getTime()}.${ext}`;
  91. const resFilename = await uploadFileObj.put(key, fileVal);
  92. if (resFilename) {
  93. file.status = "done";
  94. file.message = "";
  95. popupInnerImgArr.value.push(resFilename);
  96. } else {
  97. file.status = "failed";
  98. file.message = "上传失败";
  99. ElMessage.error("图片上传失败,请稍后再试!");
  100. }
  101. }
  102. } finally {
  103. popupInnerLoading.value = false;
  104. }
  105. };
  106. function handleConfirm() {
  107. const imgArr = getConfirmImgArr();
  108. if (props.uploadRequired && !imgArr.length) {
  109. ElMessage.warning(t('请先上传照片'));
  110. return;
  111. }
  112. emit('confirm', imgArr);
  113. }
  114. function uploadReset() {
  115. popupInnerImgArr.value = [];
  116. popupInnerLoading.value = false;
  117. uploadRef.value?.uploadReset?.();
  118. }
  119. watch(
  120. () => props.show,
  121. (val) => {
  122. if (val) {
  123. uploadReset();
  124. emit('reset');
  125. }
  126. },
  127. );
  128. defineExpose({
  129. uploadReset,
  130. });
  131. </script>
  132. <style scoped lang="scss">
  133. .upload-progress-popup {
  134. width: 100%;
  135. padding: 24px 16px;
  136. background: linear-gradient(360deg, #FFFFFF 74.2%, #D1EBFF 100%);
  137. .upload-box {
  138. margin-bottom: 12px;
  139. position: relative;
  140. min-height: 88px;
  141. .box-header {
  142. display: flex;
  143. align-items: center;
  144. justify-content: space-between;
  145. margin-bottom: 12px;
  146. .upload-title {
  147. font-size: 16px;
  148. .optional {
  149. font-size: 12px;
  150. color: rgba(18, 18, 18, 0.2);
  151. }
  152. }
  153. .ai-btn {
  154. padding: 5px 10px;
  155. border-radius: 4px;
  156. background: rgba(33, 153, 248, 0.1);
  157. color: #2199F8;
  158. border: 1px solid #2199F8;
  159. opacity: 0.5;
  160. }
  161. }
  162. .upload-result {
  163. color: #646464;
  164. padding: 6px 10px;
  165. background: rgba(161, 161, 161, 0.1);
  166. border-radius: 5px;
  167. margin-top: 12px;
  168. }
  169. }
  170. .upload-action-btns {
  171. display: flex;
  172. gap: 10px;
  173. margin-top: 16px;
  174. .cancel-btn,
  175. .confirm-btn {
  176. flex: 1;
  177. border-radius: 4px;
  178. padding: 8px;
  179. text-align: center;
  180. font-size: 16px;
  181. }
  182. .cancel-btn {
  183. border: 1px solid #dcdfe6;
  184. color: #606266;
  185. background: #ffffff;
  186. }
  187. .confirm-btn {
  188. background: #2199f8;
  189. color: #ffffff;
  190. }
  191. }
  192. }
  193. </style>