|
|
|
@ -1,11 +1,29 @@ |
|
|
|
<template> |
|
|
|
<div> |
|
|
|
<div class="imui-center"> |
|
|
|
<lemon-imui |
|
|
|
v-show="showDialog" |
|
|
|
ref="IMUI" |
|
|
|
:user="currentUser" |
|
|
|
@send="handleSendMessage" |
|
|
|
/> |
|
|
|
@pull-messages="onPullMessages" |
|
|
|
@change-menu="onChangeMenu" |
|
|
|
@change-contact="onChangeContract" |
|
|
|
@message-click="handleMessageClick" |
|
|
|
@menu-avatar-click="handleMenuAvatarClick" |
|
|
|
> |
|
|
|
<template #cover> |
|
|
|
<div class="cover"> |
|
|
|
<i class="lemon-icon-message" /> |
|
|
|
<p><b>Lemon</b> IMUI</p> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
<template #contact-title="contact"> |
|
|
|
<span>{{ contact.displayName }}</span> |
|
|
|
<small |
|
|
|
class="more" |
|
|
|
>…</small> |
|
|
|
</template> |
|
|
|
</lemon-imui> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
@ -13,9 +31,16 @@ |
|
|
|
import EventBusMiXin from '@/mixins/EventBusMiXin' |
|
|
|
import Component, { mixins } from 'vue-class-component' |
|
|
|
|
|
|
|
import { abpPagerFormat } from '@/utils' |
|
|
|
|
|
|
|
import { UserModule } from '@/store/modules/user' |
|
|
|
|
|
|
|
import ImApiService, { MyFriendGetByPaged, UserFriend, ChatMessage } from '@/api/instant-message' |
|
|
|
import ImApiService, { |
|
|
|
MyFriendGetByPaged, |
|
|
|
UserMessageGetByPaged, |
|
|
|
UserFriend, |
|
|
|
ChatMessage |
|
|
|
} from '@/api/instant-message' |
|
|
|
|
|
|
|
import { HubConnection, HubConnectionBuilder, HubConnectionState } from '@microsoft/signalr' |
|
|
|
|
|
|
|
@ -26,8 +51,58 @@ class MyContract { |
|
|
|
type = '' |
|
|
|
index = 'A' |
|
|
|
unread = 0 |
|
|
|
lastSendTime = 0 |
|
|
|
lastContent = '0' |
|
|
|
lastSendTime = 1345209465000 |
|
|
|
lastContent = '' |
|
|
|
readMsgPage = 1 |
|
|
|
} |
|
|
|
|
|
|
|
class ChatMenu { |
|
|
|
name = '' |
|
|
|
title = '' |
|
|
|
unread = 0 |
|
|
|
render?: Function |
|
|
|
renderContainer?: Function |
|
|
|
isBottom = false |
|
|
|
|
|
|
|
constructor( |
|
|
|
name: string, |
|
|
|
title: string, |
|
|
|
unread = 0, |
|
|
|
isBottom = false |
|
|
|
) { |
|
|
|
this.name = name |
|
|
|
this.title = title |
|
|
|
this.unread = unread |
|
|
|
this.isBottom = isBottom |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
class FromUser { |
|
|
|
id = '' |
|
|
|
displayName = '' |
|
|
|
avatar = '' |
|
|
|
} |
|
|
|
|
|
|
|
class Message { |
|
|
|
id = '' |
|
|
|
status = '' |
|
|
|
type = 'text' |
|
|
|
sendTime = 0 |
|
|
|
content = '' |
|
|
|
fileSize = 0 |
|
|
|
fileName = '' |
|
|
|
toContactId = '' |
|
|
|
fromUser = new FromUser() |
|
|
|
|
|
|
|
public fromChatMessage(chatMessage: ChatMessage) { |
|
|
|
this.id = chatMessage.messageId |
|
|
|
this.content = chatMessage.content |
|
|
|
this.fromUser.id = chatMessage.formUserId |
|
|
|
this.fromUser.displayName = chatMessage.formUserName |
|
|
|
this.toContactId = chatMessage.toUserId |
|
|
|
this.type = ChatMessage.getType(chatMessage.messageType) |
|
|
|
this.sendTime = new Date(chatMessage.sendTime).getTime() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Component({ |
|
|
|
@ -40,6 +115,9 @@ export default class InstantMessage extends mixins(EventBusMiXin) { |
|
|
|
private myFriends = new Array<UserFriend>() |
|
|
|
|
|
|
|
private connection!: HubConnection |
|
|
|
private chatMenus = new Array<ChatMenu>() |
|
|
|
|
|
|
|
private getChatMessageFilter = new UserMessageGetByPaged() |
|
|
|
|
|
|
|
get currentUser() { |
|
|
|
return { |
|
|
|
@ -50,7 +128,9 @@ export default class InstantMessage extends mixins(EventBusMiXin) { |
|
|
|
} |
|
|
|
|
|
|
|
mounted() { |
|
|
|
this.unSubscribeAll() |
|
|
|
this.subscribe('onShowImDialog', this.onShowImDialog) |
|
|
|
this.handleInitDefaultMenus() |
|
|
|
this.handleStartConnection() |
|
|
|
} |
|
|
|
|
|
|
|
@ -58,6 +138,40 @@ export default class InstantMessage extends mixins(EventBusMiXin) { |
|
|
|
this.unSubscribe('onShowImDialog') |
|
|
|
} |
|
|
|
|
|
|
|
private handleInitIMUI() { |
|
|
|
const imui = this.$refs.IMUI as any |
|
|
|
ImApiService |
|
|
|
.getMyFriends(this.dataFilter) |
|
|
|
.then(res => { |
|
|
|
this.myFriends = res.items |
|
|
|
this.myFriendCount = res.totalCount |
|
|
|
this.handleInitContracts(imui) |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
private handleInitContracts(imui: any) { |
|
|
|
const myContracts = new Array<MyContract>() |
|
|
|
this.myFriends |
|
|
|
.forEach(friend => { |
|
|
|
const myContract = new MyContract() |
|
|
|
myContract.id = friend.friendId |
|
|
|
myContract.displayName = friend.remarkName ?? friend.userName |
|
|
|
myContract.unread = 0 |
|
|
|
myContract.lastSendTime = new Date().getTime() |
|
|
|
myContract.lastContent = '1524545' |
|
|
|
myContract.type = 'many' |
|
|
|
myContracts.push(myContract) |
|
|
|
}) |
|
|
|
imui.initContacts(myContracts) |
|
|
|
imui.initMenus(this.chatMenus) |
|
|
|
} |
|
|
|
|
|
|
|
private handleInitDefaultMenus() { |
|
|
|
const lastMsgMenu = new ChatMenu('lastMessages', '历史消息') |
|
|
|
const contractsMenu = new ChatMenu('contacts', '联系人') |
|
|
|
this.chatMenus.push(lastMsgMenu, contractsMenu) |
|
|
|
} |
|
|
|
|
|
|
|
private handleStartConnection() { |
|
|
|
if (!this.connection) { |
|
|
|
const builder = new HubConnectionBuilder() |
|
|
|
@ -66,6 +180,10 @@ export default class InstantMessage extends mixins(EventBusMiXin) { |
|
|
|
.withUrl('/signalr-hubs/signalr-hubs/messages', { accessTokenFactory: () => userToken }) |
|
|
|
.withAutomaticReconnect({ nextRetryDelayInMilliseconds: () => 60000 }) |
|
|
|
.build() |
|
|
|
this.connection.on('getChatMessage', this.handleReceiveMessage) |
|
|
|
this.connection.onreconnected(() => { |
|
|
|
this.handleInitIMUI() |
|
|
|
}) |
|
|
|
this.connection.onclose(error => { |
|
|
|
console.log('signalr connection has closed, error:') |
|
|
|
console.log(error) |
|
|
|
@ -75,36 +193,83 @@ export default class InstantMessage extends mixins(EventBusMiXin) { |
|
|
|
this.connection |
|
|
|
.start() |
|
|
|
.then(() => { |
|
|
|
this.handleInitIMUI() |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private onShowImDialog() { |
|
|
|
this.showDialog = !this.showDialog |
|
|
|
} |
|
|
|
|
|
|
|
private onChangeMenu() { |
|
|
|
console.log('Event:change-menu') |
|
|
|
} |
|
|
|
|
|
|
|
private onPullMessages(contact: any, next: any) { |
|
|
|
console.log(contact) |
|
|
|
const imui = this.$refs.IMUI as any |
|
|
|
if (this.getChatMessageFilter.receiveUserId !== contact.id) { |
|
|
|
this.getChatMessageFilter.receiveUserId = contact.id |
|
|
|
} else { |
|
|
|
contact.readMsgPage += 1 |
|
|
|
} |
|
|
|
this.getChatMessageFilter.skipCount = abpPagerFormat(contact.readMsgPage, this.getChatMessageFilter.maxResultCount) |
|
|
|
ImApiService |
|
|
|
.getMyFriends(this.dataFilter) |
|
|
|
.getMyChatMessages(this.getChatMessageFilter) |
|
|
|
.then(res => { |
|
|
|
this.myFriends = res.items |
|
|
|
this.myFriendCount = res.totalCount |
|
|
|
this.handleInitContracts() |
|
|
|
const messages = res.items |
|
|
|
.sort((last, next) => { |
|
|
|
return next.sendTime < last.sendTime ? 1 : -1 |
|
|
|
}) |
|
|
|
.map(msg => { |
|
|
|
const message = new Message() |
|
|
|
message.fromChatMessage(msg) |
|
|
|
return message |
|
|
|
}) |
|
|
|
let isEnd = true |
|
|
|
if (imui.getMessages(contact.id).length < res.totalCount) { |
|
|
|
isEnd = false |
|
|
|
} |
|
|
|
next(messages, isEnd) |
|
|
|
}) |
|
|
|
.catch(() => { |
|
|
|
next(new Array<Message>(), true) |
|
|
|
imui.messageViewToBottom() |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
private handleInitContracts() { |
|
|
|
const myContracts = new Array<MyContract>() |
|
|
|
this.myFriends |
|
|
|
.forEach(friend => { |
|
|
|
const myContract = new MyContract() |
|
|
|
myContract.id = friend.friendId |
|
|
|
myContract.displayName = friend.remarkName ?? friend.userName |
|
|
|
myContracts.push(myContract) |
|
|
|
}) |
|
|
|
const imui = this.$refs.IMUI as any |
|
|
|
imui.initContacts(myContracts) |
|
|
|
private handleMenuAvatarClick() { |
|
|
|
console.log('Event:menu-avatar-click') |
|
|
|
} |
|
|
|
|
|
|
|
private onShowImDialog() { |
|
|
|
this.showDialog = !this.showDialog |
|
|
|
private handleMessageClick(e: any, key: any, message: any) { |
|
|
|
console.log(e) |
|
|
|
console.log(key) |
|
|
|
console.log(message) |
|
|
|
} |
|
|
|
|
|
|
|
private handleReceiveMessage(chatMessage: ChatMessage) { |
|
|
|
const message = new Message() |
|
|
|
message.fromChatMessage(chatMessage) |
|
|
|
const imui = this.$refs.IMUI as any |
|
|
|
imui.appendMessage(message) |
|
|
|
const currentContact = imui.currentContact |
|
|
|
if (currentContact && currentContact.id === chatMessage.formUserId) { |
|
|
|
currentContact.lastContent = chatMessage.content |
|
|
|
currentContact.lastSendTime = new Date(chatMessage.sendTime).getTime() |
|
|
|
} else { |
|
|
|
imui.updateContact(chatMessage.formUserId, { |
|
|
|
unread: '+1', |
|
|
|
lastSendTime: new Date(chatMessage.sendTime).getTime(), |
|
|
|
lastContent: chatMessage.content |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private handleSendMessage(message: any, next: any, file: any) { |
|
|
|
private handleSendMessage(message: Message, next: any, file: any) { |
|
|
|
console.log(message, next, file) |
|
|
|
const imui = this.$refs.IMUI as any |
|
|
|
const chatMessage = new ChatMessage() |
|
|
|
chatMessage.formUserId = message.fromUser.id |
|
|
|
chatMessage.formUserName = message.fromUser.displayName |
|
|
|
@ -117,6 +282,103 @@ export default class InstantMessage extends mixins(EventBusMiXin) { |
|
|
|
next() |
|
|
|
}, 1000) |
|
|
|
}) |
|
|
|
.catch(() => { |
|
|
|
imui |
|
|
|
.updateMessage(message.id, message.toContactId, { |
|
|
|
status: 'failed' |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
private onChangeContract(contract: any) { |
|
|
|
const imui = this.$refs.IMUI as any |
|
|
|
imui.updateContact(contract.id, { |
|
|
|
unread: 0 |
|
|
|
}) |
|
|
|
imui.closeDrawer() |
|
|
|
} |
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<style lang="scss" scoped> |
|
|
|
.body { |
|
|
|
background: #3d495c !important |
|
|
|
} |
|
|
|
.link { |
|
|
|
padding: 15px 0 |
|
|
|
} |
|
|
|
.link >>> .a { |
|
|
|
display: inline-block; |
|
|
|
font-size: 16px; |
|
|
|
color: #ccd3dc; |
|
|
|
text-decoration: none; |
|
|
|
border-radius: 5px; |
|
|
|
margin-right: 15px; |
|
|
|
&:hover { |
|
|
|
color: #85acda; |
|
|
|
} |
|
|
|
} |
|
|
|
.action { |
|
|
|
margin-top: 30px; |
|
|
|
.button { |
|
|
|
margin-right: 10px |
|
|
|
} |
|
|
|
} |
|
|
|
.imui-center { |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
left: 50%; |
|
|
|
transform: translate(-50%,-50%); |
|
|
|
} |
|
|
|
.drawer-content { |
|
|
|
padding: 15px |
|
|
|
} |
|
|
|
.more { |
|
|
|
font-size: 32px; |
|
|
|
line-height: 18px; |
|
|
|
height: 32px; |
|
|
|
position: absolute; |
|
|
|
top: 6px; |
|
|
|
right: 14px; |
|
|
|
cursor: pointer; |
|
|
|
user-select: none; |
|
|
|
color: #999; |
|
|
|
&:active { |
|
|
|
color: #000; |
|
|
|
} |
|
|
|
} |
|
|
|
.bar { |
|
|
|
text-align: center; |
|
|
|
line-height: 30px; |
|
|
|
background: #fff; |
|
|
|
margin: 15px; |
|
|
|
color: #666; |
|
|
|
user-select: none; |
|
|
|
font-size: 12px; |
|
|
|
} |
|
|
|
.cover { |
|
|
|
text-align: center; |
|
|
|
user-select: none; |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
left: 50%; |
|
|
|
transform: translate(-50%,-50%); |
|
|
|
i { |
|
|
|
font-size: 84px; |
|
|
|
color: #e6e6e6; |
|
|
|
} |
|
|
|
p { |
|
|
|
font-size: 18px; |
|
|
|
color: #ddd; |
|
|
|
line-height: 50px; |
|
|
|
} |
|
|
|
} |
|
|
|
.article-item { |
|
|
|
line-height: 34px; |
|
|
|
cursor: pointer; |
|
|
|
&:hover { |
|
|
|
text-decoration: underline; |
|
|
|
color: #318efd; |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |
|
|
|
|