index.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <!-- Used to display the search results of [Contacts]/[Groups]/[All Conversations], which is a display of user/group/conversation dimensions -->
  2. <template>
  3. <div
  4. :class="[
  5. 'search-result-list-item',
  6. !isPC && 'search-result-list-item-h5',
  7. 'search-result-list-item-' + displayType,
  8. isHovering && 'hover-' + displayType,
  9. ]"
  10. @click="onResultItemClicked"
  11. @mouseenter="setHoverStatus(true)"
  12. @mouseleave="setHoverStatus(false)"
  13. >
  14. <div
  15. v-if="displayType === 'info' || displayType === 'bubble'"
  16. :class="[displayType]"
  17. >
  18. <div :class="displayType + '-left'">
  19. <img
  20. :class="displayType + '-left-avatar'"
  21. :src="avatarForShow || ''"
  22. onerror="this.onerror=null;this.src='https://web.sdk.qcloud.com/component/TUIKit/assets/avatar_21.png'"
  23. >
  24. </div>
  25. <div :class="[displayType + '-main']">
  26. <div :class="[displayType + '-main-name']">
  27. {{ nameForShow }}
  28. </div>
  29. <div :class="[displayType + '-main-content']">
  30. <MessageAbstractText
  31. v-if="displayType === 'info' || listItem.type === TYPES.MSG_TEXT"
  32. :content="contentForShow"
  33. :highlightType="displayType === 'info' ? 'font' : 'background'"
  34. :displayType="displayType"
  35. />
  36. <MessageAbstractFile
  37. v-else-if="listItem.type === TYPES.MSG_FILE"
  38. :contentText="contentForShow"
  39. :messageContent="listItemContent"
  40. :displayType="displayType"
  41. />
  42. <div v-else-if="listItem.type === TYPES.MSG_IMAGE" />
  43. <div v-else-if="listItem.type === TYPES.MSG_VIDEO" />
  44. <MessageAbstractCustom
  45. v-else-if="listItem.type === TYPES.MSG_CUSTOM"
  46. :contentText="contentForShow"
  47. :message="listItem"
  48. :messageContent="listItemContent"
  49. />
  50. <div v-else>
  51. {{ getMessageAbstractType(listItem) }}
  52. </div>
  53. </div>
  54. </div>
  55. <div :class="displayType + '-right'">
  56. <div :class="displayType + '-right-time'">
  57. {{ timeForShow }}
  58. </div>
  59. <div
  60. v-if="displayType === 'bubble' && isHovering"
  61. :class="displayType + '-right-to'"
  62. @click.stop="navigateToChatPosition"
  63. >
  64. {{ TUITranslateService.t("TUISearch.定位到聊天位置") }}
  65. </div>
  66. </div>
  67. </div>
  68. <div
  69. v-else-if="displayType === 'file'"
  70. :class="[displayType]"
  71. >
  72. <div :class="[displayType + '-header']">
  73. <img
  74. :class="displayType + '-header-avatar'"
  75. :src="avatarForShow"
  76. onerror="this.onerror=null;this.src='https://web.sdk.qcloud.com/component/TUIKit/assets/avatar_21.png'"
  77. >
  78. <div :class="[displayType + '-header-name']">
  79. {{ nameForShow }}
  80. </div>
  81. <div
  82. v-if="isHovering"
  83. :class="displayType + '-header-to'"
  84. @click.stop="navigateToChatPosition"
  85. >
  86. {{ TUITranslateService.t("TUISearch.定位到聊天位置") }}
  87. </div>
  88. <div :class="displayType + '-header-time'">
  89. {{ timeForShow }}
  90. </div>
  91. </div>
  92. <div :class="[displayType + '-main-content']">
  93. <MessageAbstractFile
  94. :contentText="contentForShow"
  95. :messageContent="listItemContent"
  96. displayType="bubble"
  97. />
  98. </div>
  99. </div>
  100. <div
  101. v-else-if="displayType === 'image'"
  102. :class="[displayType]"
  103. >
  104. <div
  105. class="image-container"
  106. @click.stop="navigateToChatPosition"
  107. >
  108. <MessageAbstractImage
  109. v-if="listItem.type === TYPES.MSG_IMAGE"
  110. :messageContent="listItemContent"
  111. />
  112. <MessageAbstractVideo
  113. v-else-if="listItem.type === TYPES.MSG_VIDEO"
  114. :messageContent="listItemContent"
  115. />
  116. <div
  117. v-if="isHovering"
  118. class="image-container-hover"
  119. >
  120. <div class="image-container-hover-text">
  121. {{ TUITranslateService.t("TUISearch.定位到聊天位置") }}
  122. </div>
  123. </div>
  124. </div>
  125. </div>
  126. </div>
  127. </template>
  128. <script setup lang="ts">
  129. import TUIChatEngine, { TUITranslateService, IMessageModel } from '@tencentcloud/chat-uikit-engine';
  130. import { ref, watchEffect, withDefaults } from '../../../../adapter-vue';
  131. import MessageAbstractText from './message-abstract/message-abstract-text.vue';
  132. import MessageAbstractFile from './message-abstract/message-abstract-file.vue';
  133. import MessageAbstractCustom from './message-abstract/message-abstract-custom.vue';
  134. import MessageAbstractImage from './message-abstract/message-abstract-image.vue';
  135. import MessageAbstractVideo from './message-abstract/message-abstract-video.vue';
  136. import {
  137. generateSearchResultShowName,
  138. generateSearchResultAvatar,
  139. generateSearchResultShowContent,
  140. generateSearchResultTime,
  141. enterConversation,
  142. } from '../../utils';
  143. import { messageTypeAbstractMap, searchResultItemDisplayTypeValues, searchMessageTypeValues, IHighlightContent } from '../../type';
  144. import { ISearchResultListItem } from '../../../../interface';
  145. import { isPC } from '../../../../utils/env';
  146. interface IProps {
  147. listItem: IMessageModel | ISearchResultListItem;
  148. listItemContent?: Record<string, unknown>;
  149. type: searchMessageTypeValues;
  150. displayType: searchResultItemDisplayTypeValues;
  151. keywordList: string[];
  152. }
  153. const props = withDefaults(defineProps<IProps>(), {
  154. listItem: () => ({}) as IMessageModel | ISearchResultListItem,
  155. listItemContent: () => ({}) as Record<string, unknown>,
  156. type: 'allMessage',
  157. displayType: 'info',
  158. keywordList: () => ([]) as string[],
  159. });
  160. const emits = defineEmits(['showResultDetail', 'navigateToChatPosition']);
  161. const TYPES = ref(TUIChatEngine.TYPES);
  162. const avatarForShow = ref<string>('');
  163. const nameForShow = ref<string>('');
  164. const contentForShow = ref<IHighlightContent[]>([]);
  165. const timeForShow = ref<string>('');
  166. const isHovering = ref<boolean>(false);
  167. watchEffect(() => {
  168. avatarForShow.value = generateSearchResultAvatar(props.listItem);
  169. nameForShow.value = generateSearchResultShowName(props.listItem, props?.listItemContent);
  170. contentForShow.value = generateSearchResultShowContent(
  171. props.listItem,
  172. props.type,
  173. props.keywordList as string[],
  174. props?.displayType === 'info',
  175. );
  176. timeForShow.value = (props.listItem as IMessageModel)?.time
  177. ? generateSearchResultTime((props.listItem as IMessageModel)?.time * 1000)
  178. : '';
  179. });
  180. const onResultItemClicked = () => {
  181. if (props.type === 'contact' || props.type === 'group') {
  182. enterConversation(props.listItem as IMessageModel);
  183. } else {
  184. if (props.displayType === 'info' && !(props.listItem as IMessageModel)?.ID) {
  185. emits('showResultDetail', true, props.type, props.listItem);
  186. } else {
  187. navigateToChatPosition();
  188. }
  189. }
  190. };
  191. const setHoverStatus = (status: boolean) => {
  192. isHovering.value = status;
  193. };
  194. const navigateToChatPosition = () => {
  195. emits('navigateToChatPosition', props.listItem);
  196. };
  197. const getMessageAbstractType = (message: IMessageModel | ISearchResultListItem) => {
  198. return message?.type
  199. ? TUITranslateService.t(`TUISearch.${messageTypeAbstractMap[message.type]}`)
  200. : TUITranslateService.t(`TUISearch.[合并消息]`);
  201. };
  202. </script>
  203. <style lang="scss" scoped src="./style/index.scss"></style>