sendMessage.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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. export const sendMessageErrorCodeMap: Map<number, string> = new Map([
  14. [3123, '文本包含本地审核拦截词'],
  15. [4004, '图片消息失败,无效的图片格式'],
  16. [4005, '文件消息失败,禁止发送违规封禁的文件'],
  17. [7004, '文件不存在,请检查文件路径是否正确'],
  18. [7005, '文件大小超出了限制,如果上传文件,最大限制是100MB'],
  19. [8001, '消息长度超出限制,消息长度不要超过12K'],
  20. [80001, '消息或者资料中文本存在敏感内容,发送失败'],
  21. [80004, '消息中图片存在敏感内容,发送失败'],
  22. ]);
  23. export const createOfflinePushInfo = (currentConversation: IConversationModel) => {
  24. const androidInfo = {
  25. sound: 'private_ring.mp3',
  26. XiaoMiChannelID: 'high_custom_1',
  27. };
  28. const apnsInfo = {
  29. sound: '01.caf',
  30. };
  31. const userInfo = TUIStore.getData(StoreName.USER, 'userProfile');
  32. const entity = {
  33. sender: currentConversation.type === TUIChatEngine.TYPES.CONV_GROUP ? currentConversation.groupProfile?.groupID : userInfo.userID,
  34. nickName: userInfo.nick,
  35. chatType: currentConversation.type === TUIChatEngine.TYPES.CONV_GROUP ? 2 : 1,
  36. version: 1,
  37. action: 1,
  38. };
  39. return {
  40. androidInfo,
  41. apnsInfo,
  42. extension: JSON.stringify({ entity }),
  43. };
  44. };
  45. /**
  46. * 该函数仅处理 Text TextAt Image Video File 五种消息类型
  47. * @param messageList
  48. * @param currentConversation
  49. */
  50. export const sendMessages = async (
  51. messageList: ITipTapEditorContent[],
  52. currentConversation: IConversationModel,
  53. ) => {
  54. // 有 messageJumping 的情况下,发送消息自动清空,回到底部
  55. if (TUIStore.getData(StoreName.CHAT, 'messageSource')) {
  56. TUIStore.update(StoreName.CHAT, 'messageSource', undefined);
  57. }
  58. messageList?.forEach(async (content: ITipTapEditorContent) => {
  59. try {
  60. const options: SendMessageParams = {
  61. to: currentConversation?.groupProfile?.groupID || currentConversation?.userProfile?.userID,
  62. conversationType: currentConversation?.type as any,
  63. payload: {},
  64. needReadReceipt: isEnabledMessageReadReceiptGlobal(),
  65. };
  66. // handle message typing
  67. let textMessageContent;
  68. const sendMessageOptions: any = {
  69. offlinePushInfo: createOfflinePushInfo(currentConversation),
  70. };
  71. switch (content?.type) {
  72. case 'text':
  73. textMessageContent = JSON.parse(JSON.stringify(content.payload?.text));
  74. // 禁止发送空消息
  75. if (!textMessageContent) {
  76. break;
  77. }
  78. if (content.payload?.atUserList) {
  79. options.payload = {
  80. text: textMessageContent,
  81. atUserList: content.payload.atUserList,
  82. };
  83. await TUIChatService.sendTextAtMessage(options, sendMessageOptions);
  84. } else {
  85. options.payload = {
  86. text: textMessageContent,
  87. };
  88. await TUIChatService.sendTextMessage(options, sendMessageOptions);
  89. }
  90. break;
  91. case 'image':
  92. options.payload = {
  93. file: content.payload?.file,
  94. };
  95. await TUIChatService.sendImageMessage(options, sendMessageOptions);
  96. break;
  97. case 'video':
  98. options.payload = {
  99. file: content.payload?.file,
  100. };
  101. await TUIChatService.sendVideoMessage(options, sendMessageOptions);
  102. break;
  103. case 'file':
  104. options.payload = {
  105. file: content.payload?.file,
  106. };
  107. await TUIChatService.sendFileMessage(options, sendMessageOptions);
  108. break;
  109. default:
  110. break;
  111. }
  112. enableSampleTaskStatus('sendMessage');
  113. } catch (error: any) {
  114. Toast({
  115. message: sendMessageErrorCodeMap.get(error?.code)
  116. ? TUITranslateService.t(`TUIChat.${sendMessageErrorCodeMap.get(error.code) as string}`)
  117. : error?.message,
  118. type: TOAST_TYPE.ERROR,
  119. });
  120. // 如果消息发送失败,且该消息为引用消息,清除引用消息信息
  121. if (TUIStore.getData(StoreName.CHAT, 'quoteMessage')) {
  122. TUIStore.update(StoreName.CHAT, 'quoteMessage', {});
  123. }
  124. }
  125. });
  126. };
  127. export const handleMessageWithTyping = (cloudCustomData: any) => {
  128. if (!cloudCustomData) {
  129. cloudCustomData = {};
  130. }
  131. cloudCustomData.messageFeature = {
  132. needTyping: 1,
  133. version: 1,
  134. };
  135. return cloudCustomData;
  136. };
  137. export const sendTyping = (inputContentEmpty: boolean, inputBlur: boolean) => {
  138. if (!inputContentEmpty && !inputBlur) {
  139. TUIChatService.enterTypingState();
  140. } else {
  141. TUIChatService.leaveTypingState();
  142. }
  143. };