conversations.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. <template>
  2. <scroll-view class="conversations" scroll-y="true">
  3. <view class="navBox">
  4. <view class="status_bar" :style="{height: iStatusBarHeight + 'px'}"></view>
  5. <view class="nav">
  6. <view class="navLeft" ><!-- @click="goBack" -->
  7. <!-- <image src="../static/img/nav_icon_back.png" mode="aspectFit" class="backImg" @click="goback"></image> -->
  8. </view>
  9. <view class="title">{{loginInfo.supplierName}}</view>
  10. <view class="goVin" ></view>
  11. </view>
  12. </view>
  13. <view class="status_bar" :style="{height: iStatusBarHeight + 'px'}"></view>
  14. <view style="height: 44px;"></view>
  15. <view v-if="conversations.length > 0">
  16. <view class="scroll-item" v-for="(conversation, key) in conversations" :key="key">
  17. <view class="item-head">
  18. <!-- <image :src="conversation.data.avatar" class="head-icon"></image> -->
  19. <image src="/static/img/yonghu.png" class="head-icon"></image>
  20. <view class="item-head_unread" v-if="conversation.unread">{{ conversation.unread }}</view>
  21. </view>
  22. <view class="scroll-item_info" @click="chat(conversation)">
  23. <view class="item-info-top">
  24. <text class="item-info-top_name">{{ conversation.data.name }}</text>
  25. <view class="item-info-top_time">{{ formatDate(conversation.lastMessage.timestamp) }}</view>
  26. </view>
  27. <view class="item-info-bottom">
  28. <view class="item-info-bottom-item">
  29. <view class="item-info-top_content" v-if="!conversation.lastMessage.recalled">
  30. <text class="unread-text">
  31. {{ conversation.lastMessage.read === false && conversation.lastMessage.senderId === currentUser.userId ? '[未读]' : '' }}
  32. </text>
  33. <text v-if="conversation.lastMessage.senderId === currentUser.userId">我: </text>
  34. <text v-else>{{ conversation.type === 'group' ? conversation.lastMessage.senderData.name : conversation.data.name }}: </text>
  35. <text v-if="conversation.lastMessage.type === 'text'">{{ conversation.lastMessage.payload.text }}</text>
  36. <text v-else-if="conversation.lastMessage.type === 'video'">[视频消息]</text>
  37. <text v-else-if="conversation.lastMessage.type === 'audio'">[语音消息]</text>
  38. <text v-else-if="conversation.lastMessage.type === 'image'">[图片消息]</text>
  39. <text v-else-if="conversation.lastMessage.type === 'file'">[文件消息]</text>
  40. <text v-else-if="conversation.lastMessage.type === 'order'">[自定义消息:订单]</text>
  41. <text v-else-if="conversation.lastMessage.type === 'pic'">[图片消息]</text>
  42. <text v-else-if="conversation.lastMessage.type === 'car'">[车辆信息]</text>
  43. <text v-else>[[未识别内容]]</text>
  44. </view>
  45. <view class="item-info-top_content" v-else>
  46. <text>
  47. {{conversation.lastMessage.recaller.id === currentUser.userId ? '你' : conversation.lastMessage.recaller.data.name}}撤回了一条消息
  48. </text>
  49. </view>
  50. <view class="item-info-bottom_action" @click.stop="showAction(conversation)"></view>
  51. </view>
  52. </view>
  53. </view>
  54. </view>
  55. </view>
  56. <view class="no-conversation" v-else>当前没有会话</view>
  57. <view class="action-container" v-if="actionPopup.visible">
  58. <view class="layer" @click="actionPopup.visible = false"></view>
  59. <view class="action-box">
  60. <view class="action-item" @click="topConversation">
  61. {{ actionPopup.conversation.top ? '取消置顶' : '置顶聊天' }}
  62. </view>
  63. <view class="action-item" @click="deleteConversation">删除聊天</view>
  64. </view>
  65. </view>
  66. </scroll-view>
  67. </template>
  68. <script>
  69. import {formatDate} from '../lib/utils';
  70. import restApi from '../lib/restapi';
  71. const GoEasy = uni.$GoEasy;
  72. const GRTC = uni.$GRTC;
  73. export default {
  74. name: 'conversation',
  75. data() {
  76. return {
  77. conversations: [],
  78. actionPopup: {
  79. conversation: null,
  80. visible: false
  81. },
  82. currentUser: null,
  83. loginInfo:'',
  84. iStatusBarHeight:'',
  85. }
  86. },
  87. onLoad() {
  88. this.iStatusBarHeight = uni.getSystemInfoSync().statusBarHeight;
  89. },
  90. onShow() {
  91. this.loginInfo=uni.getStorageSync('loginInfo');
  92. /* uni.setNavigationBarTitle({
  93. title:this.loginInfo.supplierName
  94. }); */
  95. // uni.$currentUser = uni.getStorageSync('loginInfo');
  96. this.currentUser = uni.getStorageSync('loginInfo') // uni.$currentUser;
  97. console.log(this.currentUser)
  98. if (!this.currentUser) {
  99. uni.navigateTo({ url: './login' });
  100. return;
  101. }
  102. console.log("onShowconversations")
  103. // if (GoEasy.getConnectionStatus() === 'disconnected') {
  104. this.connectGoEasy(); //连接goeasy
  105. this.subscribeGroup(); //建立连接后,就应该订阅群聊消息,避免漏掉
  106. // }
  107. this.loadConversations(); //加载会话列表
  108. this.initGoEasyListeners();
  109. },
  110. onHide() {
  111. if (GoEasy.getConnectionStatus() === 'disconnected') {
  112. return
  113. }
  114. GoEasy.im.off(GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, this.renderConversations);
  115. },
  116. methods: {
  117. formatDate,
  118. connectGoEasy() {
  119. uni.showLoading();
  120. GoEasy.connect({
  121. id: this.currentUser.userId,
  122. data: {
  123. name: this.currentUser.supplierName,
  124. avatar: ''
  125. },
  126. onSuccess: () => {
  127. console.log('GoEasy connect successfully.')
  128. },
  129. onFailed: (error) => {
  130. console.log('Failed to connect GoEasy, code:' + error.code + ',error:' + error.content);
  131. },
  132. onProgress: (attempts) => {
  133. console.log('GoEasy is connecting', attempts);
  134. }
  135. });
  136. },
  137. initGoEasyListeners() {
  138. GoEasy.im.on(GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, this.renderConversations); //监听会话列表变化
  139. GoEasy.im.off(GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, this.setUnreadAmount); // 移除之前的设置角标回调,防止重复回调
  140. GoEasy.im.on(GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, this.setUnreadAmount); // 设置角标
  141. // #ifdef APP-PLUS || H5
  142. GRTC.off(GRTC.EVENT.RING, this.onRing); //移除之前的监听来电事件,防止重复回调
  143. GRTC.on(GRTC.EVENT.RING, this.onRing); //监听来电事件
  144. // #endif
  145. },
  146. goBack(){
  147. //app交互
  148. var standalone = window.navigator.standalone
  149. var userAgent = window.navigator.userAgent.toLowerCase()
  150. var safari = /safari/.test(userAgent)
  151. var ios = /iphone|ipod|ipad|mac/.test(userAgent)
  152. var android = /android/.test(userAgent)
  153. if (ios) {
  154. if ( true) {//!standalone&& !safari
  155. window.webkit.messageHandlers.goMyNav.postMessage(null)
  156. }
  157. } else if (android) {
  158. window.android.postMessage()
  159. }
  160. },
  161. onRing() {
  162. const currentCall = GRTC.currentCall();
  163. if (currentCall.groupId) {
  164. uni.navigateTo({
  165. url: `./rtc/group/ring`,
  166. })
  167. } else {
  168. uni.navigateTo({
  169. url: `./rtc/private/ring`,
  170. })
  171. }
  172. },
  173. // 加载最新的会话列表
  174. loadConversations() {
  175. GoEasy.im.latestConversations({
  176. onSuccess: (result) => {
  177. uni.hideLoading();
  178. let content = result.content;
  179. this.renderConversations(content);
  180. this.setUnreadAmount(content);
  181. },
  182. onFailed: (error) => {
  183. uni.hideLoading();
  184. console.log('获取最新会话列表失败, error:', error);
  185. }
  186. });
  187. },
  188. renderConversations(content) {
  189. this.conversations = content.conversations;
  190. console.log("消息列表")
  191. console.log(this.conversations)
  192. },
  193. setUnreadAmount(content) {
  194. const unreadTotal = content.unreadTotal;
  195. if(unreadTotal > 0) {
  196. uni.setTabBarBadge({
  197. index: 0,
  198. text: unreadTotal.toString()
  199. });
  200. }else{
  201. uni.removeTabBarBadge({index: 0});
  202. }
  203. // #ifdef APP-PLUS
  204. GoEasy.setBadge({
  205. badge: unreadTotal,
  206. onSuccess: function () {
  207. console.log("setBadge successfully.")
  208. },
  209. onFailed: function (error) {
  210. console.log("Failed to setBadge,error:" + error);
  211. }
  212. });
  213. // #endif
  214. },
  215. subscribeGroup() {
  216. let groups = restApi.findGroups(this.currentUser);
  217. let groupIds = groups.map(item => item.id);
  218. GoEasy.im.subscribeGroup({
  219. groupIds: groupIds,
  220. onSuccess: function () {
  221. console.log('订阅群消息成功');
  222. },
  223. onFailed: function (error) {
  224. console.log('订阅群消息失败:', error);
  225. }
  226. });
  227. },
  228. topConversation() { //会话置顶
  229. this.actionPopup.visible = false;
  230. let conversation = this.actionPopup.conversation;
  231. let description = conversation.top ? '取消置顶' : '置顶';
  232. GoEasy.im.topConversation({
  233. conversation: conversation,
  234. top: !conversation.top,
  235. onSuccess: function () {
  236. uni.showToast({
  237. title: description + '成功',
  238. icon: 'none'
  239. });
  240. },
  241. onFailed: function (error) {
  242. console.log(description, '失败:', error);
  243. }
  244. });
  245. },
  246. deleteConversation() {
  247. uni.showModal({
  248. content: '确认删除这条会话吗?',
  249. success: (res) => {
  250. if (res.confirm) {
  251. let conversation = this.actionPopup.conversation;
  252. this.actionPopup.visible = false;
  253. GoEasy.im.removeConversation({
  254. conversation: conversation,
  255. onSuccess: function () {
  256. console.log('删除会话成功');
  257. },
  258. onFailed: function (error) {
  259. console.log(error);
  260. },
  261. });
  262. } else {
  263. this.actionPopup.visible = false;
  264. }
  265. },
  266. })
  267. },
  268. chat(conversation) {
  269. let path = conversation.type === GoEasy.IM_SCENE.PRIVATE ?
  270. './privateChatG?to=' + conversation.userId :
  271. './groupChat?to=' + conversation.groupId;
  272. var friend={
  273. id:conversation.userId,
  274. supplierName:conversation.data.name,
  275. avatar:conversation.data.avatar,
  276. }
  277. uni.setStorage({
  278. key: 'friend',
  279. data: friend,
  280. success: function () {
  281. /* uni.navigateTo({
  282. url: './privateChat?to=' + friend.ID
  283. }); */
  284. uni.navigateTo({ url: path });
  285. }
  286. });
  287. },
  288. showAction(conversation) {
  289. this.actionPopup.conversation = conversation;
  290. this.actionPopup.visible = true;
  291. }
  292. }
  293. }
  294. </script>
  295. <style scoped>
  296. page {
  297. height: 100%;
  298. }
  299. .conversations {
  300. width: 750rpx;
  301. overflow-x: hidden;
  302. display: flex;
  303. flex-direction: column;
  304. height: 100%;
  305. }
  306. .conversations .scroll-item {
  307. height: 152rpx;
  308. display: flex;
  309. align-items: center;
  310. padding-left: 32rpx;
  311. }
  312. .conversations .scroll-item .head-icon {
  313. width: 100rpx;
  314. height: 100rpx;
  315. margin-right: 28rpx;
  316. }
  317. .conversations .scroll-item_info {
  318. height: 151rpx;
  319. width: 590rpx;
  320. padding-right: 32rpx;
  321. border-bottom: 1px solid #EFEFEF;
  322. }
  323. .conversations .scroll-item_info .item-info-top {
  324. padding-top: 20rpx;
  325. height: 60rpx;
  326. line-height: 60rpx;
  327. display: flex;
  328. align-items: center;
  329. justify-content: space-between;
  330. }
  331. .conversations .item-info-top_name {
  332. font-size: 30rpx;
  333. color: #262628;
  334. overflow: hidden;
  335. text-overflow: ellipsis;
  336. width: 370rpx;
  337. white-space: nowrap;
  338. }
  339. .conversations .item-info-top_time {
  340. font-size: 34rpx;
  341. color: rgba(179, 179, 179, 0.8);
  342. }
  343. .conversations .item-info-bottom {
  344. height: 40rpx;
  345. line-height: 40rpx;
  346. overflow: hidden;
  347. }
  348. .conversations .item-info-bottom-item {
  349. display: flex;
  350. justify-content: space-between;
  351. }
  352. .item-info-bottom .item-info-top_content {
  353. font-size: 34rpx;
  354. color: #b3b3b3;
  355. overflow: hidden;
  356. text-overflow: ellipsis;
  357. white-space: nowrap;
  358. }
  359. .item-info-bottom .item-info-bottom_action {
  360. width: 50rpx;
  361. height: 50rpx;
  362. font-size: 34rpx;
  363. background: url("../static/images/action.png") no-repeat center;
  364. background-size: 28rpx 30rpx;
  365. }
  366. .no-conversation {
  367. width: 100%;
  368. text-align: center;
  369. height: 80rpx;
  370. line-height: 80rpx;
  371. font-size: 34rpx;
  372. color: #9D9D9D;
  373. }
  374. .item-head {
  375. position: relative;
  376. }
  377. .item-head .item-head_unread {
  378. padding: 6rpx;
  379. background-color: #EE593C;
  380. color: #FFFFFF;
  381. font-size: 34rpx;
  382. line-height: 28rpx;
  383. border-radius: 24rpx;
  384. min-width: 24rpx;
  385. min-height: 24rpx;
  386. text-align: center;
  387. position: absolute;
  388. top: 0;
  389. right: 15rpx;
  390. }
  391. .action-container {
  392. width: 100%;
  393. height: 100%;
  394. position: fixed;
  395. top: 0;
  396. left: 0;
  397. display: flex;
  398. justify-content: center;
  399. align-items: center;
  400. }
  401. .action-container .layer {
  402. position: absolute;
  403. top: 0;
  404. left: 0;
  405. background: rgba(51, 51, 51, 0.5);
  406. width: 100%;
  407. height: 100%;
  408. z-index: 99;
  409. }
  410. .action-box {
  411. width: 400rpx;
  412. height: 240rpx;
  413. background: #ffffff;
  414. position: relative;
  415. z-index: 100;
  416. border-radius: 20rpx;
  417. overflow: hidden;
  418. }
  419. .action-item {
  420. text-align: center;
  421. line-height: 120rpx;
  422. font-size: 34rpx;
  423. color: #262628;
  424. border-bottom: 1px solid #EFEFEF;
  425. }
  426. .unread-text {
  427. color: #d02129;
  428. }
  429. .backImg{
  430. width: 44rpx;
  431. height: 44rpx;
  432. /* margin-left: 10rpx; */
  433. /* margin-right: 20rpx; */
  434. }
  435. .nav{
  436. height: 44px;
  437. display: flex;
  438. justify-content: space-between;
  439. align-items: center;
  440. border-bottom: 1px solid #eaeaea;
  441. }
  442. .goVin{
  443. width: 2rpx;
  444. color: #3F90F7;
  445. text-align: right;
  446. padding-right: 20rpx;
  447. }
  448. .navLeft{
  449. width: 2rpx;
  450. padding-left: 20rpx;
  451. }
  452. .navBox{
  453. position: fixed;
  454. left: 0;
  455. top: 0;
  456. z-index: 11;
  457. width: 100vw;
  458. }
  459. </style>