Message.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <template>
  2. <message-component>
  3. <div ref="messageIcon" class="message-icon">
  4. <span v-show="unReadMessages?.newCount" class="un-read-num"></span>
  5. <svg-icon name="message"></svg-icon>
  6. </div>
  7. <el-popover
  8. placement="bottom-start"
  9. :width="useVW(400)"
  10. :show-arrow="false"
  11. :virtual-ref="messageIcon"
  12. trigger="click"
  13. virtual-triggering
  14. >
  15. <div class="message-popover-content">
  16. <div class="title">
  17. <span class="unread-count">{{ unReadMessages?.newCount || 0 }}</span>
  18. <span>条消息</span>
  19. </div>
  20. <div class="message-list">
  21. <div
  22. v-for="message in unReadMessages?.messages"
  23. :key="message.sendUserId"
  24. class="flex message-row"
  25. @click="onReceiveMessage"
  26. >
  27. <div class="message-send-user">
  28. <div class="user-name">{{ message.sendUserName }}</div>
  29. <div class="message-time">{{ dayjs(message.sendTime).format('HH:mm') }}</div>
  30. </div>
  31. <pre class="flex-1 message-content" v-html="message.content"></pre>
  32. </div>
  33. </div>
  34. <confirm-button
  35. size="small"
  36. between
  37. ok-text="收消息"
  38. cancel-text="发消息"
  39. @confirm="onReceiveMessage"
  40. @cancel="onSendMessage"
  41. ></confirm-button>
  42. </div>
  43. </el-popover>
  44. <message-window
  45. v-model="visibleMessageWindow"
  46. v-model:type="messageWindowType"
  47. v-model:replyUserId="replyUserId"
  48. :paper-path="props.paperPath"
  49. ></message-window>
  50. </message-component>
  51. </template>
  52. <script setup lang="ts" name="Message">
  53. /** 头部消息组件 */
  54. import { defineComponent, withDefaults, ref, useSlots, watch, inject } from 'vue'
  55. import { ElPopover } from 'element-plus'
  56. import dayjs from 'dayjs'
  57. import useVW from '@/hooks/useVW'
  58. import useVModel from '@/hooks/useVModel'
  59. import useMessageLoop from '@/hooks/useMessageLoop'
  60. import useMainStore from '@/store/main'
  61. import MessageWindow from '@/components/shared/message/MessageWindow.vue'
  62. import ConfirmButton from '@/components/common/ConfirmButton.vue'
  63. import SvgIcon from '@/components/common/SvgIcon.vue'
  64. const props = withDefaults(
  65. defineProps<{
  66. type?: 'view' | 'send'
  67. replyUserId?: number | null
  68. messageVisible?: boolean | null
  69. paperPath?: string | null
  70. }>(),
  71. { type: 'view', replyUserId: null, paperPath: null, messageVisible: false }
  72. )
  73. const MessageComponent = defineComponent({
  74. setup() {
  75. const mainStore = useMainStore()
  76. return {
  77. mainStore,
  78. }
  79. },
  80. render() {
  81. const slots = useSlots()
  82. return this.mainStore?.myUserInfo?.role === 'ADMIN' ? null : slots.default?.()
  83. },
  84. })
  85. const setMessageVisible = inject<(visible: boolean) => void>('setMessageVisible')
  86. const setReplyUserId = inject<(replyUserId: number | null) => void>('setReplyUserId')
  87. const messageIcon = ref<HTMLDivElement>()
  88. const unReadMessages = useMessageLoop()
  89. const messageWindowType = useVModel(props, 'type')
  90. const replyUserId = useVModel(props, 'replyUserId')
  91. /** 发送/查看消息Modal */
  92. const visibleMessageWindow = ref<boolean>(false)
  93. watch(
  94. () => props.messageVisible,
  95. () => {
  96. if (props.messageVisible) {
  97. visibleMessageWindow.value = true
  98. messageWindowType.value = 'send'
  99. }
  100. }
  101. )
  102. watch(visibleMessageWindow, () => {
  103. if (!visibleMessageWindow.value) {
  104. setMessageVisible?.(false)
  105. }
  106. })
  107. watch(replyUserId, () => {
  108. setReplyUserId?.(replyUserId.value)
  109. })
  110. /** 收消息 */
  111. const onReceiveMessage = () => {
  112. messageWindowType.value = 'view'
  113. visibleMessageWindow.value = true
  114. }
  115. /** 发消息 */
  116. const onSendMessage = () => {
  117. messageWindowType.value = 'send'
  118. visibleMessageWindow.value = true
  119. }
  120. </script>
  121. <style scoped lang="scss">
  122. .message-icon {
  123. display: grid;
  124. place-items: center;
  125. font-size: $LargeFont;
  126. position: relative;
  127. .un-read-num {
  128. position: absolute;
  129. width: 8px;
  130. height: 8px;
  131. right: -2px;
  132. top: -2px;
  133. border-radius: 50%;
  134. background-color: $DangerColor;
  135. }
  136. }
  137. .message-popover-content {
  138. color: $NormalColor;
  139. .title {
  140. .unread-count {
  141. font-size: $MediumFont;
  142. color: $DangerColor;
  143. margin-right: 4px;
  144. }
  145. }
  146. .message-list {
  147. border-bottom: $OnePixelLine;
  148. margin: 10px 0 40px;
  149. .message-row {
  150. padding: 10px 4px;
  151. height: 52px;
  152. font-weight: 400;
  153. border-top: $OnePixelLine;
  154. &:hover {
  155. background-color: #f5f5f5;
  156. }
  157. .message-send-user {
  158. width: 49px;
  159. margin-right: 0.5em;
  160. font-size: $SmallFont;
  161. .user-name {
  162. font-weight: 500;
  163. text-align: justify;
  164. text-align-last: justify;
  165. }
  166. .message-time {
  167. text-align: center;
  168. font-weight: 300;
  169. }
  170. }
  171. .message-content {
  172. word-break: break-all;
  173. overflow: hidden;
  174. text-overflow: ellipsis;
  175. display: -webkit-box;
  176. -webkit-line-clamp: 2;
  177. -webkit-box-orient: vertical;
  178. font-size: $SmallFont;
  179. }
  180. }
  181. }
  182. }
  183. </style>