diff --git a/apis/interfaces/im.js b/apis/interfaces/im.js index 2eb828a..deb8b1c 100644 --- a/apis/interfaces/im.js +++ b/apis/interfaces/im.js @@ -117,9 +117,10 @@ const getGroupBase = (groupId) => { }) } -const getGroupUsers = (groupId) => { +const getGroupUsers = (groupId, limit) => { + limit = limit || 0 return request({ - url: 'im/groups/' + groupId + '/users' + url: 'im/groups/' + groupId + '/users?limit=' + limit }) } @@ -195,7 +196,7 @@ const joinGroup = (groupId, message) => { const quitGroup = (groupId) => { return request({ - method: 'POST', + method: 'DELETE', url: 'im/groups/' + groupId + '/quit' }) } @@ -210,6 +211,59 @@ const dismissGroup = (groupId) => { }) } +/** + * 移除群成员 + */ +const removeGroupUser = (groupId, userId) => { + return request({ + method: 'DELETE', + url: 'im/groups/' + groupId + '/users/' + userId + }) +} + +/** + * 邀请群成员 + */ +const inviteGroupUser = (groupId, userIds) => { + return request({ + method: 'POST', + url: 'im/groups/' + groupId + '/invite', + data: { + userIds + } + }) +} + +/** + * 设置群管理 + */ +const setGroupAdmin = (groupId, userId) => { + return request({ + method: 'POST', + url: 'im/groups/' + groupId + '/admin/' + userId + }) +} + +/** + * 移除群管理 + */ +const removeGroupAdmin = (groupId, userId) => { + return request({ + method: 'DELETE', + url: 'im/groups/' + groupId + '/admin/' + userId + }) +} + +/** + * 转移群主 + */ +const transferGroupOwner = (groupId, userId) => { + return request({ + method: 'DELETE', + url: 'im/groups/' + groupId + '/owner/' + userId + }) +} + export { getImToken, deleteFriend, @@ -235,5 +289,10 @@ export { joinGroupPre, joinGroup, quitGroup, - dismissGroup + dismissGroup, + inviteGroupUser, + removeGroupUser, + setGroupAdmin, + removeGroupAdmin, + transferGroupOwner } diff --git a/pages.json b/pages.json index d662e57..61a9c6a 100644 --- a/pages.json +++ b/pages.json @@ -52,8 +52,8 @@ "path": "pages/record/foods", "name": "RecordFoods", "style": { - "navigationBarTitleText": "", - "navigationStyle": "custom" + "navigationBarTitleText": "", + "navigationStyle": "custom" } }, { @@ -467,33 +467,40 @@ } } } - }, - { - "path": "pages/im/group/apply", - "name": "imGroupApply", - "style": { - "navigationBarTitleText": "申请加群" - } + }, + { + "path": "pages/im/group/apply", + "name": "imGroupApply", + "style": { + "navigationBarTitleText": "申请加群" + } }, { "path": "pages/im/group/info", "name": "imGroupInfo", "style": { - "navigationBarTitleText": "群信息" + "navigationBarTitleText": "群信息" + } + }, + { + "path": "pages/im/group/invite", + "name": "imGroupInvite", + "style": { + "navigationBarTitleText": "邀请好友" } }, { "path": "pages/im/group/users", "name": "imGroupUsers", "style": { - "navigationBarTitleText": "群成员" + "navigationBarTitleText": "群成员" } }, { "path": "pages/im/group/announcement", "name": "imGroupAnnouncement", "style": { - "navigationBarTitleText": "群公告", + "navigationBarTitleText": "群公告", "app-plus": { "titleNView": { "type": "default", @@ -511,7 +518,7 @@ "path": "pages/im/group/announceCreate", "name": "imGroupAnnouncementCreate", "style": { - "navigationBarTitleText": "发布群公告" + "navigationBarTitleText": "发布群公告" } }, { diff --git a/pages/auth/auth.vue b/pages/auth/auth.vue index 05f59cf..ec3b273 100644 --- a/pages/auth/auth.vue +++ b/pages/auth/auth.vue @@ -39,6 +39,11 @@ smsAuth } from "@/apis/interfaces/auth"; import userAuth from "@/public/userAuth"; + import { + getImToken + } from '@/apis/interfaces/im.js' + import im from '@/utils/im/index.js' + export default { data() { return { @@ -59,6 +64,11 @@ "setToken", res.token_type + " " + res.access_token ); + // 在这里,登录成功,链接IM服务 + getImToken().then(res => { + console.log('在这获取IM-TOKEN', res); + im.connect(res.token, res.userInfo, () => {}) + }) this.$Router.back(); }).catch((err) => { uni.showToast({ diff --git a/pages/im/group/chat.nvue b/pages/im/group/chat.nvue index 74bac82..151eec2 100644 --- a/pages/im/group/chat.nvue +++ b/pages/im/group/chat.nvue @@ -3,7 +3,8 @@ - + @@ -16,7 +17,7 @@ - + @@ -43,12 +44,23 @@ data() { return { targetId: '', - conversationType: 3, + conversationType: RongIMLib.ConversationType.GROUP, messages: [], groupInfo: { name: '' } } + }, + computed: { + latestMessage() { + if (this.messages.length > 1) { + return this.messages[this.messages.length - 1] + } else { + return { + sentTime: 0 + } + } + } }, onLoad(e) { this.targetId = e.targetId @@ -59,42 +71,50 @@ this.getMessageList() uni.$on('onReceiveMessage', (msg) => { if (msg.targetId == this.targetId) { - this.getMessageList() + this.getNewMessage() } - }) - uni.$once('cleanGroupMessage', this.getMessageList) - }, - onBackPress() { - uni.$off('onReceiveMessage') - console.log('Off onReceiveMessage'); + }) + uni.$once('cleanGroupMessage', this.getMessageList) }, onNavigationBarButtonTap() { uni.navigateTo({ url: '/pages/im/group/info?targetId=' + this.targetId }) }, - methods: { - toUser(item) { - if (item.senderUserId == '__system__') { - return - } - if (item.messageDirection == 1) { - uni.navigateTo({ - url: '/pages/im/friends/mine?targetId=' + item.senderUserId - }) - } else{ - uni.navigateTo({ - url: '/pages/im/friends/info?targetId=' + item.senderUserId - }) - } + methods: { + toUser(item) { + if (item.senderUserId == '__system__') { + return + } + if (item.messageDirection == 1) { + uni.navigateTo({ + url: '/pages/im/friends/mine?targetId=' + item.senderUserId + }) + } else { + uni.navigateTo({ + url: '/pages/im/friends/info?targetId=' + item.senderUserId + }) + } + }, + getNewMessage() { + im.getMessageList( + this.conversationType, + this.targetId, + this.latestMessage.sentTime, + 1, + false, + (messages) => { + this.messages = this.messages.concat(messages) + this.scrollBottom() + }) }, // 获取消息列表 getMessageList() { im.getMessageList( this.conversationType, this.targetId, - new Date().getTime(), - 20, + 0, + 100, true, (messages) => { this.messages = messages.reverse() @@ -103,12 +123,15 @@ }, // 滚动到底部 scrollBottom(type) { - // 清理当前会话,未读消息数量 - RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, new Date().getTime() + 1100) - // 发送消息已读状态给对方 - RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, new Date().getTime()) - // 更新badge提醒数量 - im.setNotifyBadge() + if (this.latestMessage) { + // 清理当前会话,未读消息数量 + RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, this.latestMessage + .sentTime) + // // 发送消息已读状态给对方 + // RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, this.latestMessage.sentTime) + // 更新badge提醒数量 + im.setNotifyBadge() + } setTimeout(() => { let el = this.$refs.chatBottom diff --git a/pages/im/group/info.vue b/pages/im/group/info.vue index 2ca4871..f716b78 100644 --- a/pages/im/group/info.vue +++ b/pages/im/group/info.vue @@ -2,8 +2,11 @@ - - + + + {{ item.name }} @@ -57,6 +60,10 @@ + + + @@ -65,7 +72,12 @@ getGroupInfo, updateGroup, quitGroup, - dismissGroup + removeGroupUser, + setGroupAdmin, + removeGroupAdmin, + dismissGroup, + transferGroupOwner, + getGroupUsers } from '@/apis/interfaces/im.js' import { uploads @@ -90,7 +102,24 @@ qrContent: 'JOINGROUP|', joinType: '', joinTypeMap: [], - showActions: false + showActions: false, + showUserAction: false, + userActionMap: [{ + key: 0, + name: '移除成员', + disabled: false + }, { + key: 1, + name: '设置管理', + disabled: true + }, + { + key: 2, + name: '转移群主', + disabled: true + } + ], + currentUser: {} } }, onLoad(e) { @@ -110,18 +139,23 @@ } }) this.initData() + this.initUsers() uni.$on('groupAnnouncementCreated', this.initData) }, onUnload() { uni.$off('groupAnnouncementCreated') }, methods: { + initUsers() { + getGroupUsers(this.targetId, 14).then(res => { + this.users = res + }) + }, initData() { getGroupInfo(this.targetId).then(res => { this.group = res.group this.groupName = res.group.name this.announcement = res.announcement - this.users = res.users this.members = res.members this.loaded = true this.joinTypeMap = res.join_type_map.map(item => { @@ -132,6 +166,7 @@ return item.key == res.join_type })[0].name }).catch(err => { + console.log('getGroupInfo ERR', err); uni.showToast({ icon: 'none', title: '群不存在' @@ -167,7 +202,9 @@ } }, inviteUser() { - + uni.navigateTo({ + url: '/pages/im/group/invite?targetId=' + this.targetId + }) }, loadMore() { uni.navigateTo({ @@ -209,7 +246,6 @@ }, // 修改群头像 onGroupAvatar() { - console.log('onGroupAvatar'); uni.chooseImage({ count: 1, sourceType: ['album'], @@ -268,7 +304,7 @@ item.disabled = false } return item - }) + }) this.initData() this.joinType = e.name this.showActions = false @@ -324,14 +360,86 @@ uni.showToast({ icon: 'none', title: '退出群聊成功' - }) + }) + // 移除指定的会话 + RongIMLib.removeConversation(this.conversationType, this.targetId) + uni.switchTab({ url: '/pages/im/index' }) + }).catch(err => { + console.log(err); }) } } }) + }, + showUserActionSheet(item) { + this.currentUser = item + // 只有管理员以上才会弹窗 + if (this.group.is_admin) { + if (this.group.is_owner) { + this.userActionMap.map((item) => { + item.disabled = false + return item + }) + } + this.showUserAction = true + } + }, + hideUserAction() { + this.currentUser = {} + this.showUserAction = false + }, + handleUserAction(e) { + switch (e.key) { + case 0: + removeGroupUser(this.targetId, this.currentUser.targetId).then(res => { + uni.showToast({ + icon: 'none', + title: '成员移除成功' + }) + }).catch(err => { + uni.showToast({ + icon: 'none', + title: err.message + }) + }).finally(() => { + this.initUsers() + }) + break; + case 1: + setGroupAdmin(this.targetId, this.currentUser.targetId).then(res => { + uni.showToast({ + icon: 'none', + title: '设置管理成功' + }) + }).catch(err => { + uni.showToast({ + icon: 'none', + title: err.message + }) + }).finally(() => { + this.initUsers() + }) + break; + case 2: + transferGroupOwner(this.targetId, this.currentUser.targetId).then(res => { + uni.showToast({ + icon: 'none', + title: '群主转让成功' + }) + }).catch(err => { + uni.showToast({ + icon: 'none', + title: err.message + }) + }).finally(() => { + this.initUsers() + this.initData() + }) + break; + } } } } @@ -367,6 +475,10 @@ justify-content: center; align-items: center; + &.active { + background-color: $window-color; + } + .name { color: $text-gray-m; width: 126rpx; diff --git a/pages/im/group/invite.vue b/pages/im/group/invite.vue new file mode 100644 index 0000000..fa5fb59 --- /dev/null +++ b/pages/im/group/invite.vue @@ -0,0 +1,21 @@ + + + + + diff --git a/pages/im/private/chat.nvue b/pages/im/private/chat.nvue index 57e407c..02dfc0f 100644 --- a/pages/im/private/chat.nvue +++ b/pages/im/private/chat.nvue @@ -6,8 +6,9 @@ {{ customCN(item.sentTime) }} - - + + @@ -23,7 +24,7 @@ - + @@ -41,6 +42,12 @@ const ChatList = uni.requireNativePlugin('dom') export default { + components: { + sentMessageBar, + showVoice, + showImage, + showText + }, data() { return { targetId: '', @@ -53,11 +60,16 @@ } } }, - components: { - sentMessageBar, - showVoice, - showImage, - showText + computed: { + latestMessage() { + if (this.messages.length > 1) { + return this.messages[this.messages.length - 1] + } else { + return { + sentTime: 0 + } + } + } }, onLoad(e) { this.targetId = e.targetId @@ -70,30 +82,48 @@ // 监听消息已读状态 uni.$on('onReadReceiptReceived', (data) => { if (data.targetId == this.targetId) { - this.getMessageList() + this.messages = this.messages.map((item) => { + if (item.messageDirection == 1 && item.sentStatus == 30 && item.receivedTime < + data.messageTime + 1000) { + item.sentStatus = 50 + } + return item + }) } }) // 监听收到新消息,判断是否是当前会话,更新会话内容 uni.$on('onReceiveMessage', (msg) => { if (msg.targetId == this.targetId) { - this.getMessageList() + this.getNewMessage() } }) }, - onBackPress() { - uni.$off('onReceiveMessage') + onUnload() { + uni.$off('onReadReceiptReceived') }, methods: { customCN(val) { return timeCustomCN(val) }, + getNewMessage() { + im.getMessageList( + this.conversationType, + this.targetId, + this.latestMessage.sentTime || 0, + 1, + false, + (messages) => { + this.messages = this.messages.concat(messages) + this.scrollBottom() + }) + }, // 获取消息列表 getMessageList() { im.getMessageList( this.conversationType, this.targetId, - new Date().getTime(), - 10, + 0, + 100, true, (messages) => { this.messages = messages.reverse() @@ -109,12 +139,15 @@ }, // 滚动到底部 scrollBottom(type) { - // 清理当前会话,未读消息数量 - RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, new Date().getTime() + 1100) - // 发送消息已读状态给对方 - RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, new Date().getTime()) - // 更新badge提醒数量 - im.setNotifyBadge() + if (this.latestMessage) { + // 清理当前会话,未读消息数量 + RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, this.latestMessage + .sentTime) + // // 发送消息已读状态给对方 + RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, this.latestMessage.sentTime) + // 更新badge提醒数量 + im.setNotifyBadge() + } setTimeout(() => { let el = this.$refs.chatBottom ChatList.scrollToElement(el, { diff --git a/pages/setting/setting.vue b/pages/setting/setting.vue index 124931b..fa6f7f5 100644 --- a/pages/setting/setting.vue +++ b/pages/setting/setting.vue @@ -1,211 +1,213 @@ - - - - - diff --git a/public/userAuth.js b/public/userAuth.js index 0257a3a..faf4df5 100644 --- a/public/userAuth.js +++ b/public/userAuth.js @@ -105,9 +105,11 @@ class userAuth { openid: authResult.authResult.openid }).then(res => { uni.closeAuthView() - store.commit('setToken', res.token_type + ' ' + res.access_token) + store.commit('setToken', res.token_type + ' ' + res + .access_token) // 在这里,登录成功,链接IM服务 getImToken().then(res => { + console.log('在这获取IM-TOKEN', res); im.connect(res.token, res.userInfo) }) resolve() diff --git a/store/modules/im.js b/store/modules/im.js index 7d482b6..8077e66 100644 --- a/store/modules/im.js +++ b/store/modules/im.js @@ -34,7 +34,7 @@ export default { } }, mutations: { - updateContactInfo(state, contactInfo) { + updateContactInfo(state, contactInfo) { Vue.set(state.contacts, contactInfo.targetId, contactInfo) }, setSenderInfo(state, contactInfo) { diff --git a/utils/im/index.js b/utils/im/index.js index 4c22b53..7fdf5dc 100644 --- a/utils/im/index.js +++ b/utils/im/index.js @@ -6,7 +6,8 @@ import listeners from './listeners.js' import { getFriends, getUserInfo, - getImToken + getImToken, + getMyGroups } from '@/apis/interfaces/im.js' const initIm = (KEY) => { @@ -58,7 +59,7 @@ const connect = (token, userInfo, callback) => { // 设置未读消息数量 setNotifyBadge() // 首次运行获取好友列表 - const FK = 'IFT_' + userInfo.targetId + const FK = 'ZHK_' + userInfo.targetId uni.getStorage({ key: FK, @@ -70,12 +71,14 @@ const connect = (token, userInfo, callback) => { }) }) }, - fail: () => { - // 程序是首次运行,初始化加载好友信息 - getFriends().then(res => { - res.map(item => { - store.dispatch('initContact', item) - }) + fail: () => { + // 程序是首次运行,初始化加载好友和群组信息 + Promise.all([getFriends(), getMyGroups()]).then(result => { + result.map(contacts => { + contacts.map(item => { + store.dispatch('initContact', item) + }) + }) uni.setStorageSync(FK, userInfo.targetId) }) } @@ -206,8 +209,8 @@ const newMessage = (msg) => { status }) => { if (code === 0) { - if (status) { - uni.vibrateLong() + if (status) { + uni.vibrateLong() triTone() } } diff --git a/utils/im/message.js b/utils/im/message.js index 15dc586..53e51d1 100644 --- a/utils/im/message.js +++ b/utils/im/message.js @@ -22,7 +22,7 @@ const getMessageList = (conversationType, targetId, timeStamp, count, isForward, conversationType, targetId, objectNames, - timeStamp + 1000, + timeStamp, count, isForward, ({