mdm-client 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/README.md +92 -0
  2. package/index.js +35 -0
  3. package/package.json +41 -0
  4. package/src/App.vue +246 -0
  5. package/src/assets/audio/moon_light.ogg +0 -0
  6. package/src/assets/font/DINPro-Medium.otf +0 -0
  7. package/src/assets/font/FZZhengHeiS-B-GB.ttf +0 -0
  8. package/src/assets/font/PingFang Regular.otf +0 -0
  9. package/src/assets/font/SourceHanSansCN-Regular.otf +0 -0
  10. package/src/assets/image/common/add_other_icon.png +0 -0
  11. package/src/assets/image/common/bottomFrame.png +0 -0
  12. package/src/assets/image/common/broadcastOn.png +0 -0
  13. package/src/assets/image/common/broadcastTask.png +0 -0
  14. package/src/assets/image/common/call.png +0 -0
  15. package/src/assets/image/common/call_user_mic_off_icon.png +0 -0
  16. package/src/assets/image/common/call_user_mic_on_icon.png +0 -0
  17. package/src/assets/image/common/cam-off.png +0 -0
  18. package/src/assets/image/common/cam-on.png +0 -0
  19. package/src/assets/image/common/cam_off_small.png +0 -0
  20. package/src/assets/image/common/camera.png +0 -0
  21. package/src/assets/image/common/cameraBtn1.png +0 -0
  22. package/src/assets/image/common/cameraBtn2.png +0 -0
  23. package/src/assets/image/common/cameraBtn3.png +0 -0
  24. package/src/assets/image/common/cameraBtn4.png +0 -0
  25. package/src/assets/image/common/cameraBtn5.png +0 -0
  26. package/src/assets/image/common/cameraBtn6.png +0 -0
  27. package/src/assets/image/common/cameraBtn7.png +0 -0
  28. package/src/assets/image/common/cameraClose.png +0 -0
  29. package/src/assets/image/common/cameraFull.png +0 -0
  30. package/src/assets/image/common/cameraOff.png +0 -0
  31. package/src/assets/image/common/cancel_icon.png +0 -0
  32. package/src/assets/image/common/card_blue.png +0 -0
  33. package/src/assets/image/common/card_grey.png +0 -0
  34. package/src/assets/image/common/chosen_icon.png +0 -0
  35. package/src/assets/image/common/chosen_icon_slided.png +0 -0
  36. package/src/assets/image/common/custom_layout_equipment_avatar.png +0 -0
  37. package/src/assets/image/common/custom_layout_user_avatar.png +0 -0
  38. package/src/assets/image/common/default_avatar.png +0 -0
  39. package/src/assets/image/common/default_avatar_mini.png +0 -0
  40. package/src/assets/image/common/delete-number.svg +3 -0
  41. package/src/assets/image/common/deviceIcon.png +0 -0
  42. package/src/assets/image/common/fourOff.png +0 -0
  43. package/src/assets/image/common/fourOn.png +0 -0
  44. package/src/assets/image/common/group.png +0 -0
  45. package/src/assets/image/common/groupManage.png +0 -0
  46. package/src/assets/image/common/histroy_meeting_icon.png +0 -0
  47. package/src/assets/image/common/icon-device.svg +12 -0
  48. package/src/assets/image/common/icon-monitor.svg +12 -0
  49. package/src/assets/image/common/icon-/345/260/217/347/250/213/345/272/217.svg +5 -0
  50. package/src/assets/image/common/icon-/345/272/224/347/255/224.svg +5 -0
  51. package/src/assets/image/common/icon-/350/247/206/351/242/221.svg +7 -0
  52. package/src/assets/image/common/input_search_icon.png +0 -0
  53. package/src/assets/image/common/launch_icon.png +0 -0
  54. package/src/assets/image/common/layout-active1.png +0 -0
  55. package/src/assets/image/common/layout-active2.png +0 -0
  56. package/src/assets/image/common/layout1.png +0 -0
  57. package/src/assets/image/common/layout2.png +0 -0
  58. package/src/assets/image/common/loading.png +0 -0
  59. package/src/assets/image/common/login/checked_icon.png +0 -0
  60. package/src/assets/image/common/login/login_bg.png +0 -0
  61. package/src/assets/image/common/login/login_form_left_icon.png +0 -0
  62. package/src/assets/image/common/login/pwd_icon.png +0 -0
  63. package/src/assets/image/common/login/user_icon.png +0 -0
  64. package/src/assets/image/common/login/verify_icon.png +0 -0
  65. package/src/assets/image/common/logo.png +0 -0
  66. package/src/assets/image/common/ltypeOff.png +0 -0
  67. package/src/assets/image/common/ltypeOn.png +0 -0
  68. package/src/assets/image/common/manager_cam_off_icon.png +0 -0
  69. package/src/assets/image/common/manager_mic_off_icon.png +0 -0
  70. package/src/assets/image/common/map-cicle-icon.svg +6 -0
  71. package/src/assets/image/common/map-icon-search-info.svg +11 -0
  72. package/src/assets/image/common/map-location.svg +37 -0
  73. package/src/assets/image/common/map.png +0 -0
  74. package/src/assets/image/common/mic-off.png +0 -0
  75. package/src/assets/image/common/mic-on.png +0 -0
  76. package/src/assets/image/common/mic_off_small.png +0 -0
  77. package/src/assets/image/common/minum_cam_off_icon.png +0 -0
  78. package/src/assets/image/common/minum_cam_on_icon.png +0 -0
  79. package/src/assets/image/common/minum_expand_icon.png +0 -0
  80. package/src/assets/image/common/minum_mic_off_icon.png +0 -0
  81. package/src/assets/image/common/minum_mic_on_icon.png +0 -0
  82. package/src/assets/image/common/minum_reset_icon.png +0 -0
  83. package/src/assets/image/common/minum_slide_icon.png +0 -0
  84. package/src/assets/image/common/more_icon.png +0 -0
  85. package/src/assets/image/common/mute.png +0 -0
  86. package/src/assets/image/common/newFolder.png +0 -0
  87. package/src/assets/image/common/newTask.png +0 -0
  88. package/src/assets/image/common/nineOff.png +0 -0
  89. package/src/assets/image/common/nineOn.png +0 -0
  90. package/src/assets/image/common/none.png +0 -0
  91. package/src/assets/image/common/offline.png +0 -0
  92. package/src/assets/image/common/oneOff.png +0 -0
  93. package/src/assets/image/common/oneOn.png +0 -0
  94. package/src/assets/image/common/online.png +0 -0
  95. package/src/assets/image/common/output_off_small.png +0 -0
  96. package/src/assets/image/common/playOff.png +0 -0
  97. package/src/assets/image/common/playOn.png +0 -0
  98. package/src/assets/image/common/playStop.png +0 -0
  99. package/src/assets/image/common/preview_icon.png +0 -0
  100. package/src/assets/image/common/preview_meet_icon.png +0 -0
  101. package/src/assets/image/common/scan-map.png +0 -0
  102. package/src/assets/image/common/screen_blue.png +0 -0
  103. package/src/assets/image/common/screen_gray.png +0 -0
  104. package/src/assets/image/common/screen_white.png +0 -0
  105. package/src/assets/image/common/select_item_check.png +0 -0
  106. package/src/assets/image/common/select_item_checked.png +0 -0
  107. package/src/assets/image/common/selector.png +0 -0
  108. package/src/assets/image/common/selectorOn.png +0 -0
  109. package/src/assets/image/common/share_icon.png +0 -0
  110. package/src/assets/image/common/signal_good.png +0 -0
  111. package/src/assets/image/common/signal_poor.png +0 -0
  112. package/src/assets/image/common/sixteenOff.png +0 -0
  113. package/src/assets/image/common/sixteenOn.png +0 -0
  114. package/src/assets/image/common/slide-bth-expand.png +0 -0
  115. package/src/assets/image/common/slide_btn.png +0 -0
  116. package/src/assets/image/common/speak.png +0 -0
  117. package/src/assets/image/common/speakOn.png +0 -0
  118. package/src/assets/image/common/speaker-off.png +0 -0
  119. package/src/assets/image/common/speaker-on.png +0 -0
  120. package/src/assets/image/common/speaking.png +0 -0
  121. package/src/assets/image/common/speed-left.svg +5 -0
  122. package/src/assets/image/common/speed-right.svg +5 -0
  123. package/src/assets/image/common/tree_checked_icon.png +0 -0
  124. package/src/assets/image/common/tree_expand_icon.png +0 -0
  125. package/src/assets/image/common/tree_slide_icon.png +0 -0
  126. package/src/assets/image/common/tree_uncheck_icon.png +0 -0
  127. package/src/assets/image/common/unchosen_icon.png +0 -0
  128. package/src/assets/image/common/up.png +0 -0
  129. package/src/assets/image/common/volume.png +0 -0
  130. package/src/assets/image/common/warning.png +0 -0
  131. package/src/assets/image/screenBlue/a1.png +0 -0
  132. package/src/assets/image/screenBlue/a2.png +0 -0
  133. package/src/assets/image/screenBlue/a3.png +0 -0
  134. package/src/assets/image/screenBlue/a4.png +0 -0
  135. package/src/assets/image/screenBlue/a5.png +0 -0
  136. package/src/assets/image/screenBlue/a6.png +0 -0
  137. package/src/assets/image/screenBlue/add.png +0 -0
  138. package/src/assets/image/screenBlue/add_group_icon.png +0 -0
  139. package/src/assets/image/screenBlue/add_to_group_icon.png +0 -0
  140. package/src/assets/image/screenBlue/arrow_icon.png +0 -0
  141. package/src/assets/image/screenBlue/audio_level_icon.png +0 -0
  142. package/src/assets/image/screenBlue/b1.png +0 -0
  143. package/src/assets/image/screenBlue/b2.png +0 -0
  144. package/src/assets/image/screenBlue/b3.png +0 -0
  145. package/src/assets/image/screenBlue/b4.png +0 -0
  146. package/src/assets/image/screenBlue/b5.png +0 -0
  147. package/src/assets/image/screenBlue/b6.png +0 -0
  148. package/src/assets/image/screenBlue/bottom_footer_bg.png +0 -0
  149. package/src/assets/image/screenBlue/call_clear_icon.png +0 -0
  150. package/src/assets/image/screenBlue/call_duration_icon.png +0 -0
  151. package/src/assets/image/screenBlue/call_fullscreen_icon.png +0 -0
  152. package/src/assets/image/screenBlue/call_mini_icon.png +0 -0
  153. package/src/assets/image/screenBlue/call_video_icon.png +0 -0
  154. package/src/assets/image/screenBlue/call_voice_icon.png +0 -0
  155. package/src/assets/image/screenBlue/cam_on_small.png +0 -0
  156. package/src/assets/image/screenBlue/close_icon.png +0 -0
  157. package/src/assets/image/screenBlue/copy-icon.png +0 -0
  158. package/src/assets/image/screenBlue/custom_layout_drag_icon.png +0 -0
  159. package/src/assets/image/screenBlue/custom_layout_grid16_active_icon.png +0 -0
  160. package/src/assets/image/screenBlue/custom_layout_grid16_icon.png +0 -0
  161. package/src/assets/image/screenBlue/custom_layout_grid4_active_icon.png +0 -0
  162. package/src/assets/image/screenBlue/custom_layout_grid4_icon.png +0 -0
  163. package/src/assets/image/screenBlue/custom_layout_grid9_active_icon.png +0 -0
  164. package/src/assets/image/screenBlue/custom_layout_grid9_icon.png +0 -0
  165. package/src/assets/image/screenBlue/custom_layout_header_icon.png +0 -0
  166. package/src/assets/image/screenBlue/custom_layout_placeholder_bg.png +0 -0
  167. package/src/assets/image/screenBlue/custom_layout_refresh_icon.png +0 -0
  168. package/src/assets/image/screenBlue/custom_layout_rightside_active_icon.png +0 -0
  169. package/src/assets/image/screenBlue/custom_layout_rightside_icon.png +0 -0
  170. package/src/assets/image/screenBlue/custom_layout_ring_active_icon.png +0 -0
  171. package/src/assets/image/screenBlue/custom_layout_ring_icon.png +0 -0
  172. package/src/assets/image/screenBlue/custom_layout_topside_active_icon.png +0 -0
  173. package/src/assets/image/screenBlue/custom_layout_topside_icon.png +0 -0
  174. package/src/assets/image/screenBlue/date_picker_icon.png +0 -0
  175. package/src/assets/image/screenBlue/dialog_check_icon.png +0 -0
  176. package/src/assets/image/screenBlue/emoji-logo.png +0 -0
  177. package/src/assets/image/screenBlue/header_alert_icon.png +0 -0
  178. package/src/assets/image/screenBlue/manager_cam_on_icon.png +0 -0
  179. package/src/assets/image/screenBlue/manager_mic_on_icon.png +0 -0
  180. package/src/assets/image/screenBlue/manager_more_icon.png +0 -0
  181. package/src/assets/image/screenBlue/meeting_board_bg.png +0 -0
  182. package/src/assets/image/screenBlue/meeting_chat_emoji_icon.png +0 -0
  183. package/src/assets/image/screenBlue/meeting_chat_icon.png +0 -0
  184. package/src/assets/image/screenBlue/meeting_chat_image_icon.png +0 -0
  185. package/src/assets/image/screenBlue/meeting_chat_logo.png +0 -0
  186. package/src/assets/image/screenBlue/meeting_copy_icon.png +0 -0
  187. package/src/assets/image/screenBlue/meeting_invite_icon.png +0 -0
  188. package/src/assets/image/screenBlue/meeting_layout_icon.png +0 -0
  189. package/src/assets/image/screenBlue/meeting_member_icon.png +0 -0
  190. package/src/assets/image/screenBlue/meeting_mode_icon.png +0 -0
  191. package/src/assets/image/screenBlue/meeting_record_icon.png +0 -0
  192. package/src/assets/image/screenBlue/meeting_setting_icon.png +0 -0
  193. package/src/assets/image/screenBlue/meeting_share_icon.png +0 -0
  194. package/src/assets/image/screenBlue/meeting_slide_small_icon.png +0 -0
  195. package/src/assets/image/screenBlue/mic_on_small.png +0 -0
  196. package/src/assets/image/screenBlue/module_bg1.png +0 -0
  197. package/src/assets/image/screenBlue/module_bg2.png +0 -0
  198. package/src/assets/image/screenBlue/monitor/circle data.png +0 -0
  199. package/src/assets/image/screenBlue/monitor/circle.png +0 -0
  200. package/src/assets/image/screenBlue/output_on_small.png +0 -0
  201. package/src/assets/image/screenBlue/page_bg.png +0 -0
  202. package/src/assets/image/screenBlue/pic-logo.png +0 -0
  203. package/src/assets/image/screenBlue/preview_date_icon.png +0 -0
  204. package/src/assets/image/screenBlue/preview_empty_icon.png +0 -0
  205. package/src/assets/image/screenBlue/preview_more_icon.png +0 -0
  206. package/src/assets/image/screenBlue/receive_hang_off_icon.png +0 -0
  207. package/src/assets/image/screenBlue/receive_hang_on_icon.png +0 -0
  208. package/src/assets/image/screenBlue/receive_video_icon.png +0 -0
  209. package/src/assets/image/screenBlue/receive_voice_icon.png +0 -0
  210. package/src/assets/image/screenBlue/send-logo.png +0 -0
  211. package/src/assets/image/screenBlue/slide_menu_bg.png +0 -0
  212. package/src/assets/image/screenBlue/top_header_bg.png +0 -0
  213. package/src/assets/image/screenBlue/yq.png +0 -0
  214. package/src/assets/json/emoji.json +222 -0
  215. package/src/assets/style/base.scss +217 -0
  216. package/src/assets/style/elForm.scss +80 -0
  217. package/src/assets/style/font.scss +16 -0
  218. package/src/assets/style/index.scss +5 -0
  219. package/src/assets/style/math.scss +11 -0
  220. package/src/assets/style/mixin.scss +69 -0
  221. package/src/components/LiveCallBoard/LiveCallBoard.vue +237 -0
  222. package/src/components/LiveInviteReceive/LiveInviteReceive.vue +150 -0
  223. package/src/components/LiveMulti/LiveMulti.vue +303 -0
  224. package/src/components/LiveMultipleMeeting/LiveMultipleMeeting.vue +4469 -0
  225. package/src/components/LiveMultipleMeeting/style/index.scss +337 -0
  226. package/src/components/LivePoint/LivePoint.vue +372 -0
  227. package/src/components/LivePointMeeting/LivePointMeeting.vue +1134 -0
  228. package/src/components/LivePointMeeting/style/index.scss +202 -0
  229. package/src/components/MeetingReadyDialog/MeetingReadyDialog.vue +583 -0
  230. package/src/components/MiniumVideoDialog/MiniumVideoDialog.vue +449 -0
  231. package/src/components/other/LayoutPlaceholder.vue +184 -0
  232. package/src/components/other/addressBook.vue +1121 -0
  233. package/src/components/other/appointDialog.vue +208 -0
  234. package/src/components/other/callBoard.vue +191 -0
  235. package/src/components/other/chatArea.vue +727 -0
  236. package/src/components/other/customGroupDialog.vue +180 -0
  237. package/src/components/other/customLayout.vue +1112 -0
  238. package/src/components/other/editGroupDialog.vue +290 -0
  239. package/src/components/other/inviteNonContactDialog.vue +160 -0
  240. package/src/components/other/layoutSwitch.vue +183 -0
  241. package/src/components/other/leaveOptionDialog.vue +90 -0
  242. package/src/components/other/memberManage.vue +502 -0
  243. package/src/components/other/moreOptionDialog.vue +291 -0
  244. package/src/components/other/screenShareBoard.vue +121 -0
  245. package/src/components/other/selectDialog.vue +279 -0
  246. package/src/components/other/selectSpecialDialog.vue +234 -0
  247. package/src/components/other/settingDialog.vue +756 -0
  248. package/src/components/other/themeDialog.vue +180 -0
  249. package/src/components/other/updateNameDialog.vue +162 -0
  250. package/src/directive/clickOutside.js +58 -0
  251. package/src/directive/drag.js +165 -0
  252. package/src/directive/scale.js +22 -0
  253. package/src/directive/throttle.js +77 -0
  254. package/src/main.js +21 -0
  255. package/src/request/index.js +27 -0
  256. package/src/utils/api.js +82 -0
  257. package/src/utils/index.js +4 -0
  258. package/src/utils/livekit/live-client-esm-old.js +1 -0
  259. package/src/utils/livekit/live-client-esm.js +1 -0
  260. package/src/utils/message.js +24 -0
  261. package/src/utils/mitt.js +4 -0
  262. package/src/utils/tool.js +154 -0
@@ -0,0 +1,727 @@
1
+ <template>
2
+ <div class="chat">
3
+ <div class="chat-head">
4
+ <div class="chat-head-left">
5
+ <div class="logo"></div>
6
+ <div class="title">聊天</div>
7
+ </div>
8
+ <div class="close" @click="closeChatArea"></div>
9
+ </div>
10
+ <div class="chat-content" id="chat-content">
11
+ <div
12
+ :class="[
13
+ 'message-item',
14
+ item.origin === localIdentity ? 'message-item-local' : 'message-item-other',
15
+ ]"
16
+ v-for="(item, index) of messageList"
17
+ :key="'m' + index"
18
+ >
19
+ <template v-if="item.origin === localIdentity">
20
+ <div class="message-item-content">
21
+ <div class="message-item-content-top">
22
+ <span>{{ item.timestamp }}</span>
23
+ <span class="name">{{ item.fromName }}</span>
24
+ </div>
25
+ <div class="message-item-content-value">
26
+ <template v-if="typeof item.content === 'string'">
27
+ <span v-if="item.contentType == 1">{{ item.content }}</span>
28
+ <el-image v-else class="message-image" :src="item.content" :preview-src-list="item.srcList" alt="" />
29
+ </template>
30
+ <template v-else>
31
+ <div v-html="renderContentWithImages(item.content)"></div>
32
+ </template>
33
+ </div>
34
+ </div>
35
+ <div class="message-item-avatar-wrapper">
36
+ <img class="message-item-avatar" src="../../assets/image/common/default_avatar.png" alt="" />
37
+ </div>
38
+ </template>
39
+ <template v-else>
40
+ <div class="message-item-avatar-wrapper">
41
+ <img class="message-item-avatar" src="../../assets/image/common/default_avatar.png" alt="" />
42
+ </div>
43
+ <div class="message-item-content">
44
+ <div class="message-item-content-top">
45
+ <span class="name">{{ item.fromName }}</span>
46
+ <span>{{ item.timestamp }}</span>
47
+ </div>
48
+ <div class="message-item-content-value">
49
+ <template v-if="typeof item.content === 'string'">
50
+ <span v-if="item.contentType == 1">{{ item.content }}</span>
51
+ <el-image v-else class="message-image" :src="item.content" :preview-src-list="item.srcList" alt="" />
52
+ </template>
53
+ <template v-else>
54
+ <div v-html="renderContentWithImages(item.content)"></div>
55
+ </template>
56
+ </div>
57
+ </div>
58
+ </template>
59
+ </div>
60
+ </div>
61
+ <div class="chat-foot">
62
+ <div class="message-input-container">
63
+ <div class="tool-wrapper">
64
+ <div class="tool-item emoji" tabindex="0" aria-label="选择表情" @click="showEmojiPanel" @keydown.enter="handleToolKeyDown"></div>
65
+ <el-upload
66
+ ref="uploadRef"
67
+ :headers="uploadHeaders"
68
+ :action="fileUploadUrl"
69
+ :multiple="false"
70
+ :show-file-list="false"
71
+ :on-success="handleFileUploaded"
72
+ :before-upload="handleBeforeUpload"
73
+ >
74
+ <div class="tool-item image" tabindex="0" aria-label="上传图片" @keydown.enter="handleToolKeyDown"></div>
75
+ </el-upload>
76
+ </div>
77
+ <div class="message-input-content" ref="messageInputRef" contenteditable="true" @keydown.enter.prevent="handleEnterPress" @paste="handlePaste" @click="saveCurrentRange" @blur="saveCurrentRange" placeholder="按Enter发送消息"></div>
78
+ <div class="send-wrapper" v-throttle-click:500="sendMessage" @keydown.enter="handleToolKeyDown">
79
+ <div class="btn">
80
+ <div class="btn-icon send" tabindex="0" aria-label="发送消息"></div>
81
+ <span>发送</span>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ <el-popover
86
+ :value="emojiPanelVisible"
87
+ placement="top"
88
+ width="200"
89
+ trigger="manual"
90
+ popper-class="custom-popover"
91
+ @hide="emojiPanelVisible = false"
92
+ >
93
+ <div class="emotion-list">
94
+ <a
95
+ href="javascript:void(0);"
96
+ @click="insertEmojiToMessage(item)"
97
+ v-for="(item, index) in faceList"
98
+ :key="index"
99
+ class="emotion-item"
100
+ >{{ item }}</a>
101
+ </div>
102
+ <div slot="reference" class="emoji-panel-anchor"></div>
103
+ </el-popover>
104
+ </div>
105
+ </div>
106
+ </template>
107
+
108
+ <script>
109
+ import { ShowMessage } from "@/utils/index";
110
+ import emojiData from "@/assets/json/emoji.json";
111
+
112
+ export default {
113
+ name: "ChatArea",
114
+ props: {
115
+ localIdentity: {
116
+ type: String
117
+ },
118
+ messageList: {
119
+ type: Array
120
+ },
121
+ baseUrl: {
122
+ type: String,
123
+ default: "",
124
+ },
125
+ token: {
126
+ type: String,
127
+ default: "",
128
+ }
129
+ },
130
+ data() {
131
+ return {
132
+ faceList: [],
133
+ emojiPanelVisible: false,
134
+ savedRange: null,
135
+ showMessage: new ShowMessage()
136
+ };
137
+ },
138
+ computed: {
139
+ fileUploadUrl() {
140
+ return this.baseUrl + "/api/v1/common/uploadFile";
141
+ },
142
+ uploadHeaders() {
143
+ return {
144
+ satoken: this.token || ""
145
+ };
146
+ },
147
+ messageNum() {
148
+ return this.messageList.length;
149
+ }
150
+ },
151
+ watch: {
152
+ messageNum() {
153
+ this.$nextTick(() => {
154
+ this.scrollToBottom();
155
+ });
156
+ }
157
+ },
158
+ mounted() {
159
+ emojiData.forEach((emo) => {
160
+ this.faceList.push(emo.char);
161
+ });
162
+
163
+ // 给contenteditable添加placeholder效果
164
+ if (this.$refs.messageInputRef) {
165
+ this.$refs.messageInputRef.addEventListener('focus', () => {
166
+ if (this.$refs.messageInputRef.innerHTML === '') {
167
+ this.$refs.messageInputRef.removeAttribute('placeholder-active');
168
+ }
169
+ });
170
+
171
+ this.$refs.messageInputRef.addEventListener('blur', () => {
172
+ if (this.$refs.messageInputRef.innerHTML === '') {
173
+ this.$refs.messageInputRef.setAttribute('placeholder-active', true);
174
+ }
175
+ });
176
+
177
+ // 初始显示placeholder
178
+ if (this.$refs.messageInputRef.innerHTML === '') {
179
+ this.$refs.messageInputRef.setAttribute('placeholder-active', true);
180
+ }
181
+ }
182
+ },
183
+ methods: {
184
+ clearInputContent() {
185
+ if (this.$refs.messageInputRef) {
186
+ this.$refs.messageInputRef.innerHTML = "";
187
+ }
188
+ },
189
+
190
+ scrollToBottom() {
191
+ let chatContainer = document.getElementById("chat-content");
192
+ if (!chatContainer) {
193
+ console.error("不存在消息队列容器");
194
+ return;
195
+ }
196
+ chatContainer.scrollTop = chatContainer.scrollHeight + 180;
197
+ },
198
+
199
+ closeChatArea() {
200
+ this.$emit("close");
201
+ },
202
+
203
+ getMessageContent() {
204
+ if (!this.$refs.messageInputRef) return "";
205
+ return this.$refs.messageInputRef.innerHTML;
206
+ },
207
+
208
+ sendMessage() {
209
+ const messageContent = this.getMessageContent();
210
+
211
+ if (!messageContent || messageContent.trim() === "") {
212
+ this.showMessage.message("error", "不能发送空白消息");
213
+ return;
214
+ }
215
+
216
+ // 处理消息内容,可以是纯文本或包含图片的HTML
217
+ let finalContent = messageContent;
218
+
219
+ // 发送消息
220
+ this.$emit("messageSend", {
221
+ content: finalContent,
222
+ contentType: this.isImage(finalContent) ? 2 : 1
223
+ });
224
+
225
+ // 清空输入框
226
+ this.clearInputContent();
227
+ },
228
+
229
+ handleEnterPress(e) {
230
+ if (!e.shiftKey) {
231
+ e.preventDefault();
232
+ this.sendMessage();
233
+ }
234
+ },
235
+
236
+ isImage(url) {
237
+ if (typeof url !== 'string') return false;
238
+ return /\.(jpg|jpeg|png|gif|bmp)$/i.test(url);
239
+ },
240
+
241
+ renderContentWithImages(content) {
242
+ // 如果内容已经是HTML格式,则直接返回
243
+ return content;
244
+ },
245
+
246
+ // 保存当前光标位置
247
+ saveCurrentRange() {
248
+ const selection = window.getSelection();
249
+ if (selection.rangeCount > 0) {
250
+ this.savedRange = selection.getRangeAt(0);
251
+ }
252
+ },
253
+
254
+ // 恢复保存的光标位置
255
+ restoreSelection() {
256
+ if (this.savedRange) {
257
+ const selection = window.getSelection();
258
+ selection.removeAllRanges();
259
+ selection.addRange(this.savedRange);
260
+ } else if (this.$refs.messageInputRef) {
261
+ // 如果没有保存的范围,将光标放到内容的最后
262
+ this.$refs.messageInputRef.focus();
263
+ const range = document.createRange();
264
+ range.selectNodeContents(this.$refs.messageInputRef);
265
+ range.collapse(false); // 折叠到末尾
266
+ const selection = window.getSelection();
267
+ selection.removeAllRanges();
268
+ selection.addRange(range);
269
+ this.savedRange = range;
270
+ }
271
+ },
272
+
273
+ showEmojiPanel() {
274
+ // 切换表情面板
275
+ this.emojiPanelVisible = !this.emojiPanelVisible;
276
+ },
277
+
278
+ insertEmojiToMessage(emoji) {
279
+ // 恢复光标位置
280
+ this.restoreSelection();
281
+
282
+ if (!this.$refs.messageInputRef) return;
283
+
284
+ // 获取当前选区
285
+ const selection = window.getSelection();
286
+ const range = selection.getRangeAt(0);
287
+
288
+ // 创建包含表情的文本节点
289
+ const textNode = document.createTextNode(emoji);
290
+
291
+ // 在选中位置插入表情
292
+ range.deleteContents();
293
+ range.insertNode(textNode);
294
+
295
+ // 将光标移到插入表情后的位置
296
+ range.setStartAfter(textNode);
297
+ range.setEndAfter(textNode);
298
+ selection.removeAllRanges();
299
+ selection.addRange(range);
300
+
301
+ // 更新保存的范围
302
+ this.savedRange = range;
303
+
304
+ // 聚焦输入框
305
+ this.$refs.messageInputRef.focus();
306
+
307
+ // 关闭表情面板
308
+ this.emojiPanelVisible = false;
309
+ },
310
+
311
+ handleFileUploaded(response) {
312
+ console.log('fileUploaded', response);
313
+ if(response.code == 200) {
314
+ const url = `${this.baseUrl}/api/v1/common/reviewFile/${response.data.fileID}?satoken=${this.token || ""}`;
315
+ this.$emit("messageSend", {
316
+ content: url,
317
+ contentType: 2
318
+ })
319
+ console.log('imageUrl', url);
320
+
321
+ } else {
322
+ this.showMessage.message("error", "上传失败");
323
+ }
324
+ },
325
+
326
+ insertImageToMessage(imageUrl) {
327
+ // 恢复光标位置
328
+ this.restoreSelection();
329
+
330
+ if (!this.$refs.messageInputRef) return;
331
+
332
+ // 获取选中区域
333
+ const selection = window.getSelection();
334
+ const range = selection.getRangeAt(0);
335
+
336
+ // 创建图片元素
337
+ const imgElement = document.createElement('img');
338
+ imgElement.src = imageUrl;
339
+ imgElement.className = 'content-image';
340
+
341
+ // 在选中位置插入图片
342
+ range.deleteContents();
343
+ range.insertNode(imgElement);
344
+
345
+ // 将光标移到插入图片后的位置
346
+ range.setStartAfter(imgElement);
347
+ range.setEndAfter(imgElement);
348
+ selection.removeAllRanges();
349
+ selection.addRange(range);
350
+
351
+ // 更新保存的范围
352
+ this.savedRange = range;
353
+
354
+ // 聚焦输入框
355
+ this.$refs.messageInputRef.focus();
356
+ },
357
+
358
+ handleBeforeUpload(file) {
359
+ if (!this.isImage(file.name)) {
360
+ this.showMessage.message("error", "请上传图片");
361
+ return false;
362
+ } else if (file.size > 20 * 1024 * 1024) {
363
+ this.showMessage.message("error", "文件大小不得超过20M");
364
+ return false;
365
+ } else {
366
+ return true;
367
+ }
368
+ },
369
+
370
+ handlePaste(e) {
371
+ const clipboardData = e.clipboardData;
372
+ if (!clipboardData) return;
373
+
374
+ const items = clipboardData.items;
375
+ let hasImage = false;
376
+
377
+ for (let i = 0; i < items.length; i++) {
378
+ if (items[i].type.indexOf('image') !== -1) {
379
+ hasImage = true;
380
+
381
+ // 处理图片粘贴
382
+ const blob = items[i].getAsFile();
383
+ const formData = new FormData();
384
+ formData.append('file', blob);
385
+
386
+ // 上传图片
387
+ fetch(this.fileUploadUrl, {
388
+ method: 'POST',
389
+ body: formData
390
+ })
391
+ .then(response => response.json())
392
+ .then(result => {
393
+ if (result.url) {
394
+ const url = this.baseUrl + result.url.substring(result.url.indexOf("/equipmentphoto"));
395
+ this.insertImageToMessage(url);
396
+ }
397
+ })
398
+ .catch(error => {
399
+ console.error('上传粘贴的图片失败:', error);
400
+ });
401
+
402
+ e.preventDefault();
403
+ break;
404
+ }
405
+ }
406
+
407
+ // 如果没有图片,则默认行为(粘贴文本)
408
+ if (!hasImage) {
409
+ // 允许默认粘贴行为
410
+ }
411
+ },
412
+
413
+ handleToolKeyDown(e) {
414
+ if (e.key === 'Enter') {
415
+ e.currentTarget.click();
416
+ }
417
+ }
418
+ }
419
+ };
420
+ </script>
421
+
422
+ <style lang="scss" scoped>
423
+ @import "../../assets/style/mixin.scss";
424
+ .chat {
425
+ width: 347px;
426
+ height: 100%;
427
+ padding: 20px;
428
+ background: var(--dialog-bg);
429
+ box-shadow: 0px 0px 8px 0px var(--dialog-shadow-color);
430
+ border: 1px solid var(--dialog-border-color);
431
+ border-radius: 5px;
432
+ display: flex;
433
+ flex-direction: column;
434
+
435
+ &-head {
436
+ width: 100%;
437
+ height: 42px;
438
+ border-bottom: 1px solid var(--dialog-border-color);
439
+ display: flex;
440
+ align-items: center;
441
+ justify-content: space-between;
442
+ padding-top: 5px;
443
+
444
+ &-left {
445
+ display: flex;
446
+ align-items: center;
447
+ flex-wrap: nowrap;
448
+
449
+ .logo {
450
+ width: 24px;
451
+ height: 24px;
452
+ background: var(--meeting-chat-logo) no-repeat center / 100% 100%;
453
+ margin-right: 12px;
454
+ }
455
+
456
+ .title {
457
+ font-weight: 400;
458
+ font-size: 18px;
459
+ font-family: var(--title-font);
460
+ color: var(--theme-font-color);
461
+ white-space: nowrap;
462
+ }
463
+ }
464
+
465
+ .close {
466
+ cursor: pointer;
467
+ width: 16px;
468
+ height: 16px;
469
+ background: var(--close-icon) no-repeat center / 100% 100%;
470
+ }
471
+ }
472
+
473
+ &-content {
474
+ padding-top: 20px;
475
+ width: 100%;
476
+ flex: 1;
477
+ max-height: 100%;
478
+ overflow-y: auto;
479
+
480
+ &::-webkit-scrollbar {
481
+ width: 2px;
482
+ }
483
+
484
+ &::-webkit-scrollbar-thumb {
485
+ border-radius: 2px;
486
+ background-color: rgba(0, 0, 0, 0.25);
487
+ }
488
+
489
+ &::-webkit-scrollbar-track {
490
+ box-shadow: none !important;
491
+ background: transparent !important;
492
+ border-radius: 5px;
493
+ }
494
+
495
+ .message-item {
496
+ width: 100%;
497
+ display: flex;
498
+ align-items: flex-start;
499
+ margin-bottom: 20px;
500
+ &-avatar-wrapper {
501
+ padding-top: 10px;
502
+ }
503
+ &-avatar {
504
+ width: 32px;
505
+ height: 32px;
506
+ }
507
+
508
+ &-content {
509
+ width: calc(100% - 80px);
510
+ display: flex;
511
+ flex-direction: column;
512
+
513
+ &-top {
514
+ display: flex;
515
+ flex-wrap: nowrap;
516
+ align-items: center;
517
+ font-weight: 400;
518
+ font-size: 14px;
519
+ color: var(--meeting-chat-font-color);
520
+ margin-bottom: 1px;
521
+
522
+ span {
523
+ white-space: nowrap;
524
+ line-height: 20px;
525
+ }
526
+
527
+ .name {
528
+ max-width: 126px;
529
+ overflow: hidden;
530
+ text-overflow: ellipsis;
531
+ display: inline-block;
532
+ }
533
+ }
534
+
535
+ &-value {
536
+ border-radius: 6px;
537
+ padding: 4px 10px;
538
+ font-weight: 400;
539
+ font-size: 16px;
540
+ line-height: 23px;
541
+ color: var(--theme-font-color);
542
+ word-break: break-all;
543
+ max-width: 100%;
544
+
545
+ .message-image, :deep(.content-image) {
546
+ max-width: 100%;
547
+ margin: 4px 0;
548
+ border-radius: 4px;
549
+ }
550
+ }
551
+ }
552
+
553
+ &-local {
554
+ justify-content: flex-end;
555
+ .message-item-avatar {
556
+ margin-left: 10px;
557
+ }
558
+
559
+ .message-item-content {
560
+ align-items: flex-end;
561
+
562
+ &-top {
563
+ justify-content: flex-end;
564
+ .name {
565
+ margin-left: 12px;
566
+ }
567
+ }
568
+
569
+ &-value {
570
+ color: var(--theme-font-color);
571
+ background: var(--meeting-chat-local-bg);
572
+ }
573
+ }
574
+ }
575
+
576
+ &-other {
577
+ justify-content: flex-start;
578
+
579
+ .message-item-avatar {
580
+ margin-right: 10px;
581
+ }
582
+
583
+ .message-item-content {
584
+ align-items: flex-start;
585
+ &-top {
586
+ justify-content: flex-start;
587
+ .name {
588
+ margin-right: 12px;
589
+ }
590
+ }
591
+ &-value {
592
+ background: var(--meeting-chat-remote-bg);
593
+ color: var(--theme-font-color);
594
+ }
595
+ }
596
+ }
597
+ }
598
+ }
599
+
600
+ &-foot {
601
+ width: 100%;
602
+ margin-top: 12px;
603
+ position: relative;
604
+
605
+ .message-input-container {
606
+ background: var(--meeting-chat-input-bg);
607
+ border-radius: 8px;
608
+ display: flex;
609
+ flex-direction: column;
610
+ border: 1px solid var(--dialog-border-color);
611
+ padding: 10px;
612
+
613
+ .tool-wrapper {
614
+ display: flex;
615
+ align-items: center;
616
+ gap: 16px;
617
+ margin-bottom: 12px;
618
+ }
619
+
620
+ .message-input-content {
621
+ min-height: 48px;
622
+ max-height: 96px;
623
+ overflow-y: auto;
624
+ color: var(--theme-font-color);
625
+ font-size: 14px;
626
+ line-height: 24px;
627
+ outline: none;
628
+ word-break: break-all;
629
+
630
+ &:empty:before {
631
+ content: attr(placeholder);
632
+ color: var(--meeting-chat-font-color);
633
+ font-weight: 400;
634
+ }
635
+
636
+ &[placeholder-active="true"]:empty:before {
637
+ content: attr(placeholder);
638
+ color: var(--meeting-chat-font-color);
639
+ font-weight: 400;
640
+ }
641
+
642
+ .content-image {
643
+ max-width: 100px;
644
+ max-height: 100px;
645
+ vertical-align: middle;
646
+ margin: 2px;
647
+ }
648
+ }
649
+
650
+ .send-wrapper {
651
+ display: flex;
652
+ justify-content: flex-end;
653
+ align-items: center;
654
+ font-weight: 400;
655
+ font-size: 14px;
656
+ color: var(--theme-font-color);
657
+ font-family: var(--main-font);
658
+ .btn {
659
+ width: 74px;
660
+ height: 28px;
661
+ @include button;
662
+ @include btnPrimary;
663
+ border-radius: 14px !important;
664
+ &-icon {
665
+ margin-right: 6px !important;
666
+ }
667
+ .send {
668
+ background: url("../../assets/image/screenBlue/send-logo.png") no-repeat center / 100% 100%;
669
+ }
670
+ }
671
+ }
672
+
673
+ .tool-item {
674
+ cursor: pointer;
675
+ width: 16px;
676
+ height: 16px;
677
+ transition: opacity 0.2s;
678
+
679
+ &:hover {
680
+ opacity: 0.8;
681
+ }
682
+
683
+ &.emoji {
684
+ background: var(--meeting-chat-emoji-icon) no-repeat center / 100% 100%;
685
+ }
686
+
687
+ &.image {
688
+ background: var(--meeting-chat-image-icon) no-repeat center / 100% 100%;
689
+ }
690
+
691
+ }
692
+ }
693
+
694
+ .emoji-panel-anchor {
695
+ position: absolute;
696
+ width: 1px;
697
+ height: 1px;
698
+ top: 10px;
699
+ left: 20px;
700
+ opacity: 0;
701
+ }
702
+
703
+ .emotion-list {
704
+ display: flex;
705
+ flex-wrap: wrap;
706
+ padding: 10px;
707
+
708
+ .emotion-item {
709
+ width: 20px;
710
+ font-size: 18px;
711
+ text-align: center;
712
+ line-height: 20px;
713
+ }
714
+ }
715
+ }
716
+ }
717
+
718
+ :deep(.el-upload) {
719
+ display: block;
720
+ }
721
+
722
+ :deep(.custom-popover) {
723
+ background-color: #252e3d;
724
+ border: 1px solid var(--dialog-border-color);
725
+ }
726
+ </style>
727
+