MediaMessageRender.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <template>
  2. <view class="media_message_container" @click="clickMediaItem">
  3. <image
  4. class="image_content"
  5. :src="getImgUrl"
  6. :style="{ width: '120px', height: maxHeight + 'px' }"
  7. mode="scaleToFill"
  8. ></image>
  9. <view v-if="isVideo" class="play_icon_wrapper">
  10. <image class="play_icon" src="@/pages_im/static/images/chating_message_video_play.png" alt="" srcset="" />
  11. </view>
  12. <text v-if="isVideo" class="video_duration">{{ getDuration }}</text>
  13. </view>
  14. </template>
  15. <script>
  16. import { mapGetters } from 'vuex';
  17. // import { checkFileIsExist } from '../../../../../util/common';
  18. import { secFormat } from '../../../../../util/imCommon';
  19. import { myPreview } from '../../../../../util/preview';
  20. import { MessageType } from '@/pages_im/constant/imConstants';
  21. export default {
  22. name: '',
  23. props: {
  24. message: Object
  25. },
  26. data() {
  27. return {};
  28. },
  29. computed: {
  30. ...mapGetters(['storeCacheMap']),
  31. isVideo() {
  32. return this.message.contentType === MessageType.VideoMessage;
  33. },
  34. getImgUrl() {
  35. if (this.isVideo) {
  36. return this.message.videoElem.snapshotUrl;
  37. }
  38. return this.message.pictureElem.snapshotPicture?.url ?? this.message.pictureElem.sourcePath;
  39. },
  40. getDuration() {
  41. if (!this.isVideo) {
  42. return 0;
  43. }
  44. return secFormat(this.message.videoElem.duration);
  45. },
  46. maxHeight() {
  47. const imageHeight = this.isVideo ? this.message.videoElem.snapshotHeight : this.message.pictureElem.sourcePicture.height;
  48. const imageWidth = this.isVideo ? this.message.videoElem.snapshotWidth : this.message.pictureElem.sourcePicture.width;
  49. const aspectRatio = imageHeight / imageWidth;
  50. // 200rpx = 100px
  51. return 100 * aspectRatio;
  52. }
  53. },
  54. methods: {
  55. /**
  56. * 触摸开始,记录时间
  57. */
  58. handleTouchStart() {
  59. this.touchStartTime = Date.now();
  60. this.isLongPress = false;
  61. },
  62. /**
  63. * 长按事件
  64. */
  65. handleLongPress() {
  66. this.isLongPress = true;
  67. this.$emit('longpress', this.message);
  68. },
  69. /**
  70. * 点击媒体项,拦截长按误触
  71. */
  72. async clickMediaItem() {
  73. // 通过时间差和标志位双重拦截
  74. const duration = Date.now() - this.touchStartTime;
  75. if (this.isLongPress || duration > 350) return;
  76. // console.log('clickMediaItem triggered', this.isVideo);
  77. // uni.showToast({ title: 'Clicked', icon: 'none' });
  78. if (this.isVideo) {
  79. const path = this.storeCacheMap[this.message.clientMsgID]?.path;
  80. const localPath = await this.checkFileIsExist({
  81. key: this.message.clientMsgID,
  82. path
  83. });
  84. const previewVideoUrl = localPath || this.message.videoElem.videoUrl;
  85. this.$emit('enterSubPage');
  86. uni.navigateTo({
  87. url: `/pages_im/pages/conversation/previewVideo/index?clientMsgID=${this.message.clientMsgID}&previewVideoUrl=${previewVideoUrl}&snapshotUrl=${this.message.videoElem.snapshotUrl}`
  88. });
  89. } else {
  90. this.$emit('enterSubPage');
  91. const list = this.$store.getters.storePreviewImageList;
  92. const currentUrl = this.message.pictureElem.sourcePicture.url;
  93. const idx = list.findIndex((item) => item === currentUrl);
  94. // Fallback if not found in list
  95. if (idx === -1) {
  96. myPreview(0, [currentUrl]);
  97. } else {
  98. myPreview(idx, list);
  99. }
  100. }
  101. },
  102. checkFileIsExist({ key, path }){
  103. return new Promise((resolve) => {
  104. if (!path) {
  105. resolve("");
  106. return;
  107. }
  108. plus.io.resolveLocalFileSystemURL(
  109. path,
  110. (res) => {
  111. resolve(path);
  112. },
  113. (err) => {
  114. // console.log(err);
  115. getStore().dispatch("user/deleteCacheData", key);
  116. resolve("");
  117. },
  118. );
  119. });
  120. }
  121. }
  122. };
  123. </script>
  124. <style lang="scss" scoped>
  125. .media_message_container {
  126. position: relative;
  127. border-radius: 16rpx;
  128. overflow: hidden;
  129. width: 120px;
  130. background-color: #E0E0E0;
  131. }
  132. .image_content {
  133. width: 120px;
  134. border-radius: 12rpx;
  135. }
  136. .play_icon_wrapper {
  137. position: absolute;
  138. top: 0;
  139. left: 0;
  140. right: 0;
  141. bottom: 0;
  142. justify-content: center;
  143. align-items: center;
  144. z-index: 10;
  145. }
  146. .play_icon {
  147. width: 30px;
  148. height: 30px;
  149. }
  150. .video_duration {
  151. position: absolute;
  152. bottom: 12rpx;
  153. right: 24rpx;
  154. color: #fff;
  155. font-size: 16px;
  156. }
  157. </style>