conversations.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  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: 88rpx;
  314. height: 88rpx;
  315. margin-right: 28rpx;
  316. border-radius: 8rpx;
  317. }
  318. .conversations .scroll-item_info {
  319. height: 151rpx;
  320. width: 590rpx;
  321. padding-right: 32rpx;
  322. border-bottom: 1px solid #EFEFEF;
  323. }
  324. .conversations .scroll-item_info .item-info-top {
  325. padding-top: 20rpx;
  326. height: 60rpx;
  327. line-height: 60rpx;
  328. display: flex;
  329. align-items: center;
  330. justify-content: space-between;
  331. }
  332. .conversations .item-info-top_name {
  333. font-size: 30rpx;
  334. color: #1C1C1C;
  335. overflow: hidden;
  336. text-overflow: ellipsis;
  337. width: 370rpx;
  338. white-space: nowrap;
  339. }
  340. .conversations .item-info-top_time {
  341. font-size: 24rpx;
  342. color: #BFBFBF;
  343. }
  344. .conversations .item-info-bottom {
  345. height: 40rpx;
  346. line-height: 40rpx;
  347. overflow: hidden;
  348. }
  349. .conversations .item-info-bottom-item {
  350. display: flex;
  351. justify-content: space-between;
  352. }
  353. .item-info-bottom .item-info-top_content {
  354. font-size: 26rpx;
  355. color: #A5A5A5;
  356. overflow: hidden;
  357. text-overflow: ellipsis;
  358. white-space: nowrap;
  359. }
  360. .item-info-bottom .item-info-bottom_action {
  361. width: 50rpx;
  362. height: 50rpx;
  363. font-size: 34rpx;
  364. background: url("../static/images/action.png") no-repeat center;
  365. background-size: 28rpx 30rpx;
  366. }
  367. .no-conversation {
  368. width: 100%;
  369. text-align: center;
  370. height: 80rpx;
  371. line-height: 80rpx;
  372. font-size: 34rpx;
  373. color: #9D9D9D;
  374. }
  375. .item-head {
  376. position: relative;
  377. }
  378. .item-head .item-head_unread {
  379. padding: 6rpx;
  380. background-color: #EE593C;
  381. color: #FFFFFF;
  382. font-size: 34rpx;
  383. line-height: 28rpx;
  384. border-radius: 24rpx;
  385. min-width: 24rpx;
  386. min-height: 24rpx;
  387. text-align: center;
  388. position: absolute;
  389. top: -10rpx;
  390. right: 15rpx;
  391. }
  392. .action-container {
  393. width: 100%;
  394. height: 100%;
  395. position: fixed;
  396. top: 0;
  397. left: 0;
  398. display: flex;
  399. justify-content: center;
  400. align-items: center;
  401. }
  402. .action-container .layer {
  403. position: absolute;
  404. top: 0;
  405. left: 0;
  406. background: rgba(51, 51, 51, 0.5);
  407. width: 100%;
  408. height: 100%;
  409. z-index: 99;
  410. }
  411. .action-box {
  412. width: 400rpx;
  413. height: 240rpx;
  414. background: #ffffff;
  415. position: relative;
  416. z-index: 100;
  417. border-radius: 20rpx;
  418. overflow: hidden;
  419. }
  420. .action-item {
  421. text-align: center;
  422. line-height: 120rpx;
  423. font-size: 34rpx;
  424. color: #262628;
  425. border-bottom: 1px solid #EFEFEF;
  426. }
  427. .unread-text {
  428. color: #d02129;
  429. }
  430. .backImg{
  431. width: 44rpx;
  432. height: 44rpx;
  433. /* margin-left: 10rpx; */
  434. /* margin-right: 20rpx; */
  435. }
  436. .nav{
  437. height: 44px;
  438. display: flex;
  439. justify-content: space-between;
  440. align-items: center;
  441. border-bottom: 1px solid #eaeaea;
  442. }
  443. .goVin{
  444. width: 2rpx;
  445. color: #3F90F7;
  446. text-align: right;
  447. padding-right: 20rpx;
  448. }
  449. .navLeft{
  450. width: 2rpx;
  451. padding-left: 20rpx;
  452. }
  453. .navBox{
  454. position: fixed;
  455. left: 0;
  456. top: 0;
  457. z-index: 11;
  458. width: 100vw;
  459. }
  460. .nav .title{
  461. font-size: 32rpx;font-weight: 500;
  462. }
  463. </style>