index.vue 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <template>
  2. <div class="chat">
  3. <div :class="['tui-chat', !isPC && 'tui-chat-h5']">
  4. <div
  5. v-if="!currentConversationID"
  6. :class="['tui-chat-default', !isPC && 'tui-chat-h5-default']"
  7. >
  8. <slot />
  9. </div>
  10. <div v-if="currentConversationID" :class="['tui-chat', !isPC && 'tui-chat-h5']">
  11. <ChatHeader
  12. :class="[
  13. 'tui-chat-header',
  14. !isPC && 'tui-chat-H5-header',
  15. isUniFrameWork && 'tui-chat-uniapp-header',
  16. ]"
  17. @closeChat="closeChat"
  18. />
  19. <Forward />
  20. <MessageList
  21. :address="address"
  22. ref="messageListRef"
  23. :class="['tui-chat-message-list', !isPC && 'tui-chat-h5-message-list']"
  24. :isGroup="isGroup"
  25. :groupID="groupID"
  26. @handleEditor="handleEditor"
  27. @closeInputToolBar="() => changeToolbarDisplayType('none')"
  28. :jobInfoData="jobInfoData"
  29. @emitStatus="emitStatus"
  30. />
  31. <!-- 兼容 uni 打包支付宝小程序 v-show 无效问题 -->
  32. <MessageInputToolbar
  33. v-if="isInputToolbarShow"
  34. :class="[
  35. 'tui-chat-message-input-toolbar',
  36. !isPC && 'tui-chat-h5-message-input-toolbar',
  37. isUniFrameWork && 'tui-chat-uni-message-input-toolbar',
  38. ]"
  39. :displayType="inputToolbarDisplayType"
  40. @insertEmoji="insertEmoji"
  41. @changeToolbarDisplayType="changeToolbarDisplayType"
  42. @scrollToLatestMessage="scrollToLatestMessage"
  43. />
  44. <MessageInput
  45. ref="messageInputRef"
  46. :class="[
  47. 'tui-chat-message-input',
  48. !isPC && 'tui-chat-h5-message-input',
  49. isUniFrameWork && 'tui-chat-uni-message-input',
  50. isWeChat && 'tui-chat-wx-message-input',
  51. ]"
  52. :isMuted="false"
  53. :muteText="TUITranslateService.t('TUIChat.您已被管理员禁言')"
  54. :placeholder="TUITranslateService.t('TUIChat.请输入消息')"
  55. :inputToolbarDisplayType="inputToolbarDisplayType"
  56. @changeToolbarDisplayType="changeToolbarDisplayType"
  57. :jobInfoData="jobInfoData"
  58. />
  59. </div>
  60. <!-- 群组管理 -->
  61. <div
  62. v-if="isUniFrameWork && isGroup && groupManageExt"
  63. class="group-profile"
  64. @click="handleGroup"
  65. >
  66. {{ groupManageExt.text }}
  67. <!-- 更多 -->
  68. </div>
  69. </div>
  70. </div>
  71. </template>
  72. <script lang="ts" setup>
  73. import TUIChatEngine, {
  74. TUITranslateService,
  75. TUIConversationService,
  76. TUIStore,
  77. StoreName,
  78. IMessageModel,
  79. IConversationModel,
  80. } from "@tencentcloud/chat-uikit-engine";
  81. import TUICore, { TUIConstants, ExtensionInfo } from "@tencentcloud/tui-core";
  82. import { ref, onMounted, onUnmounted, computed } from "../../adapter-vue";
  83. import ChatHeader from "./chat-header/index.vue";
  84. import MessageList from "./message-list/index.vue";
  85. import MessageInput from "./message-input/index.vue";
  86. import Forward from "./forward/index.vue";
  87. import MessageInputToolbar from "./message-input-toolbar/index.vue";
  88. import { isPC, isWeChat, isUniFrameWork } from "../../utils/env";
  89. import { ToolbarDisplayType } from "../../interface";
  90. import TUIChatConfig from "./config";
  91. import config from "@/request/config";
  92. import { onLoad, onShow } from "@dcloudio/uni-app";
  93. const address = ref();
  94. onShow(() => {
  95. uni.$on("commitMapClick", function (res) {
  96. address.value = res;
  97. console.log("11111", address.value); // 为 B 页面传过来的值
  98. });
  99. });
  100. const emits = defineEmits(["closeChat"]);
  101. const messageInputRef = ref();
  102. const messageListRef = ref<InstanceType<typeof MessageList>>();
  103. const currentConversationID = ref();
  104. // 是否显示群组管理
  105. const isGroup = ref(false);
  106. const groupID = ref("");
  107. const groupManageExt = ref<ExtensionInfo | undefined>(undefined);
  108. const inputToolbarDisplayType = ref<ToolbarDisplayType>("none");
  109. // 沟通职位信息
  110. const jobInfoData = ref({});
  111. // 获取地址栏参数
  112. function getParamValue(paramName) {
  113. const regExp = new RegExp("[?&]" + paramName + "=([^&#]*)");
  114. const results = regExp.exec(window.location.href);
  115. if (results) {
  116. return decodeURIComponent(results[1]);
  117. } else {
  118. return null;
  119. }
  120. }
  121. onMounted(() => {
  122. initData();
  123. TUIStore.watch(StoreName.CONV, {
  124. currentConversation: onCurrentConversationUpdate,
  125. });
  126. });
  127. const initData = () => {
  128. let data = {
  129. companyUserId: getParamValue("companyUserId"),
  130. recruitUserId: getParamValue("recruitUserId"),
  131. postId: getParamValue("postId"),
  132. };
  133. // 发送消息后本地存储文本
  134. let url = config.baseUrl + "/recruit/recruitCommunicate/status";
  135. const header = {
  136. "Content-Type": "application/x-www-form-urlencoded",
  137. Authorization: uni.getStorageSync("token")
  138. ? uni.getStorageSync("token")
  139. : uni.getStorageSync("unitoken"),
  140. };
  141. uni.request({
  142. url: url,
  143. method: "GET",
  144. header: header,
  145. data: data,
  146. success: function (res) {
  147. jobInfoData.value = res.data.data;
  148. },
  149. });
  150. };
  151. onUnmounted(() => {
  152. TUIStore.unwatch(StoreName.CONV, {
  153. currentConversation: onCurrentConversationUpdate,
  154. });
  155. reset();
  156. });
  157. function onCurrentConversationUpdate(conversation: IConversationModel) {
  158. if (currentConversationID.value === conversation?.conversationID) {
  159. return;
  160. }
  161. // TUIChat 每次切换会话,需要初始化 chatType;
  162. TUIChatConfig.setChatType(conversation?.type);
  163. // 由 TUICustomerServicePlugin 插件判断如果当前会话是客服会话,则设置 chatType 并激活会话。
  164. TUICore.callService({
  165. serviceName: TUIConstants.TUICustomerServicePlugin.SERVICE.NAME,
  166. method: TUIConstants.TUICustomerServicePlugin.SERVICE.METHOD.ACTIVE_CONVERSATION,
  167. params: { conversationID: conversation?.conversationID },
  168. });
  169. currentConversationID.value = conversation?.conversationID;
  170. isGroup.value = conversation?.type === TUIChatEngine.TYPES.CONV_GROUP;
  171. // while chat converstaion changed, notify callkit current conversation type, c2c or group
  172. TUICore.notifyEvent(
  173. TUIConstants.TUIChat.EVENT.CHAT_STATE_CHANGED,
  174. TUIConstants.TUIChat.EVENT_SUB_KEY.CHAT_OPENED,
  175. {
  176. groupID: conversation?.groupProfile?.groupID,
  177. }
  178. );
  179. if (
  180. isUniFrameWork &&
  181. isGroup.value &&
  182. groupID.value !== conversation?.groupProfile?.groupID
  183. ) {
  184. const extList = TUICore.getExtensionList(
  185. TUIConstants.TUIChat.EXTENSION.CHAT_HEADER.EXT_ID,
  186. {
  187. filterManageGroup: !isGroup.value,
  188. }
  189. );
  190. groupManageExt.value = extList[0];
  191. }
  192. if (isUniFrameWork && !isGroup.value) {
  193. groupManageExt.value = undefined;
  194. }
  195. groupID.value = conversation?.groupProfile?.groupID;
  196. }
  197. const isInputToolbarShow = computed<boolean>(() => {
  198. return isUniFrameWork ? inputToolbarDisplayType.value !== "none" : true;
  199. });
  200. // 清空当前 conversationID
  201. const reset = () => {
  202. TUIConversationService.switchConversation();
  203. };
  204. const closeChat = (conversationID: string) => {
  205. emits("closeChat", conversationID);
  206. reset();
  207. };
  208. const insertEmoji = (emojiObj: object) => {
  209. messageInputRef.value?.insertEmoji(emojiObj);
  210. };
  211. const handleEditor = (message: IMessageModel, type: string) => {
  212. if (!message || !type) return;
  213. switch (type) {
  214. case "reference":
  215. // todo
  216. break;
  217. case "reply":
  218. // todo
  219. break;
  220. case "reedit":
  221. if (message?.payload?.text) {
  222. messageInputRef?.value?.reEdit(message?.payload?.text);
  223. }
  224. break;
  225. default:
  226. break;
  227. }
  228. };
  229. const emitStatus = (status: Boolean) => {
  230. if (status) {
  231. initData();
  232. }
  233. };
  234. const handleGroup = () => {
  235. groupManageExt.value.listener.onClicked({ groupID: groupID.value });
  236. };
  237. function changeToolbarDisplayType(type: ToolbarDisplayType) {
  238. inputToolbarDisplayType.value = inputToolbarDisplayType.value === type ? "none" : type;
  239. if (inputToolbarDisplayType.value !== "none" && isUniFrameWork) {
  240. uni.$emit("scroll-to-bottom");
  241. }
  242. }
  243. function scrollToLatestMessage() {
  244. messageListRef.value?.scrollToLatestMessage();
  245. }
  246. </script>
  247. <style scoped lang="scss" src="./style/index.scss"></style>