detail.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936
  1. <template>
  2. <view class="page-session" :style="{
  3. height,
  4. }" @touchmove="onTouchMove">
  5. <view class="header">
  6. <cl-topbar color="#ffffff" backgroundColor="transparent">
  7. <view class="cl-topbar__text" @click="toDetail()">
  8. <text class="cl-topbar__title">{{nickName}}</text>
  9. </view>
  10. <template slot="append">
  11. <template v-if="conversationType=='GROUP'">
  12. <image class="member-icon" src="../../static/sms/group_more.png" @tap="member"></image>
  13. </template>
  14. <template v-else>
  15. <view class="cl-topbar__icon" @tap="report">
  16. 举报
  17. </view>
  18. </template>
  19. </template>
  20. </cl-topbar>
  21. </view>
  22. <progress :percent="percent" show-info stroke-width="3" v-if="progressShow" />
  23. <!-- 消息列表 -->
  24. <view class="message-list" @tap="onRetract">
  25. <scroll-view class="scroller" scroll-y scroll-with-animation :scroll-top="scroller.top"
  26. :upper-threshold="20" @scrolltoupper="refresh()">
  27. <!-- 加载更多 -->
  28. <view class="loadmore" v-if="loading">
  29. <cl-loadmore :finish="isCompleted" loading :divider="false"></cl-loadmore>
  30. </view>
  31. <!-- 内容块 -->
  32. <chat-message ref="message" :list="list" :conversationType="conversationType"></chat-message>
  33. </scroll-view>
  34. <!-- 录音弹窗 -->
  35. <cl-popup :visible.sync="voice.visible" direction="center" padding="0" border-radius="10rpx">
  36. <view class="popup-voice" :class="[
  37. {
  38. 'is-cancel': voiceIsCancel,
  39. },
  40. ]">
  41. <text class="popup-voice__time">{{ voice.duration | voice_duration }}</text>
  42. <text class="popup-voice__desc">松开发送,上滑取消</text>
  43. </view>
  44. </cl-popup>
  45. </view>
  46. <!-- 操作栏 -->
  47. <view class="opbar">
  48. <view class="main">
  49. <!-- 麦克风 -->
  50. <view class="icon">
  51. <text class="chat-iconfont icon-microphone" v-if="!op.isMicrophone" @tap="showMicrophone"></text>
  52. <text class="chat-iconfont icon-keyboard" @tap="hideMicrophone" v-else></text>
  53. </view>
  54. <!-- #ifndef H5 -->
  55. <!-- #endif -->
  56. <!-- 输入框 -->
  57. <view class="input">
  58. <button v-if="op.isMicrophone" class="press-btn" @longpress="onLongPress" @touchend="onRelease">
  59. {{ voice.visible ? "松开结束" : "按住说话" }}
  60. </button>
  61. <cl-input v-else v-model="value" confirm-type="send" confirm-hold fill :placeholder="placeholder"
  62. :cursor-spacing="10" :adjust-position="false" @focus="onFocus" @blur="onBlur"
  63. @confirm="onTextSend" @keyboardheightchange="onKeyBoardHeightChange"></cl-input>
  64. </view>
  65. <!-- 表情图标 -->
  66. <view class="icon">
  67. <text class="chat-iconfont icon-emoji" v-if="!op.isEmoji" @tap="showEmoji"></text>
  68. <text class="chat-iconfont icon-keyboard" v-else @tap="hideEmoji"></text>
  69. </view>
  70. <!-- 工具栏图标 -->
  71. <template v-if="value == ''">
  72. <view class="icon send">
  73. <text class="chat-iconfont icon-add-circle" v-if="!op.isTools" @tap="showTools"></text>
  74. <text class="chat-iconfont icon-subtract-circle" @tap="hideTools" v-else></text>
  75. </view>
  76. </template>
  77. <template v-else>
  78. <!-- 发送按钮 -->
  79. <view class="icon send">
  80. <text class="send-button" @tap="onTextSend">发送</text>
  81. </view>
  82. </template>
  83. </view>
  84. <view class="append">
  85. <!-- 工具栏 -->
  86. <chat-tools :visible="op.isTools" :userId="userID" :conversationType="conversationType"></chat-tools>
  87. <!-- 表情 -->
  88. <chat-emoji :visible="op.isEmoji" @select="onEmojiSelect"></chat-emoji>
  89. </view>
  90. </view>
  91. <!-- 视频弹窗 -->
  92. <cl-popup :visible.sync="video.visible" direction="center" force-update padding="0" border-radius="10rpx"
  93. @close="onVideoClose">
  94. <video id="video" autoplay :src="video.url" style="display: block"></video>
  95. </cl-popup>
  96. <member ref="member"></member>
  97. </view>
  98. </template>
  99. <script>
  100. import {
  101. debounce
  102. } from "../../uni_modules/cl-uni/utils";
  103. import ChatTools from "./components/tools";
  104. import ChatMessage from "./components/message";
  105. import ChatEmoji from "./components/emoji";
  106. import Member from "./components/member";
  107. // 录音设备
  108. const recorderManager = uni.getRecorderManager();
  109. // 平台
  110. const {
  111. platform
  112. } = uni.getSystemInfoSync();
  113. export default {
  114. components: {
  115. ChatTools,
  116. ChatMessage,
  117. ChatEmoji,
  118. Member,
  119. },
  120. data() {
  121. return {
  122. skey: '',
  123. page: 1,
  124. userInfos: [],
  125. placeholder: "",
  126. conversationID: "",
  127. conversationType: "",
  128. percent: 0,
  129. progressShow: false,
  130. firstLoad: true,
  131. isCompleted: false,
  132. nextReqMessageID: null,
  133. userID: 0,
  134. nickName: "",
  135. // 平台
  136. platform,
  137. // 输入框文本
  138. value: "",
  139. // 键盘高度
  140. keyBoardHeight: 0,
  141. // 聊天记录数据
  142. list: [],
  143. // 底部操作栏配置
  144. // list: [],
  145. op: {
  146. isMicrophone: false,
  147. isEmoji: false,
  148. isTools: false,
  149. },
  150. // 滚动条配置
  151. scroller: {
  152. top: 0,
  153. intoView: "",
  154. },
  155. // 视频配置
  156. video: {
  157. visible: false,
  158. },
  159. // 音频配置
  160. voice: {
  161. visible: false,
  162. duration: 0,
  163. timer: null,
  164. down: 0,
  165. move: 0,
  166. },
  167. // 加载进度
  168. loading: false,
  169. };
  170. },
  171. onLoad(option) {
  172. this.skey = option.skey || getApp().globalData.skey;
  173. this.userID = "8";
  174. this.nickName = "老杨";
  175. this.conversationID = "";
  176. this.conversationType = "C2C"; //GROUP,C2C
  177. //detail?userID=%25222%2522&nickName=%2522prk%2522&conversationID=%2522c2c_11%2522&conversationType=%2522C2C%2522
  178. //detail?userID=%25221%2522&nickName=%2522群%22522&conversationID=%2522GROUP_15%2522&conversationType=%2522GROUP%2522
  179. try {
  180. this.userID = JSON.parse(decodeURIComponent(option.userID));
  181. this.nickName = JSON.parse(decodeURIComponent(option.nickName));
  182. this.conversationID = JSON.parse(decodeURIComponent(option.conversationID));
  183. this.conversationType = JSON.parse(decodeURIComponent(option.conversationType));
  184. if (this.conversationType == "GROUP") {
  185. this.placeholder = "发布违规言论会被禁言哦~";
  186. }
  187. console.log("this.conversationID", this.conversationID);
  188. // this.TIM.setMessageRead(this.conversationID);
  189. if (this.conversationID != null && this.conversationID != "") {}
  190. } catch (e) {
  191. console.log("e", e)
  192. }
  193. this.getList();
  194. // this.getUserInfo();
  195. let that = this;
  196. // if (getApp().globalData.socket == null) {
  197. // getApp().globalData.socket = new wsRequest(
  198. // `wss://e.fan-quan.com/Gapi/ws`,
  199. // that.skey
  200. // );
  201. // }
  202. if (getApp().globalData.socket != null) {
  203. getApp().globalData.socket.getMessage(function(res) {
  204. console.log("res-c", res.data);
  205. let resdata = JSON.parse(res.data)
  206. // res-c {"seq":"reqBCb1Ov1rEi","cmd":"msg",
  207. // "response":{"code":200,"codeMsg":"Ok",
  208. // "data":{"target":"","type":"text",
  209. // "msg":"{\"mode\":\"text\",\"from\":1,\"avatar\":\"p\",\"payload\":{\"text\":\"222\"},\"create_time\":\"2024-10-05 19:49:26\"}","from":"1"}}}
  210. if (resdata.cmd == "msg") {
  211. // console.log("res-d", msgdata.mode + ";" + msgdata.payload.text);
  212. }
  213. // console.log("res-cmd", resdata.cmd);
  214. });
  215. console.log("detail-addgroup1");
  216. that.addGroup();
  217. }
  218. uni.$on('updateGroup', this.addGroup)
  219. uni.$on('messageUpdate', this.acceptMessage)
  220. uni.$on('sendMessage', this.sendMessage)
  221. uni.$on('messageSend', this.messageSend) //发送状态返回
  222. uni.$on('messageProgress', this.messageProgress)
  223. },
  224. computed: {
  225. // 计算屏幕高度
  226. height() {
  227. return this.keyBoardHeight > 0 ?
  228. `calc(100% - ${this.keyBoardHeight}px + env(safe-area-inset-bottom))` :
  229. "100%";
  230. },
  231. // 录音滑动是否取消
  232. voiceIsCancel() {
  233. return this.voice.move ? this.voice.down - this.voice.move > 50 : false;
  234. },
  235. },
  236. filters: {
  237. voice_duration(t) {
  238. return `00:${t < 10 ? `0${t}` : t}`;
  239. },
  240. },
  241. methods: {
  242. member() {
  243. // this.$refs.member.open(this.userID);
  244. uni.navigateTo({
  245. url: '/pages/chat/groupSetting?groupId=' + this.userID
  246. })
  247. },
  248. acceptMessage(message) {
  249. let msgdata = JSON.parse(message)
  250. this.list.push(msgdata)
  251. this.scrollToBottom();
  252. // for (let i = 0; i < message.length; i++) {
  253. // if (message[i].conversationID == this.conversationID) {
  254. // this.list.push(message[i]);
  255. // this.scrollToBottom();
  256. // }
  257. // }
  258. },
  259. addGroup() {
  260. let that = this;
  261. getApp().globalData.socket.send({
  262. cmd: "addGroup",
  263. data: {
  264. "uuid": getApp().globalData.uuid,
  265. "appId": 101,
  266. "userId": getApp().globalData.userId,
  267. "groupId": that.conversationID
  268. },
  269. success() {
  270. console.log("addGroup-succ", "ok");
  271. },
  272. fail(e) {
  273. console.log("addGroup-err", e);
  274. }
  275. });
  276. },
  277. async getList() {
  278. var offset = (this.page - 1) * 20;
  279. uni.request({
  280. url: this.$apiHost2 + '/Chat/msgList', //仅为示例,并非真实接口地址。
  281. data: {
  282. uuid: getApp().globalData.uuid,
  283. userID: this.userID,
  284. conversationID: this.conversationID,
  285. offset: offset
  286. },
  287. header: {
  288. 'content-type': 'application/json' //自定义请求头信息
  289. },
  290. success: (res) => {
  291. console.log("this.conversationID", this.conversationID);
  292. console.log("----", res.data);
  293. if (res.data.list == undefined || res.data.list == null) {
  294. res.data.list = []
  295. }
  296. this.isCompleted = res.data.isCompleted;
  297. this.nextReqMessageID = res.data.nextReqMessageID;
  298. if (res.data.list.length > 0) {
  299. // this.is_no_data = 0;
  300. }
  301. if (this.firstLoad) {
  302. this.list = res.data.list;
  303. this.scrollToBottom();
  304. } else {
  305. // this.list = this.list.concat(res.data.list)
  306. this.list = [...res.data.list, ...this.list];
  307. }
  308. this.firstLoad = false;
  309. uni.stopPullDownRefresh();
  310. console.log("this.list", this.list);
  311. this.loading = false;
  312. this.page++;
  313. // this.setUserInfo();
  314. }
  315. });
  316. return;
  317. let res = await this.TIM.getMessageList(this.conversationID, this.nextReqMessageID);
  318. let messageList = res.data.messageList;
  319. this.isCompleted = res.data.isCompleted;
  320. this.nextReqMessageID = res.data.nextReqMessageID;
  321. for (let i = 0; i < messageList.length; i++) {
  322. messageList[i].create_time = this.timestampToTime(messageList[i].time);
  323. messageList[i].sex = "3";
  324. }
  325. if (this.firstLoad) {
  326. this.list = messageList;
  327. this.scrollToBottom();
  328. } else {
  329. this.list = messageList.concat(this.list);
  330. }
  331. this.firstLoad = false;
  332. uni.stopPullDownRefresh();
  333. this.loading = false;
  334. this.setUserInfo();
  335. },
  336. async getUserInfo() {
  337. // let [err, res] = await this.$http.get('Group/members', {
  338. // 'id': this.userID,
  339. // 'type': this.conversationType
  340. // });
  341. // if (!this.$http.errorCheck(err, res)) {
  342. // return;
  343. // }
  344. // this.userInfos = res.data.data;
  345. this.userInfos = [{
  346. id: 1,
  347. user_icon: "https://cool-comm.oss-cn-shenzhen.aliyuncs.com/show/imgs/chat/avatar/5.jpg",
  348. username: 'ab',
  349. sex: 1
  350. },
  351. {
  352. id: 2,
  353. user_icon: "https://cool-comm.oss-cn-shenzhen.aliyuncs.com/show/imgs/chat/avatar/5.jpg",
  354. username: 'cd',
  355. sex: 1
  356. }
  357. ];
  358. this.setUserInfo();
  359. },
  360. setUserInfo() {
  361. if (this.list.length == 0 || this.userInfos.length == 0) {
  362. return
  363. }
  364. for (let i = 0; i < this.list.length; i++) {
  365. let fromID = this.list[i].from
  366. for (let j = 0; j < this.userInfos.length; j++) {
  367. if (fromID == this.userInfos[j].id) {
  368. this.list[i].avatar = this.userInfos[j].user_icon;
  369. this.list[i].sex = this.userInfos[j].sex;
  370. break;
  371. }
  372. }
  373. }
  374. this.list = this.list
  375. this.scrollToBottom();
  376. },
  377. toDetail() {
  378. return;
  379. if (this.conversationType == "C2C") {
  380. uni.navigateTo({
  381. url: "/pages/detail/index?uid=" + this.userID,
  382. });
  383. }
  384. },
  385. report() {
  386. setTimeout(() => {
  387. uni.showToast({
  388. title: '举报成功,我们会尽快进行处理!',
  389. icon: "none"
  390. });
  391. }, 500);
  392. },
  393. refresh() {
  394. this.loading = true;
  395. if (this.isCompleted) {
  396. return;
  397. }
  398. this.getList();
  399. },
  400. messageProgress(e) {
  401. this.percent = e * 100;
  402. if (e == 1) {
  403. this.progressShow = false;
  404. } else {
  405. this.progressShow = true;
  406. }
  407. },
  408. timestampToTime(timestamp) {
  409. var date = new Date(timestamp * 1000); //时间戳为10位需*1000,时间戳为13位的话不需乘1000
  410. var Y = date.getFullYear() + '-';
  411. var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
  412. //var D = date.getDate() + ' ';
  413. var D = (date.getDate() + 1 < 10 ? '0' + (date.getDate()) : date.getDate()) + ' ';
  414. var h = date.getHours() + ':';
  415. var m = (date.getMinutes() + 1 < 10 ? '0' + (date.getMinutes()) : date.getMinutes()) + ' ';
  416. var s = date.getSeconds();
  417. return M + D + h + m;
  418. },
  419. // 监听键盘高度
  420. onKeyBoardHeightChange(e) {
  421. this.keyBoardHeight = e.detail.height;
  422. },
  423. // 滑动监听
  424. onTouchMove(e) {
  425. if (this.voice.visible) {
  426. // 记录移动的位置
  427. this.voice.move = e.changedTouches[0].clientY;
  428. }
  429. },
  430. // 长按说话
  431. onLongPress(e) {
  432. // uni.showToast({
  433. // title: '待开放',
  434. // icon: "none"
  435. // });
  436. // return;
  437. // uni.authorize({
  438. // scope: 'scope.record',
  439. // success() {
  440. // uni.getLocation()
  441. // }
  442. // });
  443. // 关闭已存在播放声音
  444. this.$refs["message"].voicePause();
  445. console.log("按下按钮了");
  446. this.$nextTick(() => {
  447. // 记录按下位置
  448. this.voice.down = e.touches[0].pageY;
  449. // 清空移动位置
  450. this.voice.move = 0;
  451. // 显示弹窗
  452. this.voice.visible = true;
  453. // 开始录音
  454. recorderManager.start({
  455. // duration: 60000,
  456. // sampleRate: 44100,
  457. // numberOfChannels: 1,
  458. // encodeBitRate: 192000,
  459. // format: "aac",
  460. });
  461. // 计数器
  462. this.voice.timer = setInterval(() => {
  463. if (this.voice.duration >= 60) {
  464. this.onRelease(e);
  465. } else {
  466. this.voice.duration += 1;
  467. }
  468. }, 1000);
  469. });
  470. },
  471. // 松开
  472. onRelease(e) {
  473. // 记录移动位置
  474. this.voice.move = e.changedTouches[0].clientY;
  475. let duration = this.voice.duration * 1000;
  476. console.log("松开按钮了");
  477. let that = this;
  478. // 暂停事件
  479. recorderManager.onStop((res) => {
  480. // 判断是否取消
  481. if (!this.voiceIsCancel) {
  482. res.duration = duration;
  483. res.size = 34271;
  484. console.log("res", res.tempFilePath);
  485. // this.TIM.sendAudioMessage(res, this.userID, this.conversationType);
  486. const uploadTask = uni.uploadFile({
  487. url: that.$apiHost + '/Xweb/upload_recorder',
  488. filePath: res.tempFilePath,
  489. formData: {
  490. 'uuid': getApp().globalData.uuid,
  491. 'duration': res.duration,
  492. 'size': res.size
  493. },
  494. name: 'file', // 待确认
  495. // header: {
  496. // 'Content-Type': 'multipart/form-data',
  497. // // 'Authorization': getApp().globalData.token || 'Basic YXBwOmFwcA=='
  498. // },
  499. success: function(uploadFileRes) {
  500. let resdata = JSON.parse(uploadFileRes.data)
  501. console.log('Success1:', resdata);
  502. console.log('Success2:', resdata.url);
  503. if (resdata.success == 'yes') {
  504. uni.$emit('sendMessage', {
  505. mode: 'voice',
  506. message: resdata.url
  507. })
  508. }
  509. // _self.imgsID.push(JSON.parse(uploadFileRes.data).data.fileId);
  510. // console.log('_self.imgsID:', _self.imgsID)
  511. },
  512. fail: function(uploadFileFail) {
  513. console.log('Error:', uploadFileFail.data);
  514. },
  515. complete: () => {
  516. console.log('Complete:');
  517. }
  518. });
  519. }
  520. });
  521. // 清除计时器
  522. clearInterval(this.voice.timer);
  523. // 暂停录音
  524. recorderManager.stop();
  525. // 关闭弹窗
  526. this.voice.visible = false;
  527. // 清空时常
  528. this.voice.duration = 0;
  529. },
  530. // 显示麦克风
  531. showMicrophone() {
  532. this.op.isMicrophone = true;
  533. this.hideTools();
  534. this.hideEmoji();
  535. this.hideKeyBoard();
  536. },
  537. // 隐藏麦克风
  538. hideMicrophone() {
  539. this.op.isMicrophone = false;
  540. },
  541. // 显示表情
  542. showEmoji() {
  543. this.op.isEmoji = true;
  544. this.hideTools();
  545. this.hideMicrophone();
  546. this.scrollToBottom();
  547. },
  548. // 隐藏表情
  549. hideEmoji() {
  550. this.op.isEmoji = false;
  551. },
  552. // 显示工具栏
  553. showTools() {
  554. this.op.isTools = true;
  555. this.hideEmoji();
  556. this.hideMicrophone();
  557. this.scrollToBottom();
  558. },
  559. // 隐藏工具栏
  560. hideTools() {
  561. this.op.isTools = false;
  562. },
  563. // 隐藏键盘
  564. hideKeyBoard() {
  565. this.keyBoardHeight = 0;
  566. },
  567. // 滑动到底部
  568. scrollToBottom: debounce(function() {
  569. this.$nextTick(() => {
  570. this.scroller.top = 2000000 + parseInt(Math.random() * 100);
  571. });
  572. }, 100),
  573. // 收起
  574. onRetract() {
  575. this.hideTools();
  576. this.hideEmoji();
  577. },
  578. // 聚焦
  579. onFocus() {
  580. this.hideEmoji();
  581. this.hideTools();
  582. this.scrollToBottom();
  583. },
  584. // 失焦
  585. onBlur() {
  586. this.hideKeyBoard();
  587. },
  588. // 发送消息
  589. onTextSend() {
  590. if (this.value) {
  591. uni.showLoading({})
  592. setTimeout(function() {
  593. uni.hideLoading()
  594. }, 5000)
  595. getApp().globalData.socket.send({
  596. cmd: "sendMsg",
  597. data: {
  598. "uuid": getApp().globalData.uuid,
  599. "appId": 101,
  600. "mode": "text",
  601. "userID": this.userID,
  602. "conversationID": this.conversationID,
  603. "conversationType": this.conversationType,
  604. "message": this.value
  605. }
  606. });
  607. // console.log('-v:', this.value)
  608. // uni.request({
  609. // url: this.$apiHost2 + '/Chat/sendMessage', //仅为示例,并非真实接口地址。
  610. // data: {
  611. // uuid: getApp().globalData.uuid,
  612. // userID: this.userID,
  613. // conversationID: this.conversationID,
  614. // conversationType: this.conversationType,
  615. // message: this.value
  616. // },
  617. // header: {
  618. // 'content-type': 'application/json' //自定义请求头信息
  619. // },
  620. // success: (res) => {
  621. // console.log("----", res.data);
  622. // if (res.data.success == "yes") {
  623. // if (res.data.conversation_id != "") {
  624. // this.conversationID = res.data.conversation_id;
  625. // }
  626. // }
  627. // }
  628. // });
  629. // this.TIM.sendTextMessage(this.value, this.userID, this.conversationType);
  630. this.value = "";
  631. }
  632. },
  633. sendMessage(msg) { //发送图片
  634. getApp().globalData.socket.send({
  635. cmd: "sendMsg",
  636. data: {
  637. "uuid": getApp().globalData.uuid,
  638. "appId": 101,
  639. "mode": msg.mode,
  640. "userID": this.userID,
  641. "conversationID": this.conversationID,
  642. "conversationType": this.conversationType,
  643. "message": msg.message
  644. }
  645. });
  646. },
  647. messageSend(msg) {
  648. console.log("messageSend:", msg);
  649. uni.hideLoading()
  650. if (msg.code == 200) {
  651. if (msg.codeMsg != "") {
  652. this.conversationID = msg.codeMsg;
  653. }
  654. } else {
  655. getApp().globalData.socket.restart();
  656. uni.showToast({
  657. title: msg.codeMsg,
  658. icon: 'none'
  659. });
  660. }
  661. },
  662. hackMessage() {
  663. if (this.list.length > 0) {
  664. let item = JSON.parse(JSON.stringify(this.list[0]))
  665. item.avatar = "/static/logo.png";
  666. item._mode = "text";
  667. item.payload.text = "客服小姐姐正在赶来,请稍后~"
  668. item.from = "51"
  669. this.list.push(item)
  670. } else {
  671. this.list.push({
  672. avatar: "/static/logo.png",
  673. _mode: "text",
  674. payload: {
  675. text: "客服小姐姐正在赶来,请稍后~"
  676. },
  677. from: "51"
  678. })
  679. }
  680. },
  681. // 表情选择
  682. onEmojiSelect(e) {
  683. this.value = this.value + e;
  684. },
  685. // 追加数据到开头
  686. prepend(...data) {
  687. this.list.unshift(...data.filter(Boolean).reverse());
  688. },
  689. // 追加数据到结尾
  690. append(...data) {
  691. this.list.push(
  692. ...data
  693. .map((e) => {
  694. e.animation = true;
  695. return e;
  696. })
  697. .filter(Boolean)
  698. );
  699. this.scrollToBottom();
  700. },
  701. // 关闭视频弹窗
  702. onVideoClose() {
  703. const video = uni.createVideoContext("video");
  704. video.pause();
  705. }
  706. },
  707. };
  708. </script>
  709. <style lang="scss">
  710. @import "../../static/css/iconfont.scss";
  711. page {
  712. height: 100%;
  713. overflow: hidden;
  714. background-color: #121212;
  715. }
  716. </style>
  717. <style lang="scss" scoped>
  718. .page-session {
  719. display: flex;
  720. flex-direction: column;
  721. padding-bottom: env(safe-area-inset-bottom);
  722. box-sizing: border-box;
  723. height: 100%;
  724. background-color: #121212;
  725. background: url('../../static/sms/chat_bg_top.png');
  726. background-size: 750rpx 460rpx;
  727. background-repeat: no-repeat;
  728. .message-list {
  729. flex: 1;
  730. overflow: hidden;
  731. position: relative;
  732. .loadmore {
  733. margin: 10rpx 0;
  734. }
  735. .scroller {
  736. height: 100%;
  737. }
  738. /deep/.cl-popup {
  739. &__wrapper {
  740. position: absolute;
  741. }
  742. }
  743. }
  744. .opbar {
  745. flex-shrink: 0;
  746. z-index: 9;
  747. border-top: 1rpx solid #393939;
  748. .main {
  749. display: flex;
  750. align-items: center;
  751. height: 100rpx;
  752. .send {
  753. margin-right: 30rpx;
  754. }
  755. .icon {
  756. height: 80rpx;
  757. width: 80rpx;
  758. line-height: 80rpx;
  759. text-align: center;
  760. flex-shrink: 0;
  761. color: #fff;
  762. .chat-iconfont {
  763. font-size: 60rpx;
  764. }
  765. .send-button {
  766. background-color: #393939;
  767. color: #fff;
  768. border-radius: 10rpx;
  769. padding: 6rpx 10rpx;
  770. font-size: 28rpx;
  771. }
  772. }
  773. .input {
  774. flex: 1;
  775. margin: 0 10rpx;
  776. height: 70rpx;
  777. line-height: 70rpx;
  778. .press-btn {
  779. display: inline-block;
  780. height: 70rpx;
  781. width: 100%;
  782. line-height: 70rpx;
  783. color: #fff;
  784. border: 0rpx solid #dcdfe6;
  785. font-size: 24rpx;
  786. background-color: #282828;
  787. margin: 0;
  788. border-radius: 70rpx;
  789. box-sizing: border-box;
  790. &::after {
  791. border: 0;
  792. }
  793. &:active {
  794. background-color: #464646;
  795. }
  796. }
  797. }
  798. }
  799. }
  800. .popup-voice {
  801. display: flex;
  802. flex-direction: column;
  803. align-items: center;
  804. padding: 20rpx;
  805. &.is-cancel {
  806. background-color: red;
  807. color: #fff;
  808. }
  809. &__time {
  810. font-size: 28rpx;
  811. margin-bottom: 20rpx;
  812. letter-spacing: 1rpx;
  813. }
  814. &__desc {
  815. font-size: 24rpx;
  816. }
  817. }
  818. }
  819. .cl-topbar__icon {
  820. font-size: 25rpx;
  821. color: red;
  822. padding: 0rpx 10rpx;
  823. color: #fff;
  824. }
  825. .member-icon {
  826. width: 50rpx;
  827. height: 50rpx;
  828. margin-right: 30rpx;
  829. }
  830. .cl-topbar {
  831. width: 100%;
  832. height: 100rpx;
  833. background-color: #121212;
  834. display: flex;
  835. flex-direction: row;
  836. justify-content: space-between;
  837. align-items: center;
  838. padding: 10rpx 20rpx;
  839. }
  840. .cl-input {
  841. border-radius: 16rpx;
  842. border: 0;
  843. background-color: #282828;
  844. color: #fff;
  845. }
  846. </style>