index.vue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <template>
  2. <el-dialog
  3. :visible.sync="isPreviewing"
  4. custom-class="c-dialog--transparent"
  5. :close-on-click-modal="false"
  6. v-bind="$attrs"
  7. v-on="$listeners"
  8. >
  9. <template v-if="isPreviewing">
  10. <auto-image
  11. v-if="isImage"
  12. class="o-image--preview"
  13. :src="assetUrl"
  14. retry
  15. />
  16. <video
  17. v-if="isVideo"
  18. class="o-video--preview"
  19. :src="assetUrl"
  20. autoplay
  21. controls
  22. />
  23. <audio
  24. v-if="isAudio"
  25. :src="assetUrl"
  26. autoplay
  27. controls
  28. />
  29. <i
  30. class="o-close o-icon el-icon-close has-active u-bold u-pointer"
  31. @click="onCloseDialog"
  32. />
  33. <template v-if="isMultipleFiles">
  34. <i
  35. class="o-arrow o-icon el-icon-arrow-left has-active u-bold u-pointer"
  36. @click="onPresent"
  37. />
  38. <i
  39. class="o-arrow o-icon el-icon-arrow-right has-active u-bold u-pointer"
  40. @click="onNext"
  41. />
  42. <div class="o-total">{{ active + 1 }}/{{ total }}</div>
  43. </template>
  44. </template>
  45. </el-dialog>
  46. </template>
  47. <script>
  48. import { getAssetUrl } from '@/api/asset'
  49. import { AssetType } from '@/constant'
  50. export default {
  51. name: 'PreviewDialog',
  52. data () {
  53. return {
  54. isPreviewing: false,
  55. isMultipleFiles: false,
  56. total: 0,
  57. active: 0,
  58. source: null
  59. }
  60. },
  61. computed: {
  62. fileType () {
  63. return this.source?.type
  64. },
  65. isImage () {
  66. return this.fileType === AssetType.IMAGE
  67. },
  68. isVideo () {
  69. return this.fileType === AssetType.VIDEO
  70. },
  71. isAudio () {
  72. return this.fileType === AssetType.AUDIO
  73. },
  74. assetUrl () {
  75. return this.source && getAssetUrl(this.source.url)
  76. }
  77. },
  78. methods: {
  79. show (source) {
  80. this.$sources = source?.files?.length ? source.files : [source]
  81. this.isMultipleFiles = this.$sources.length > 1
  82. this.total = this.$sources.length
  83. this.active = 0
  84. this.source = this.$sources[this.active]
  85. this.isPreviewing = true
  86. },
  87. onCloseDialog () {
  88. this.isPreviewing = false
  89. },
  90. onPresent () {
  91. this.active = (this.active - 1 + this.total) % this.total
  92. this.source = this.$sources[this.active]
  93. },
  94. onNext () {
  95. this.active = (this.active + 1) % this.total
  96. this.source = this.$sources[this.active]
  97. }
  98. }
  99. }
  100. </script>
  101. <style lang="scss" scoped>
  102. .o-image--preview {
  103. min-width: 96px;
  104. max-width: 100%;
  105. min-height: 96px;
  106. max-height: 100%;
  107. color: #fff;
  108. font-size: 32px;
  109. line-height: 0;
  110. }
  111. .o-video--preview {
  112. max-width: 100%;
  113. max-height: 100%;
  114. }
  115. .o-close {
  116. position: absolute;
  117. color: #fff;
  118. top: 0;
  119. right: 0;
  120. transform: translateY(-100%);
  121. }
  122. .o-arrow {
  123. position: absolute;
  124. color: #fff;
  125. top: 50%;
  126. &.el-icon-arrow-left {
  127. left: 0;
  128. transform: translate(-100%, -50%);
  129. }
  130. &.el-icon-arrow-right {
  131. right: 0;
  132. transform: translate(100%, -50%);
  133. }
  134. }
  135. .o-total {
  136. position: absolute;
  137. left: 50%;
  138. bottom: -48px;
  139. color: #fff;
  140. font-size: 24px;
  141. transform: translateX(-50%);
  142. }
  143. </style>