Image.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <!--
  2. Composant Image permettant de charger et d'afficher une image stockée sur les serveurs Opentalent à partir de son id.
  3. Permet d'afficher une image par défaut si l'image demandée n'est pas disponible ou invalide.
  4. Si la propriété 'upload' est à 'true', propose aussi un input pour uploader une nouvelle image.
  5. -->
  6. <template>
  7. <main>
  8. <div class="image-wrapper" :style="{width: width + 'px'}">
  9. <v-img
  10. :src="imageSrc"
  11. :lazy-src="defaultImagePath"
  12. :height="height"
  13. :width="width"
  14. aspect-ratio="1"
  15. @click="refresh"
  16. >
  17. <template #placeholder>
  18. <v-row
  19. class="fill-height ma-0"
  20. align="center"
  21. justify="center"
  22. v-if="pending"
  23. >
  24. <v-progress-circular
  25. :indeterminate="true"
  26. color="grey lighten-1"
  27. />
  28. </v-row>
  29. </template>
  30. </v-img>
  31. <div>
  32. <div v-if="upload" class="click-action hover" @click="openUpload=true"><v-icon>mdi-upload</v-icon></div>
  33. <UiInputImage
  34. v-if="openUpload"
  35. @close="openUpload=false"
  36. :existingImageId="id"
  37. :field="field"
  38. :ownerId="ownerId"
  39. @update="$emit('update', $event, field); openUpload=false"
  40. @reload="onReload"
  41. @reset="reset"
  42. ></UiInputImage>
  43. </div>
  44. </div>
  45. </main>
  46. </template>
  47. <script setup lang="ts">
  48. import {ref, Ref} from "@vue/reactivity";
  49. import {useImageFetch} from "~/composables/data/useImageFetch";
  50. import {onUnmounted, watch, WatchStopHandle} from "@vue/runtime-core";
  51. import {useImageManager} from "~/composables/data/useImageManager";
  52. const props = defineProps({
  53. id: {
  54. type: Number,
  55. required: false,
  56. default: null
  57. },
  58. defaultImage: {
  59. type: String,
  60. required: false
  61. },
  62. height: {
  63. type: Number,
  64. required: false
  65. },
  66. width: {
  67. type: Number,
  68. required: false
  69. },
  70. field: {
  71. type: String,
  72. required: false
  73. },
  74. upload: {
  75. type: Boolean,
  76. required: false,
  77. default: false
  78. },
  79. ownerId:{
  80. type: Number,
  81. required: false
  82. }
  83. })
  84. const { imageManager } = useImageManager()
  85. const { fetch } = useImageFetch()
  86. const defaultImagePath = props.defaultImage ?? imageManager.defaultImage
  87. const openUpload: Ref<Boolean> = ref(false)
  88. const { data: imageSrc, pending, refresh } = fetch(props.id ?? null, defaultImagePath, props.height, props.width)
  89. const unwatch: WatchStopHandle = watch(() => props.id, async (newValue, oldValue) => {
  90. await refresh()
  91. })
  92. const onReload = async () => {
  93. await refresh()
  94. openUpload.value = false
  95. }
  96. /**
  97. * Quand on souhaite faire un reset de l'image
  98. */
  99. const reset = () => {
  100. imageSrc.value = defaultImagePath
  101. openUpload.value = false
  102. }
  103. /**
  104. * Lorsqu'on démonte le component on supprime le watcher
  105. */
  106. onUnmounted(() => {
  107. unwatch()
  108. })
  109. </script>
  110. <style lang="scss">
  111. div.image-wrapper {
  112. display: block;
  113. position: relative;
  114. img{
  115. max-width: 100%;
  116. }
  117. .click-action{
  118. position: absolute;
  119. top:0;
  120. left:0;
  121. width: 100%;
  122. height: 100%;
  123. background: transparent;
  124. opacity: 0;
  125. transition: all .2s;
  126. &:hover{
  127. opacity: 1;
  128. background:rgba(0,0,0,0.3);
  129. cursor: pointer;
  130. }
  131. i{
  132. color: #fff;
  133. position: absolute;
  134. top: 50%;
  135. left: 50%;
  136. transform: translate(-50% , -50%);
  137. font-size: 50px;
  138. z-index: 1;
  139. opacity: 1;
  140. &:hover{
  141. color: rgba(#3fb37f, 0.7);
  142. }
  143. }
  144. }
  145. }
  146. </style>