MessageList.vue 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <template>
  2. <div class="flex radius-base overflow-hidden message-list-modal">
  3. <slot></slot>
  4. <!-- <div class="message-list p-base scroll-y-auto">
  5. <template v-if="!!(messageList || []).length">
  6. <div
  7. v-for="message in messageList"
  8. :key="message.id"
  9. class="radius-base fill-blank p-base m-b-mini relative message-item"
  10. :class="{ active: currentMessage?.sendUserId === message.sendUserId, 'un-read': message.unReadCount > 0 }"
  11. @click="checkMessage(message)"
  12. >
  13. <div class="flex items-center m-b-base message-title">
  14. <div class="message-send-user">{{ message.sendUserName }}</div>
  15. <div class="m-l-auto message-send-time">{{ dayjs(message.sendTime).format('HH:mm') }}</div>
  16. </div>
  17. <pre class="message-content">{{ transHtmlContent(message.content) }}</pre>
  18. </div>
  19. </template>
  20. <div v-else class="none-msg-box">
  21. <div class="center-box">
  22. <svg-icon name="none_message" style="font-size: 120px"></svg-icon>
  23. <p class="tip">暂无消息</p>
  24. </div>
  25. </div>
  26. </div> -->
  27. <div class="radius-base message-info-container">
  28. <div class="flex direction-column message-info">
  29. <div class="flex items-center p-base message-info-header">
  30. <div class="flex items-center send-user">
  31. <!-- <span class="m-r-mini">发件人</span> -->
  32. <span class="radius-base user-name">{{ currentMessage?.sendUserName }}</span>
  33. </div>
  34. <div class="grid pointer m-l-auto close-icon" @click="$emit('close')">
  35. <el-icon><close /></el-icon>
  36. </div>
  37. </div>
  38. <div class="flex-1 p-base">
  39. <!-- <pre
  40. class="full-h radius-base p-extra-base scroll-y-auto message-info-content"
  41. @click="onContentClick"
  42. v-html="currentMessage?.content"
  43. ></pre> -->
  44. <div ref="historyMsgWrap" class="history-box scroll-auto">
  45. <div v-for="(message, index) in historyReverse" :key="index" class="m-b-base">
  46. <div class="m-b-mini message-header">
  47. <span class="m-r-base user-name">{{ message.sendUserName }}</span>
  48. <span class="message-time">{{ message.sendTime }}</span>
  49. </div>
  50. <div class="history-message-info-content" @click="onContentClick" v-html="message.content"></div>
  51. </div>
  52. </div>
  53. </div>
  54. <div class="p-base" style="padding-top: 0">
  55. <div class="p-base radius-base overflow-hidden msg-content-box">
  56. <div style="height: calc(100% - 18px)" class="scroll-y-auto">
  57. <content-edit-able
  58. v-model="messageContent"
  59. class="full content-edit-able"
  60. @click="onContentClick"
  61. ></content-edit-able>
  62. </div>
  63. <div class="limit-tip">{{ messageContent.length }} / 2000</div>
  64. </div>
  65. </div>
  66. <div class="p-base flex items-center justify-end">
  67. <!-- <el-button size="small" type="primary" :disabled="!currentMessage" @click="onReply">回复</el-button> -->
  68. <!-- <el-button size="small" plain :disabled="!currentMessage" @click="toggleHistory">历史消息</el-button> -->
  69. <el-button size="small" type="primary" :disabled="!allowSend" :loading="sendLoading" @click="onSendMessage"
  70. >发送</el-button
  71. >
  72. </div>
  73. </div>
  74. <!-- <message-history v-if="showHistory" :send-user-id="currentMessage?.sendUserId"></message-history> -->
  75. </div>
  76. </div>
  77. <image-preview
  78. v-model="previewModalVisible"
  79. resize-key="can-resize22"
  80. :url="paperPath"
  81. :is-big="true"
  82. ></image-preview>
  83. </template>
  84. <script setup lang="ts" name="MessageList">
  85. /** 消息列表*/
  86. import { ref, watch, onUnmounted, computed, nextTick, unref } from 'vue'
  87. import { ElButton, ElIcon, ElMessage } from 'element-plus'
  88. import { Close } from '@element-plus/icons-vue'
  89. import useFetch from '@/hooks/useFetch'
  90. import MessageHistory from '@/components/shared/message/MessageHistory.vue'
  91. import ImagePreview from '../ImagePreview.vue'
  92. import useMainStore from '@/store/main'
  93. import { setLastMsgs } from '@/hooks/useMessageLoop'
  94. import bus from '@/utils/bus'
  95. import type { ExtractApiResponse } from '@/api/api'
  96. import ContentEditAble from '@/components/common/ContentEditAble.vue'
  97. type MessageType = ExtractArrayValue<ExtractApiResponse<'getMessageList'>>
  98. const historyMsgWrap = ref()
  99. const mainStore = useMainStore()
  100. const emits = defineEmits(['close', 'change-type', 'reply'])
  101. const { fetch: getMessageHistory, result: history, loading } = useFetch('getMessageHistory')
  102. const historyReverse = computed(() => {
  103. return ((history.value as any) || []).reverse()
  104. })
  105. /** 图片预览 */
  106. const previewModalVisible = ref<boolean>(false)
  107. /** 消息内容 */
  108. const messageContent = ref<string>('')
  109. /** 图片路径 */
  110. const paperPath = ref<string>('')
  111. const showHistory = ref<boolean>(false)
  112. const { fetch: getMessageList, result: messageList } = useFetch('getMessageList')
  113. const currentMessage = ref<MessageType>()
  114. function scrollToBottom() {
  115. let scrollHeight = historyMsgWrap.value.scrollHeight
  116. if (scrollHeight > 200) {
  117. historyMsgWrap.value.scrollTop = scrollHeight - 200 + 100
  118. }
  119. }
  120. watch(historyReverse, (newVal: any, oldVal: any) => {
  121. let oldV = unref(oldVal)
  122. if ((oldV || []).length == 0) {
  123. nextTick(() => {
  124. scrollToBottom()
  125. })
  126. }
  127. })
  128. watch(currentMessage, (newVal: any, oldVal: any) => {
  129. if (currentMessage.value) {
  130. useFetch('handleReadMessage')
  131. .fetch({ id: currentMessage.value.id })
  132. .then(() => {
  133. if (currentMessage.value?.unReadCount) {
  134. // currentMessage.value.unReadCount--
  135. currentMessage.value.unReadCount = 0
  136. }
  137. if (currentMessage.value?.sendUserId) {
  138. getMessageHistory({ sendUserId: currentMessage.value.sendUserId }).then(() => {
  139. let newV = unref(newVal)
  140. let oldV = unref(oldVal)
  141. if (newV.id != oldV.id) {
  142. setTimeout(scrollToBottom, 1)
  143. }
  144. })
  145. }
  146. })
  147. }
  148. })
  149. const allowSend = computed<boolean>(() => {
  150. return !!(messageContent.value && currentMessage.value?.sendUserId)
  151. })
  152. const { fetch: sendMessage, loading: sendLoading } = useFetch('sendMessage')
  153. /** 发送消息 */
  154. const onSendMessage = async () => {
  155. try {
  156. if (messageContent.value.length > 2000) {
  157. return ElMessage.error('输入内容过长')
  158. }
  159. await sendMessage({
  160. content: messageContent.value,
  161. receiveUserIds: [currentMessage.value?.sendUserId as number],
  162. })
  163. ElMessage.success('发送成功')
  164. messageContent.value = ''
  165. if (currentMessage.value?.sendUserId) {
  166. getMessageHistory({ sendUserId: currentMessage.value.sendUserId }).then(() => {
  167. setTimeout(scrollToBottom, 1)
  168. })
  169. }
  170. // emit('close')
  171. } catch (error) {
  172. console.error(error)
  173. }
  174. }
  175. // const checkMessage = (message: MessageType) => {
  176. // currentMessage.value = message
  177. // }
  178. bus.on('clickChangeMsg', (msg: any) => {
  179. currentMessage.value = msg
  180. })
  181. const toggleHistory = () => {
  182. showHistory.value = !showHistory.value
  183. }
  184. const onReply = () => {
  185. if (currentMessage.value) {
  186. emits('change-type', 'send')
  187. emits('reply', currentMessage.value.sendUserId, currentMessage.value.sendUserName)
  188. }
  189. }
  190. const onContentClick = (e: Event) => {
  191. const target = e.target as HTMLButtonElement
  192. const path = target.getAttribute('data-path')
  193. if (path) {
  194. previewModalVisible.value = true
  195. paperPath.value = path
  196. }
  197. }
  198. // getMessageList().then((result) => {
  199. // currentMessage.value = result?.[0]
  200. // if (result[0]) {
  201. // bus.emit('getCurMsg', result[0])
  202. // }
  203. // })
  204. // watch(
  205. // () => mainStore.newMsgs,
  206. // () => {
  207. // getMessageList().then((res) => {
  208. // if (res && Array.isArray(res)) {
  209. // let find = res.find((item) => item.sendUserId == currentMessage.value?.sendUserId)
  210. // if (!!find) {
  211. // currentMessage.value = find
  212. // }
  213. // }
  214. // })
  215. // }
  216. // )
  217. onUnmounted(() => {
  218. useFetch('getUnReadMessage')
  219. .fetch()
  220. .then((res) => {
  221. setLastMsgs(res)
  222. })
  223. })
  224. </script>
  225. <style scoped lang="scss">
  226. .message-list-modal {
  227. width: 750px;
  228. background-color: transparent;
  229. border-top-left-radius: 0;
  230. border-bottom-left-radius: 0;
  231. .message-info-container {
  232. // width: 600px;
  233. width: calc(100% - 260px);
  234. position: relative;
  235. .history-box {
  236. height: 200px;
  237. border: 1px solid #eee;
  238. border-radius: 4px;
  239. padding: 15px;
  240. .message-header {
  241. color: $color--primary;
  242. }
  243. .history-message-info-content {
  244. white-space: pre-wrap;
  245. }
  246. }
  247. .msg-content-box {
  248. height: 100px;
  249. font-size: 12px;
  250. border: 1px solid #0091ff;
  251. .limit-tip {
  252. text-align: right;
  253. height: 18px;
  254. padding-top: 5px;
  255. }
  256. }
  257. .message-info {
  258. height: 446px;
  259. background-color: $color--white;
  260. .message-info-header {
  261. border-bottom: $OnePixelLine;
  262. .send-user {
  263. font-size: $SmallFont;
  264. color: $RegularFontColor;
  265. .user-name {
  266. display: inline-block;
  267. width: 160px;
  268. padding: 0 12px;
  269. border: $OnePixelLine;
  270. height: 38px;
  271. line-height: 36px;
  272. }
  273. }
  274. .close-icon {
  275. width: 20px;
  276. height: 20px;
  277. place-items: center;
  278. font-size: 18px;
  279. color: $RegularFontColor;
  280. &:hover {
  281. color: $NormalColor;
  282. }
  283. }
  284. }
  285. .message-info-content {
  286. border: $OnePixelLine;
  287. font-size: $SmallFont;
  288. white-space: pre-wrap;
  289. }
  290. }
  291. }
  292. }
  293. </style>