MessageMenu.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. <template>
  2. <view :style="{ left: getLeft, right: getRight,'grid-template-columns': `repeat(${menuList.length}, 1fr` }" class="message_menu_container" :class="{ message_menu_container_bottom: is_bottom }">
  3. <view class="message_menu_item" v-for="item in menuList" v-if="item.visible" @click="menuClick(item)" :key="item.idx">
  4. <image :src="item.icon" alt="" srcset="" />
  5. <text>{{ item.title }}</text>
  6. </view>
  7. </view>
  8. </template>
  9. <script>
  10. import { mapGetters, mapActions } from 'vuex';
  11. import { MessageMenuTypes, ContactChooseTypes, PageEvents } from '../../../../../constant';
  12. import IMSDK, { GroupMemberRole, MessageType, SessionType } from 'openim-uniapp-polyfill';
  13. import { parseAt } from '../../../../../util/imCommon';
  14. import { isDoctorAction } from '../../../../../util/common';
  15. const canCopyTypes = [MessageType.TextMessage, MessageType.AtTextMessage, MessageType.QuoteMessage, MessageType.GroupAnnouncementUpdated];
  16. const copy = 'https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/shop/image/chating_message_copy.png';
  17. const forward = 'https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/shop/image/chating_message_forward.png';
  18. const reply = 'https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/shop/image/chating_message_reply.png';
  19. const revoke = 'https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/shop/image/chating_message_revoke.png';
  20. const multiple = 'https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/shop/image/chating_message_multiple.png';
  21. const del = 'https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/shop/image/chating_message_del.png';
  22. export default {
  23. components: {},
  24. props: {
  25. message: {
  26. type: Object
  27. },
  28. is_bottom: {
  29. type: Boolean,
  30. default: true
  31. },
  32. isSender: Boolean,
  33. paterWidth: Number
  34. },
  35. data() {
  36. return {
  37. contentType: null
  38. };
  39. },
  40. computed: {
  41. ...mapGetters(['storeCurrentMemberInGroup', 'storeCurrentUserID', 'storeCurrentConversation']),
  42. getLeft() {
  43. // 145 + 145*0.2
  44. if (this.isSender && this.paterWidth < 174) {
  45. return 'auto';
  46. }
  47. if (!this.isSender && this.paterWidth < 174) {
  48. return '0';
  49. }
  50. return '20%';
  51. },
  52. getRight() {
  53. if (this.isSender && this.paterWidth < 174) {
  54. return '0';
  55. }
  56. return 'auto';
  57. },
  58. canRevoke() {
  59. const interval = this.message.sendTime < Date.now() - 5 * 60 * 1000;
  60. if (interval) {
  61. return false;
  62. }
  63. if (this.message.sessionType !== SessionType.Single && this.storeCurrentMemberInGroup.roleLevel !== GroupMemberRole.Nomal) {
  64. return true;
  65. }
  66. return this.isSender;
  67. },
  68. isGroupAnnouncement() {
  69. return this.message.contentType === MessageType.GroupAnnouncementUpdated;
  70. },
  71. menuList() {
  72. // 公共基础菜单(非医生也能看到的项)
  73. const baseMenus = [
  74. {
  75. idx: 0,
  76. type: MessageMenuTypes.Copy,
  77. title: "复制",
  78. icon: copy,
  79. visible: canCopyTypes.includes(this.message.contentType),
  80. },
  81. { idx: 1,
  82. type: MessageMenuTypes.Del,
  83. title: "删除",
  84. icon: del,
  85. visible: true ,
  86. },
  87. {
  88. idx: 3,
  89. type: MessageMenuTypes.Reply,
  90. title: "回复",
  91. icon: reply,
  92. visible: !this.isGroupAnnouncement
  93. },
  94. {
  95. idx: 4,
  96. type: MessageMenuTypes.Revoke,
  97. title: "撤回",
  98. icon: revoke,
  99. visible: this.canRevoke && !this.isGroupAnnouncement
  100. }
  101. ];
  102. const menus1 = [
  103. {
  104. idx: 2,
  105. type: MessageMenuTypes.Forward,
  106. title: "转发",
  107. icon: forward,
  108. visible: !this.isGroupAnnouncement && this.message.contentType==MessageType.VoiceMessage
  109. },
  110. {
  111. idx: 5,
  112. type: MessageMenuTypes.Multiple,
  113. title: "多选",
  114. icon: multiple,
  115. visible: !this.isGroupAnnouncement && this.message.contentType==MessageType.VoiceMessage
  116. }
  117. ];
  118. let tempMenuArrs=isDoctorAction(this.storeCurrentConversation.userID) ? baseMenus: [...baseMenus, ...menus1];
  119. let menuList=[];
  120. tempMenuArrs.forEach((item) => {
  121. if(item.visible){
  122. menuList.push(item);
  123. }
  124. });
  125. return menuList;
  126. }
  127. },
  128. mounted() {
  129. this.contentType = this.message.contentType;
  130. },
  131. methods: {
  132. ...mapActions('message', ['deleteMessages', 'updateOneMessage', 'updateQuoteMessageRevoke']),
  133. ...mapActions('conversation', ['addRevokedMessage']),
  134. async menuClick({ type }) {
  135. switch (type) {
  136. case MessageMenuTypes.Copy:
  137. uni.setClipboardData({
  138. data: this.getCopyText(),
  139. success: () => {
  140. uni.hideToast();
  141. this.$nextTick(() => {
  142. uni.$u.toast('复制成功');
  143. });
  144. }
  145. });
  146. break;
  147. case MessageMenuTypes.Del:
  148. try {
  149. await IMSDK.asyncApi(IMSDK.IMMethods.DeleteMessage, IMSDK.uuid(), {
  150. conversationID: this.$store.getters.storeCurrentConversation.conversationID,
  151. clientMsgID: this.message.clientMsgID
  152. });
  153. this.deleteMessages([this.message]);
  154. uni.$u.toast('删除成功');
  155. } catch (error) {
  156. try {
  157. await IMSDK.asyncApi(IMSDK.IMMethods.DeleteMessageFromLocalStorage, IMSDK.uuid(), {
  158. conversationID: this.$store.getters.storeCurrentConversation.conversationID,
  159. clientMsgID: this.message.clientMsgID
  160. });
  161. this.deleteMessages([this.message]);
  162. uni.$u.toast('删除成功');
  163. } catch (error) {
  164. uni.$u.toast('删除失败');
  165. }
  166. }
  167. break;
  168. case MessageMenuTypes.Forward:
  169. uni.navigateTo({
  170. url: `/pages_im/pages/common/contactChoose/index?type=${ContactChooseTypes.ForWard}&forwardMessage=${encodeURIComponent(JSON.stringify(this.message))}`
  171. });
  172. break;
  173. case MessageMenuTypes.Multiple:
  174. uni.$emit(PageEvents.MutipleCheckUpdate, {
  175. flag: true,
  176. message: this.message
  177. });
  178. break;
  179. case MessageMenuTypes.Reply:
  180. this.$store.commit('message/SET_QUOTE_MESSAGE', this.message);
  181. break;
  182. case MessageMenuTypes.Revoke:
  183. IMSDK.asyncApi(IMSDK.IMMethods.RevokeMessage, IMSDK.uuid(), {
  184. conversationID: this.$store.getters.storeCurrentConversation.conversationID,
  185. clientMsgID: this.message.clientMsgID
  186. })
  187. .then(() => {
  188. if (canCopyTypes.includes(this.contentType) && this.message.sendID === this.storeCurrentUserID) {
  189. this.addRevokedMessage(this.message);
  190. }
  191. this.updateOneMessage({
  192. message: {
  193. ...this.message,
  194. contentType: MessageType.RevokeMessage,
  195. notificationElem: {
  196. detail: JSON.stringify({
  197. clientMsgID: this.message.clientMsgID,
  198. revokeTime: Date.now(),
  199. revokerID: this.storeCurrentUserID,
  200. revokerNickname: '你',
  201. revokerRole: 0,
  202. seq: this.message.seq,
  203. sessionType: this.message.sessionType,
  204. sourceMessageSendID: this.message.sendID,
  205. sourceMessageSendTime: this.message.sendTime,
  206. sourceMessageSenderNickname: this.message.senderNickname
  207. })
  208. }
  209. }
  210. });
  211. this.updateQuoteMessageRevoke({
  212. clientMsgID: this.message.clientMsgID
  213. });
  214. })
  215. .catch(() => uni.$u.toast('撤回失败'));
  216. break;
  217. default:
  218. break;
  219. }
  220. this.$emit('close');
  221. },
  222. getCopyText() {
  223. if (this.isGroupAnnouncement) {
  224. let detail = {};
  225. try {
  226. detail = JSON.parse(this.message.notificationElem.detail);
  227. } catch (e) {}
  228. return detail.group?.notification ?? '';
  229. }
  230. if (this.message.contentType === MessageType.AtTextMessage) {
  231. return parseAt(this.message.atTextElem, true);
  232. }
  233. if (this.message.contentType === MessageType.QuoteMessage) {
  234. return this.message.quoteElem.text;
  235. }
  236. return this.message.textElem.content;
  237. }
  238. }
  239. };
  240. </script>
  241. <style scoped lang="scss">
  242. .message_menu_container {
  243. display: grid;
  244. //grid-template-columns: repeat(5, 1fr);
  245. background-color: #5b5b5b;
  246. padding: 8rpx 0;
  247. border-radius: 16rpx;
  248. position: absolute;
  249. top: -12px;
  250. transform: translateY(-100%);
  251. z-index: 9;
  252. width: max-content; /* 宽度根据内容自适应 */
  253. &_bottom {
  254. top: unset;
  255. bottom: 0;
  256. transform: translateY(110%);
  257. }
  258. .message_menu_item {
  259. @include colBox(false);
  260. align-items: center;
  261. font-size: 12px;
  262. color: #fff;
  263. padding: 16rpx 24rpx;
  264. image {
  265. width: 17px;
  266. height: 19px;
  267. margin-bottom: 4px;
  268. }
  269. text {
  270. min-width: max-content;
  271. }
  272. }
  273. }
  274. </style>