Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
杨俊
/
spread_im
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit
6425bbce
...
6425bbcee7a7fe9dd058ffda69cda23d46fc50a7
authored
2022-09-09 14:15:09 +0800
by
huhai
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
im相关改造
1 parent
2603d85b
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1235 additions
and
762 deletions
.env.development
.env.production
.eslintrc
src/components/conversation/conversation-item.vue
src/components/conversation/conversationProfile/group-member-info.vue
src/components/conversation/conversationProfile/group-member-list.vue
src/components/message/message-bubble.vue
src/components/message/message-elements/audio-element.vue
src/components/message/message-elements/custom-element.vue
src/components/message/message-send-box.vue
src/index.vue
src/utils/helper.js
src/utils/hrequest.js
src/utils/request.js
.env.development
View file @
6425bbc
...
...
@@ -7,3 +7,5 @@ VUE_APP_API_SECRET='eb219c4b42bdbbf5dca38f21f5be26ab38f1c157d0ba4277d5acce6507f2
#VUE_APP_API_KEY=1400514886
#VUE_APP_API_SECRET='9c0cbbb0f08e4087e1b06295cd32fc1f9f368c011539123517f769c59274147a'
VUE_APP_API_EXPIRETIME=604800
VUE_APP_API_UNI_URL='https://spread-dev.hikoon.com/api'
...
...
.env.production
View file @
6425bbc
...
...
@@ -5,3 +5,4 @@ VUE_APP_API_URL='http://spread_dev.hikoon.com/mapi'
VUE_APP_API_KEY=1400514950
VUE_APP_API_SECRET='eb219c4b42bdbbf5dca38f21f5be26ab38f1c157d0ba4277d5acce6507f2d727'
VUE_APP_API_EXPIRETIME=604800
VUE_APP_API_UNI_URL='https://spread.hikoon.com/api'
\ No newline at end of file
...
...
.eslintrc
View file @
6425bbc
...
...
@@ -9,8 +9,8 @@
],
"rules": {
"no-console": 'off',
"quotes": ["error", "single"],
"semi": ["error","never"],
//
"quotes": ["error", "single"],
//
"semi": ["error","never"],
"space-before-blocks": "error",
"space-unary-ops": "error"
},
...
...
src/components/conversation/conversation-item.vue
View file @
6425bbc
<
template
>
<div
class=
"conversation-item-container"
:class=
"
{ 'choose': conversation.conversationID === currentConversation.conversationID }"
:class=
"
{
choose:
conversation.conversationID === currentConversation.conversationID,
}"
@click="selectConversation"
>
<div
class=
"close-btn"
>
<span
class=
"tim-icon-close"
title=
"删除会话"
@
click=
"deleteConversation"
></span>
<span
class=
"tim-icon-close"
title=
"删除会话"
@
click=
"deleteConversation"
></span>
</div>
<div
class=
"warp"
>
<avatar
:src=
"avatar"
:type=
"conversation.type"
/>
<avatar
:src=
"avatar"
:type=
"conversation.type"
/>
<div
class=
"content"
>
<div
class=
"row-1"
>
<div
class=
"name"
>
<div
class=
"text-ellipsis"
>
<span
:title=
"conversation.userProfile.nick || conversation.userProfile.userID"
<span
:title=
"
conversation.userProfile.nick ||
conversation.userProfile.userID
"
v-if=
"conversation.type === TIM.TYPES.CONV_C2C"
>
{{
conversation
.
userProfile
.
nick
||
conversation
.
userProfile
.
userID
}}
>
{{
conversation
.
userProfile
.
nick
||
conversation
.
userProfile
.
userID
}}
</span>
<span
:title=
"conversation.groupProfile.name || conversation.groupProfile.groupID"
<span
:title=
"
conversation.groupProfile.name ||
conversation.groupProfile.groupID
"
v-else-if=
"conversation.type === TIM.TYPES.CONV_GROUP"
>
{{
conversation
.
groupProfile
.
name
||
conversation
.
groupProfile
.
groupID
}}
>
{{
conversation
.
groupProfile
.
name
||
conversation
.
groupProfile
.
groupID
}}
</span>
<span
v-else-if=
"conversation.type === TIM.TYPES.CONV_SYSTEM"
<span
v-else-if=
"conversation.type === TIM.TYPES.CONV_SYSTEM"
>
系统通知
</span>
</div>
</div>
<div
class=
"unread-count"
>
<span
class=
"badge"
v-if=
"showUnreadCount"
>
{{
conversation
.
unreadCount
>
99
?
'99+'
:
conversation
.
unreadCount
}}
{{
conversation
.
unreadCount
>
99
?
"99+"
:
conversation
.
unreadCount
}}
</span>
</div>
</div>
<div
class=
"row-2"
>
<div
class=
"summary"
>
<div
v-if=
"conversation.lastMessage"
class=
"text-ellipsis"
>
<span
class=
"remind"
style=
"color:red;"
v-if=
"hasMessageAtMe"
>
[有人提到我]
</span>
<span
class=
"text"
:title=
"conversation.lastMessage.messageForShow"
>
<span
class=
"remind"
style=
"color: red"
v-if=
"hasMessageAtMe"
>
[有人提到我]
</span
>
<span
class=
"text"
:title=
"conversation.lastMessage.messageForShow"
>
{{
messageForShow
}}
</span>
</div>
...
...
@@ -49,158 +76,172 @@
</div>
</div>
</div>
</
template
>
<
script
>
import
{
mapGetters
,
mapState
}
from
'vuex'
import
_
from
'loadsh'
import
{
getDate
,
getTime
,
isToday
}
from
'../../utils/date'
import
{
mapGetters
,
mapState
}
from
"vuex"
;
import
_
from
"loadsh"
;
import
{
getDate
,
getTime
,
isToday
}
from
"../../utils/date"
;
export
default
{
name
:
'conversation-item'
,
props
:
[
'conversation'
],
name
:
"conversation-item"
,
props
:
[
"conversation"
],
filters
:
{},
data
()
{
return
{
popoverVisible
:
false
,
hasMessageAtMe
:
false
}
hasMessageAtMe
:
false
,
}
;
},
computed
:
{
showUnreadCount
()
{
if
(
this
.
$store
.
getters
.
hidden
)
{
return
this
.
conversation
.
unreadCount
>
0
return
this
.
conversation
.
unreadCount
>
0
;
}
// 是否显示未读计数。当前会话和未读计数为0的会话,不显示。
return
(
this
.
currentConversation
.
conversationID
!==
this
.
conversation
.
conversationID
&&
this
.
conversation
.
unreadCount
>
0
)
)
;
},
date
()
{
if
(
!
this
.
conversation
.
lastMessage
||
!
this
.
conversation
.
lastMessage
.
lastTime
)
{
return
''
return
""
;
}
const
date
=
new
Date
(
this
.
conversation
.
lastMessage
.
lastTime
*
1000
)
const
date
=
new
Date
(
this
.
conversation
.
lastMessage
.
lastTime
*
1000
)
;
if
(
isToday
(
date
))
{
return
getTime
(
date
)
return
getTime
(
date
)
;
}
return
getDate
(
date
)
return
getDate
(
date
)
;
},
avatar
:
function
()
{
switch
(
this
.
conversation
.
type
)
{
case
'GROUP'
:
return
this
.
conversation
.
groupProfile
.
avatar
case
'C2C'
:
return
this
.
conversation
.
userProfile
.
avatar
case
"GROUP"
:
return
this
.
conversation
.
groupProfile
.
avatar
;
case
"C2C"
:
return
this
.
conversation
.
userProfile
.
avatar
;
default
:
return
''
return
""
;
}
},
conversationName
:
function
()
{
if
(
this
.
conversation
.
type
===
this
.
TIM
.
TYPES
.
CONV_C2C
)
{
return
this
.
conversation
.
userProfile
.
nick
||
this
.
conversation
.
userProfile
.
userID
return
(
this
.
conversation
.
userProfile
.
nick
||
this
.
conversation
.
userProfile
.
userID
);
}
if
(
this
.
conversation
.
type
===
this
.
TIM
.
TYPES
.
CONV_GROUP
)
{
return
this
.
conversation
.
groupProfile
.
name
||
this
.
conversation
.
groupProfile
.
groupID
return
(
this
.
conversation
.
groupProfile
.
name
||
this
.
conversation
.
groupProfile
.
groupID
);
}
if
(
this
.
conversation
.
type
===
this
.
TIM
.
TYPES
.
CONV_SYSTEM
)
{
return
'系统通知'
return
"系统通知"
;
}
return
''
return
""
;
},
showGrayBadge
()
{
if
(
this
.
conversation
.
type
!==
this
.
TIM
.
TYPES
.
CONV_GROUP
)
{
return
false
return
false
;
}
return
(
this
.
conversation
.
groupProfile
.
selfInfo
.
messageRemindType
===
'AcceptNotNotify'
)
"AcceptNotNotify"
)
;
},
messageForShow
()
{
if
(
this
.
conversation
.
lastMessage
.
isRevoked
)
{
if
(
this
.
conversation
.
lastMessage
.
fromAccount
===
this
.
currentUserProfile
.
userID
)
{
return
'你撤回了一条消息'
if
(
this
.
conversation
.
lastMessage
.
fromAccount
===
this
.
currentUserProfile
.
userID
)
{
return
"你撤回了一条消息"
;
}
if
(
this
.
conversation
.
type
===
this
.
TIM
.
TYPES
.
CONV_C2C
)
{
return
'对方撤回了一条消息'
return
"对方撤回了一条消息"
;
}
return
`
${
this
.
conversation
.
lastMessage
.
fromAccount
}
撤回了一条消息`
return
`
${
this
.
conversation
.
lastMessage
.
nick
||
this
.
conversation
.
lastMessage
.
fromAccount
}
撤回了一条消息
`;
} else {
switch
(
_
.
get
(
this
.
conversation
.
lastMessage
,
'payload.data'
,
'other'
))
{
case
'image'
:
return
'[图片]'
case
'video'
:
return
'[视频]'
switch (_.get(this.conversation.lastMessage,
"payload.data", "other"
)) {
case
"image"
:
return
"[图片]";
case
"video"
:
return
"[视频]";
default:
return
this
.
conversation
.
lastMessage
.
messageForShow
return this.conversation.lastMessage.messageForShow
;
}
}
},
...mapState({
currentConversation
:
state
=>
state
.
conversation
.
currentConversation
,
currentUserProfile
:
state
=>
state
.
user
.
currentUserProfile
currentConversation:
(state)
=> state.conversation.currentConversation,
currentUserProfile:
(state) => state.user.currentUserProfile,
}),
...
mapGetters
([
'toAccount'
])
...mapGetters([
"toAccount"]),
},
mounted() {
this
.
$bus
.
$on
(
'new-messsage-at-me'
,
event
=>
{
this.$bus.$on(
"new-messsage-at-me", (event)
=> {
if (
event.data.conversationID === this.conversation.conversationID &&
this.conversation.conversationID !==
this.currentConversation.conversationID
) {
this
.
hasMessageAtMe
=
true
this.hasMessageAtMe = true
;
}
})
})
;
},
methods: {
selectConversation() {
if
(
this
.
conversation
.
conversationID
!==
this
.
currentConversation
.
conversationID
)
{
if (
this.conversation.conversationID !==
this.currentConversation.conversationID
) {
this.$store.dispatch(
'checkoutConversation'
,
"checkoutConversation"
,
this.conversation.conversationID
)
)
;
}
},
deleteConversation(event) {
// 停止冒泡,避免和点击会话的事件冲突
event
.
stopPropagation
()
event.stopPropagation()
;
this.tim
.deleteConversation(this.conversation.conversationID)
.then(() => {
this
.
$store
.
commit
(
'showMessage'
,
{
this.$store.commit("showMessage"
, {
message: `
会话【
$
{
this
.
conversationName
}
】删除成功!`
,
type
:
'success'
})
this
.
popoverVisible
=
false
this
.
$store
.
commit
(
'resetCurrentConversation'
)
type
:
"success"
,
});
this
.
popoverVisible
=
false
;
this
.
$store
.
commit
(
"resetCurrentConversation"
);
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
.
catch
((
error
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
`会话【
${
this
.
conversationName
}
】删除失败!, error=
${
error
.
message
}
`
,
type
:
'error'
})
this
.
popoverVisible
=
false
})
type
:
"error"
,
});
this
.
popoverVisible
=
false
;
});
},
showContextMenu
()
{
this
.
popoverVisible
=
true
this
.
popoverVisible
=
true
;
},
},
watch
:
{
currentConversation
(
next
)
{
if
(
next
.
conversationID
===
this
.
conversation
.
conversationID
)
{
this
.
hasMessageAtMe
=
false
}
}
this
.
hasMessageAtMe
=
false
;
}
}
},
},
};
</
script
>
<
style
lang=
"stylus"
scoped
>
...
...
src/components/conversation/conversationProfile/group-member-info.vue
View file @
6425bbc
...
...
@@ -3,24 +3,32 @@
<div>
<span
class=
"label"
>
ID:
</span>
{{
member
.
userID
}}
<el-button
v-if=
"showCancelBan"
type=
"text"
@
click=
"cancelMute"
>
取消禁言
</el-button>
<el-button
v-if=
"showCancelBan"
type=
"text"
@
click=
"cancelMute"
>
取消禁言
</el-button
>
<el-popover
title=
"禁言"
v-model=
"popoverVisible"
v-show=
"showBan"
>
<el-input
v-model=
"muteTime"
placeholder=
"请输入禁言时间"
@
keydown
.
enter
.
native=
"setGroupMemberMuteTime"
/>
<el-button
slot=
"reference"
type=
"text"
style=
"color:red;"
>
禁言
</el-button>
<el-button
slot=
"reference"
type=
"text"
style=
"color: red"
>
禁言
</el-button
>
</el-popover>
</div>
<div>
<span
class=
"label"
>
昵称:
</span>
{{
member
.
nick
||
'暂无'
}}
{{
member
.
nick
||
"暂无"
}}
</div>
<div>
<span
class=
"label"
>
名片:
</span>
{{
member
.
nameCard
||
'暂无'
}}
<el-popover
title=
"修改群名片"
v-model=
"nameCardPopoverVisible"
v-show=
"showEditNameCard"
>
{{
member
.
nameCard
||
"暂无"
}}
<el-popover
title=
"修改群名片"
v-model=
"nameCardPopoverVisible"
v-show=
"showEditNameCard"
>
<el-input
v-model=
"nameCard"
placeholder=
"请输入群名片"
...
...
@@ -30,7 +38,7 @@
class=
"el-icon-edit"
title=
"修改群名片"
slot=
"reference"
style=
"cursor:pointer; font-size:1.6rem;
"
style=
"cursor: pointer; font-size: 1.6rem
"
></i>
</el-popover>
</div>
...
...
@@ -53,64 +61,83 @@
</
template
>
<
script
>
import
{
mapState
}
from
'vuex'
import
{
Popover
}
from
'element-ui'
import
{
getFullDate
}
from
'../../../utils/date'
import
Helper
from
'../../../utils/helper'
import
{
mapState
}
from
"vuex"
;
import
{
Popover
}
from
"element-ui"
;
import
{
getFullDate
}
from
"../../../utils/date"
;
import
Helper
from
"../../../utils/helper"
;
export
default
{
components
:
{
ElPopover
:
Popover
ElPopover
:
Popover
,
},
props
:
[
'member'
],
props
:
[
"member"
],
filters
:
{
role
:
val
=>
val
===
'Member'
?
'成员'
:
(
val
===
'Admin'
?
'管理员'
:
'群主'
)
role
:
(
val
)
=>
val
===
"Member"
?
"成员"
:
val
===
"Admin"
?
"管理员"
:
"群主"
,
},
data
()
{
return
{
muteTime
:
''
,
muteTime
:
""
,
popoverVisible
:
false
,
nameCardPopoverVisible
:
false
,
nameCard
:
this
.
member
.
nameCard
}
nameCard
:
this
.
member
.
nameCard
,
};
},
mounted
()
{
// 初始化监听器
console
.
log
(
"this.currentUserProfile is "
,
this
.
currentUserProfile
);
console
.
log
(
"this.currentConversation.groupProfile.selfInfo is "
,
this
.
currentConversation
.
groupProfile
.
selfInfo
);
},
computed
:
{
...
mapState
({
currentConversation
:
state
=>
state
.
conversation
.
currentConversation
,
currentUserProfile
:
state
=>
state
.
user
.
currentUserProfile
,
current
:
state
=>
state
.
current
currentConversation
:
(
state
)
=>
state
.
conversation
.
currentConversation
,
currentUserProfile
:
(
state
)
=>
state
.
user
.
currentUserProfile
,
current
:
(
state
)
=>
state
.
current
,
}),
// 是否显示踢出群成员按钮
showKickout
()
{
return
(
this
.
isOwner
||
this
.
isAdmin
)
&&
!
this
.
isMine
return
(
this
.
isOwner
||
this
.
isAdmin
)
&&
!
this
.
isMine
;
},
isOwner
()
{
return
this
.
currentConversation
.
groupProfile
.
selfInfo
.
role
===
'Owner'
return
this
.
currentConversation
.
groupProfile
.
selfInfo
.
role
===
"Owner"
;
},
isAdmin
()
{
return
this
.
currentConversation
.
groupProfile
.
selfInfo
.
role
===
'Admin'
let
isA
=
false
;
if
(
this
.
currentConversation
.
groupProfile
.
selfInfo
.
role
===
"Admin"
)
{
isA
=
true
;
}
else
if
(
this
.
currentUserProfile
.
userID
.
substr
(
0
,
13
)
==
"Administrator"
&&
this
.
currentUserProfile
.
nick
==
"超级管理员"
)
{
isA
=
true
;
}
return
isA
;
},
isMine
()
{
return
this
.
currentUserProfile
.
userID
===
this
.
member
.
userID
console
.
log
(
"in isMine "
,
this
.
member
.
userID
);
return
this
.
currentUserProfile
.
userID
===
this
.
member
.
userID
;
},
canChangeRole
()
{
return
(
this
.
isOwner
&&
[
'ChatRoom'
,
'Public'
].
includes
(
this
.
currentConversation
.
subType
)
)
[
"ChatRoom"
,
"Public"
].
includes
(
this
.
currentConversation
.
subType
)
)
;
},
changeRoleTitle
()
{
if
(
!
this
.
canChangeRole
)
{
return
''
return
""
;
}
return
this
.
isOwner
&&
this
.
member
.
role
===
'Admin'
?
'设为:Member'
:
'设为:Admin'
return
this
.
isOwner
&&
this
.
member
.
role
===
"Admin"
?
"设为:Member"
:
"设为:Admin"
;
},
// 是否显示禁言时间
showMuteUntil
()
{
// 禁言时间小于当前时间
return
this
.
member
.
muteUntil
*
1000
>
this
.
current
return
this
.
member
.
muteUntil
*
1000
>
this
.
current
;
},
// 是否显示取消禁言按钮
showCancelBan
()
{
...
...
@@ -119,42 +146,48 @@ export default {
this
.
currentConversation
.
type
===
this
.
TIM
.
TYPES
.
CONV_GROUP
&&
!
this
.
isMine
)
{
return
this
.
isOwner
||
this
.
isAdmin
return
this
.
isOwner
||
this
.
isAdmin
;
}
return
false
return
false
;
},
// 是否显示禁言按钮
showBan
()
{
if
(
this
.
currentConversation
.
type
===
this
.
TIM
.
TYPES
.
CONV_GROUP
)
{
return
this
.
isOwner
||
this
.
isAdmin
return
this
.
isOwner
||
this
.
isAdmin
;
}
return
false
return
false
;
},
// 是否显示编辑群名片按钮
showEditNameCard
()
{
return
this
.
isOwner
||
this
.
isAdmin
return
this
.
isOwner
||
this
.
isAdmin
;
},
// 日期格式化后的禁言时间
muteUntil
()
{
return
getFullDate
(
new
Date
(
this
.
member
.
muteUntil
*
1000
))
}
return
getFullDate
(
new
Date
(
this
.
member
.
muteUntil
*
1000
))
;
}
,
},
methods
:
{
kickoutGroupMember
()
{
Helper
.
groupMemberDelete
(
this
.
currentConversation
.
groupProfile
.
groupID
,
this
.
member
.
userID
)
Helper
.
groupMemberDelete
(
this
.
currentConversation
.
groupProfile
.
groupID
,
this
.
member
.
userID
)
.
then
(()
=>
{
this
.
$store
.
commit
(
'deleteGroupMember'
,
this
.
member
.
userID
)
this
.
$store
.
commit
(
'updateCurrentUnMemberList'
,
[{
this
.
$store
.
commit
(
"deleteGroupMember"
,
this
.
member
.
userID
);
this
.
$store
.
commit
(
"updateCurrentUnMemberList"
,
[
{
esm_id
:
this
.
member
.
userID
,
name
:
this
.
member
.
nick
,
avatar
:
this
.
member
.
avatar
}])
}).
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
avatar
:
this
.
member
.
avatar
,
},
]);
})
.
catch
((
error
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
error
.
message
,
});
});
// this.tim
// .deleteGroupMember({
// groupID: this.currentConversation.groupProfile.groupID,
...
...
@@ -173,39 +206,39 @@ export default {
},
changeMemberRole
()
{
if
(
!
this
.
canChangeRole
)
{
return
return
;
}
let
currentRole
=
this
.
member
.
role
let
currentRole
=
this
.
member
.
role
;
this
.
tim
.
setGroupMemberRole
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
userID
:
this
.
member
.
userID
,
role
:
currentRole
===
'Admin'
?
'Member'
:
'Admin'
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
role
:
currentRole
===
"Admin"
?
"Member"
:
"Admin"
,
})
.
catch
((
error
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
error
.
message
,
});
});
},
setGroupMemberMuteTime
()
{
this
.
tim
.
setGroupMemberMuteTime
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
userID
:
this
.
member
.
userID
,
muteTime
:
Number
(
this
.
muteTime
)
muteTime
:
Number
(
this
.
muteTime
),
})
.
then
(()
=>
{
this
.
muteTime
=
''
this
.
popoverVisible
=
false
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
this
.
muteTime
=
""
;
this
.
popoverVisible
=
false
;
})
.
catch
((
error
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
error
.
message
,
});
});
},
// 取消禁言
cancelMute
()
{
...
...
@@ -213,47 +246,47 @@ export default {
.
setGroupMemberMuteTime
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
userID
:
this
.
member
.
userID
,
muteTime
:
0
muteTime
:
0
,
})
.
then
(()
=>
{
this
.
muteTime
=
''
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
this
.
muteTime
=
""
;
})
.
catch
((
error
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
error
.
message
,
});
});
},
setGroupMemberNameCard
()
{
if
(
this
.
nameCard
.
trim
().
length
===
0
)
{
this
.
$store
.
commit
(
'showMessage'
,
{
message
:
'不能设置空的群名片'
,
type
:
'warning'
})
return
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
"不能设置空的群名片"
,
type
:
"warning"
,
})
;
return
;
}
this
.
tim
.
setGroupMemberNameCard
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
userID
:
this
.
member
.
userID
,
nameCard
:
this
.
nameCard
nameCard
:
this
.
nameCard
,
})
.
then
(()
=>
{
this
.
nameCardPopoverVisible
=
false
this
.
$store
.
commit
(
'showMessage'
,
{
message
:
'修改成功'
})
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
this
.
nameCardPopoverVisible
=
false
;
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
"修改成功"
,
});
})
})
}
}
}
.
catch
((
error
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
error
.
message
,
});
});
},
},
};
</
script
>
<
style
lang=
"stylus"
scoped
>
...
...
src/components/conversation/conversationProfile/group-member-list.vue
View file @
6425bbc
<
template
>
<div
class=
"group-member-list-wrapper"
>
<div
class=
"header"
>
<span
class=
"member-count text-ellipsis"
>
群成员:
{{
currentConversation
.
groupProfile
.
memberCount
}}
</span>
<popover
v-show=
"currentUnMemberList.length !== 0"
v-model=
"addGroupMemberVisible"
>
<add-group-member
:group=
"currentConversation.groupProfile.groupID"
/>
<span
class=
"member-count text-ellipsis"
>
群成员:
{{
currentConversation
.
groupProfile
.
memberCount
}}
</span
>
<popover
v-show=
"currentUnMemberList.length !== 0"
v-model=
"addGroupMemberVisible"
>
<add-group-member
:group=
"currentConversation.groupProfile.groupID"
/>
<div
slot=
"reference"
class=
"btn-add-member"
title=
"添加群成员"
>
<span
class=
"tim-icon-friend-add"
></span>
</div>
...
...
@@ -13,13 +18,24 @@
<div
class=
"group-member-list"
>
<div
v-for=
"member in members"
:key=
"member.userID"
>
<popover
placement=
"right"
:key=
"member.userID"
>
<group-member-info
:member=
"member"
/>
<div
slot=
"reference"
class=
"group-member"
@
click=
"currentMemberID = member.userID"
>
<avatar
:title=
getGroupMemberAvatarText(member.role)
:src=
"member.avatar"
/>
<group-member-info
:member=
"member"
/>
<div
slot=
"reference"
class=
"group-member"
@
click=
"currentMemberID = member.userID"
>
<avatar
:title=
"getGroupMemberAvatarText(member.role)"
:src=
"member.avatar"
/>
<div
class=
"member-name text-ellipsis"
>
<span
v-if=
"member.nameCard"
:title=
member.nameCard
>
{{
member
.
nameCard
}}
</span>
<span
v-else-if=
"member.nick"
:title=
member.nick
>
{{
member
.
nick
}}
</span>
<span
v-else
:title=
member.userID
>
{{
member
.
userID
}}
</span>
<span
v-if=
"member.nameCard"
:title=
"member.nameCard"
>
{{
member
.
nameCard
}}
</span>
<span
v-else-if=
"member.nick"
:title=
"member.nick"
>
{{
member
.
nick
}}
</span>
<span
v-else
:title=
"member.userID"
>
{{
member
.
userID
}}
</span>
</div>
</div>
</popover>
...
...
@@ -27,66 +43,71 @@
</div>
</div>
<div
class=
"more"
>
<el-button
v-if=
"showLoadMore"
type=
"text"
@
click=
"loadMore"
>
查看更多
<el-button
v-if=
"showLoadMore"
type=
"text"
@
click=
"loadMore"
>
查看更多
</el-button>
</div>
</div>
</
template
>
<
script
>
import
{
Popover
}
from
'element-ui'
import
{
mapState
}
from
'vuex'
import
AddGroupMember
from
'./add-group-member.vue'
import
GroupMemberInfo
from
'./group-member-info.vue'
import
{
Popover
}
from
"element-ui"
;
import
{
mapState
}
from
"vuex"
;
import
AddGroupMember
from
"./add-group-member.vue"
;
import
GroupMemberInfo
from
"./group-member-info.vue"
;
export
default
{
data
()
{
return
{
addGroupMemberVisible
:
false
,
addGroupMemberList
:
[],
currentMemberID
:
''
,
count
:
30
// 显示的群成员数量
}
currentMemberID
:
""
,
count
:
30
,
// 显示的群成员数量
}
;
},
props
:
[
'groupProfile'
],
props
:
[
"groupProfile"
],
components
:
{
Popover
,
AddGroupMember
,
GroupMemberInfo
GroupMemberInfo
,
},
computed
:
{
...
mapState
({
currentConversation
:
state
=>
state
.
conversation
.
currentConversation
,
currentMemberList
:
state
=>
state
.
group
.
currentMemberList
,
currentUnMemberList
:
state
=>
state
.
group
.
currentUnMemberList
currentConversation
:
(
state
)
=>
state
.
conversation
.
currentConversation
,
currentMemberList
:
(
state
)
=>
state
.
group
.
currentMemberList
,
currentUnMemberList
:
(
state
)
=>
state
.
group
.
currentUnMemberList
,
}),
showLoadMore
()
{
return
this
.
members
.
length
<
this
.
groupProfile
.
memberCount
return
this
.
members
.
length
<
this
.
groupProfile
.
memberCount
;
},
members
()
{
return
this
.
currentMemberList
.
slice
(
0
,
this
.
count
)
}
console
.
log
(
"currentMemberList is "
,
this
.
currentMemberList
.
slice
(
0
,
this
.
count
)
);
return
this
.
currentMemberList
.
slice
(
0
,
this
.
count
);
},
},
methods
:
{
getGroupMemberAvatarText
(
role
)
{
switch
(
role
)
{
case
'Owner'
:
return
'群主'
case
'Admin'
:
return
'管理员'
case
"Owner"
:
return
"群主"
;
case
"Admin"
:
return
"管理员"
;
default
:
return
'群成员'
return
"群成员"
;
}
},
loadMore
()
{
this
.
$store
.
dispatch
(
'getGroupMemberList'
,
this
.
groupProfile
.
groupID
)
this
.
$store
.
dispatch
(
"getGroupMemberList"
,
this
.
groupProfile
.
groupID
)
.
then
(()
=>
{
this
.
count
+=
30
})
this
.
count
+=
30
;
});
},
}
}
}
,
}
;
</
script
>
<
style
lang=
"stylus"
scoped
>
...
...
@@ -167,6 +188,4 @@ export default {
//
text-align
:
center
;
//
line-height
:
30px
;
//
}
</
style
>
...
...
src/components/message/message-bubble.vue
View file @
6425bbc
<
template
>
<div
class=
"chat-bubble"
@
mousedown
.
stop
@
contextmenu
.
prevent
>
<el-dropdown
trigger=
""
ref=
"dropdown"
v-if=
"!message.isRevoked"
@
command=
"handleCommand"
>
<el-dropdown
trigger=
""
ref=
"dropdown"
v-if=
"!message.isRevoked"
@
command=
"handleCommand"
>
<div
style=
"display: flex"
>
<div
v-if=
"isMine && messageReadByPeer"
class=
"message-status"
>
<span>
{{
messageReadByPeer
}}
</span>
<span>
{{
messageReadByPeer
}}
</span>
</div>
<div
class=
"message-content"
:class=
"bubbleStyle"
>
<slot></slot>
...
...
@@ -15,136 +20,165 @@
</el-dropdown-menu>
</el-dropdown>
<div
class=
"group-tip-element-wrapper"
v-if=
"message.isRevoked"
>
{{
text
}}
<el-button
type=
"text"
size=
"mini"
class=
"edit-button"
v-show=
"isEdit"
@
click=
"reEdit"
>
重新编辑
</el-button>
{{
text
}}
<el-button
type=
"text"
size=
"mini"
class=
"edit-button"
v-show=
"isEdit"
@
click=
"reEdit"
>
重新编辑
</el-button
>
</div>
</div>
</
template
>
<
script
>
export
default
{
name
:
'MessageBubble'
,
name
:
"MessageBubble"
,
data
()
{
return
{
isTimeout
:
false
}
isTimeout
:
false
,
}
;
},
props
:
{
isMine
:
{
type
:
Boolean
type
:
Boolean
,
},
isNew
:
{
type
:
Boolean
type
:
Boolean
,
},
message
:
{
type
:
Object
,
required
:
true
}
required
:
true
,
}
,
},
created
()
{
this
.
isTimeoutHandler
()
this
.
isTimeoutHandler
()
;
},
mounted
()
{
if
(
this
.
$refs
.
dropdown
&&
this
.
$refs
.
dropdown
.
$el
)
{
this
.
$refs
.
dropdown
.
$el
.
addEventListener
(
'mousedown'
,
this
.
handleDropDownMousedown
)
this
.
$refs
.
dropdown
.
$el
.
addEventListener
(
"mousedown"
,
this
.
handleDropDownMousedown
);
}
},
beforeDestroy
()
{
if
(
this
.
$refs
.
dropdown
&&
this
.
$refs
.
dropdown
.
$el
)
{
this
.
$refs
.
dropdown
.
$el
.
removeEventListener
(
'mousedown'
,
this
.
handleDropDownMousedown
)
this
.
$refs
.
dropdown
.
$el
.
removeEventListener
(
"mousedown"
,
this
.
handleDropDownMousedown
);
}
},
computed
:
{
bubbleStyle
()
{
let
classString
=
''
let
classString
=
""
;
if
(
this
.
isMine
)
{
classString
+=
'message-send'
classString
+=
"message-send"
;
}
else
{
classString
+=
'message-received'
classString
+=
"message-received"
;
}
if
(
this
.
isNew
)
{
classString
+=
'new'
classString
+=
"new"
;
}
return
classString
return
classString
;
},
text
()
{
if
(
this
.
message
.
conversationType
===
this
.
TIM
.
TYPES
.
CONV_C2C
&&
!
this
.
isMine
)
{
return
'对方撤回了一条消息'
if
(
this
.
message
.
conversationType
===
this
.
TIM
.
TYPES
.
CONV_C2C
&&
!
this
.
isMine
)
{
return
"对方撤回了一条消息"
;
}
if
(
this
.
message
.
conversationType
===
this
.
TIM
.
TYPES
.
CONV_GROUP
&&
!
this
.
isMine
)
{
return
`
${
this
.
message
.
from
}
撤回了一条消息`
if
(
this
.
message
.
conversationType
===
this
.
TIM
.
TYPES
.
CONV_GROUP
&&
!
this
.
isMine
)
{
return
`
${
this
.
message
.
nick
||
this
.
message
.
from
}
撤回了一条消息`
;
}
return
'你撤回了一条消息'
return
"你撤回了一条消息"
;
},
messageReadByPeer
()
{
if
(
this
.
message
.
status
!==
'success'
)
{
return
false
if
(
this
.
message
.
status
!==
"success"
)
{
return
false
;
}
if
(
this
.
message
.
conversationType
===
this
.
TIM
.
TYPES
.
CONV_C2C
&&
this
.
message
.
isPeerRead
)
{
return
'已读'
if
(
this
.
message
.
conversationType
===
this
.
TIM
.
TYPES
.
CONV_C2C
&&
this
.
message
.
isPeerRead
)
{
return
"已读"
;
}
if
(
this
.
message
.
conversationType
===
this
.
TIM
.
TYPES
.
CONV_C2C
&&
!
this
.
message
.
isPeerRead
)
{
return
'未读'
if
(
this
.
message
.
conversationType
===
this
.
TIM
.
TYPES
.
CONV_C2C
&&
!
this
.
message
.
isPeerRead
)
{
return
"未读"
;
}
return
''
return
""
;
},
isEdit
()
{
if
(
!
this
.
isMine
)
{
return
false
return
false
;
}
if
(
this
.
message
.
type
!==
this
.
TIM
.
TYPES
.
MSG_TEXT
)
{
return
false
return
false
;
}
if
(
this
.
isTimeout
)
{
return
false
return
false
;
}
return
true
return
true
;
},
},
methods
:
{
handleDropDownMousedown
(
e
)
{
if
(
!
this
.
isMine
||
this
.
isTimeout
)
{
return
return
;
}
if
(
e
.
buttons
===
2
)
{
if
(
this
.
$refs
.
dropdown
.
visible
)
{
this
.
$refs
.
dropdown
.
hide
()
this
.
$refs
.
dropdown
.
hide
()
;
}
else
{
this
.
$refs
.
dropdown
.
show
()
this
.
$refs
.
dropdown
.
show
()
;
}
}
},
handleCommand
(
command
)
{
switch
(
command
)
{
case
'revoke'
:
this
.
tim
.
revokeMessage
(
this
.
message
).
then
(()
=>
{
this
.
isTimeoutHandler
()
}).
catch
((
err
)
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
message
:
err
,
type
:
'warning'
})
case
"revoke"
:
this
.
tim
.
revokeMessage
(
this
.
message
)
.
then
(()
=>
{
this
.
isTimeoutHandler
();
})
break
case
'delete'
:
break
.
catch
((
err
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
err
,
type
:
"warning"
,
});
});
break
;
case
"delete"
:
break
;
default
:
break
break
;
}
},
isTimeoutHandler
()
{
// 从发送消息时间开始算起,两分钟内可以编辑
let
now
=
new
Date
()
isTimeoutHandler
()
{
// 从发送消息时间开始算起,两分钟内可以编辑
let
now
=
new
Date
();
if
(
parseInt
(
now
.
getTime
()
/
1000
)
-
this
.
message
.
time
>
2
*
60
)
{
this
.
isTimeout
=
true
return
this
.
isTimeout
=
true
;
return
;
}
setTimeout
(
this
.
isTimeoutHandler
,
1000
)
setTimeout
(
this
.
isTimeoutHandler
,
1000
)
;
},
reEdit
()
{
this
.
$bus
.
$emit
(
'reEditMessage'
,
this
.
message
.
payload
.
text
)
}
}
}
this
.
$bus
.
$emit
(
"reEditMessage"
,
this
.
message
.
payload
.
text
);
}
,
}
,
}
;
</
script
>
<
style
lang=
"stylus"
scoped
>
...
...
src/components/message/message-elements/audio-element.vue
0 → 100644
View file @
6425bbc
<
template
>
<message-bubble
:isMine=
"isMine"
:message=
"message"
>
<div
class=
"m-e-content"
@
click=
"goAudioDetail"
>
<img
:src=
"coverUrl"
class=
"covor"
/>
<span
class=
"title"
v-if=
"name"
>
{{
name
}}
</span>
<span
class=
"title"
v-else=
"name"
>
未命名音乐文件
</span>
<!--
<div
style=
"position: absolute; right: 15px"
>
<u-icon
name=
"list"
color=
"#fff"
size=
"32"
></u-icon>
</div>
-->
</div>
</message-bubble>
<!--
<div
class=
"chat-bubble"
>
<div
class=
"message-content"
:class=
"isMine ? 'message-send' : 'message-received'"
>
<template
v-for=
"(item, index) in contentList"
>
<span
:key=
"index"
v-if=
"item.name === 'text'"
>
{{
item
.
text
}}
</span>
<img
v-else-if=
"item.name === 'img'"
:src=
"item.src"
width=
"20px"
height=
"20px"
:key=
"index"
/>
</
template
>
</div>
</div>
-->
</template>
<
script
>
import
MessageBubble
from
"../message-bubble"
;
export
default
{
name
:
"AudioElement"
,
components
:
{
MessageBubble
,
},
props
:
{
payload
:
{
type
:
Object
,
required
:
true
,
},
message
:
{
type
:
Object
,
required
:
true
,
},
isMine
:
{
type
:
Boolean
,
},
},
methods
:
{
goAudioDetail
()
{
console
.
log
(
"in goAudioDetail"
);
// this.$emit("goAudioDetail");
},
previewImage
()
{
uni
.
previewImage
({
current
:
0
,
urls
:
[
this
.
imagePath
],
});
},
},
computed
:
{
audioUrl
()
{
return
this
.
payload
.
description
;
},
coverUrl
()
{
try
{
let
res
=
JSON
.
parse
(
this
.
payload
.
extension
);
return
res
.
cover_url
;
}
catch
(
e
)
{}
return
""
;
},
name
()
{
try
{
let
res
=
JSON
.
parse
(
this
.
payload
.
extension
);
return
res
.
name
;
}
catch
(
e
)
{}
return
""
;
},
},
mounted
()
{
console
.
log
(
"this.message is "
,
this
.
message
);
},
};
</
script
>
<
style
lang=
"stylus"
scoped
>
.covor
{
width
:
80px
;
height
:
80px
;
//
border-top-left-radius
:
10px
;
//
border-bottom-left-radius
:
10px
;
border-radius
:
6px
;
}
.m-e-content
{
display
:
flex
;
flex-direction
:
row
;
align-items
:
center
;
width
:
250px
;
height
:
80px
//
background-color
:
#2D2F39
;
position
:
relative
;
}
.title
{
width
:
150px
;
//
color
:
#E9E9EA
;
font-size
:
13px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
/* #ifndef APP-PLUS-NVUE */
display
:
-webkit-box
;
word-break
:
break-all
;
-webkit-box-orient
:
vertical
;
-webkit-line-clamp
:
2
;
/* #endif */
/* #ifdef APP-PLUS-NVUE */
lines
:
2
;
text-overflow
:
ellipsis
;
/* #endif */
margin-left
:
15px
}
</
style
>
src/components/message/message-elements/custom-element.vue
View file @
6425bbc
...
...
@@ -2,18 +2,36 @@
<div
class=
"custom-element-wrapper"
>
<image-element
v-if=
"this.payload.data === 'image'"
:isMine=
isMine
:payload=
"Object.assign(message.payload,
{ imageInfoArray:[ { url: message.payload.description } ] })"
:message="message"/>
:isMine=
"isMine"
:payload=
"
Object.assign(message.payload,
{
imageInfoArray: [{ url: message.payload.description }],
})
"
:message="message"
/>
<video-element
v-else-if=
"this.payload.data === 'video'"
:isMine=
"isMine"
:payload=
"Object.assign(message.payload,
{ videoUrl: message.payload.description })"
:payload=
"
Object.assign(message.payload,
{
videoUrl: message.payload.description,
})
"
:message="message"
/>
<audio-element
v-else-if=
"this.payload.data === 'audio'"
:isMine=
"isMine"
:payload=
"message.payload"
:message=
"message"
/>
<template
v-else
>
<message-bubble
:isMine=
isMine
:message=
message
>
<message-group-live-status
v-if=
"text.isFromGroupLive && text.isFromGroupLive === 1"
:liveInfo=
'text'
/>
<message-bubble
:isMine=
"isMine"
:message=
"message"
>
<message-group-live-status
v-if=
"text.isFromGroupLive && text.isFromGroupLive === 1"
:liveInfo=
"text"
/>
<template
v-else
>
{{
text
}}
</
template
>
</message-bubble>
</template>
...
...
@@ -21,74 +39,79 @@
</template>
<
script
>
import
{
mapState
}
from
'vuex'
import
MessageBubble
from
'../message-bubble'
import
MessageGroupLiveStatus
from
'../message-group-live-status'
import
ImageElement
from
'../message-elements/image-element.vue'
import
VideoElement
from
'./video-element'
import
{
mapState
}
from
"vuex"
;
import
MessageBubble
from
"../message-bubble"
;
import
MessageGroupLiveStatus
from
"../message-group-live-status"
;
import
ImageElement
from
"../message-elements/image-element.vue"
;
import
VideoElement
from
"./video-element"
;
import
AudioElement
from
"./audio-element.vue"
;
export
default
{
name
:
'CustomElement'
,
name
:
"CustomElement"
,
props
:
{
payload
:
{
type
:
Object
,
required
:
true
required
:
true
,
},
message
:
{
type
:
Object
,
required
:
true
required
:
true
,
},
isMine
:
{
type
:
Boolean
}
type
:
Boolean
,
}
,
},
components
:
{
VideoElement
,
MessageBubble
,
MessageGroupLiveStatus
,
ImageElement
,
AudioElement
,
},
computed
:
{
...
mapState
({
currentUserProfile
:
state
=>
state
.
user
.
currentUserProfile
currentUserProfile
:
(
state
)
=>
state
.
user
.
currentUserProfile
,
}),
text
()
{
return
this
.
translateCustomMessage
(
this
.
payload
)
return
this
.
translateCustomMessage
(
this
.
payload
)
;
},
rate
()
{
return
parseInt
(
this
.
payload
.
description
)
}
return
parseInt
(
this
.
payload
.
description
)
;
}
,
},
methods
:
{
guid
()
{
return
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
.
replace
(
/
[
xy
]
/g
,
function
(
c
)
{
let
r
=
Math
.
random
()
*
16
|
0
,
v
=
c
==
'x'
?
r
:
(
r
&
0x3
|
0x8
)
return
v
.
toString
(
16
)
})
return
"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
.
replace
(
/
[
xy
]
/g
,
function
(
c
)
{
let
r
=
(
Math
.
random
()
*
16
)
|
0
,
v
=
c
==
"x"
?
r
:
(
r
&
0x3
)
|
0x8
;
return
v
.
toString
(
16
);
}
);
},
translateCustomMessage
(
payload
)
{
let
videoPayload
=
{}
let
videoPayload
=
{}
;
try
{
videoPayload
=
JSON
.
parse
(
payload
.
data
)
videoPayload
=
JSON
.
parse
(
payload
.
data
)
;
}
catch
(
e
)
{
videoPayload
=
{}
videoPayload
=
{}
;
}
if
(
payload
.
data
===
'group_create'
)
{
return
`
${
payload
.
extension
}
`
if
(
payload
.
data
===
"group_create"
)
{
return
`
${
payload
.
extension
}
`
;
}
if
(
videoPayload
.
roomId
)
{
videoPayload
.
roomId
=
videoPayload
.
roomId
.
toString
()
videoPayload
.
isFromGroupLive
=
1
return
videoPayload
videoPayload
.
roomId
=
videoPayload
.
roomId
.
toString
()
;
videoPayload
.
isFromGroupLive
=
1
;
return
videoPayload
;
}
if
(
payload
.
text
)
{
return
payload
.
text
return
payload
.
text
;
}
else
{
return
'[自定义消息]'
return
"[自定义消息]"
;
}
},
}
}
}
,
}
;
</
script
>
<
style
lang=
"stylus"
scoped
>
...
...
src/components/message/message-send-box.vue
View file @
6425bbc
<
template
>
<div
id=
"message-send-box-wrapper"
:style=
"focus ?
{'backgroundColor': 'white'} : {}" @drop="dropHandler">
<div
id=
"message-send-box-wrapper"
:style=
"focus ?
{ backgroundColor: 'white' } : {}"
@drop="dropHandler"
>
<div
class=
"send-header-bar"
>
<el-popover
placement=
"top"
width=
"400"
trigger=
"click"
>
<div
class=
"emojis"
>
<div
v-for=
"item in emojiName"
class=
"emoji"
:key=
"item"
@
click=
"chooseEmoji(item)"
>
<img
:src=
"emojiUrl + emojiMap[item]"
style=
"width:30px;height:30px"
alt=
""
/>
<div
v-for=
"item in emojiName"
class=
"emoji"
:key=
"item"
@
click=
"chooseEmoji(item)"
>
<img
:src=
"emojiUrl + emojiMap[item]"
style=
"width: 30px; height: 30px"
alt=
""
/>
</div>
</div>
<i
class=
"iconfont icon-smile"
slot=
"reference"
title=
"发表情"
></i>
</el-popover>
<i
class=
"iconfont icon-tupian"
title=
"发图片"
@
click=
"handleSendImageClick"
></i>
<i
class=
"el-icon-camera"
title=
"发视频"
@
click=
"handleSendVideoClick"
></i>
<!--
<i
class=
"iconfont icon-wenjian"
title=
"发文件"
@
click=
"handleSendFileClick"
></i>
-->
<i
class=
"iconfont icon-tupian"
title=
"发图片"
@
click=
"handleSendImageClick"
></i>
<i
class=
"el-icon-camera"
title=
"发视频"
@
click=
"handleSendVideoClick"
></i>
<i
class=
"el-icon-link"
v-if=
"currentConversationType === TIM.TYPES.CONV_GROUP"
title=
"发歌曲详情"
@
click=
"handleSendAudio"
></i>
<!--
<i
class=
"iconfont icon-wenjian"
title=
"发文件"
@
click=
"handleSendFileClick"
></i>
-->
<!--
<i
class=
"iconfont icon-zidingyi"
title=
"发自定义消息"
@
click=
"sendCustomDialogVisible = true"
></i>
-->
<!--
<el-dropdown>
-->
<!--
<span
class=
"el-dropdown-link"
>
-->
...
...
@@ -29,7 +57,11 @@
<!--
<i
class=
"group-live-icon-hover"
></i>
-->
<!--
</div>
-->
</div>
<el-dialog
title=
"发自定义消息"
:visible
.
sync=
"sendCustomDialogVisible"
width=
"30%"
>
<el-dialog
title=
"发自定义消息"
:visible
.
sync=
"sendCustomDialogVisible"
width=
"30%"
>
<el-form
label-width=
"100px"
>
<el-form-item
label=
"data"
>
<el-input
v-model=
"form.data"
></el-input>
...
...
@@ -46,7 +78,11 @@
<el-button
type=
"primary"
@
click=
"sendCustomMessage"
>
确 定
</el-button>
</span>
</el-dialog>
<el-dialog
title=
"对IM Web demo的建议和使用感受"
:visible
.
sync=
"surveyDialogVisible"
width=
"30%"
>
<el-dialog
title=
"对IM Web demo的建议和使用感受"
:visible
.
sync=
"surveyDialogVisible"
width=
"30%"
>
<el-form
label-width=
"100px"
>
<el-form-item
label=
"评分"
>
<div
class=
"block"
>
...
...
@@ -72,16 +108,18 @@
trigger=
"manual"
v-model=
"showAtGroupMember"
placement=
"top"
style=
"max-height:500px;overflow-y:scroll;
"
style=
"max-height: 500px; overflow-y: scroll
"
>
<el-radio-group
v-model=
"atUserID"
style=
"display:flex;flex-decoration: column;
"
style=
"display: flex; flex-decoration: column
"
v-for=
"member in memberList"
:key=
"member.userID"
@
change=
"handleSelectAtUser"
>
<el-radio
:label=
"member.userID"
>
{{
member
.
nameCard
||
member
.
nick
||
member
.
userID
}}
</el-radio>
<el-radio
:label=
"member.userID"
>
{{
member
.
nameCard
||
member
.
nick
||
member
.
userID
}}
</el-radio>
</el-radio-group>
</el-popover>
<div
class=
"bottom"
>
...
...
@@ -116,11 +154,29 @@
ref=
"imagePicker"
accept=
".jpg, .jpeg, .png, .gif, .bmp"
@
change=
"sendImage"
style=
"display:none"
style=
"display: none"
/>
<input
type=
"file"
id=
"filePicker"
ref=
"filePicker"
@
change=
"sendFile"
style=
"display: none"
/>
<input
type=
"file"
id=
"videoPicker"
ref=
"videoPicker"
@
change=
"sendVideo"
style=
"display: none"
accept=
".mp4"
/>
<input
type=
"file"
id=
"filePicker"
ref=
"filePicker"
@
change=
"sendFile"
style=
"display:none"
/>
<input
type=
"file"
id=
"videoPicker"
ref=
"videoPicker"
@
change=
"sendVideo"
style=
"display:none"
accept=
".mp4"
/>
<div
class=
"calling-member-list"
v-if=
"currentConversationType === TIM.TYPES.CONV_GROUP && showCallingMember"
>
<div
class=
"calling-member-list"
v-if=
"
currentConversationType === TIM.TYPES.CONV_GROUP && showCallingMember
"
>
<calling-member-list
@
getList=
"getList"
></calling-member-list>
<div
class=
"calling-list-btn"
>
<span
class=
"calling-btn"
@
click=
"cancelCalling"
>
取消
</span>
...
...
@@ -131,14 +187,24 @@
</
template
>
<
script
>
import
{
mapGetters
,
mapState
}
from
'vuex'
import
callingMemberList
from
'./trtc-calling/group-member-list'
import
{
Dialog
,
Form
,
FormItem
,
Input
,
Popover
,
Radio
,
RadioGroup
,
Rate
,
Tooltip
}
from
'element-ui'
import
{
emojiMap
,
emojiName
,
emojiUrl
}
from
'../../utils/emojiMap'
import
{
mapGetters
,
mapState
}
from
"vuex"
;
import
callingMemberList
from
"./trtc-calling/group-member-list"
;
import
{
Dialog
,
Form
,
FormItem
,
Input
,
Popover
,
Radio
,
RadioGroup
,
Rate
,
Tooltip
,
}
from
"element-ui"
;
import
{
emojiMap
,
emojiName
,
emojiUrl
}
from
"../../utils/emojiMap"
;
import
hrequest
from
"../../utils/hrequest"
;
export
default
{
name
:
'message-send-box'
,
props
:
[
'scrollMessageListToButtom'
],
name
:
"message-send-box"
,
props
:
[
"scrollMessageListToButtom"
],
components
:
{
callingMemberList
:
callingMemberList
,
ElInput
:
Input
,
...
...
@@ -149,274 +215,275 @@ export default {
ElRadioGroup
:
RadioGroup
,
ElRadio
:
Radio
,
ElTooltip
:
Tooltip
,
ElRate
:
Rate
ElRate
:
Rate
,
},
data
()
{
return
{
callingList
:
[],
callingType
:
''
,
callingType
:
""
,
showCallingMember
:
false
,
colors
:
[
'#99A9BF'
,
'#F7BA2A'
,
'#FF9900'
],
messageContent
:
''
,
colors
:
[
"#99A9BF"
,
"#F7BA2A"
,
"#FF9900"
],
messageContent
:
""
,
isSendCustomMessage
:
false
,
sendCustomDialogVisible
:
false
,
surveyDialogVisible
:
false
,
form
:
{
data
:
''
,
description
:
''
,
extension
:
''
data
:
""
,
description
:
""
,
extension
:
""
,
},
rate
:
5
,
// 评分
suggestion
:
''
,
// 建议
file
:
''
,
suggestion
:
""
,
// 建议
file
:
""
,
emojiMap
:
emojiMap
,
emojiName
:
emojiName
,
emojiUrl
:
emojiUrl
,
showAtGroupMember
:
false
,
atUserID
:
''
,
focus
:
false
}
atUserID
:
""
,
focus
:
false
,
}
;
},
computed
:
{
...
mapGetters
([
'toAccount'
,
'currentConversationType'
]),
...
mapGetters
([
"toAccount"
,
"currentConversationType"
]),
...
mapState
({
memberList
:
state
=>
state
.
group
.
currentMemberList
,
userID
:
state
=>
state
.
user
.
userID
,
groupProfile
:
state
=>
state
.
conversation
.
currentConversation
.
groupProfile
})
memberList
:
(
state
)
=>
state
.
group
.
currentMemberList
,
userID
:
(
state
)
=>
state
.
user
.
userID
,
groupProfile
:
(
state
)
=>
state
.
conversation
.
currentConversation
.
groupProfile
,
}),
},
mounted
()
{
this
.
$refs
[
'text-input'
].
addEventListener
(
'paste'
,
this
.
handlePaste
)
this
.
$bus
.
$on
(
'reEditMessage'
,
this
.
reEditMessage
)
this
.
$refs
[
"text-input"
].
addEventListener
(
"paste"
,
this
.
handlePaste
);
this
.
$bus
.
$on
(
"reEditMessage"
,
this
.
reEditMessage
);
},
beforeDestroy
()
{
this
.
$refs
[
'text-input'
].
removeEventListener
(
'paste'
,
this
.
handlePaste
)
this
.
$refs
[
"text-input"
].
removeEventListener
(
"paste"
,
this
.
handlePaste
);
},
methods
:
{
getList
(
value
)
{
this
.
callingList
=
value
this
.
callingList
=
value
;
},
cancelCalling
()
{
this
.
showCallingMember
=
false
this
.
showCallingMember
=
false
;
},
callingHandler
()
{
if
(
this
.
callingList
.
length
<
1
)
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'warning'
,
message
:
'请选择成员'
})
return
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"warning"
,
message
:
"请选择成员"
,
})
;
return
;
}
this
.
showCallingMember
=
false
this
.
showCallingMember
=
false
;
let
callingData
=
{
memberList
:
this
.
callingList
,
type
:
this
.
TIM
.
TYPES
.
CONV_GROUP
type
:
this
.
TIM
.
TYPES
.
CONV_GROUP
,
};
this
.
$store
.
commit
(
"setCallingList"
,
callingData
);
if
(
this
.
callingType
===
"video"
)
{
this
.
$bus
.
$emit
(
"video-call"
);
return
;
}
this
.
$store
.
commit
(
'setCallingList'
,
callingData
)
if
(
this
.
callingType
===
'video'
)
{
this
.
$bus
.
$emit
(
'video-call'
)
return
}
if
(
this
.
callingType
===
'audio'
)
{
this
.
$bus
.
$emit
(
'audio-call'
)
return
if
(
this
.
callingType
===
"audio"
)
{
this
.
$bus
.
$emit
(
"audio-call"
);
return
;
}
},
trtcCalling
(
type
)
{
if
(
type
===
'video'
)
{
this
.
callingType
=
'video'
if
(
type
===
"video"
)
{
this
.
callingType
=
"video"
;
}
if
(
type
===
'audio'
)
{
this
.
callingType
=
'audio'
if
(
type
===
"audio"
)
{
this
.
callingType
=
"audio"
;
}
// 呼叫方设置
if
(
this
.
currentConversationType
===
'C2C'
)
{
let
member
=
[
this
.
toAccount
]
if
(
this
.
currentConversationType
===
"C2C"
)
{
let
member
=
[
this
.
toAccount
]
;
let
callingData
=
{
memberList
:
member
,
type
:
'C2C'
}
this
.
$store
.
commit
(
'setCallingList'
,
callingData
)
this
.
$bus
.
$emit
(
`
${
type
}
-call`
)
return
type
:
"C2C"
,
}
;
this
.
$store
.
commit
(
"setCallingList"
,
callingData
);
this
.
$bus
.
$emit
(
`
${
type
}
-call`
)
;
return
;
}
if
(
this
.
currentConversationType
===
this
.
TIM
.
TYPES
.
CONV_GROUP
)
{
this
.
showCallingMember
=
true
this
.
showCallingMember
=
true
;
}
// this.$store.commit('pushCurrentMessageList', true)
},
audioCall
()
{
this
.
$bus
.
$emit
(
'audio-call'
)
this
.
$store
.
commit
(
'showAudioCall'
,
true
)
this
.
$bus
.
$emit
(
"audio-call"
);
this
.
$store
.
commit
(
"showAudioCall"
,
true
);
},
handleEmojiShow
()
{
this
.
emojiShow
=
true
this
.
bigEmojiShow
=
false
this
.
emojiShow
=
true
;
this
.
bigEmojiShow
=
false
;
},
handleBigEmojiShow
(
index
)
{
let
elm
=
document
.
getElementById
(
'bigEmojiBox'
)
elm
&&
(
elm
.
scrollTop
=
0
)
this
.
curItemIndex
=
index
this
.
curBigEmojiItemList
=
this
.
bigEmojiList
[
index
].
list
this
.
emojiShow
=
false
this
.
bigEmojiShow
=
true
let
elm
=
document
.
getElementById
(
"bigEmojiBox"
);
elm
&&
(
elm
.
scrollTop
=
0
)
;
this
.
curItemIndex
=
index
;
this
.
curBigEmojiItemList
=
this
.
bigEmojiList
[
index
].
list
;
this
.
emojiShow
=
false
;
this
.
bigEmojiShow
=
true
;
},
chooseBigEmoji
(
item
)
{
this
.
popoverVisible
=
false
this
.
popoverVisible
=
false
;
let
message
=
this
.
tim
.
createFaceMessage
({
to
:
this
.
toAccount
,
conversationType
:
this
.
currentConversationType
,
payload
:
{
index
:
this
.
curItemIndex
+
1
,
data
:
`
${
item
}
@2x`
}
})
this
.
$store
.
commit
(
'pushCurrentMessageList'
,
message
)
this
.
$bus
.
$emit
(
'scroll-bottom'
)
this
.
tim
.
sendMessage
(
message
).
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
})
data
:
`
${
item
}
@2x`
,
}
,
})
;
this
.
$store
.
commit
(
"pushCurrentMessageList"
,
message
);
this
.
$bus
.
$emit
(
"scroll-bottom"
);
this
.
tim
.
sendMessage
(
message
).
catch
(
(
error
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
error
.
message
,
})
;
})
;
},
reEditMessage
(
payload
)
{
this
.
messageContent
=
payload
this
.
messageContent
=
payload
;
},
handleSelectAtUser
()
{
this
.
messageContent
+=
this
.
atUserID
+
' '
this
.
showAtGroupMember
=
false
this
.
messageContent
+=
this
.
atUserID
+
" "
;
this
.
showAtGroupMember
=
false
;
},
handleUp
()
{
const
index
=
this
.
memberList
.
findIndex
(
member
=>
member
.
userID
===
this
.
atUserID
)
(
member
)
=>
member
.
userID
===
this
.
atUserID
)
;
if
(
index
-
1
<
0
)
{
return
return
;
}
this
.
atUserID
=
this
.
memberList
[
index
-
1
].
userID
this
.
atUserID
=
this
.
memberList
[
index
-
1
].
userID
;
},
handleDown
()
{
const
index
=
this
.
memberList
.
findIndex
(
member
=>
member
.
userID
===
this
.
atUserID
)
(
member
)
=>
member
.
userID
===
this
.
atUserID
)
;
if
(
index
+
1
>=
this
.
memberList
.
length
)
{
return
return
;
}
this
.
atUserID
=
this
.
memberList
[
index
+
1
].
userID
this
.
atUserID
=
this
.
memberList
[
index
+
1
].
userID
;
},
handleEnter
()
{
if
(
this
.
showAtGroupMember
)
{
this
.
handleSelectAtUser
()
this
.
handleSelectAtUser
()
;
}
else
{
this
.
sendTextMessage
()
this
.
sendTextMessage
()
;
}
},
handleLine
()
{
this
.
messageContent
+=
'\n'
this
.
messageContent
+=
"\n"
;
},
handlePaste
(
e
)
{
let
clipboardData
=
e
.
clipboardData
let
file
let
clipboardData
=
e
.
clipboardData
;
let
file
;
if
(
clipboardData
&&
clipboardData
.
files
&&
clipboardData
.
files
.
length
>
0
)
{
file
=
clipboardData
.
files
[
0
]
file
=
clipboardData
.
files
[
0
]
;
}
if
(
typeof
file
===
'undefined'
)
{
return
if
(
typeof
file
===
"undefined"
)
{
return
;
}
// 1. 创建消息实例,接口返回的实例可以上屏
let
message
=
this
.
tim
.
createImageMessage
({
to
:
this
.
toAccount
,
conversationType
:
this
.
currentConversationType
,
payload
:
{
file
:
file
file
:
file
,
},
onProgress
:
percent
=>
{
this
.
$set
(
message
,
'progress'
,
percent
)
// 手动给message 实例加个响应式属性: progress
}
})
this
.
$store
.
commit
(
'pushCurrentMessageList'
,
message
)
onProgress
:
(
percent
)
=>
{
this
.
$set
(
message
,
"progress"
,
percent
);
// 手动给message 实例加个响应式属性: progress
}
,
})
;
this
.
$store
.
commit
(
"pushCurrentMessageList"
,
message
);
// 2. 发送消息
let
promise
=
this
.
tim
.
sendMessage
(
message
)
promise
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
})
let
promise
=
this
.
tim
.
sendMessage
(
message
)
;
promise
.
catch
(
(
error
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
error
.
message
,
})
;
})
;
},
dropHandler
(
e
)
{
e
.
preventDefault
()
let
file
=
e
.
dataTransfer
.
files
[
0
]
let
message
=
{}
if
(
file
.
type
===
'video/mp4'
)
{
e
.
preventDefault
()
;
let
file
=
e
.
dataTransfer
.
files
[
0
]
;
let
message
=
{}
;
if
(
file
.
type
===
"video/mp4"
)
{
message
=
this
.
tim
.
createVideoMessage
({
to
:
this
.
toAccount
,
conversationType
:
this
.
currentConversationType
,
payload
:
{
file
:
file
file
:
file
,
},
onProgress
:
percent
=>
{
this
.
$set
(
message
,
'progress'
,
percent
)
// 手动给message 实例加个响应式属性: progress
}
})
onProgress
:
(
percent
)
=>
{
this
.
$set
(
message
,
"progress"
,
percent
);
// 手动给message 实例加个响应式属性: progress
}
,
})
;
}
else
{
message
=
this
.
tim
.
createFileMessage
({
to
:
this
.
toAccount
,
conversationType
:
this
.
currentConversationType
,
payload
:
{
file
:
file
file
:
file
,
},
onProgress
:
percent
=>
{
this
.
$set
(
message
,
'progress'
,
percent
)
// 手动给message 实例加个响应式属性: progress
}
})
onProgress
:
(
percent
)
=>
{
this
.
$set
(
message
,
"progress"
,
percent
);
// 手动给message 实例加个响应式属性: progress
}
,
})
;
}
this
.
$store
.
commit
(
'pushCurrentMessageList'
,
message
)
this
.
$store
.
commit
(
"pushCurrentMessageList"
,
message
);
this
.
tim
.
sendMessage
(
message
)
.
then
(()
=>
{
this
.
$refs
.
videoPicker
.
value
=
null
this
.
$refs
.
videoPicker
.
value
=
null
;
})
.
catch
(
imError
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
.
catch
((
imError
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
imError
.
message
,
type
:
'error'
})
})
type
:
"error"
,
});
});
},
sendTextMessage
()
{
if
(
this
.
messageContent
===
''
||
this
.
messageContent
===
""
||
this
.
messageContent
.
trim
().
length
===
0
)
{
this
.
messageContent
=
''
this
.
$store
.
commit
(
'showMessage'
,
{
message
:
'不能发送空消息哦!'
,
type
:
'info'
})
return
this
.
messageContent
=
""
;
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
"不能发送空消息哦!"
,
type
:
"info"
,
})
;
return
;
}
const
message
=
this
.
tim
.
createTextMessage
({
to
:
this
.
toAccount
,
conversationType
:
this
.
currentConversationType
,
payload
:
{
text
:
this
.
messageContent
}
})
this
.
$store
.
commit
(
'pushCurrentMessageList'
,
message
)
this
.
$bus
.
$emit
(
'scroll-bottom'
)
this
.
tim
.
sendMessage
(
message
).
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
})
this
.
messageContent
=
''
payload
:
{
text
:
this
.
messageContent
},
})
;
this
.
$store
.
commit
(
"pushCurrentMessageList"
,
message
);
this
.
$bus
.
$emit
(
"scroll-bottom"
);
this
.
tim
.
sendMessage
(
message
).
catch
(
(
error
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
error
.
message
,
})
;
})
;
this
.
messageContent
=
""
;
},
sendCustomMessage
()
{
if
(
...
...
@@ -424,11 +491,11 @@ export default {
this
.
form
.
description
.
length
===
0
&&
this
.
form
.
extension
.
length
===
0
)
{
this
.
$store
.
commit
(
'showMessage'
,
{
message
:
'不能发送空消息'
,
type
:
'info'
})
return
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
"不能发送空消息"
,
type
:
"info"
,
})
;
return
;
}
const
message
=
this
.
tim
.
createCustomMessage
({
to
:
this
.
toAccount
,
...
...
@@ -436,151 +503,222 @@ export default {
payload
:
{
data
:
this
.
form
.
data
,
description
:
this
.
form
.
description
,
extension
:
this
.
form
.
extension
}
})
this
.
$store
.
commit
(
'pushCurrentMessageList'
,
message
)
this
.
tim
.
sendMessage
(
message
).
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
})
extension
:
this
.
form
.
extension
,
}
,
})
;
this
.
$store
.
commit
(
"pushCurrentMessageList"
,
message
);
this
.
tim
.
sendMessage
(
message
).
catch
(
(
error
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
error
.
message
,
})
;
})
;
Object
.
assign
(
this
.
form
,
{
data
:
''
,
description
:
''
,
extension
:
''
})
this
.
sendCustomDialogVisible
=
false
data
:
""
,
description
:
""
,
extension
:
""
,
})
;
this
.
sendCustomDialogVisible
=
false
;
},
random
(
min
,
max
)
{
return
Math
.
floor
(
Math
.
random
()
*
(
max
-
min
+
1
)
+
min
)
return
Math
.
floor
(
Math
.
random
()
*
(
max
-
min
+
1
)
+
min
)
;
},
sendSurvey
()
{
const
message
=
this
.
tim
.
createCustomMessage
({
to
:
this
.
toAccount
,
conversationType
:
this
.
currentConversationType
,
payload
:
{
data
:
'survey'
,
data
:
"survey"
,
description
:
String
(
this
.
rate
),
extension
:
this
.
suggestion
}
})
this
.
$store
.
commit
(
'pushCurrentMessageList'
,
message
)
extension
:
this
.
suggestion
,
}
,
})
;
this
.
$store
.
commit
(
"pushCurrentMessageList"
,
message
);
Object
.
assign
(
this
.
form
,
{
data
:
''
,
description
:
''
,
extension
:
''
})
data
:
""
,
description
:
""
,
extension
:
""
,
})
;
this
.
tim
.
sendMessage
(
message
)
.
then
(()
=>
{
Object
.
assign
(
this
,
{
rate
:
5
,
suggestion
:
''
suggestion
:
""
,
});
})
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
})
this
.
surveyDialogVisible
=
false
.
catch
((
error
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
error
.
message
,
});
});
this
.
surveyDialogVisible
=
false
;
},
chooseEmoji
(
item
)
{
this
.
messageContent
+=
item
this
.
messageContent
+=
item
;
},
handleSendImageClick
()
{
this
.
$refs
.
imagePicker
.
click
()
this
.
$refs
.
imagePicker
.
click
()
;
},
handleSendFileClick
()
{
this
.
$refs
.
filePicker
.
click
()
this
.
$refs
.
filePicker
.
click
()
;
},
handleSendVideoClick
()
{
this
.
$refs
.
videoPicker
.
click
()
this
.
$refs
.
videoPicker
.
click
()
;
},
handleSendAudio
()
{
this
.
sendActivityAudio
();
},
groupLive
()
{
this
.
$store
.
commit
(
'updateGroupLiveInfo'
,
{
this
.
$store
.
commit
(
"updateGroupLiveInfo"
,
{
groupID
:
this
.
toAccount
,
anchorID
:
this
.
userID
,
})
this
.
$bus
.
$emit
(
'open-group-live'
,
{
channel
:
1
})
})
;
this
.
$bus
.
$emit
(
"open-group-live"
,
{
channel
:
1
});
},
sendImage
()
{
const
message
=
this
.
tim
.
createImageMessage
({
to
:
this
.
toAccount
,
conversationType
:
this
.
currentConversationType
,
payload
:
{
file
:
document
.
getElementById
(
'imagePicker'
)
// 或者用event.target
file
:
document
.
getElementById
(
"imagePicker"
),
// 或者用event.target
},
onProgress
:
percent
=>
{
this
.
$set
(
message
,
'progress'
,
percent
)
// 手动给message 实例加个响应式属性: progress
}
})
this
.
$store
.
commit
(
'pushCurrentMessageList'
,
message
)
onProgress
:
(
percent
)
=>
{
this
.
$set
(
message
,
"progress"
,
percent
);
// 手动给message 实例加个响应式属性: progress
}
,
})
;
this
.
$store
.
commit
(
"pushCurrentMessageList"
,
message
);
this
.
tim
.
sendMessage
(
message
)
.
then
(()
=>
{
this
.
$refs
.
imagePicker
.
value
=
null
this
.
$refs
.
imagePicker
.
value
=
null
;
})
.
catch
(
imError
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
.
catch
((
imError
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
imError
.
message
,
type
:
'error'
})
})
type
:
"error"
,
});
});
},
sendFile
()
{
const
message
=
this
.
tim
.
createFileMessage
({
to
:
this
.
toAccount
,
conversationType
:
this
.
currentConversationType
,
payload
:
{
file
:
document
.
getElementById
(
'filePicker'
)
// 或者用event.target
file
:
document
.
getElementById
(
"filePicker"
),
// 或者用event.target
},
onProgress
:
percent
=>
{
this
.
$set
(
message
,
'progress'
,
percent
)
// 手动给message 实例加个响应式属性: progress
}
})
this
.
$store
.
commit
(
'pushCurrentMessageList'
,
message
)
onProgress
:
(
percent
)
=>
{
this
.
$set
(
message
,
"progress"
,
percent
);
// 手动给message 实例加个响应式属性: progress
}
,
})
;
this
.
$store
.
commit
(
"pushCurrentMessageList"
,
message
);
this
.
tim
.
sendMessage
(
message
)
.
then
(()
=>
{
this
.
$refs
.
filePicker
.
value
=
null
this
.
$refs
.
filePicker
.
value
=
null
;
})
.
catch
(
imError
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
.
catch
((
imError
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
imError
.
message
,
type
:
'error'
})
})
type
:
"error"
,
});
});
},
sendVideo
()
{
const
message
=
this
.
tim
.
createVideoMessage
({
to
:
this
.
toAccount
,
conversationType
:
this
.
currentConversationType
,
payload
:
{
file
:
document
.
getElementById
(
'videoPicker'
)
// 或者用event.target
file
:
document
.
getElementById
(
"videoPicker"
),
// 或者用event.target
},
onProgress
:
percent
=>
{
this
.
$set
(
message
,
'progress'
,
percent
)
// 手动给message 实例加个响应式属性: progress
}
})
this
.
$store
.
commit
(
'pushCurrentMessageList'
,
message
)
onProgress
:
(
percent
)
=>
{
this
.
$set
(
message
,
"progress"
,
percent
);
// 手动给message 实例加个响应式属性: progress
}
,
})
;
this
.
$store
.
commit
(
"pushCurrentMessageList"
,
message
);
this
.
tim
.
sendMessage
(
message
)
.
then
(()
=>
{
this
.
$refs
.
videoPicker
.
value
=
null
this
.
$refs
.
videoPicker
.
value
=
null
;
})
.
catch
(
imError
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
.
catch
((
imError
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
imError
.
message
,
type
:
'error'
})
})
type
:
"error"
,
});
});
},
sendActivityAudio
()
{
console
.
log
(
"in sendActivityAudio"
,
this
.
groupProfile
);
let
activityID
=
""
;
this
.
groupProfile
.
groupCustomField
.
forEach
((
item
)
=>
{
const
{
key
,
value
}
=
item
;
if
(
key
==
"ActivityKey"
)
{
console
.
log
(
"get activityID is "
,
key
);
activityID
=
value
;
}
});
if
(
!
activityID
)
{
return
;
}
}
hrequest
.
get
(
`v3/activitys/
${
activityID
}
`
).
then
((
res
)
=>
{
if
(
res
&&
res
.
data
&&
res
.
data
.
data
&&
res
.
data
.
data
.
activity
)
{
let
activity
=
res
.
data
.
data
.
activity
;
const
{
activity_name
,
banner
,
audio_file
}
=
activity
;
let
imageUrl
=
""
;
let
audioUrl
=
""
;
if
(
banner
&&
banner
.
length
>=
1
)
{
let
innerBanner
=
banner
[
0
];
imageUrl
=
innerBanner
.
url
;
}
if
(
audio_file
)
{
audioUrl
=
audio_file
.
url
;
}
// console.log("activity_name is ", activity_name);
// console.log("imageUrl is ", imageUrl);
// console.log("audioUrl is ", audioUrl);
this
.
sendMatiral
(
activityID
,
activity_name
,
imageUrl
,
audioUrl
);
}
});
},
sendMatiral
(
id
,
activityName
,
imageUrl
,
audioUrl
)
{
let
extension
=
JSON
.
stringify
({
cover_url
:
imageUrl
,
name
:
activityName
,
activity_id
:
id
,
});
// 3.创建伪消息 用于展示
let
message
=
this
.
tim
.
createCustomMessage
({
to
:
this
.
toAccount
,
conversationType
:
this
.
currentConversationType
,
payload
:
{
data
:
"audio"
,
// 用于标识该消息是骰子类型消息
description
:
audioUrl
,
// 获取骰子点数
extension
:
extension
,
},
});
this
.
$store
.
commit
(
"pushCurrentMessageList"
,
message
);
this
.
tim
.
sendMessage
(
message
)
.
then
((
res
)
=>
{
console
.
log
(
"res is "
,
res
);
})
.
catch
((
imError
)
=>
{
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
imError
.
message
,
type
:
"error"
,
});
});
},
},
};
</
script
>
<
style
lang=
"stylus"
scoped
>
#message-send-box-wrapper
{
...
...
src/index.vue
View file @
6425bbc
<
template
>
<div
class=
"container"
>
<div
class=
"loading"
v-loading=
"showLoading"
element-loading-text=
"正在拼命初始化..."
element-loading-background=
"rgba(0, 0, 0, 0.8)"
>
<div
class=
"loading"
v-loading=
"showLoading"
element-loading-text=
"正在拼命初始化..."
element-loading-background=
"rgba(0, 0, 0, 0.8)"
>
<div
class=
"chat-wrapper"
>
<el-row>
<el-col
:xs=
"10"
:sm=
"10"
:md=
"8"
:lg=
"8"
:xl=
"7"
>
<side-bar/>
<side-bar
/>
</el-col>
<el-col
:xs=
"14"
:sm=
"14"
:md=
"16"
:lg=
"16"
:xl=
"17"
>
<current-conversation/>
<current-conversation
/>
</el-col>
</el-row>
</div>
<calling
ref=
"callLayer"
class=
"chat-wrapper"
/>
<image-previewer/>
<group-live/>
<calling
ref=
"callLayer"
class=
"chat-wrapper"
/>
<image-previewer
/>
<group-live
/>
</div>
<div
class=
"bg"
></div>
</div>
</
template
>
<
script
>
import
{
Notification
}
from
'element-ui'
import
{
mapState
}
from
'vuex'
import
CurrentConversation
from
'./components/conversation/current-conversation'
import
SideBar
from
'./components/layout/side-bar'
import
ImagePreviewer
from
'./components/message/image-previewer.vue'
import
{
translateGroupSystemNotice
}
from
'./utils/common'
import
GroupLive
from
'./components/group-live/index'
import
Calling
from
'./components/message/trtc-calling/calling-index'
import
{
ACTION
}
from
'./utils/trtcCustomMessageMap'
import
MTA
from
'./utils/mta'
import
Helper
from
'./utils/helper'
import
{
Notification
}
from
"element-ui"
;
import
{
mapState
}
from
"vuex"
;
import
CurrentConversation
from
"./components/conversation/current-conversation"
;
import
SideBar
from
"./components/layout/side-bar"
;
import
ImagePreviewer
from
"./components/message/image-previewer.vue"
;
import
{
translateGroupSystemNotice
}
from
"./utils/common"
;
import
GroupLive
from
"./components/group-live/index"
;
import
Calling
from
"./components/message/trtc-calling/calling-index"
;
import
{
ACTION
}
from
"./utils/trtcCustomMessageMap"
;
import
MTA
from
"./utils/mta"
;
import
Helper
from
"./utils/helper"
;
export
default
{
title
:
'星斗推'
,
title
:
"星斗推"
,
components
:
{
SideBar
,
CurrentConversation
,
...
...
@@ -44,49 +48,54 @@ export default {
},
computed
:
{
...
mapState
({
currentUserProfile
:
state
=>
state
.
user
.
currentUserProfile
,
currentConversation
:
state
=>
state
.
conversation
.
currentConversation
,
videoCall
:
state
=>
state
.
conversation
.
videoCall
,
audioCall
:
state
=>
state
.
conversation
.
audioCall
,
isLogin
:
state
=>
state
.
user
.
isLogin
,
isSDKReady
:
state
=>
state
.
user
.
isSDKReady
,
isBusy
:
state
=>
state
.
video
.
isBusy
,
userID
:
state
=>
state
.
user
.
userID
,
userSig
:
state
=>
state
.
user
.
userSig
,
sdkAppID
:
state
=>
state
.
user
.
sdkAppID
currentUserProfile
:
(
state
)
=>
state
.
user
.
currentUserProfile
,
currentConversation
:
(
state
)
=>
state
.
conversation
.
currentConversation
,
videoCall
:
(
state
)
=>
state
.
conversation
.
videoCall
,
audioCall
:
(
state
)
=>
state
.
conversation
.
audioCall
,
isLogin
:
(
state
)
=>
state
.
user
.
isLogin
,
isSDKReady
:
(
state
)
=>
state
.
user
.
isSDKReady
,
isBusy
:
(
state
)
=>
state
.
video
.
isBusy
,
userID
:
(
state
)
=>
state
.
user
.
userID
,
userSig
:
(
state
)
=>
state
.
user
.
userSig
,
sdkAppID
:
(
state
)
=>
state
.
user
.
sdkAppID
,
}),
// 是否显示 Loading 状态
showLoading
()
{
return
!
this
.
isSDKReady
}
return
!
this
.
isSDKReady
;
}
,
},
mounted
()
{
// 初始化监听器
this
.
initListener
()
this
.
initListener
();
},
created
()
{
Helper
.
verifyToken
().
then
(
user
=>
this
.
tim
.
login
({
userID
:
user
.
id
,
userSig
:
user
.
sign
})
Helper
.
verifyToken
().
then
((
user
)
=>
this
.
tim
.
login
({
userID
:
user
.
id
,
userSig
:
user
.
sign
})
.
then
(()
=>
{
this
.
loading
=
false
this
.
$store
.
commit
(
'toggleIsLogin'
,
true
)
this
.
$store
.
commit
(
'startComputeCurrent'
)
this
.
$store
.
commit
(
'GET_USER_INFO'
,
{
this
.
loading
=
false
;
this
.
$store
.
commit
(
"toggleIsLogin"
,
true
);
this
.
$store
.
commit
(
"startComputeCurrent"
);
this
.
$store
.
commit
(
"GET_USER_INFO"
,
{
userID
:
user
.
id
,
userSig
:
user
.
sign
,
sdkAppID
:
process
.
env
.
VUE_APP_API_KEY
})
sdkAppID
:
process
.
env
.
VUE_APP_API_KEY
,
})
;
// this.$store.commit('showMessage', {type: 'success', message: '登录成功'})
})
.
catch
(
error
=>
{
this
.
loading
=
false
this
.
$store
.
commit
(
'showMessage'
,
{
message
:
'登录失败:'
+
error
.
message
,
type
:
'error'
})
}))
.
catch
((
error
)
=>
{
this
.
loading
=
false
;
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
"登录失败:"
+
error
.
message
,
type
:
"error"
,
});
})
);
},
watch
:
{
isLogin
(
next
)
{
if
(
next
)
{
MTA
.
clickStat
(
'link_two'
,
{
show
:
'true'
})
MTA
.
clickStat
(
"link_two"
,
{
show
:
"true"
});
}
},
},
...
...
@@ -94,54 +103,65 @@ export default {
methods
:
{
initListener
()
{
// 登录成功后会触发 SDK_READY 事件,该事件触发后,可正常使用 SDK 接口
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
SDK_READY
,
this
.
onReadyStateUpdate
,
this
)
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
SDK_READY
,
this
.
onReadyStateUpdate
,
this
)
;
// SDK NOT READT
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
SDK_NOT_READY
,
this
.
onReadyStateUpdate
,
this
)
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
SDK_NOT_READY
,
this
.
onReadyStateUpdate
,
this
)
;
// 被踢出
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
KICKED_OUT
,
this
.
onKickOut
)
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
KICKED_OUT
,
this
.
onKickOut
)
;
// SDK内部出错
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
ERROR
,
this
.
onError
)
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
ERROR
,
this
.
onError
)
;
// 收到新消息
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
MESSAGE_RECEIVED
,
this
.
onReceiveMessage
)
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
MESSAGE_RECEIVED
,
this
.
onReceiveMessage
)
;
// 会话列表更新
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
CONVERSATION_LIST_UPDATED
,
this
.
onUpdateConversationList
)
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
CONVERSATION_LIST_UPDATED
,
this
.
onUpdateConversationList
);
// 群组列表更新
// this.tim.on(this.TIM.EVENT.GROUP_LIST_UPDATED, this.onUpdateGroupList)
// 网络监测
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
NET_STATE_CHANGE
,
this
.
onNetStateChange
)
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
NET_STATE_CHANGE
,
this
.
onNetStateChange
)
;
// 已读回执
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
MESSAGE_READ_BY_PEER
,
this
.
onMessageReadByPeer
)
this
.
tim
.
on
(
this
.
TIM
.
EVENT
.
MESSAGE_READ_BY_PEER
,
this
.
onMessageReadByPeer
);
},
onReceiveMessage
({
data
:
messageList
})
{
this
.
handleVideoMessage
(
messageList
)
this
.
handleAt
(
messageList
)
this
.
handleQuitGroupTip
(
messageList
)
this
.
handleCloseGroupLive
(
messageList
)
this
.
$store
.
commit
(
'pushCurrentMessageList'
,
messageList
)
this
.
$store
.
commit
(
'pushAvChatRoomMessageList'
,
messageList
)
onReceiveMessage
({
data
:
messageList
})
{
this
.
handleVideoMessage
(
messageList
)
;
this
.
handleAt
(
messageList
)
;
this
.
handleQuitGroupTip
(
messageList
)
;
this
.
handleCloseGroupLive
(
messageList
)
;
this
.
$store
.
commit
(
"pushCurrentMessageList"
,
messageList
);
this
.
$store
.
commit
(
"pushAvChatRoomMessageList"
,
messageList
);
},
onError
({
data
})
{
if
(
data
.
message
!==
'Network Error'
)
{
this
.
$store
.
commit
(
'showMessage'
,
{
onError
({
data
})
{
if
(
data
.
message
!==
"Network Error"
)
{
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
data
.
message
,
type
:
'error'
})
type
:
"error"
,
})
;
}
},
onMessageReadByPeer
()
{
},
onReadyStateUpdate
({
name
})
{
const
isSDKReady
=
name
===
this
.
TIM
.
EVENT
.
SDK_READY
this
.
$store
.
commit
(
'toggleIsSDKReady'
,
isSDKReady
)
onMessageReadByPeer
()
{},
onReadyStateUpdate
({
name
})
{
const
isSDKReady
=
name
===
this
.
TIM
.
EVENT
.
SDK_READY
;
this
.
$store
.
commit
(
"toggleIsSDKReady"
,
isSDKReady
);
if
(
isSDKReady
)
{
this
.
tim
.
getMyProfile
()
.
then
(({
data
})
=>
this
.
$store
.
commit
(
'updateCurrentUserProfile'
,
data
))
.
catch
(
error
=>
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
}))
this
.
$store
.
dispatch
(
'getBlacklist'
)
this
.
tim
.
getMyProfile
()
.
then
(({
data
})
=>
this
.
$store
.
commit
(
"updateCurrentUserProfile"
,
data
)
)
.
catch
((
error
)
=>
this
.
$store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
error
.
message
,
})
);
this
.
$store
.
dispatch
(
"getBlacklist"
);
// Helper.contactList({type: 'admin'}).then(res => this.$store.commit('updateAdminList', res.data))
// Helper.contactList({
// type: 'scheme',
...
...
@@ -155,62 +175,65 @@ export default {
kickedOutReason
(
type
)
{
switch
(
type
)
{
case
this
.
TIM
.
TYPES
.
KICKED_OUT_MULT_ACCOUNT
:
return
'由于多实例登录'
return
"由于多实例登录"
;
case
this
.
TIM
.
TYPES
.
KICKED_OUT_MULT_DEVICE
:
return
'由于多设备登录'
return
"由于多设备登录"
;
case
this
.
TIM
.
TYPES
.
KICKED_OUT_USERSIG_EXPIRED
:
return
'由于 userSig 过期'
return
"由于 userSig 过期"
;
default
:
return
''
return
""
;
}
},
checkoutNetState
(
state
)
{
switch
(
state
)
{
case
this
.
TIM
.
TYPES
.
NET_STATE_CONNECTED
:
return
{
message
:
'已接入网络'
,
type
:
'success'
}
return
{
message
:
"已接入网络"
,
type
:
"success"
};
case
this
.
TIM
.
TYPES
.
NET_STATE_CONNECTING
:
return
{
message
:
'当前网络不稳定'
,
type
:
'warning'
}
return
{
message
:
"当前网络不稳定"
,
type
:
"warning"
};
case
this
.
TIM
.
TYPES
.
NET_STATE_DISCONNECTED
:
return
{
message
:
'当前网络不可用'
,
type
:
'error'
}
return
{
message
:
"当前网络不可用"
,
type
:
"error"
};
default
:
return
''
return
""
;
}
},
onNetStateChange
(
event
)
{
this
.
$store
.
commit
(
'showMessage'
,
this
.
checkoutNetState
(
event
.
data
.
state
))
this
.
$store
.
commit
(
"showMessage"
,
this
.
checkoutNetState
(
event
.
data
.
state
)
);
},
onKickOut
(
event
)
{
this
.
$store
.
commit
(
'showMessage'
,
{
this
.
$store
.
commit
(
"showMessage"
,
{
message
:
`
${
this
.
kickedOutReason
(
event
.
data
.
type
)}
被踢出,请重新登录。`
,
type
:
'error'
})
this
.
$store
.
commit
(
'toggleIsLogin'
,
false
)
this
.
$store
.
commit
(
'reset'
)
type
:
"error"
,
})
;
this
.
$store
.
commit
(
"toggleIsLogin"
,
false
);
this
.
$store
.
commit
(
"reset"
);
},
onUpdateConversationList
(
event
)
{
this
.
$store
.
commit
(
'updateConversationList'
,
event
.
data
)
this
.
$store
.
commit
(
"updateConversationList"
,
event
.
data
);
},
// onUpdateGroupList(event) {
// this.$store.commit('updateGroupList', event.data)
// },
onReceiveGroupSystemNotice
(
event
)
{
const
isKickedout
=
event
.
data
.
type
===
4
const
isKickedout
=
event
.
data
.
type
===
4
;
const
isCurrentConversation
=
`GROUP
${
event
.
data
.
message
.
payload
.
groupProfile
.
groupID
}
`
===
this
.
currentConversation
.
conversationID
this
.
currentConversation
.
conversationID
;
// 在当前会话被踢,需reset当前会话
if
(
isKickedout
&&
isCurrentConversation
)
{
this
.
$store
.
commit
(
'resetCurrentConversation'
)
this
.
$store
.
commit
(
"resetCurrentConversation"
);
}
Notification
({
title
:
'新系统通知'
,
title
:
"新系统通知"
,
message
:
translateGroupSystemNotice
(
event
.
data
.
message
),
duration
:
3000
,
onClick
:
()
=>
{
const
SystemConversationID
=
'@TIM#SYSTEM'
this
.
$store
.
dispatch
(
'checkoutConversation'
,
SystemConversationID
)
}
})
const
SystemConversationID
=
"@TIM#SYSTEM"
;
this
.
$store
.
dispatch
(
"checkoutConversation"
,
SystemConversationID
);
}
,
})
;
},
/**
* 处理 @ 我的消息
...
...
@@ -219,83 +242,85 @@ export default {
handleAt
(
messageList
)
{
// 筛选有 @ 符号的文本消息
const
atTextMessageList
=
messageList
.
filter
(
message
=>
(
message
)
=>
message
.
type
===
this
.
TIM
.
TYPES
.
MSG_TEXT
&&
message
.
payload
.
text
.
includes
(
'@'
)
)
message
.
payload
.
text
.
includes
(
"@"
)
)
;
for
(
let
i
=
0
;
i
<
atTextMessageList
.
length
;
i
++
)
{
const
message
=
atTextMessageList
[
i
]
const
matched
=
message
.
payload
.
text
.
match
(
/@
\w
+/g
)
const
message
=
atTextMessageList
[
i
]
;
const
matched
=
message
.
payload
.
text
.
match
(
/@
\w
+/g
)
;
if
(
!
matched
)
{
continue
continue
;
}
// @ 我的
if
(
matched
.
includes
(
`@
${
this
.
currentUserProfile
.
userID
}
`
))
{
// 当前页面不可见时,调用window.Notification接口,系统级别通知。
if
(
this
.
$store
.
getters
.
hidden
)
{
this
.
notifyMe
(
message
)
this
.
notifyMe
(
message
)
;
}
Notification
({
title
:
`有人在群
${
message
.
conversationID
.
slice
(
5
)}
提到了你`
,
message
:
message
.
payload
.
text
,
duration
:
3000
})
this
.
$bus
.
$emit
(
'new-messsage-at-me'
,
{
data
:
{
conversationID
:
message
.
conversationID
}
})
duration
:
3000
,
})
;
this
.
$bus
.
$emit
(
"new-messsage-at-me"
,
{
data
:
{
conversationID
:
message
.
conversationID
},
})
;
}
}
},
selectConversation
(
conversationID
)
{
if
(
conversationID
!==
this
.
currentConversation
.
conversationID
)
{
this
.
$store
.
dispatch
(
'checkoutConversation'
,
conversationID
)
this
.
$store
.
dispatch
(
"checkoutConversation"
,
conversationID
);
}
},
isJsonStr
(
str
)
{
try
{
JSON
.
parse
(
str
)
return
true
JSON
.
parse
(
str
)
;
return
true
;
}
catch
{
return
false
return
false
;
}
},
handleVideoMessage
(
messageList
)
{
const
videoMessageList
=
messageList
.
filter
(
message
=>
message
.
type
===
this
.
TIM
.
TYPES
.
MSG_CUSTOM
&&
this
.
isJsonStr
(
message
.
payload
.
data
)
)
if
(
videoMessageList
.
length
===
0
)
return
const
videoPayload
=
JSON
.
parse
(
videoMessageList
[
0
].
payload
.
data
)
(
message
)
=>
message
.
type
===
this
.
TIM
.
TYPES
.
MSG_CUSTOM
&&
this
.
isJsonStr
(
message
.
payload
.
data
)
);
if
(
videoMessageList
.
length
===
0
)
return
;
const
videoPayload
=
JSON
.
parse
(
videoMessageList
[
0
].
payload
.
data
);
if
(
videoPayload
.
action
===
ACTION
.
VIDEO_CALL_ACTION_DIALING
)
{
if
(
this
.
isBusy
)
{
this
.
$bus
.
$emit
(
'busy'
,
videoPayload
,
videoMessageList
[
0
])
return
this
.
$bus
.
$emit
(
"busy"
,
videoPayload
,
videoMessageList
[
0
]);
return
;
}
this
.
$store
.
commit
(
'GENERATE_VIDEO_ROOM'
,
videoPayload
.
room_id
)
this
.
selectConversation
(
videoMessageList
[
0
].
conversationID
)
// 切换当前会话页
this
.
$store
.
commit
(
"GENERATE_VIDEO_ROOM"
,
videoPayload
.
room_id
);
this
.
selectConversation
(
videoMessageList
[
0
].
conversationID
)
;
// 切换当前会话页
if
(
videoMessageList
[
0
].
from
!==
this
.
userID
)
{
this
.
$bus
.
$emit
(
'isCalled'
)
this
.
$bus
.
$emit
(
"isCalled"
);
}
}
if
(
videoPayload
.
action
===
ACTION
.
VIDEO_CALL_ACTION_SPONSOR_CANCEL
)
{
this
.
$bus
.
$emit
(
'missCall'
)
this
.
$bus
.
$emit
(
"missCall"
);
}
if
(
videoPayload
.
action
===
ACTION
.
VIDEO_CALL_ACTION_REJECT
)
{
this
.
$bus
.
$emit
(
'isRefused'
)
this
.
$bus
.
$emit
(
"isRefused"
);
}
if
(
videoPayload
.
action
===
ACTION
.
VIDEO_CALL_ACTION_SPONSOR_TIMEOUT
)
{
this
.
$bus
.
$emit
(
'missCall'
)
this
.
$bus
.
$emit
(
"missCall"
);
}
if
(
videoPayload
.
action
===
ACTION
.
VIDEO_CALL_ACTION_ACCEPTED
)
{
this
.
$bus
.
$emit
(
'isAccept'
)
this
.
$bus
.
$emit
(
"isAccept"
);
}
if
(
videoPayload
.
action
===
ACTION
.
VIDEO_CALL_ACTION_HANGUP
)
{
this
.
$bus
.
$emit
(
'isHungUp'
)
this
.
$bus
.
$emit
(
"isHungUp"
);
}
if
(
videoPayload
.
action
===
ACTION
.
VIDEO_CALL_ACTION_LINE_BUSY
)
{
this
.
$bus
.
$emit
(
'isRefused'
)
this
.
$bus
.
$emit
(
"isRefused"
);
}
if
(
videoPayload
.
action
===
ACTION
.
VIDEO_CALL_ACTION_ERROR
)
{
this
.
$bus
.
$emit
(
'isRefused'
)
this
.
$bus
.
$emit
(
"isRefused"
);
}
},
/**
...
...
@@ -304,32 +329,32 @@ export default {
*/
notifyMe
(
message
)
{
// 需检测浏览器支持和用户授权
if
(
!
(
'Notification'
in
window
))
{
return
}
else
if
(
window
.
Notification
.
permission
===
'granted'
)
{
this
.
handleNotify
(
message
)
}
else
if
(
window
.
Notification
.
permission
!==
'denied'
)
{
window
.
Notification
.
requestPermission
().
then
(
permission
=>
{
if
(
!
(
"Notification"
in
window
))
{
return
;
}
else
if
(
window
.
Notification
.
permission
===
"granted"
)
{
this
.
handleNotify
(
message
)
;
}
else
if
(
window
.
Notification
.
permission
!==
"denied"
)
{
window
.
Notification
.
requestPermission
().
then
(
(
permission
)
=>
{
// 如果用户同意,就可以向他们发送通知
if
(
permission
===
'granted'
)
{
this
.
handleNotify
(
message
)
if
(
permission
===
"granted"
)
{
this
.
handleNotify
(
message
)
;
}
})
})
;
}
},
handleNotify
(
message
)
{
const
notification
=
new
window
.
Notification
(
'有人提到了你'
,
{
icon
:
'https://webim-1252463788.file.myqcloud.com/demo/img/logo.dc3be0d4.png'
,
body
:
message
.
payload
.
text
})
const
notification
=
new
window
.
Notification
(
"有人提到了你"
,
{
icon
:
"https://webim-1252463788.file.myqcloud.com/demo/img/logo.dc3be0d4.png"
,
body
:
message
.
payload
.
text
,
})
;
notification
.
onclick
=
()
=>
{
window
.
focus
()
this
.
$store
.
dispatch
(
'checkoutConversation'
,
message
.
conversationID
)
notification
.
close
()
}
window
.
focus
()
;
this
.
$store
.
dispatch
(
"checkoutConversation"
,
message
.
conversationID
);
notification
.
close
()
;
}
;
},
handleLinkClick
()
{
MTA
.
clickStat
(
'link_two'
,
{
click
:
'true'
})
MTA
.
clickStat
(
"link_two"
,
{
click
:
"true"
});
},
/**
* 收到有群成员退群/被踢出的groupTip时,需要将相关群成员从当前会话的群成员列表中移除
...
...
@@ -337,19 +362,28 @@ export default {
*/
handleQuitGroupTip
(
messageList
)
{
// 筛选出当前会话的退群/被踢群的 groupTip
const
groupTips
=
messageList
.
filter
(
message
=>
{
return
this
.
currentConversation
.
conversationID
===
message
.
conversationID
&&
const
groupTips
=
messageList
.
filter
((
message
)
=>
{
return
(
this
.
currentConversation
.
conversationID
===
message
.
conversationID
&&
message
.
type
===
this
.
TIM
.
TYPES
.
MSG_GRP_TIP
&&
(
message
.
payload
.
operationType
===
this
.
TIM
.
TYPES
.
GRP_TIP_MBR_QUIT
||
message
.
payload
.
operationType
===
this
.
TIM
.
TYPES
.
GRP_TIP_MBR_KICKED_OUT
)
})
message
.
payload
.
operationType
===
this
.
TIM
.
TYPES
.
GRP_TIP_MBR_KICKED_OUT
)
);
});
// 清理当前会话的群成员列表
if
(
groupTips
.
length
>
0
)
{
groupTips
.
forEach
(
groupTip
=>
{
if
(
Array
.
isArray
(
groupTip
.
payload
.
userIDList
)
||
groupTip
.
payload
.
userIDList
.
length
>
0
)
{
this
.
$store
.
commit
(
'deleteGroupMemberList'
,
groupTip
.
payload
.
userIDList
)
}
})
groupTips
.
forEach
((
groupTip
)
=>
{
if
(
Array
.
isArray
(
groupTip
.
payload
.
userIDList
)
||
groupTip
.
payload
.
userIDList
.
length
>
0
)
{
this
.
$store
.
commit
(
"deleteGroupMemberList"
,
groupTip
.
payload
.
userIDList
);
}
});
}
},
/**
...
...
@@ -357,22 +391,25 @@ export default {
* @param {Message[]} messageList
*/
handleCloseGroupLive
(
messageList
)
{
messageList
.
forEach
(
message
=>
{
if
(
this
.
currentConversation
.
conversationID
===
message
.
conversationID
&&
message
.
type
===
this
.
TIM
.
TYPES
.
MSG_CUSTOM
)
{
let
data
=
{}
messageList
.
forEach
((
message
)
=>
{
if
(
this
.
currentConversation
.
conversationID
===
message
.
conversationID
&&
message
.
type
===
this
.
TIM
.
TYPES
.
MSG_CUSTOM
)
{
let
data
=
{};
try
{
data
=
JSON
.
parse
(
message
.
payload
.
data
)
data
=
JSON
.
parse
(
message
.
payload
.
data
)
;
}
catch
(
e
)
{
data
=
{}
data
=
{}
;
}
if
(
data
.
roomId
&&
Number
(
data
.
roomStatus
)
===
0
)
{
this
.
$bus
.
$emit
(
'close-group-live'
)
this
.
$bus
.
$emit
(
"close-group-live"
);
}
}
})
})
;
},
}
}
}
,
}
;
</
script
>
<
style
lang=
"stylus"
>
...
...
src/utils/helper.js
View file @
6425bbc
import
request
from
'./request'
import
request
from
"./request"
;
export
default
class
Helper
{
static
getKey
()
{
return
parseInt
(
process
.
env
.
VUE_APP_API_KEY
)
return
parseInt
(
process
.
env
.
VUE_APP_API_KEY
);
}
static
getSecret
()
{
return
process
.
env
.
VUE_APP_API_SECRET
return
process
.
env
.
VUE_APP_API_SECRET
;
}
static
getExpire
()
{
return
parseInt
(
process
.
env
.
VUE_APP_API_EXPIRETIME
)
return
parseInt
(
process
.
env
.
VUE_APP_API_EXPIRETIME
);
}
static
getUrlKey
(
name
)
{
return
decodeURIComponent
((
new
RegExp
(
'[?|&]'
+
name
+
'='
+
'([^&;]+?)(&|#|;|$)'
).
exec
(
location
.
href
)
||
[,
''
])[
1
].
replace
(
/
\+
/g
,
'%20'
))
||
null
return
(
decodeURIComponent
(
(
new
RegExp
(
"[?|&]"
+
name
+
"="
+
"([^&;]+?)(&|#|;|$)"
).
exec
(
location
.
href
)
||
[,
""
])[
1
].
replace
(
/
\+
/g
,
"%20"
)
)
||
null
);
}
static
getToken
()
{
return
this
.
getUrlKey
(
'token'
)
return
this
.
getUrlKey
(
"token"
);
}
static
getSignature
(
userID
)
{
const
generator
=
new
window
.
LibGenerateTestUserSig
(
this
.
getKey
(),
this
.
getSecret
(),
this
.
getExpire
())
return
generator
.
genTestUserSig
(
userID
)
const
generator
=
new
window
.
LibGenerateTestUserSig
(
this
.
getKey
(),
this
.
getSecret
(),
this
.
getExpire
()
);
return
generator
.
genTestUserSig
(
userID
);
}
/**
...
...
@@ -33,29 +41,29 @@ export default class Helper {
* @returns {Promise<never>|Promise<{sign, id}>}
*/
static
verifyToken
()
{
return
request
.
get
(
'auth'
).
then
(
res
=>
{
const
{
esm_id
}
=
res
.
data
return
Promise
.
resolve
({
id
:
esm_id
,
sign
:
this
.
getSignature
(
esm_id
)})
})
return
request
.
get
(
"auth"
).
then
((
res
)
=>
{
const
{
esm_id
}
=
res
.
data
;
return
Promise
.
resolve
({
id
:
esm_id
,
sign
:
this
.
getSignature
(
esm_id
)
});
});
}
static
contactList
(
params
=
{})
{
return
request
.
get
(
'im/contacts'
,
{
params
})
return
request
.
get
(
"im/contacts"
,
{
params
});
}
static
groupList
(
params
=
{})
{
return
request
.
get
(
'im/groups'
,
{
params
})
return
request
.
get
(
"im/groups"
,
{
params
});
}
static
groupMemberList
(
group
,
params
=
{})
{
return
request
.
get
(
`im/groups/
${
group
}
/members`
,
{
params
})
return
request
.
get
(
`im/groups/
${
group
}
/members`
,
{
params
});
}
static
groupMemberDelete
(
group
,
member
)
{
return
request
.
delete
(
`im/groups/
${
group
}
/members/
${
member
}
`
)
return
request
.
delete
(
`im/groups/
${
group
}
/members/
${
member
}
`
);
}
static
joinGroup
(
id
,
member
)
{
return
request
.
post
(
`im/groups/
${
id
}
/members`
,
{
member
})
return
request
.
post
(
`im/groups/
${
id
}
/members`
,
{
member
});
}
}
...
...
src/utils/hrequest.js
0 → 100644
View file @
6425bbc
import
axios
from
"axios"
;
const
hservice
=
axios
.
create
({
baseURL
:
process
.
env
.
VUE_APP_API_UNI_URL
,
// withCredentials: true, // send cookies when cross-domain requests
timeout
:
5000
,
// request timeout
});
export
default
hservice
;
src/utils/request.js
View file @
6425bbc
import
axios
from
'axios'
import
Helper
from
'./helper'
import
Store
from
'../store'
import
tim
from
'../tim'
import
axios
from
"axios"
;
import
Helper
from
"./helper"
;
import
Store
from
"../store"
;
import
tim
from
"../tim"
;
const
service
=
axios
.
create
({
baseURL
:
process
.
env
.
VUE_APP_API_URL
,
// withCredentials: true, // send cookies when cross-domain requests
timeout
:
5000
// request timeout
})
timeout
:
5000
,
// request timeout
})
;
service
.
interceptors
.
request
.
use
(
config
=>
{
config
.
headers
[
'Authorization'
]
=
'Bearer '
+
Helper
.
getToken
()
config
.
headers
[
'Accept'
]
=
'application/json'
return
config
},
error
=>
{
return
Promise
.
reject
(
error
)
})
service
.
interceptors
.
request
.
use
(
(
config
)
=>
{
config
.
headers
[
"Authorization"
]
=
"Bearer "
+
Helper
.
getToken
();
config
.
headers
[
"Accept"
]
=
"application/json"
;
return
config
;
},
(
error
)
=>
{
return
Promise
.
reject
(
error
);
}
);
service
.
interceptors
.
response
.
use
(
response
=>
{
service
.
interceptors
.
response
.
use
(
(
response
)
=>
{
switch
(
response
.
data
.
code
)
{
case
200
:
return
response
.
data
return
response
.
data
;
case
401
:
Store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
'身份信息已失效,请重新登录'
})
Store
.
commit
(
"showMessage"
,
{
type
:
"error"
,
message
:
"身份信息已失效,请重新登录"
,
});
tim
.
logout
().
then
(()
=>
{
Store
.
commit
(
'user/toggleIsLogin'
)
Store
.
commit
(
'user/stopComputeCurrent'
)
Store
.
commit
(
'user/reset'
)
})
break
Store
.
commit
(
"user/toggleIsLogin"
);
Store
.
commit
(
"user/stopComputeCurrent"
);
Store
.
commit
(
"user/reset"
);
});
break
;
default
:
return
Promise
.
reject
(
response
.
data
)
return
Promise
.
reject
(
response
.
data
);
}
},
(
error
)
=>
{
return
Promise
.
reject
(
error
);
}
},
error
=>
{
return
Promise
.
reject
(
error
)
})
);
export
default
service
export
default
service
;
...
...
Please
register
or
sign in
to post a comment