index.vue 8.8 KB

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