conversations.vue 14 KB

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