MessageMenu.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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" @click="menuClick(item)" :key="item.idx">
  4. <image :src="item.icon" />
  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. import copy from '../../../../../static/images/chating_message_copy.png';
  16. import forward from '../../../../../static/images/chating_message_forward.png';
  17. import reply from '../../../../../static/images/chating_message_reply.png';
  18. import revoke from '../../../../../static/images/chating_message_revoke.png';
  19. import multiple from '../../../../../static/images/chating_message_multiple.png';
  20. import del from '../../../../../static/images/chating_message_del.png';
  21. const canCopyTypes = [MessageType.TextMessage, MessageType.AtTextMessage, MessageType.QuoteMessage, MessageType.GroupAnnouncementUpdated];
  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. getMenuList(){
  223. // 公共基础菜单(非医生也能看到的项)
  224. let baseMenus = [
  225. {
  226. idx: 0,
  227. type: MessageMenuTypes.Copy,
  228. title: "复制",
  229. icon: copy,
  230. visible: canCopyTypes.includes(this.message.contentType),
  231. },
  232. { idx: 1,
  233. type: MessageMenuTypes.Del,
  234. title: "删除",
  235. icon: del,
  236. visible: true ,
  237. },
  238. {
  239. idx: 3,
  240. type: MessageMenuTypes.Reply,
  241. title: "回复",
  242. icon: reply,
  243. visible: true
  244. },
  245. {
  246. idx: 4,
  247. type: MessageMenuTypes.Revoke,
  248. title: "撤回",
  249. icon: revoke,
  250. visible: this.canRevoke && !this.isGroupAnnouncement
  251. }
  252. ];
  253. let menus1 = [
  254. {
  255. idx: 2,
  256. type: MessageMenuTypes.Forward,
  257. title: "转发",
  258. icon: forward,
  259. visible: !this.isGroupAnnouncement && this.message.contentType==MessageType.VoiceMessage
  260. },
  261. {
  262. idx: 5,
  263. type: MessageMenuTypes.Multiple,
  264. title: "多选",
  265. icon: multiple,
  266. visible: !this.isGroupAnnouncement && this.message.contentType==MessageType.VoiceMessage
  267. }
  268. ];
  269. let tempMenuArrs=isDoctorAction(this.storeCurrentConversation.userID) ? baseMenus: [...baseMenus, ...menus1];
  270. let menuList=[];
  271. for(let i=0;i<tempMenuArrs.length;i++){
  272. let item=tempMenuArrs[i];
  273. if(item.visible){
  274. menuList.push(item);
  275. }
  276. }
  277. console.log("qxj menuList:");
  278. console.log(menuList);
  279. return menuList;
  280. },
  281. getCopyText() {
  282. if (this.isGroupAnnouncement) {
  283. let detail = {};
  284. try {
  285. detail = JSON.parse(this.message.notificationElem.detail);
  286. } catch (e) {}
  287. return detail.group?.notification ?? '';
  288. }
  289. if (this.message.contentType === MessageType.AtTextMessage) {
  290. return parseAt(this.message.atTextElem, true);
  291. }
  292. if (this.message.contentType === MessageType.QuoteMessage) {
  293. return this.message.quoteElem.text;
  294. }
  295. return this.message.textElem.content;
  296. }
  297. }
  298. };
  299. </script>
  300. <style scoped lang="scss">
  301. .message_menu_container {
  302. display: grid;
  303. //grid-template-columns: repeat(5, 1fr);
  304. background-color: #5b5b5b;
  305. padding: 8rpx 0;
  306. border-radius: 16rpx;
  307. position: absolute;
  308. top: -12px;
  309. transform: translateY(-100%);
  310. z-index: 1002;
  311. width: max-content; /* 宽度根据内容自适应 */
  312. &_bottom {
  313. top: unset;
  314. bottom: 0;
  315. transform: translateY(110%);
  316. }
  317. .message_menu_item {
  318. @include colBox(false);
  319. align-items: center;
  320. font-size: 12px;
  321. color: #fff;
  322. padding: 16rpx 24rpx;
  323. image {
  324. width: 14px;
  325. height: 16px;
  326. margin-bottom: 4px;
  327. }
  328. text {
  329. min-width: max-content;
  330. }
  331. }
  332. }
  333. </style>