index.vue 7.2 KB

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