bImage.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <template>
  2. <div class="img-list" v-viewer>
  3. <div class="img-item" v-for="(it,key) in imageList" :key="key">
  4. <div v-if="it.blobUrl" style="height: 100%;">
  5. <img :src="it.blobUrl"/>
  6. <ion-icon v-if="!readonly" :icon="closeCircleOutline" color="danger" class="remove-icon"
  7. @click="deleteFile(it)"></ion-icon>
  8. </div>
  9. </div>
  10. <div class="img-item" v-if="(!isSingle || imageList.length==0) && !readonly">
  11. <ion-button color="light" @click="takePicture()">
  12. <ion-icon :icon="addOutline" size="large"></ion-icon>
  13. </ion-button>
  14. </div>
  15. <ion-item v-if="readonly && imageList.length==0">
  16. <ion-label style="flex: 0 0 100% !important;"><p>暂无</p></ion-label>
  17. </ion-item>
  18. </div>
  19. </template>
  20. <script lang="ts">
  21. import {defineComponent, ref} from "vue";
  22. import {camera, cameraOutline, addOutline, closeCircleOutline} from "ionicons/icons";
  23. import {alertController, IonIcon, IonThumbnail, loadingController} from '@ionic/vue';
  24. import {Camera, CameraResultType, CameraSource} from '@capacitor/camera';
  25. import {deleteFile as deleteFileApi, getFileBase64, getList, uploadBase64} from '@/api/system/file';
  26. import {presentAlert} from "@/api/common";
  27. import {dealImage, base64ToBlob} from "@/utils/imageUtils";
  28. export default defineComponent({
  29. name: 'b-image',
  30. components: {IonIcon},
  31. props: {
  32. fileRefId: {type: String, default: ''},
  33. fileType: {type: Number, default: 1},
  34. readonly: {type: Boolean, default: true},
  35. isSingle: {type: Boolean, default: false} //只能上次一张图片
  36. },
  37. setup(props) {
  38. const accept = 'png,jpeg,jpg,gif';
  39. const imageList = ref<any>([]);
  40. const getImageList = () => {
  41. imageList.value = [];
  42. if (props.fileRefId)
  43. getList({fileRefID: props.fileRefId}).then(resultList => {
  44. imageList.value = resultList as any;
  45. imageList.value.forEach((img: any) => {
  46. if (!img.base64) {
  47. getFileBase64(img.fileId).then(base64Str => {
  48. if (base64Str)
  49. img.blobUrl = URL.createObjectURL(base64ToBlob("data:image/png;base64," + base64Str));
  50. });
  51. }
  52. });
  53. });
  54. };
  55. const takePicture = async () => {
  56. if (props.fileRefId === '' || props.fileRefId == null) {
  57. await presentAlert("参数fileRefId为空");
  58. return false;
  59. }
  60. const image = await Camera.getPhoto({
  61. quality: 90,
  62. allowEditing: true,
  63. source: CameraSource.Photos,
  64. resultType: CameraResultType.Uri,
  65. });
  66. if (!accept?.split(',').includes(image.format)) {
  67. await presentAlert("只能上传格式为:" + accept + "的文件");
  68. return null;
  69. }
  70. dealImage(image.webPath as string, 1000, saveFile);
  71. };
  72. const saveFile = async (newBase64: string) => {
  73. const formData = new FormData();
  74. formData.append('base64Str', newBase64 as any);
  75. formData.append("fileRefId", props.fileRefId);
  76. formData.append("fileType", props.fileType.toString());
  77. formData.append("isSingle", props.isSingle ? "1" : "0");
  78. const loading = await loadingController.create({
  79. cssClass: 'my-custom-class',
  80. message: '正在上传,请稍等...',
  81. duration: 2000,
  82. });
  83. await loading.present();
  84. uploadBase64(formData).then((result) => {
  85. if (result) {
  86. presentAlert("上传成功");
  87. /*getImageList();*/
  88. getList({fileRefID: props.fileRefId}).then(resultList => {
  89. const imgList = resultList as any;
  90. imgList.forEach((img: any) => {
  91. if (imageList.value.filter((it: any) => it.fileId === img.fileId).length == 0) {
  92. getFileBase64(img.fileId).then(base64Str => {
  93. if (base64Str) {
  94. img.blobUrl = URL.createObjectURL(base64ToBlob("data:image/png;base64," + base64Str));
  95. imageList.value.push(img);
  96. }
  97. });
  98. }
  99. });
  100. });
  101. }
  102. })
  103. };
  104. const deleteFile = async (item: any) => {
  105. const alert = await alertController.create({
  106. header: '提示!',
  107. message: '是否确认删除?',
  108. buttons: [
  109. {
  110. text: '取消',
  111. role: 'cancel'
  112. },
  113. {
  114. text: '确认删除',
  115. handler: async () => {
  116. const loading = await loadingController.create({
  117. cssClass: 'my-custom-class',
  118. message: '正在删除,请稍等...',
  119. duration: 2000,
  120. });
  121. await loading.present();
  122. deleteFileApi({fileId: item.fileId}).then(result => {
  123. if (result) {
  124. imageList.value = imageList.value.filter((it: any) => it.fileId != item.fileId);
  125. }
  126. });
  127. }
  128. }
  129. ],
  130. });
  131. await alert.present();
  132. }
  133. getImageList();
  134. return {
  135. camera,
  136. IonThumbnail,
  137. takePicture,
  138. imageList,
  139. deleteFile,
  140. addOutline,
  141. closeCircleOutline
  142. }
  143. }
  144. }
  145. );
  146. </script>
  147. <style lang="less">
  148. .img-list {
  149. display: flex;
  150. text-align: center;
  151. flex-direction: row;
  152. flex-wrap: wrap;
  153. padding: 5px 10px;
  154. .img-item {
  155. width: 25%;
  156. position: relative;
  157. padding: 0 5px;
  158. height: 80px;
  159. img {
  160. height: 100%;
  161. object-fit: cover;
  162. border-radius: 10px;
  163. width: 100%;
  164. }
  165. .remove-icon {
  166. position: absolute;
  167. right: -3px;
  168. top: -6px;
  169. font-size: 20px;
  170. }
  171. ion-button {
  172. --box-shadow: 0px;
  173. height: 73px;
  174. width: 75px;
  175. }
  176. }
  177. }
  178. .showbigimg {
  179. z-index: 10;
  180. width: 100%;
  181. height: 100%;
  182. background: #e1e1e1;
  183. display: flex;
  184. justify-content: center; /*在主轴上的对齐*/
  185. align-items: center; /*在交叉轴上中心点的对齐*/
  186. img {
  187. opacity: 1;
  188. vertical-align: middle;
  189. }
  190. }
  191. </style>