ContentMedias.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <template>
  2. <div class="ContentMedias">
  3. <q-linear-progress v-if="fetchLoading"
  4. indeterminate />
  5. <div v-if="canAddMedia && !readonly"
  6. class="q-mb-md">
  7. <entity-create ref="entityCreate"
  8. v-model:value="inputs"
  9. title="تعریف چند رسانه ای"
  10. :api="api"
  11. :entity-id-key="entityIdKey"
  12. :entity-param-key="entityParamKey"
  13. :show-close-button="false"
  14. :show-edit-button="false"
  15. :show-expand-button="false"
  16. :show-save-button="false"
  17. :show-reload-button="false">
  18. <template #after-form-builder>
  19. <q-btn color="primary"
  20. class="full-width q-mt-md"
  21. :loading="entityCreateLoading"
  22. @click="entityCreate">
  23. افزودن چند رسانه ای
  24. </q-btn>
  25. </template>
  26. </entity-create>
  27. </div>
  28. <media-category v-if="imageMedias.list.length > 0"
  29. :medias="imageMedias"
  30. icon="visibility"
  31. title="تصویر"
  32. class="q-mt-lg"
  33. :can-delete="canDelete"
  34. @onView="onView"
  35. @onDelete="onDelete" />
  36. <media-category v-if="soundMedias.list.length > 0"
  37. :medias="soundMedias"
  38. icon="mic_none"
  39. title="صوت"
  40. class="q-mt-lg"
  41. :can-delete="canDelete"
  42. @onView="onView"
  43. @onDelete="onDelete" />
  44. <media-category v-if="videoMedias.list.length > 0"
  45. :medias="videoMedias"
  46. icon="play_circle_outline"
  47. title="ویدیو"
  48. class="q-mt-lg"
  49. :can-delete="canDelete"
  50. @onView="onView"
  51. @onDelete="onDelete" />
  52. <media-category v-if="documentMedias.list.length > 0"
  53. :medias="documentMedias"
  54. icon="receipt_long"
  55. title="سند"
  56. class="q-mt-lg"
  57. :can-delete="canDelete"
  58. @onView="onView"
  59. @onDelete="onDelete" />
  60. </div>
  61. </template>
  62. <script>
  63. import { EntityCreate } from 'quasar-crud'
  64. import { APIGateway } from 'src/api/APIGateway.js'
  65. import { Media, MediaList } from 'src/models/Media.js'
  66. import { FormBuilderAssist } from 'quasar-form-builder'
  67. import MediaCategory from 'src/components/FormBuilderCustumComponents/ContentMedias/MediaCategory.vue'
  68. export default {
  69. name: 'ContentMedias',
  70. components: { MediaCategory, EntityCreate },
  71. props: {
  72. value: {
  73. default: () => [],
  74. type: [Array, String, Number, Boolean]
  75. },
  76. disable: {
  77. default: false,
  78. type: Boolean
  79. },
  80. canDelete: {
  81. type: Boolean,
  82. default: true
  83. },
  84. canAddMedia: {
  85. type: Boolean,
  86. default: true
  87. },
  88. sourceType: {
  89. type: String,
  90. default: 'CONTENT'
  91. },
  92. readonly: {
  93. default: false,
  94. type: Boolean
  95. },
  96. showPageLink: {
  97. default: true,
  98. type: Boolean
  99. },
  100. showDownloadLink: {
  101. default: false,
  102. type: Boolean
  103. }
  104. },
  105. emits: ['update:value'],
  106. data () {
  107. return {
  108. fetchLoading: false,
  109. medias: new MediaList(),
  110. api: APIGateway.media.APIAdresses.base,
  111. entityIdKey: 'id',
  112. entityParamKey: 'id',
  113. inputs: [
  114. { type: 'file', name: 'file', responseKey: 'file', label: 'فایل', placeholder: ' ', col: 'col-md-4 col-12' },
  115. { type: 'input', name: 'title', responseKey: 'title', label: 'عنوان', placeholder: ' ', col: 'col-md-4 col-12' },
  116. { type: 'select', name: 'type', responseKey: 'type', label: 'نوع', placeholder: ' ', options: (new Media()).typeEnums, col: 'col-md-4 col-12' },
  117. { type: 'input', name: 'url', responseKey: 'url', label: 'url', placeholder: ' ', col: 'col-12' },
  118. { type: 'input', name: 'iframe_code', responseKey: 'iframe_code', label: 'iframe_code', placeholder: ' ', col: 'col-12' },
  119. { type: 'input', name: 'script_code', responseKey: 'script_code', label: 'script_code', placeholder: ' ', col: 'col-12' },
  120. { type: 'hidden', name: 'source_type', responseKey: 'source_type', value: 'CONTENT' }
  121. ],
  122. entityCreateLoading: false
  123. }
  124. },
  125. computed: {
  126. videoMedias () {
  127. return new MediaList(this.medias.getType('VIDEO'))
  128. },
  129. soundMedias () {
  130. return new MediaList(this.medias.getType('SOUND'))
  131. },
  132. imageMedias () {
  133. return new MediaList(this.medias.getType('IMAGE'))
  134. },
  135. documentMedias () {
  136. return new MediaList(this.medias.getType('DOCUMENT'))
  137. }
  138. },
  139. watch: {
  140. value: {
  141. handler () {
  142. this.inputData = this.value
  143. if (this.value && this.value.length > 0 && this.value[0].id) {
  144. this.medias = new MediaList(this.value)
  145. this.$emit('update:value', this.medias.list.map(item => item.id))
  146. }
  147. },
  148. immediate: true
  149. }
  150. },
  151. created () {
  152. FormBuilderAssist.setAttributeByName(this.inputs, 'source_type', 'value', this.sourceType)
  153. this.inputData = this.value
  154. this.medias = new MediaList(this.value)
  155. },
  156. methods: {
  157. onView (media) {
  158. if (this.showPageLink) {
  159. const routeData = this.$router.resolve({ name: 'Admin.Media.Show', params: { id: media.id } })
  160. window.open(routeData.href, '_blank')
  161. return
  162. }
  163. if (this.showDownloadLink) {
  164. if (media.url) {
  165. window.open(media.url, '_blank')
  166. }
  167. const source = media.file
  168. if (!source) {
  169. return
  170. }
  171. const fileName = (source.match(/(?<=\/)[^/?#]+(?=[^/]*$)/gm) || [media.title])[0]
  172. this.fetchLoading = true
  173. fetch(source)
  174. .then(response => response.blob())
  175. .then(blob => {
  176. const link = document.createElement('a')
  177. link.href = URL.createObjectURL(blob)
  178. link.download = fileName
  179. link.click()
  180. this.fetchLoading = false
  181. })
  182. .catch(() => {
  183. this.fetchLoading = false
  184. })
  185. }
  186. },
  187. onDelete (media) {
  188. this.removeMedia(media.id)
  189. },
  190. removeMedia (mediaId) {
  191. const mediaIndex = this.medias.list.findIndex(item => item.id === mediaId)
  192. if (mediaIndex === -1) {
  193. return
  194. }
  195. this.medias.list.splice(mediaIndex, 1)
  196. this.$emit('update:value', this.medias.list.map(item => item.id))
  197. },
  198. entityCreate () {
  199. this.entityCreateLoading = true
  200. this.$refs.entityCreate.createEntity(false)
  201. .then(response => {
  202. this.medias.list.push(new Media(response.data))
  203. this.entityCreateLoading = false
  204. this.$emit('update:value', this.medias.list.map(item => item.id))
  205. })
  206. .catch(() => {
  207. this.entityCreateLoading = false
  208. })
  209. }
  210. }
  211. }
  212. </script>
  213. <style lang="scss" scoped>
  214. .ContentMedias {
  215. width: 100%;
  216. }
  217. </style>