index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. <script>
  2. export default {
  3. name: "index",
  4. };
  5. </script>
  6. <script setup>
  7. import { ref, reactive, toRaw, toRefs, nextTick, computed, watchEffect } from "vue";
  8. import { useRouter, useRoute } from "vue-router";
  9. import useUserStore from "@/store/modules/user";
  10. import word from "@/assets/images/word2.png";
  11. import chat from "@/assets/images/profile.png";
  12. import cebian from "@/assets/images/cebian.png";
  13. import send from "@/assets/images/send.png";
  14. import downFile from "@/assets/images/down-file.png";
  15. import forwardFile from "@/assets/images/forward-file.png";
  16. import sendFile from "@/assets/images/send-file.png";
  17. import { parseTime } from "@/utils/ruoyi";
  18. import store from "@/store";
  19. import {
  20. msgFriend,
  21. userTree,
  22. userInfo,
  23. msgSend,
  24. msgRecord,
  25. delMsg,
  26. dirTree,
  27. fileTree,
  28. spaceInfo,
  29. fileDownload,
  30. } from "@/api/chat/msg";
  31. import Addperson from "@/components/AddPerson/index.vue"; //添加人员的弹框
  32. import FileTreeChoice from "@/components/FileTreeChoice/index.vue"; //选择文件发送的列表
  33. import forwordTree from "@/components/forwordTree/index.vue"; //选择文件发送的列表
  34. //websocket连接====
  35. import useWebsoctStore from "@/store/modules/websocket";
  36. import { ElMessage } from "element-plus";
  37. const route = useRoute();
  38. const websoctStore = useWebsoctStore();
  39. //====
  40. const { proxy } = getCurrentInstance();
  41. const userIds = useUserStore();
  42. const height = ref(document.documentElement.clientHeight - 74 + "px;");
  43. const messageText = ref(""); //发送的内容
  44. const headerName = ref("");
  45. const total = ref(0);
  46. const sendId = ref(""); //选择发送的文件id
  47. const isForward = ref(false);
  48. const openFile = ref(false); //文件目录
  49. const openForwardFile = ref(false); //转发目录
  50. const showCircel = ref(""); //是否 显示圆点
  51. const chatRecords = reactive({ data: [] });
  52. const loading = ref(false);
  53. const wangzhi=import.meta.env.VITE_APP_BASE_API
  54. const sendCont = reactive({
  55. //发送聊天内容数据组装
  56. data: {
  57. content: "",
  58. fileList: [],
  59. toId: 0,
  60. msgType: "",
  61. },
  62. });
  63. const searchText = ref(""); //搜
  64. const searchData = ref([]);
  65. //聊天列表数据模拟
  66. const personList = reactive({ data: [] });
  67. //获取好友列表
  68. const getMsgList = async () => {
  69. const resFriend = await msgFriend();
  70. personList.data = resFriend.rows;
  71. // .filter(
  72. // (item) => item.toId !== useUserStore().uid
  73. // );
  74. searchData.value = personList.data;
  75. //圆点======
  76. searchData.value.map((i) => {
  77. if (i.fromId == websoctStore.messOne?.fromId) {
  78. i.showCircel = true;
  79. }
  80. });
  81. //圆点======
  82. sendCont.data.toId =
  83. personList.data[0]?.toId == userIds.uid
  84. ? personList.data[0].fromId
  85. : personList.data[0].toId;
  86. headerName.value =
  87. personList.data[0]?.toId == userIds.uid
  88. ? personList.data[0].fromName
  89. : personList.data[0].toName;
  90. if (sendCont.data.toId) {
  91. //调用聊天记录
  92. msgRecordEvent(sendCont.data.toId);
  93. }
  94. };
  95. const noMes = ref(false);
  96. const boottmScroll = () => {
  97. //发送消息后滚动到最底部显示最新消息
  98. const chatContainer = document.querySelector(".right-container");
  99. // 计算滚动的目标位置
  100. const targetScrollTop = chatContainer.scrollHeight;
  101. // 设置滚动位置
  102. nextTick(() => {
  103. chatContainer.scrollTop = targetScrollTop;
  104. });
  105. };
  106. //获取用户的聊天记录
  107. const msgRecordEvent = async (toIdValue) => {
  108. const queryParams = {
  109. pageNum: 1,
  110. pageSize: 10,
  111. };
  112. const resMsgData = await msgRecord(toIdValue, queryParams);
  113. resMsgData.rows.map((i) => (i.isForward = false));
  114. chatRecords.data = resMsgData.rows.reverse();
  115. const PageNum = Math.ceil(chatRecords.data.length / 10) + 1;
  116. if (PageNum * 10 >= resMsgData.total && !noMes.value) {
  117. loading.value = false;
  118. noMes.value = true;
  119. }
  120. const nowtime = parseTime(new Date().getTime(), "{y}-{m}-{d}");
  121. chatRecords.data.map((i) => {
  122. if (nowtime == i.createTime.substr(0, 10))
  123. i.createTime = i.createTime.substring(11);
  124. });
  125. total.value = resMsgData.total;
  126. boottmScroll();
  127. };
  128. //点击左侧新建聊天
  129. const open = ref(false);
  130. const userTreeData = reactive({ data: [] });
  131. const clickNewPerson = async () => {
  132. const res = await userTree();
  133. userTreeData.data = res;
  134. toRaw(userTreeData.data);
  135. open.value = true;
  136. };
  137. //点击左侧聊天列表
  138. const clickPersonIndex = ref("");
  139. const clickPerson = (index, item) => {
  140. sendCont.data.toId = item.userId
  141. ? item.userId
  142. : item.toId == userIds.uid
  143. ? item.fromId
  144. : item.toId;
  145. headerName.value = item.nickName
  146. ? item.nickName
  147. : item.toId == userIds.uid
  148. ? item.fromName
  149. : item.toName;
  150. noMes.value = false;
  151. clickPersonIndex.value = index;
  152. //点击某个人就不显示红点
  153. searchData.value.map((i) => {
  154. if (i.fromId == item.fromId) {
  155. i.showCircel = false;
  156. }
  157. });
  158. const chatContainer = document.querySelector(".right-container");
  159. // 计算滚动的目标位置
  160. const targetScrollTop = chatContainer.scrollHeight;
  161. // 设置滚动位置
  162. chatContainer.scrollTop = targetScrollTop;
  163. msgRecordEvent(sendCont.data.toId);
  164. };
  165. //删除聊天
  166. const delClick = (msgId) => {
  167. proxy.$modal
  168. .confirm("删除后,将清空该聊天的消息记录")
  169. .then(function () {
  170. return delMsg(msgId);
  171. })
  172. .then(() => {
  173. getMsgList();
  174. proxy.$modal.msgSuccess("删除成功");
  175. });
  176. };
  177. //树选中的人传过来的选中人的信息,push进入列表中
  178. const changeMsg = async (val) => {
  179. const resInfo = await userInfo(val.id);
  180. if (searchData.value.length > 0) {
  181. //判断是否有相同的聊天人
  182. const filerData = searchData.value.filter(
  183. (vPerson) =>
  184. (vPerson.toId && vPerson.toId == resInfo.userId) ||
  185. (vPerson.userId && vPerson.userId == resInfo.userId)
  186. );
  187. if (filerData.length > 0) {
  188. return ElMessage({ message: "该聊天已存在", type: "error" });
  189. } else {
  190. searchData.value.unshift(resInfo);
  191. }
  192. } else {
  193. //为空数组的时候无需判断
  194. searchData.value.unshift(resInfo);
  195. }
  196. sendCont.data.toId = resInfo.userId;
  197. msgRecordEvent(sendCont.data.toId);
  198. headerName.value = resInfo.nickName;
  199. };
  200. //发送聊天
  201. const inputRef = ref(null);
  202. const msgSendClick = (event) => {
  203. if (event.ctrlKey && event.keyCode == 13) {
  204. //CTRL+enter键换行
  205. const textarea = event.target;
  206. const start = textarea.selectionStart;
  207. const end = textarea.selectionEnd;
  208. const text = messageText.value;
  209. messageText.value = text.slice(0, start) + "\n" + text.slice(end);
  210. nextTick(() => {
  211. textarea.selectionStart = start + 1;
  212. textarea.selectionEnd = start + 1;
  213. });
  214. event.preventDefault();
  215. } else if (event.shiftKey && event.keyCode == 13) {
  216. event.preventDefault();
  217. } else {
  218. noMes.value = false;
  219. if (messageText.value.trim() == "") {
  220. return ElMessage({ message: "不能发送空白消息", type: "error" });
  221. }
  222. const message = {
  223. content: messageText.value,
  224. msgType: "2",
  225. fileList: [],
  226. toId: sendCont.data.toId,
  227. };
  228. websoctStore.sendMessage(message);
  229. boottmScroll();
  230. event.preventDefault();
  231. messageText.value = "";
  232. // 将光标设置到输入框第一行
  233. }
  234. };
  235. //发送文件确认按钮
  236. const fileChangeMsg = async (val) => {
  237. const message = {
  238. content: val.id,
  239. msgType: "1",
  240. fileList: [],
  241. toId: sendCont.data.toId,
  242. };
  243. sendId.value = val.id;
  244. websoctStore.sendMessage(message);
  245. };
  246. const getNewMsgList=async ()=>{
  247. const resFriend = await msgFriend();
  248. personList.data = resFriend.rows;
  249. //圆点======
  250. searchData.value.map((i) => {
  251. personList.data.map((v)=>{
  252. if (v.fromId == websoctStore.messOne?.fromId) {
  253. v.showCircel = true;
  254. }
  255. if(i.msgId==v.msgId){
  256. i=v
  257. }
  258. })
  259. });
  260. console.log('searchData.value', searchData.value)
  261. }
  262. //点击发送文件图标
  263. const fileUserTreeData = reactive({ data: {} });
  264. const sendFileClick = async () => {
  265. const resDir = await fileTree(3);
  266. fileUserTreeData.data = resDir;
  267. toRaw(fileUserTreeData.data);
  268. openFile.value = true;
  269. };
  270. //获取用户聊天记录
  271. const handleNewMessage = async () => {
  272. if (websoctStore.newMessage) {
  273. msgRecordEvent(sendCont.data.toId); //获取用户的聊天记录
  274. getNewMsgList();
  275. websoctStore.newMessage = false; // 重置新消息标记
  276. }
  277. };
  278. watchEffect(() => {
  279. if (websoctStore.messOne?.fromId) {
  280. msgRecordEvent(websoctStore.messOne.fromId);
  281. getNewMsgList();
  282. }
  283. });
  284. // 滚动翻页========
  285. const mainContainer = ref(null);
  286. const handleScroll = (event) => {
  287. // 在滚动到顶部时,加载上一页的聊天记录
  288. const mainContainer2 = document.querySelector(".right-container");
  289. if (
  290. event.deltaY < 0 &&
  291. mainContainer2.scrollTop <= 1 &&
  292. !noMes.value &&
  293. !loading.value
  294. ) {
  295. loading.value = true;
  296. loadPreviousPage();
  297. }
  298. };
  299. const loadPreviousPage = async () => {
  300. const currentPageNum = Math.ceil(chatRecords.data.length / 10) + 1;
  301. const queryParams = {
  302. pageNum: currentPageNum,
  303. pageSize: 10,
  304. };
  305. // setTimeout(async () => {
  306. const resMsgData = await msgRecord(sendCont.data.toId, queryParams);
  307. const previousPageData = resMsgData.rows.reverse();
  308. chatRecords.data = [...previousPageData, ...chatRecords.data];
  309. const nowtime2 = parseTime(new Date().getTime(), "{y}-{m}-{d}");
  310. chatRecords.data.map((i) => {
  311. if (nowtime2 == i.createTime.substr(0, 10))
  312. i.createTime = i.createTime.substring(11);
  313. });
  314. noMes.value = false;
  315. if (currentPageNum * 10 >= resMsgData.total && !noMes.value) {
  316. loading.value = false;
  317. noMes.value = true;
  318. return;
  319. }
  320. //获取数据后滚动到获得新消息的最后一条,而不是第一条=========
  321. await nextTick();
  322. const mainContainer = document.querySelector(".right-container");
  323. const newMessages = document.querySelectorAll(".message-container");
  324. const firstNewMessage = newMessages[previousPageData.length];
  325. const firstNewMessageTop = mainContainer.offsetHeight + 100;
  326. mainContainer.scrollTop = firstNewMessageTop;
  327. chatRecords.data;
  328. //===========
  329. // 将加载的上一页聊天记录插入到 chatRecords.data 的前面
  330. loading.value = false;
  331. // }, 50);
  332. };
  333. const transferFiles = (forwardVal, msgIds, indexs) => {
  334. chatRecords.data.map((i, index) => {
  335. if (i.msgId == msgIds && i.msgType == "1" && indexs == index) {
  336. i.isForward = true;
  337. } else {
  338. i.isForward = false;
  339. }
  340. });
  341. };
  342. // 点击转存
  343. const forwardTreeData = reactive({ data: {} });
  344. const spaceId = ref("");
  345. const docId = ref("");
  346. const forwardClick = async (indexs, docIds) => {
  347. docId.value = docIds ? docIds.toString() : "";
  348. const resDir = await dirTree(3);
  349. forwardTreeData.data = resDir;
  350. toRaw(forwardTreeData.data);
  351. //获取最上层树的id
  352. const topSpaceid = await spaceInfo(3);
  353. spaceId.value = topSpaceid.data.spaceId.toString();
  354. openForwardFile.value = true;
  355. };
  356. const forwardChangeMsg = async (val) => {};
  357. //点击下载
  358. const downClick = async (fileId) => {
  359. location.href = `${import.meta.env.VITE_APP_BASE_API}/api/download/${fileId}`;
  360. };
  361. //搜索的点击事件
  362. const SearchChat = () => {
  363. if (searchText.value) {
  364. searchData.value = personList.data.filter((i) => {
  365. return i.toName == searchText.value;
  366. });
  367. } else {
  368. getMsgList();
  369. }
  370. };
  371. //转聊天记录的/n为实际样式
  372. const formatText = (text) => {
  373. const formattedText = text.replace(/\n/g, "<br>");
  374. return formattedText;
  375. };
  376. // 滚动翻页========
  377. onMounted(() => {
  378. getMsgList();
  379. websoctStore.connect();
  380. setInterval(handleNewMessage, 1000); // 每秒钟检查是否有新消息
  381. });
  382. </script>
  383. <template>
  384. <div class="main" :style="'height:' + height">
  385. <!-- 左侧用户列表 -->
  386. <div class="left-main">
  387. <div class="left-top search">
  388. <el-input
  389. v-model="searchText"
  390. maxlength="32"
  391. class="w-50 m-2"
  392. size="small"
  393. clearable
  394. placeholder="搜索聊天"
  395. suffix-icon="Search"
  396. @change="SearchChat"
  397. />
  398. <!-- 添加聊天人员 -->
  399. <el-icon
  400. size="24"
  401. color="#505870"
  402. @click="clickNewPerson"
  403. style="margin-right: 8px"
  404. ><Plus
  405. /></el-icon>
  406. <!-- 新建聊天弹框 -->
  407. <Addperson
  408. :open="open"
  409. @close="open = false"
  410. :userTreeData="userTreeData.data"
  411. @changeMsg="changeMsg"
  412. ></Addperson>
  413. </div>
  414. <!-- 列表 -->
  415. <div
  416. :class="
  417. clickPersonIndex == index
  418. ? 'activ-left-container left-container'
  419. : 'left-container'
  420. "
  421. v-for="(item, index) in searchData"
  422. :key="index"
  423. @click="clickPerson(index, item)"
  424. >
  425. <img :src="cebian" class="cebian" v-if="clickPersonIndex == index" />
  426. <!-- <button
  427. class="del-chat"
  428. v-if="clickPersonIndex == index"
  429. @click="delClick(item.msgId)"
  430. >
  431. 删除聊天
  432. </button> -->
  433. <div>
  434. <!-- <img :src="item.avatar?item.avatar : chat" class="head-sculpture" /> -->
  435. <img
  436. :src="wangzhi + item.fromAvatar"
  437. class="head-sculpture"
  438. v-if="item.toId == userIds.uid && item.fromAvatar"
  439. />
  440. <img :src="item.avatar " alt="" v-else-if="item.avatar"/>
  441. <img
  442. :src="wangzhi + item.toAvatar"
  443. class="head-sculpture"
  444. v-else-if="item.toId != userIds.uid && item.toAvatar"
  445. />
  446. <span
  447. style="
  448. background-color: #7a89ba;
  449. display: inline-block;
  450. color: #fff;
  451. font-weight: 600;
  452. text-align: center;
  453. line-height: 40px;
  454. "
  455. class="head-sculpture"
  456. v-else
  457. >{{ item.nickName
  458. ? item.nickName?.slice(0, 1):item.toId == userIds.uid? item.fromName?.slice(0, 1): item.toName?.slice(0, 1) }}</span>
  459. </div>
  460. <div class="spill">
  461. <span class="person-name">{{
  462. item.nickName
  463. ? item.nickName
  464. : item.toId == userIds.uid
  465. ? item.fromName
  466. : item.toName
  467. }}</span
  468. ><span class="person-cont spill">
  469. {{ item.file?.fileName ? item.file?.fileName : item.content }}</span
  470. >
  471. </div>
  472. <span
  473. class="yuandian"
  474. v-if="item.showCircel && $route.path == '/index'"
  475. ></span>
  476. </div>
  477. </div>
  478. <!-- 右侧聊天 -->
  479. <div class="right-main">
  480. <div
  481. class="common-layout"
  482. style="display: flex; flex-direction: column; height: 100vh"
  483. >
  484. <el-container>
  485. <el-header height="64px" class="right-header flex-buju">{{
  486. headerName
  487. }}</el-header>
  488. <!-- 聊天 -->
  489. <el-main
  490. class="right-container"
  491. @mousewheel="handleScroll"
  492. ref="mainContainer"
  493. >
  494. <div v-loading="loading"></div>
  495. <!-- <div v-if="noMes" style="color:#9fa1a5 ;">无更多聊天记录</div> -->
  496. <div
  497. class="message-container"
  498. v-for="(record, index) in chatRecords.data"
  499. :class="{
  500. 'message-left': useUserStore().uid == record.toId,
  501. 'message-right': useUserStore().uid !== record.toId,
  502. }"
  503. :key="index"
  504. >
  505. <div>
  506. <div
  507. v-if="useUserStore().uid !== record.toId"
  508. style="display: flex"
  509. >
  510. <div
  511. :class="
  512. record.msgType == '1'
  513. ? 'file-msg right-back'
  514. : 'time-text right-back'
  515. "
  516. >
  517. <img
  518. :src="word"
  519. v-if="record.msgType == '1'"
  520. class="head-sculpture"
  521. />
  522. <div
  523. :class="
  524. record.msgType == '2' ? 'clip-path' : 'clip-path-right'
  525. "
  526. >
  527. <div
  528. style="
  529. color: #c1cce3;
  530. font-size: 12px;
  531. margin-bottom: 4px;
  532. "
  533. >
  534. {{ record.createTime.slice(0, -3) }}
  535. </div>
  536. <span v-if="record.msgType == '1'">{{
  537. record.file?.fileName
  538. }}</span>
  539. <!-- <span v-else-if="record.msgType == '2'">{{
  540. record.content
  541. }}</span> -->
  542. <span
  543. v-else-if="record.msgType == '2'"
  544. v-html="formatText(record.content)"
  545. ></span>
  546. </div>
  547. </div>
  548. <div>
  549. <img
  550. :src="wangzhi + record.fromAvatar"
  551. class="head-sculpture"
  552. v-if="
  553. useUserStore().uid != record.toId && record.fromAvatar
  554. "
  555. />
  556. <img
  557. :src="wangzhi + record.toAvatar"
  558. class="head-sculpture"
  559. v-else-if="
  560. useUserStore().uid == record.toId && record.toAvatar
  561. "
  562. />
  563. <span
  564. style="
  565. background-color: #7a89ba;
  566. display: inline-block;
  567. color: #fff;
  568. font-weight: 600;
  569. text-align: center;
  570. line-height: 40px;
  571. "
  572. class="head-sculpture"
  573. v-else
  574. >{{ record.fromName.slice(0, 1) }}</span
  575. >
  576. </div>
  577. </div>
  578. <!-- 头像 -->
  579. <!-- <img :src="chat" class="head-sculpture" /> -->
  580. </div>
  581. <div style="display: flex; align-items: center">
  582. <div
  583. v-if="useUserStore().uid == record.toId"
  584. style="display: flex"
  585. >
  586. <div>
  587. <img
  588. :src="wangzhi + record.fromAvatar"
  589. class="head-sculpture"
  590. v-if="
  591. useUserStore().uid == record.toId && record.fromAvatar
  592. "
  593. />
  594. <img
  595. :src="wangzhi + record.toAvatar"
  596. class="head-sculpture"
  597. v-else-if="
  598. useUserStore().uid != record.toId && record.toAvatar
  599. "
  600. />
  601. <span
  602. style="
  603. background-color: #7a89ba;
  604. display: inline-block;
  605. color: #fff;
  606. font-weight: 600;
  607. text-align: center;
  608. line-height: 40px;
  609. "
  610. class="head-sculpture"
  611. v-else
  612. >{{ record.fromName.slice(0, 1) }}</span
  613. >
  614. </div>
  615. <div
  616. :class="
  617. record.msgType == '1' ? 'file-msg left-back' : 'left-back'
  618. "
  619. @click="transferFiles(record.msgType, record.msgId, index)"
  620. >
  621. <img
  622. v-if="record.msgType == '1'"
  623. :src="word"
  624. class="head-sculpture"
  625. />
  626. <div
  627. :class="
  628. record.msgType == '2' ? 'clip-path' : 'clip-path-left'
  629. "
  630. >
  631. <div
  632. style="
  633. color: #7a89ba;
  634. font-size: 12px;
  635. margin-bottom: 4px;
  636. "
  637. >
  638. {{ record.createTime.slice(0, -3) }}
  639. </div>
  640. <span v-if="record.msgType == '1'">{{
  641. record.file?.fileName
  642. }}</span>
  643. <span
  644. v-else-if="record.msgType == '2'"
  645. v-html="formatText(record.content)"
  646. ></span>
  647. </div>
  648. </div>
  649. </div>
  650. <img
  651. :src="forwardFile"
  652. class="zhuanfa forwd"
  653. alt="转存"
  654. v-if="record.isForward"
  655. @click="forwardClick(index, record.file?.docId)"
  656. />
  657. <img
  658. :src="downFile"
  659. class="zhuanfa downf"
  660. alt="下载"
  661. v-if="record.isForward"
  662. @click="downClick(record.file.fileId)"
  663. />
  664. </div>
  665. </div>
  666. </el-main>
  667. <!-- 底部 -->
  668. <el-footer height="112px" class="right-footer">
  669. <!-- 发送文件 -->
  670. <img
  671. :src="sendFile"
  672. class="send-info-file"
  673. @click="sendFileClick"
  674. />
  675. <FileTreeChoice
  676. :openFile="openFile"
  677. @close="openFile = false"
  678. :fileUserTreeData="fileUserTreeData.data"
  679. @fileChangeMsg="fileChangeMsg"
  680. ></FileTreeChoice>
  681. <el-input
  682. v-model="messageText"
  683. class="w-50 m-2"
  684. type="textarea"
  685. :autosize="{ minRows: 3, maxRows: 5 }"
  686. clearable
  687. ref="inputRef"
  688. size="small"
  689. placeholder="请输入聊天内容"
  690. maxlength="800"
  691. @keyup.ctrl.enter="msgSendClick($event)"
  692. @keyup.shift.enter="msgSendClick($event)"
  693. @keyup.enter="msgSendClick($event)"
  694. />
  695. <!-- 发送按钮 -->
  696. <img :src="send" class="send-info" @click="msgSendClick" />
  697. </el-footer>
  698. </el-container>
  699. </div>
  700. </div>
  701. </div>
  702. <!-- 发送消息按钮选择的文件 -->
  703. <forwordTree
  704. :openForwardFile="openForwardFile"
  705. :docId="docId"
  706. :spaceId="spaceId"
  707. @close="openForwardFile = false"
  708. :forwardTreeData="forwardTreeData.data"
  709. @forwardChangeMsg="forwardChangeMsg"
  710. ></forwordTree>
  711. </template>
  712. <style lang="scss" scoped>
  713. @import "@/assets/styles/my-common.scss";
  714. .left-container {
  715. position: relative;
  716. }
  717. .yuandian {
  718. width: 8px;
  719. height: 8px;
  720. position: absolute;
  721. right: 8px;
  722. top: 6px;
  723. background: #fa5151;
  724. border-radius: 4px;
  725. }
  726. :deep(.el-textarea__inner) {
  727. resize: none;
  728. }
  729. </style>