index.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. <!-- 聊天 -->
  2. <template>
  3. <view class="page page--divider">
  4. <headerline navstyle="left:18%;width:60%;" :reditem="unreadnum" issearch="true" :showsearch="showsearch"
  5. searchtips="请输入搜索内容" @clicksearch='clicksearch' :shownav="false" :title="navtitle" :menuitem="menuitem"
  6. :navselect="navselect" :statusbarheight='statusBarHeight' :islogo="false" @tapnav="tapnav"
  7. @tapmenu="tapmenu" rightmenu="true"></headerline>
  8. <view class="widget" v-if="navselect==0 && !showsearch">
  9. <scroll-view v-if="chats.length>0" refresher-enabled='true' refresher-threshold='60'
  10. :refresher-triggered="isfresh" :refresher-default-style='refreshstyle'
  11. @refresherpulling='refresherpulling' @refresherrefresh='refresherrefresh'>
  12. <view class="fresh" v-if="isfresh==true">
  13. {{fresh_tip}}
  14. </view>
  15. <view :class="{'item':true,'istop':item.istop}" v-for="(item, index) in chats" :key="item.key"
  16. @tap="handleClick(item)" @longtap="msgAction(item)">
  17. <image :src="image_cache(item.avatar)" class="leftImg" />
  18. <view class="rightContent">
  19. <view class="topCont">
  20. <view class="userName">{{item.nickname||'匿名'}}</view>
  21. <view class="time">{{ timestamp(item.timestamp) || '--:--' }}</view>
  22. </view>
  23. <view class="bottomCont">
  24. <view class="content" v-if="item.message.type!='tips'">
  25. <block v-if="item.self || item.sender.nickname!=undefined">
  26. {{item.self? '[我]': item.sender.nickname+':'}}
  27. </block>
  28. <text style='color: #666666;font-size: 28upx'
  29. v-if="item.message.type=='voice'">[语音]</text>
  30. <text style='color: #666666;font-size: 28upx'
  31. v-else-if="item.message.type=='redpacket'">[红包]</text>
  32. <text style='color: #666666;font-size: 28upx'
  33. v-else-if="item.message.type=='image'">[图片]</text>
  34. <text style='color: #666666;font-size: 28upx'
  35. v-else-if="item.message.type=='vedio'">[视频]</text>
  36. <text style='color: #666666;font-size: 28upx'
  37. v-else-if="item.message.type=='emotion'">[表情]</text>
  38. <text style='color: #666666;font-size: 28upx'
  39. v-else-if="item.message.type=='apply'">{{item.message.content.text}}</text>
  40. <text style='color: #666666;font-size: 28upx' v-else-if="item.message.type=='tips'">
  41. <block v-if="item.message.content.type=='time'">
  42. {{item.message.content.text}}
  43. </block>
  44. <block v-else>
  45. {{item.message.content}}
  46. </block>
  47. </text>
  48. <text style='color: #666666;font-size: 28upx' v-else-if="item.message.type=='text'">
  49. <text v-if="item.message.content.type!='emotion' ">
  50. <block
  51. v-if="item.message.content.type=='remind' && toText(item.message.content.content).indexOf('@我')>-1 ">
  52. <text style="color:#1d830a">
  53. {{item.message.content.type=="remind"?toText(item.message.content.content):toText(item.message.content) }}</text>
  54. </block>
  55. <block v-else>
  56. {{item.message.content.type=="remind"?toText(item.message.content.content):toText(item.message.content) }}
  57. </block>
  58. </text>
  59. <text v-if="item.message.content.type=='emotion' ">
  60. {{item.message.content.content}}
  61. </text>
  62. </text>
  63. <text style='color: #999999;font-size: 28upx' v-else-if="item.message.msg_type=='show'">
  64. {{item.message.content.text}}
  65. </text>
  66. </view>
  67. <view class="content" v-else>
  68. <text style='color: #999999;font-size: 28upx'>
  69. <block v-if="item.message.content.type=='time'">
  70. {{item.message.content.text}}
  71. </block>
  72. <block v-else>
  73. {{item.message.content}}
  74. </block>
  75. </text>
  76. </view>
  77. <view class="badge" v-if="item.unread && item.unread>99"
  78. style="width: auto;padding: 0 5px;">99+</view>
  79. <view class="badge" v-if="item.unread && item.unread<=99">{{item.unread}}</view>
  80. </view>
  81. </view>
  82. </view>
  83. </scroll-view>
  84. <view v-else class="nodata">
  85. 您还没有任何消息
  86. </view>
  87. </view>
  88. </view>
  89. </template>
  90. <script>
  91. import scode from "../../library/scode.js"
  92. import api from "../../library/index.js"
  93. import chat from "../../library/chat.js"
  94. import http from "../../library/http.js"
  95. import message from "../../library/message.js"
  96. import action from "../../library/action.js"
  97. import headerline from '../../components/header.vue'
  98. var windowHeight = uni.getSystemInfoSync().windowHeight;
  99. var statusBarHeight = uni.getSystemInfoSync().statusBarHeight;
  100. var contenttop = statusBarHeight + 45;
  101. var conentheight = windowHeight - contenttop;
  102. var lottHeight = conentheight - 30;
  103. var lottTop = contenttop + 30;
  104. export default {
  105. components: {
  106. headerline,
  107. },
  108. data() {
  109. return {
  110. statusBarHeight: statusBarHeight + 'px',
  111. contenttop: contenttop + 'px',
  112. contentheight: conentheight + 'px',
  113. lottHeight: lottHeight + 'px',
  114. lottTop: lottTop + 'px',
  115. shownav: false,
  116. // navtitle:'消息',
  117. navselect: 0,
  118. menuitem: [],
  119. newfriendNotify: false,
  120. showMenu: false,
  121. newfriendnum: 0,
  122. clickkey: false,
  123. reading_id: -1,
  124. actions: [],
  125. user: uni.getStorageSync('userInfo'),
  126. showsearch: false,
  127. friends: uni.getStorageSync(uni.getStorageSync('access_token') + '_frienddata'),
  128. pinyin: [],
  129. char_select: false,
  130. kefunum: 0,
  131. unreadnum: [0, 0, 0],
  132. refreshstyle: 'none',
  133. isfresh: false,
  134. fresh_tip: '下拉刷新'
  135. }
  136. },
  137. computed: {
  138. chats() {
  139. var res = this.$store.getters['chat/msglist'];
  140. return res;
  141. },
  142. navtitle() {
  143. var num = 0;
  144. var msg_list = this.$store.getters['chat/msglist'];
  145. msg_list.map(item => {
  146. num += parseInt(item.unread)
  147. })
  148. if (num == 0) return '消息';
  149. else return '消息(' + num + ')'
  150. }
  151. },
  152. watch: {
  153. chats(val) {
  154. var num = 0;
  155. for (var i = 0; i < val.length; i++) {
  156. num += val[i].unread;
  157. }
  158. this.unreadnum.splice(0, 3);
  159. this.unreadnum.push(num);
  160. this.unreadnum.push(0);
  161. this.unreadnum.push(0);
  162. this.$forceUpdate();
  163. }
  164. },
  165. methods: {
  166. refresherpulling() {
  167. this.refreshstyle = 'none';
  168. this.isfresh = true;
  169. this.fresh_tip = '下拉刷新...';
  170. },
  171. refresherrefresh() {
  172. this.refreshstyle = 'black';
  173. this.fresh_tip = '正在刷新...';
  174. this.lastchat();
  175. },
  176. href(path, opts) {
  177. if (!opts || opts == undefined || opts == null) opts = {};
  178. this.$jump(path, opts);
  179. },
  180. open_detail(item) {
  181. this.$jump('friend.detail', {
  182. id: item.id
  183. });
  184. },
  185. toText(str) {
  186. str = str.toString()
  187. str = str.split('-qute-')[0]
  188. str = str.replace(/&nbsp;/g, " ");
  189. str = str.replace(/<br>/g, " ");
  190. str = str.replace(/<[^<>]+>/g, '')
  191. return str;
  192. },
  193. timestamp(time) {
  194. // return action.timestampFormat(new Date(time.replace(/(-|年|月)/g, '/').replace('日', '')).getTime()/1000)
  195. return action.timestampFormat(time)
  196. },
  197. tapnav(num) {
  198. this.navselect = num;
  199. if (num == 1) this.friendlist();
  200. else this.lastchat();
  201. },
  202. clicksearch(e) {
  203. this.showsearch = e;
  204. },
  205. go_search(e) {
  206. http.setWait(true).get('user.php?act=searchUser', {
  207. keywords: e
  208. }).then(res => {
  209. if (res.data.length > 0) {
  210. var id = res.data[0].id;
  211. uni.navigateTo({
  212. url: '../friend/detail?id=' + id + '&from=' + res.data[0].from
  213. })
  214. } else {
  215. uni.showToast({
  216. icon: 'none',
  217. title: '没有搜索到相关用户',
  218. duration: 1500
  219. })
  220. }
  221. })
  222. },
  223. tapmenu(num) {
  224. if (this.$action.loginTips('未登录用户,无法完成此操作', '/pages/game/index') == false) return false;
  225. if (this.$action.check_userlock() == false) return false;
  226. if (num == 0) {
  227. if (this.user.nickname == '' || this.user.nickname == this.user.name) {
  228. this.$action.profileTips('未设置昵称,不能创建群', '/pages/group/create');
  229. return false;
  230. } else
  231. this.$jump('group.create');
  232. } else if (num == 1) {
  233. this.$jump('group.list', {
  234. method: 0
  235. });
  236. } else if (num == 2) {
  237. this.$jump('group.list', {
  238. method: 1
  239. });
  240. } else if (num == 3) {
  241. this.$jump('mine.note');
  242. } else if (num == 4) {
  243. return uni.scanCode({
  244. success(res) {
  245. scode.getScode(res)
  246. },
  247. fail(e) {
  248. console.log(JSON.stringify(e));
  249. console.log('扫码失败')
  250. }
  251. });
  252. }
  253. },
  254. group_read(group_id) {
  255. http.setWait(false).post('group.php?act=setReadTime', {
  256. group_id: group_id,
  257. userid: this.user.id
  258. }).then(res => {
  259. this.lastchat();
  260. })
  261. },
  262. user_read(userid) {
  263. http.setWait(false).post('group.php?act=setReadTime', {
  264. group_id: 0,
  265. userid: this.userid,
  266. sendid: this.user.id
  267. }).then(res => {
  268. this.lastchat();
  269. })
  270. },
  271. handleClick(info) {
  272. if (info.unread > 0) this.$store.commit('chat/clearunread', info.cache_key);
  273. if (this.clickkey == info.cache_key) return false;
  274. this.clickkey = info.cache_key;
  275. if (info.cache_key == "U1") {
  276. return this.$jump('friend.request?type=' + info.sender.id);
  277. } else {
  278. if (info.cache_key.indexOf('U') > -1) {
  279. let friend = {
  280. id: info.id,
  281. nickname: info.nickname
  282. }
  283. //this.user_read(info.id);
  284. return this.$jump('friend.chat', friend);
  285. } else {
  286. if (info.message.content.type == 'remind' && this.toText(info.message.content.content).indexOf(
  287. '@我') > -1)
  288. var atme = 1;
  289. else var atme = 0;
  290. // this.group_read(info.id);
  291. this.$jump('group.chat', {
  292. id: info.id,
  293. nickname: info.nickname,
  294. atme: atme,
  295. msg_id: info.msg_id
  296. });
  297. }
  298. }
  299. },
  300. msgtopChanage(istop, cache_key) {
  301. istop = !istop
  302. var msgtop = uni.getStorageSync('msgtop') ? uni.getStorageSync('msgtop') : [];
  303. if (istop) {
  304. msgtop.push(cache_key)
  305. } else {
  306. for (var i = 0; i < msgtop.length; i++) {
  307. if (msgtop[i] == cache_key) {
  308. msgtop.splice(i, 1)
  309. }
  310. }
  311. }
  312. uni.setStorageSync('msgtop', msgtop);
  313. this.$store.commit('chat/set_istop');
  314. var data = {
  315. cache_key: cache_key,
  316. userid: this.user.id,
  317. istop: istop
  318. };
  319. http.setWait(false).get('group.php?act=set_msgtop', data).then(res => {
  320. })
  321. },
  322. msgAction(msg) {
  323. var user_id = uni.getStorageSync('access_token');
  324. // console.log(msg);
  325. let that = this;
  326. var itemList = [];
  327. if (msg.istop < 1) itemList.push('置顶');
  328. else itemList.push('取消置顶');
  329. if (msg.unread > 0) itemList.push('标记已读');
  330. else itemList.push('标记未读');
  331. itemList.push('删除会话')
  332. uni.showActionSheet({
  333. itemList: itemList,
  334. success: function(res) {
  335. switch (res.tapIndex) {
  336. case 2:
  337. that.delete_msg(msg.cache_key)
  338. break;
  339. case 0:
  340. that.msgtopChanage(msg.istop, msg.cache_key)
  341. // console.log(msg.cache_key)
  342. break;
  343. case 1:
  344. that.$store.commit('chat/set_read', msg);
  345. break;
  346. default:
  347. break;
  348. }
  349. },
  350. fail: function(res) {
  351. //console.log(res.errMsg);
  352. }
  353. });
  354. },
  355. lastchat() {
  356. var userid = parseInt(uni.getStorageSync('access_token'));
  357. var postdata = {
  358. userid: userid,
  359. reading_id: this.reading_id
  360. };
  361. var msg_list_key = userid + '_chat_msglist';
  362. var temp1 = [];
  363. var temp2 = [];
  364. http.setWait(false).get('group.php?act=lastchat', postdata).then(res => {
  365. var data = res.data;
  366. var msglist = [];
  367. for (var i = 0; i < data.length; i++) {
  368. var item = data[i];
  369. // console.log(item)
  370. // console.log(item.cache_key,item.unread,this.timestamp(item.readtime))
  371. var result = {};
  372. result['key'] = userid + '_chat_' + item['cache_key'];
  373. var msg = {};
  374. msg['id'] = item.group.id;
  375. msg['cache_key'] = item['cache_key'];
  376. msg['group_id'] = item.group.id;
  377. msg['nickname'] = item.group['nickname'];
  378. // msg['kefu']=item.group.kefu
  379. msg['avatar'] = item.group['avatar'];
  380. msg['isloading'] = 1;
  381. msg['istop'] = item.istop;
  382. msg['msg_id'] = item.id;
  383. msg['timestamp'] = item.addtime;
  384. if (parseInt(item.userid) == userid) msg['self'] = 1;
  385. else msg['self'] = 0;
  386. msg['none'] = false;
  387. msg['sender_id'] = item.userid;
  388. msg['message'] = {
  389. 'type': item.type,
  390. 'content': item.content
  391. };
  392. msg['unread'] = parseInt(item.unread);
  393. msg['readtime'] = item.readtime;
  394. if (item.groupid == 1) {
  395. msg['sender'] = {
  396. 'nickname': item.sender_name,
  397. id: item.reqtype
  398. }
  399. } else msg['sender'] = {
  400. 'nickname': item.sender_name
  401. };
  402. result['msg'] = msg;
  403. if (msg.istop) temp1.push(result)
  404. else temp2.push(result)
  405. }
  406. temp1.sort((a, b) => b.timestamp - a.timestamp);
  407. temp2.sort((a, b) => b.timestamp - a.timestamp);
  408. msglist = temp1.concat(temp2);
  409. this.update_msglist(msglist);
  410. var that = this;
  411. this.fresh_tip = '刷新成功'
  412. this.refreshstyle = 'none';
  413. setTimeout(function() {
  414. that.isfresh = false;
  415. }, 500)
  416. })
  417. },
  418. setrightmenu() {
  419. var action = [
  420. {
  421. title: '新建群',
  422. icon: 'plus'
  423. },
  424. {
  425. title: '我的创建',
  426. icon: 'personadd'
  427. },
  428. {
  429. title: '加入的群',
  430. icon: 'person'
  431. },
  432. // #ifdef APP-PLUS
  433. {
  434. title: '通知设置',
  435. icon: 'gear'
  436. },
  437. {
  438. title: '扫一扫',
  439. icon: 'scan'
  440. },
  441. // #endif
  442. ]
  443. this.menuitem = action;
  444. },
  445. fresh_msg() {
  446. var msglist = uni.getStorageSync(uni.getStorageSync('access_token') + '_chat_msglist');
  447. this.update_msglist(msglist);
  448. this.$action.setStatusTips();
  449. },
  450. },
  451. created() {
  452. uni.$on('toChat', message => {
  453. //console.log('index')
  454. this.$action.toChat(message);
  455. })
  456. },
  457. onShow() {
  458. this.unreadnum[0] = this.$action.setStatusTips()
  459. this.clickkey = false
  460. uni.setStorageSync('cache_key', '');
  461. uni.hideKeyboard();
  462. var userid = parseInt(uni.getStorageSync('access_token'));
  463. if (userid > 0) {
  464. this.lastchat();
  465. this.$action.setStatusTips();
  466. if (uni.getStorageSync('ispush') == true) {
  467. var message = uni.getStorageSync('pushmessage');
  468. this.$action.toChat(message);
  469. uni.setStorageSync('ispush', false)
  470. }
  471. } else {
  472. uni.setStorageSync('gourl', '/pages/index/index');
  473. this.$jump('login.index');
  474. }
  475. },
  476. onLoad() {
  477. var userid = parseInt(uni.getStorageSync('access_token'));
  478. if (userid > 0) {
  479. var that = this;
  480. this.$socket.on('chat', (res) => {
  481. setTimeout(function() {
  482. that.fresh_msg();
  483. }, 100)
  484. })
  485. that.setrightmenu();
  486. setTimeout(function() {
  487. api.getMyGroup({
  488. userid: userid
  489. }).then(res => {
  490. // console.log(res.data)
  491. uni.setStorageSync(userid + '_groups', res.data)
  492. })
  493. api.getMyFriend({
  494. userid: userid
  495. }).then(resss => {
  496. uni.setStorageSync(userid + '_frienddata', resss.data);
  497. })
  498. }, 3000)
  499. }
  500. }
  501. }
  502. </script>
  503. <style lang="scss">
  504. .fresh {
  505. height: 30px;
  506. line-height: 30px;
  507. font-size: 14px;
  508. text-align: center;
  509. color: #666;
  510. }
  511. .btn_yellow {
  512. background-color: yellow;
  513. color: #000;
  514. font-size: 12px;
  515. display: inline-block;
  516. height: 18px;
  517. line-height: 18px;
  518. padding: 0px 5px;
  519. border-radius: 5px;
  520. text-align: center;
  521. margin: 0px 2px;
  522. }
  523. .btn_green {
  524. background-color: #0aad6c;
  525. color: #fff;
  526. font-size: 12px;
  527. display: inline-block;
  528. height: 18px;
  529. line-height: 18px;
  530. padding: 0px 5px;
  531. border-radius: 5px;
  532. text-align: center;
  533. margin: 0px 2px;
  534. }
  535. .btn_blue {
  536. background-color: $uni-color-primary;
  537. color: #fff;
  538. font-size: 12px;
  539. display: inline-block;
  540. height: 18px;
  541. line-height: 18px;
  542. padding: 0px 5px;
  543. border-radius: 5px;
  544. text-align: center;
  545. margin: 0px 2px;
  546. }
  547. .btn_grey {
  548. background-color: #ddd;
  549. color: #000;
  550. font-size: 12px;
  551. display: inline-block;
  552. height: 18px;
  553. line-height: 18px;
  554. padding: 0px 5px;
  555. border-radius: 5px;
  556. text-align: center;
  557. margin: 0px 2px;
  558. }
  559. .nodata {
  560. height: 35px;
  561. line-height: 35px;
  562. color: #666;
  563. font-size: 12px;
  564. text-align: center;
  565. }
  566. .item {
  567. height: 120upx;
  568. overflow: hidden;
  569. padding: 0px 30upx;
  570. display: flex;
  571. flex-direction: row;
  572. justify-content: flex-start;
  573. align-items: center;
  574. margin-top: 5px;
  575. }
  576. .item:hover {
  577. background-color: #eee;
  578. }
  579. .leftImg {
  580. width: 100upx;
  581. height: 100upx;
  582. margin-right: $uni-spacing-row-base;
  583. border-radius: $uni-border-radius-base;
  584. display: flex;
  585. flex-flow: wrap;
  586. justify-content: center;
  587. background-color: #eee;
  588. align-items: center;
  589. &:not(image) {
  590. padding: 1upx;
  591. }
  592. view,
  593. image {
  594. width: (76upx-2upx*4)/3;
  595. height: (76upx-2upx*4)/3;
  596. margin: 1upx;
  597. }
  598. }
  599. .rightContent {
  600. flex: 1;
  601. border-bottom: 1px solid #fbfbfb;
  602. }
  603. .rightContent,
  604. .topCont {
  605. overflow: hidden;
  606. line-height: 50upx;
  607. }
  608. .topCont {
  609. display: flex;
  610. flex-direction: row;
  611. justify-content: space-between;
  612. align-items: center;
  613. vertical-align: top;
  614. }
  615. .userName {
  616. color: $uni-text-color;
  617. font-size: 32upx;
  618. }
  619. .time {
  620. color: #999999;
  621. font-size: 24upx;
  622. }
  623. .bottomCont {
  624. width: 100%;
  625. font-size: 24upx;
  626. color: #999999;
  627. display: flex;
  628. align-items: center;
  629. justify-content: space-between;
  630. flex-direction: row;
  631. }
  632. .content {
  633. font-size: 28upx;
  634. white-space: nowrap;
  635. text-overflow: ellipsis;
  636. overflow: hidden;
  637. word-break: break-all;
  638. height: 30px;
  639. line-height: 30px;
  640. display: flex;
  641. flex-direction: row;
  642. max-width: 100%;
  643. }
  644. .content text {
  645. white-space: nowrap;
  646. text-overflow: ellipsis;
  647. overflow: hidden;
  648. word-break: break-all;
  649. max-width: 100%;
  650. }
  651. .badge {
  652. background-color: red;
  653. color: #fff;
  654. border-radius: 40upx;
  655. line-height: 40upx;
  656. width: 40upx;
  657. height: 40upx;
  658. font-size: 24upx;
  659. text-align: center;
  660. flex-shrink: 0;
  661. }
  662. </style>