sendMessage.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import TUIChatEngine, {
  2. TUIChatService,
  3. TUIStore,
  4. StoreName,
  5. TUITranslateService,
  6. IConversationModel,
  7. SendMessageParams,
  8. } from '@tencentcloud/chat-uikit-engine';
  9. import { Toast, TOAST_TYPE } from '../../common/Toast/index';
  10. import { isEnabledMessageReadReceiptGlobal } from '../utils/utils';
  11. import { ITipTapEditorContent } from '../../../interface';
  12. import { enableSampleTaskStatus } from '../../../utils/enableSampleTaskStatus';
  13. import OfflinePushInfoManager, { IOfflinePushInfoCreateParams } from '../offlinePushInfoManager/index';
  14. export const sendMessageErrorCodeMap: Map<number, string> = new Map([
  15. [3123, '文本包含本地审核拦截词'],
  16. [4004, '图片消息失败,无效的图片格式'],
  17. [4005, '文件消息失败,禁止发送违规封禁的文件'],
  18. [7004, '文件不存在,请检查文件路径是否正确'],
  19. [7005, '文件大小超出了限制,如果上传文件,最大限制是100MB'],
  20. [8001, '消息长度超出限制,消息长度不要超过12K'],
  21. [80001, '消息或者资料中文本存在敏感内容,发送失败'],
  22. [80004, '消息中图片存在敏感内容,发送失败'],
  23. ]);
  24. export const createOfflinePushInfo = (conversation: IConversationModel) => {
  25. const androidInfo = {
  26. sound: 'private_ring.mp3',
  27. XiaoMiChannelID: 'high_custom_1',
  28. OPPOChannelID: 'tuikit',
  29. };
  30. const apnsInfo = {
  31. sound: '01.caf',
  32. image: 'https://web.sdk.qcloud.com/im/demo/latest/faviconnew.png',
  33. };
  34. const userInfo = TUIStore.getData(StoreName.USER, 'userProfile');
  35. const entity = {
  36. sender: conversation.type === TUIChatEngine.TYPES.CONV_GROUP ? conversation.groupProfile?.groupID : userInfo.userID,
  37. nickName: userInfo.nick,
  38. chatType: conversation.type === TUIChatEngine.TYPES.CONV_GROUP ? 2 : 1,
  39. version: 1,
  40. action: 1,
  41. };
  42. return {
  43. extension: JSON.stringify({ entity }),
  44. androidInfo,
  45. apnsInfo,
  46. };
  47. };
  48. /**
  49. * This function only processes five message types: Text/TextAt/Image/Video/File
  50. * @param messageList
  51. * @param currentConversation
  52. */
  53. export const sendMessages = async (
  54. messageList: ITipTapEditorContent[],
  55. currentConversation: IConversationModel,
  56. ) => {
  57. // In case of messageJumping, the sent message is automatically cleared and returns to the bottom
  58. if (TUIStore.getData(StoreName.CHAT, 'messageSource')) {
  59. TUIStore.update(StoreName.CHAT, 'messageSource', undefined);
  60. }
  61. messageList?.forEach(async (content: ITipTapEditorContent) => {
  62. try {
  63. const options: SendMessageParams = {
  64. to: currentConversation?.groupProfile?.groupID || currentConversation?.userProfile?.userID,
  65. conversationType: currentConversation?.type as any,
  66. payload: {},
  67. needReadReceipt: isEnabledMessageReadReceiptGlobal(),
  68. };
  69. // handle message typing
  70. let textMessageContent;
  71. const sendMessageOptions = {
  72. offlinePushInfo: {},
  73. };
  74. const offlinePushInfoCreateParams: IOfflinePushInfoCreateParams = {
  75. conversation: currentConversation,
  76. payload: content.payload,
  77. messageType: '',
  78. };
  79. switch (content?.type) {
  80. case 'text':
  81. textMessageContent = JSON.parse(JSON.stringify(content.payload?.text));
  82. // Do not send empty messages
  83. if (!textMessageContent) {
  84. break;
  85. }
  86. options.payload = {
  87. text: textMessageContent,
  88. };
  89. offlinePushInfoCreateParams.messageType = TUIChatEngine.TYPES.MSG_TEXT;
  90. sendMessageOptions.offlinePushInfo = OfflinePushInfoManager.create(offlinePushInfoCreateParams);
  91. if (content.payload?.atUserList) {
  92. options.payload.atUserList = content.payload.atUserList;
  93. await TUIChatService.sendTextAtMessage(options, sendMessageOptions);
  94. } else {
  95. await TUIChatService.sendTextMessage(options, sendMessageOptions);
  96. }
  97. break;
  98. case 'image':
  99. options.payload = {
  100. file: content.payload?.file,
  101. };
  102. offlinePushInfoCreateParams.messageType = TUIChatEngine.TYPES.MSG_IMAGE;
  103. sendMessageOptions.offlinePushInfo = OfflinePushInfoManager.create(offlinePushInfoCreateParams);
  104. await TUIChatService.sendImageMessage(options, sendMessageOptions);
  105. break;
  106. case 'video':
  107. options.payload = {
  108. file: content.payload?.file,
  109. };
  110. offlinePushInfoCreateParams.messageType = TUIChatEngine.TYPES.MSG_VIDEO;
  111. sendMessageOptions.offlinePushInfo = OfflinePushInfoManager.create(offlinePushInfoCreateParams);
  112. await TUIChatService.sendVideoMessage(options, sendMessageOptions);
  113. break;
  114. case 'file':
  115. options.payload = {
  116. file: content.payload?.file,
  117. };
  118. offlinePushInfoCreateParams.messageType = TUIChatEngine.TYPES.MSG_FILE;
  119. sendMessageOptions.offlinePushInfo = OfflinePushInfoManager.create(offlinePushInfoCreateParams);
  120. await TUIChatService.sendFileMessage(options, sendMessageOptions);
  121. break;
  122. default:
  123. break;
  124. }
  125. enableSampleTaskStatus('sendMessage');
  126. } catch (error: any) {
  127. Toast({
  128. message: sendMessageErrorCodeMap.get(error?.code)
  129. ? TUITranslateService.t(`TUIChat.${sendMessageErrorCodeMap.get(error.code) as string}`)
  130. : error?.message,
  131. type: TOAST_TYPE.ERROR,
  132. });
  133. // If the message fails to be sent and the message is a reference message, clear the reference message information
  134. if (TUIStore.getData(StoreName.CHAT, 'quoteMessage')) {
  135. TUIStore.update(StoreName.CHAT, 'quoteMessage', {});
  136. }
  137. }
  138. });
  139. };
  140. export const handleMessageWithTyping = (cloudCustomData: any) => {
  141. if (!cloudCustomData) {
  142. cloudCustomData = {};
  143. }
  144. cloudCustomData.messageFeature = {
  145. needTyping: 1,
  146. version: 1,
  147. };
  148. return cloudCustomData;
  149. };
  150. export const sendTyping = (inputContentEmpty: boolean, inputBlur: boolean) => {
  151. if (!inputContentEmpty && !inputBlur) {
  152. TUIChatService.enterTypingState();
  153. } else {
  154. TUIChatService.leaveTypingState();
  155. }
  156. };