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
ef808ca3
...
ef808ca31dd105637fd549812f6ac2f6fd74822c
authored
2021-05-17 19:18:24 +0800
by
yangjun@hikoon.cn
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
更新
1 parent
2c6e46e5
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
602 additions
and
530 deletions
package.json
public/debug/GenerateTestUserSig.js
src/components/conversation/conversation-item.vue
src/components/conversation/conversationProfile/add-group-member.vue
src/components/conversation/conversationProfile/group-member-info.vue
src/components/conversation/conversationProfile/group-member-list.vue
src/components/conversation/conversationProfile/group-profile.vue
src/components/friend/friend-list.vue
src/components/group/group-item.vue
src/components/message/message-elements/custom-element.vue
src/components/message/message-elements/image-element.vue
src/components/message/message-elements/video-element.vue
src/components/message/message-item.vue
src/components/user/login.vue
src/index.vue
src/store/modules/conversation.js
src/store/modules/friend.js
src/store/modules/group.js
src/store/modules/user.js
src/tim.js
src/trtc-calling.js
src/utils/helper.js
src/utils/request.js
vue.config.js
yarn.lock
package.json
View file @
ef808ca
...
...
@@ -9,10 +9,12 @@
"lint"
:
"node node_modules/@vue/cli-service/bin/vue-cli-service.js lint src --ext .vue,.js --fix"
},
"dependencies"
:
{
"add"
:
"^2.0.6"
,
"axios"
:
"^0.21.0"
,
"core-js"
:
"^2.6.11"
,
"cos-js-sdk-v5"
:
"^0.5.22"
,
"element-ui"
:
"^2.13.0"
,
"loadsh"
:
"^0.0.4"
,
"md5"
:
"^2.3.0"
,
"mta-h5-analysis"
:
"^2.0.15"
,
"tim-js-sdk"
:
"^2.10.2"
,
...
...
@@ -23,7 +25,8 @@
"vue"
:
"^2.6.11"
,
"vue-clipboard2"
:
"^0.3.1"
,
"vue-infinite-scroll"
:
"^2.0.2"
,
"vuex"
:
"^3.1.2"
"vuex"
:
"^3.1.2"
,
"yarn"
:
"^1.22.10"
},
"devDependencies"
:
{
"@vue/cli-plugin-babel"
:
"^3.12.1"
,
...
...
public/debug/GenerateTestUserSig.js
View file @
ef808ca
/*eslint-disable*/
/*
* Module: GenerateTestUserSig
*
...
...
@@ -17,38 +18,38 @@
* Reference:https://cloud.tencent.com/document/product/647/17275#Server
*/
function
genTestUserSig
(
userID
)
{
/**
* 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。
*
* 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ) 创建应用,即可看到 SDKAppId,
* 它是腾讯云用于区分客户的唯一标识。
*/
var
SDKAPPID
=
1400514950
;
/**
* 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。
*
* 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ) 创建应用,即可看到 SDKAppId,
* 它是腾讯云用于区分客户的唯一标识。
*/
var
SDKAPPID
=
0
/**
* 签名过期时间,建议不要设置的过短
* <p>
* 时间单位:秒
* 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天
*/
var
EXPIRETIME
=
604800
;
/**
* 签名过期时间,建议不要设置的过短
* <p>
* 时间单位:秒
* 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天
*/
var
EXPIRETIME
=
604800
/**
* 计算签名用的加密密钥,获取步骤如下:
*
* step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ),如果还没有应用就创建一个,
* step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。
* step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中
*
* 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。
* 文档:https://cloud.tencent.com/document/product/647/17275#Server
*/
var
SECRETKEY
=
'eb219c4b42bdbbf5dca38f21f5be26ab38f1c157d0ba4277d5acce6507f2d727'
;
/**
* 计算签名用的加密密钥,获取步骤如下:
*
* step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ),如果还没有应用就创建一个,
* step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。
* step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中
*
* 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。
* 文档:https://cloud.tencent.com/document/product/647/17275#Server
*/
var
SECRETKEY
=
''
var
generator
=
new
window
.
LibGenerateTestUserSig
(
SDKAPPID
,
SECRETKEY
,
EXPIRETIME
);
var
userSig
=
generator
.
genTestUserSig
(
userID
);
return
{
SDKAppID
:
SDKAPPID
,
userSig
:
userSig
};
}
\ No newline at end of file
var
generator
=
new
window
.
LibGenerateTestUserSig
(
SDKAPPID
,
SECRETKEY
,
EXPIRETIME
)
var
userSig
=
generator
.
genTestUserSig
(
userID
)
return
{
SDKAppID
:
SDKAPPID
,
userSig
:
userSig
}
}
...
...
src/components/conversation/conversation-item.vue
View file @
ef808ca
...
...
@@ -37,11 +37,7 @@
<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=
"图片"
v-if=
"conversation.lastMessage.type === 'TIMCustomElem' && conversation.lastMessage.payload.data === 'image'"
>
[图片]
</span>
<span
v-else
class=
"text"
:title=
"conversation.lastMessage.messageForShow"
>
<span
class=
"text"
:title=
"conversation.lastMessage.messageForShow"
>
{{
messageForShow
}}
</span>
</div>
...
...
@@ -58,6 +54,7 @@
<
script
>
import
{
mapGetters
,
mapState
}
from
'vuex'
import
_
from
'loadsh'
import
{
getDate
,
getTime
,
isToday
}
from
'../../utils/date'
export
default
{
...
...
@@ -134,8 +131,16 @@ export default {
return
'对方撤回了一条消息'
}
return
`
${
this
.
conversation
.
lastMessage
.
fromAccount
}
撤回了一条消息`
}
else
{
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
,
...
...
src/components/conversation/conversationProfile/add-group-member.vue
View file @
ef808ca
...
...
@@ -22,14 +22,21 @@ import {mapState} from 'vuex'
import
Helper
from
'../../../utils/helper'
export
default
{
props
:
{
group
:
{
type
:
String
,
required
:
true
}
},
computed
:
{
...
mapState
({
users
:
state
=>
state
.
friend
.
userList
,
currentConversation
:
state
=>
state
.
conversation
.
currentConversation
,
currentMemberList
:
state
=>
state
.
group
.
currentMemberList
currentMemberList
:
state
=>
state
.
group
.
currentMemberList
,
currentUnMemberList
:
state
=>
state
.
group
.
currentUnMemberList
}),
currentUnMemberList
()
{
return
this
.
users
.
filter
(
item
=>
this
.
currentMemberList
.
filter
(
data
=>
data
.
userID
===
item
.
esm_id
).
length
===
0
)
},
data
()
{
return
{
list
:
[]
}
},
methods
:
{
...
...
@@ -67,6 +74,9 @@ export default {
// this.$store.commit('showMessage', {type: 'error', message: error.message})
// })
}
},
mounted
()
{
console
.
log
(
12312321
)
}
}
</
script
>
...
...
src/components/conversation/conversationProfile/group-member-info.vue
View file @
ef808ca
...
...
@@ -6,9 +6,9 @@
<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"
v-model=
"muteTime"
placeholder=
"请输入禁言时间"
@
keydown
.
enter
.
native=
"setGroupMemberMuteTime"
/>
<el-button
slot=
"reference"
type=
"text"
style=
"color:red;"
>
禁言
</el-button>
</el-popover>
...
...
@@ -22,15 +22,15 @@
{{
member
.
nameCard
||
'暂无'
}}
<el-popover
title=
"修改群名片"
v-model=
"nameCardPopoverVisible"
v-show=
"showEditNameCard"
>
<el-input
v-model=
"nameCard"
placeholder=
"请输入群名片"
@
keydown
.
enter
.
native=
"setGroupMemberNameCard"
v-model=
"nameCard"
placeholder=
"请输入群名片"
@
keydown
.
enter
.
native=
"setGroupMemberNameCard"
/>
<i
class=
"el-icon-edit"
title=
"修改群名片"
slot=
"reference"
style=
"cursor:pointer; font-size:1.6rem;"
class=
"el-icon-edit"
title=
"修改群名片"
slot=
"reference"
style=
"cursor:pointer; font-size:1.6rem;"
></i>
</el-popover>
</div>
...
...
@@ -44,7 +44,7 @@
</div>
<el-button
type=
"text"
v-if=
"canChangeRole"
@
click=
"changeMemberRole"
>
{{
member
.
role
===
'Admin'
?
'取消管理员'
:
'设为管理员'
member
.
role
===
'Admin'
?
'取消管理员'
:
'设为管理员'
}}
</el-button>
<el-button
type=
"text"
v-if=
"showKickout"
style=
"color:red;"
@
click=
"kickoutGroupMember"
>
踢出群组
</el-button>
...
...
@@ -52,9 +52,10 @@
</
template
>
<
script
>
import
{
mapState
}
from
'vuex'
import
{
Popover
}
from
'element-ui'
import
{
getFullDate
}
from
'../../../utils/date'
import
{
mapState
}
from
'vuex'
import
{
Popover
}
from
'element-ui'
import
{
getFullDate
}
from
'../../../utils/date'
export
default
{
components
:
{
ElPopover
:
Popover
...
...
@@ -89,8 +90,8 @@ export default {
},
canChangeRole
()
{
return
(
this
.
isOwner
&&
[
'ChatRoom'
,
'Public'
].
includes
(
this
.
currentConversation
.
subType
)
this
.
isOwner
&&
[
'ChatRoom'
,
'Public'
].
includes
(
this
.
currentConversation
.
subType
)
)
},
changeRoleTitle
()
{
...
...
@@ -98,8 +99,8 @@ export default {
return
''
}
return
this
.
isOwner
&&
this
.
member
.
role
===
'Admin'
?
'设为:Member'
:
'设为:Admin'
?
'设为:Member'
:
'设为:Admin'
},
// 是否显示禁言时间
showMuteUntil
()
{
...
...
@@ -109,9 +110,9 @@ export default {
// 是否显示取消禁言按钮
showCancelBan
()
{
if
(
this
.
showMuteUntil
&&
this
.
currentConversation
.
type
===
this
.
TIM
.
TYPES
.
CONV_GROUP
&&
!
this
.
isMine
this
.
showMuteUntil
&&
this
.
currentConversation
.
type
===
this
.
TIM
.
TYPES
.
CONV_GROUP
&&
!
this
.
isMine
)
{
return
this
.
isOwner
||
this
.
isAdmin
}
...
...
@@ -136,20 +137,20 @@ export default {
methods
:
{
kickoutGroupMember
()
{
this
.
tim
.
deleteGroupMember
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
reason
:
'我要踢你出群'
,
userIDList
:
[
this
.
member
.
userID
]
})
.
then
(()
=>
{
this
.
$store
.
commit
(
'deleteGroupMemeber'
,
this
.
member
.
userID
)
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
.
deleteGroupMember
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
reason
:
'我要踢你出群'
,
userIDList
:
[
this
.
member
.
userID
]
})
.
then
(()
=>
{
this
.
$store
.
commit
(
'deleteGroupMember'
,
this
.
member
.
userID
)
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
})
})
},
changeMemberRole
()
{
if
(
!
this
.
canChangeRole
)
{
...
...
@@ -157,53 +158,53 @@ export default {
}
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
.
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
})
})
})
},
setGroupMemberMuteTime
()
{
this
.
tim
.
setGroupMemberMuteTime
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
userID
:
this
.
member
.
userID
,
muteTime
:
Number
(
this
.
muteTime
)
})
.
then
(()
=>
{
this
.
muteTime
=
''
this
.
popoverVisible
=
false
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
.
setGroupMemberMuteTime
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
userID
:
this
.
member
.
userID
,
muteTime
:
Number
(
this
.
muteTime
)
})
.
then
(()
=>
{
this
.
muteTime
=
''
this
.
popoverVisible
=
false
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
})
})
},
// 取消禁言
cancelMute
()
{
this
.
tim
.
setGroupMemberMuteTime
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
userID
:
this
.
member
.
userID
,
muteTime
:
0
})
.
then
(()
=>
{
this
.
muteTime
=
''
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
.
setGroupMemberMuteTime
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
userID
:
this
.
member
.
userID
,
muteTime
:
0
})
.
then
(()
=>
{
this
.
muteTime
=
''
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
})
})
},
setGroupMemberNameCard
()
{
if
(
this
.
nameCard
.
trim
().
length
===
0
)
{
...
...
@@ -214,23 +215,23 @@ export default {
return
}
this
.
tim
.
setGroupMemberNameCard
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
userID
:
this
.
member
.
userID
,
nameCard
:
this
.
nameCard
})
.
then
(()
=>
{
this
.
nameCardPopoverVisible
=
false
this
.
$store
.
commit
(
'showMessage'
,
{
message
:
'修改成功'
.
setGroupMemberNameCard
({
groupID
:
this
.
currentConversation
.
groupProfile
.
groupID
,
userID
:
this
.
member
.
userID
,
nameCard
:
this
.
nameCard
})
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
.
then
(()
=>
{
this
.
nameCardPopoverVisible
=
false
this
.
$store
.
commit
(
'showMessage'
,
{
message
:
'修改成功'
})
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
})
})
}
}
}
...
...
src/components/conversation/conversationProfile/group-member-list.vue
View file @
ef808ca
...
...
@@ -3,7 +3,7 @@
<div
class=
"header"
>
<span
class=
"member-count text-ellipsis"
>
群成员:
{{
currentConversation
.
groupProfile
.
memberCount
}}
</span>
<popover
v-model=
"addGroupMemberVisible"
>
<add-group-member
style=
"width: 200px;max-height: 70vh;overflow: auto"
></add-group-member
>
<add-group-member
class=
"add-member-list"
:group=
"currentConversation.groupProfile.groupID"
/
>
<div
slot=
"reference"
class=
"btn-add-member"
title=
"添加群成员"
>
<span
class=
"tim-icon-friend-add"
></span>
</div>
...
...
@@ -42,6 +42,7 @@ export default {
data
()
{
return
{
addGroupMemberVisible
:
false
,
addGroupMemberList
:
[],
currentMemberID
:
''
,
count
:
30
// 显示的群成员数量
}
...
...
@@ -76,12 +77,11 @@ export default {
}
},
loadMore
()
{
this
.
$store
.
dispatch
(
'getGroupMemberList'
,
this
.
groupProfile
.
groupID
)
this
.
$store
.
dispatch
(
'getGroupMemberList'
,
this
.
groupProfile
.
groupID
)
.
then
(()
=>
{
this
.
count
+=
30
})
}
}
,
}
}
</
script
>
...
...
@@ -93,6 +93,11 @@ export default {
padding
10px
16px
10px
20px
border-bottom
1px
solid
$
border-base
>>>
.add-member-list
width
:
200px
;
max-height
:
70vh
;
overflow
:
auto
.member-count
display
inline-block
max-width
130px
...
...
src/components/conversation/conversationProfile/group-profile.vue
View file @
ef808ca
...
...
@@ -203,15 +203,15 @@
@
keydown
.
enter
.
native=
"editNameCard"
/>
</div>
<div
class=
"info-item"
>
<div
class=
"label"
:class=
"
{'active' : active}">全体禁言
</div
>
<el-switch
v-model=
"muteAllMembers"
active-color=
"#409eff"
inactive-color=
"#dcdfe6"
@
change=
'changeMuteStatus'
>
</el-switch
>
</div
>
<!--
<div
class=
"info-item"
>
--
>
<!--
<div
class=
"label"
:class=
"
{'active' : active}">全体禁言
</div>
--
>
<!--
<el-switch-->
<!-- v-model="muteAllMembers"-->
<!-- active-color="#409eff"-->
<!-- inactive-color="#dcdfe6"-->
<!-- @change='changeMuteStatus'>--
>
<!--
</el-switch>
--
>
<!--
</div>
--
>
<div
v-if=
"isOwner"
>
<el-button
type=
"text"
@
click=
"showChangeGroupOwner = true"
>
转让群组
</el-button>
<el-input
...
...
src/components/friend/friend-list.vue
View file @
ef808ca
...
...
@@ -28,7 +28,6 @@ export default {
},
computed
:
{
...
mapState
({
friendList
:
state
=>
state
.
friend
.
friendList
,
adminList
(
state
)
{
const
list
=
state
.
friend
.
adminList
||
[]
return
this
.
select
.
length
===
0
?
list
:
list
.
filter
(
item
=>
item
.
name
.
indexOf
(
this
.
select
)
>
-
1
)
...
...
src/components/group/group-item.vue
View file @
ef808ca
...
...
@@ -3,16 +3,20 @@
<div
class=
"group-item"
>
<avatar
src=
""
/>
<div
class=
"group-name text-ellipsis"
>
{{
group
.
title
}}
</div>
<el-tag
v-if=
"group.is_stated===1"
effect=
"dark"
type=
"danger"
size=
"mini"
>
已结算
</el-tag>
</div>
</div>
</
template
>
<
script
>
import
{
MessageBox
}
from
'element-ui'
import
{
MessageBox
,
Tag
}
from
'element-ui'
import
Helper
from
'../../utils/helper'
export
default
{
props
:
[
'group'
],
components
:
{
ElTag
:
Tag
},
data
()
{
return
{
visible
:
false
,
...
...
src/components/message/message-elements/custom-element.vue
View file @
ef808ca
<
template
>
<message-bubble
:isMine=
isMine
:message=
message
>
<div
class=
"custom-element-wrapper"
>
<div
class=
"survey"
v-if=
"this.payload.data === 'survey'"
>
<div
class=
"title"
>
对IM DEMO的评分和建议
</div>
<el-rate
v-model=
"rate"
disabled
show-score
text-color=
"#ff9900"
score-template=
"
{value}">
</el-rate>
<div
class=
"suggestion"
>
{{
this
.
payload
.
extension
}}
</div>
</div>
<span
class=
"text"
title=
"您可以自行解析自定义消息"
v-else
>
<template
v-if=
"text.isFromGroupLive && text.isFromGroupLive === 1"
>
<message-group-live-status
:liveInfo=
'text'
/>
</
template
>
<
template
v-else-if=
"this.payload.data === 'image'"
>
<el-image
:src=
"this.payload.description"
:preview-src-list=
"[this.payload.description]"
/>
<!--
<img
alt=
"image"
class=
"image-element"
:src=
"this.payload.description"
@
load=
"onImageLoaded"
--
>
<!-- @click="handlePreview"/>-->
</
template
>
<
template
v-else
>
{{
text
}}
</
template
>
</span>
</div>
</message-bubble>
<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"/>
<video-element
v-else-if=
"this.payload.data === 'video'"
:isMine=
"isMine"
:payload=
"Object.assign(message.payload,
{ videoUrl: message.payload.description })"
:message="message"
/>
<template
v-else
>
<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>
</div>
</template>
<
script
>
import
{
mapState
}
from
'vuex'
import
MessageBubble
from
'../message-bubble'
import
{
Rate
}
from
'element-ui'
import
MessageGroupLiveStatus
from
'../message-group-live-status'
import
ImageElement
from
'../message-elements/image-element.vue'
import
VideoElement
from
'./video-element'
export
default
{
name
:
'CustomElement'
,
...
...
@@ -50,8 +43,8 @@ export default {
}
},
components
:
{
VideoElement
,
MessageBubble
,
ElRate
:
Rate
,
MessageGroupLiveStatus
,
ImageElement
,
},
...
...
@@ -94,14 +87,6 @@ export default {
return
'[自定义消息]'
}
},
onImageLoaded
(
event
)
{
this
.
$bus
.
$emit
(
'image-loaded'
,
event
)
},
handlePreview
()
{
this
.
$bus
.
$emit
(
'image-preview'
,
{
url
:
this
.
payload
.
description
})
}
}
}
</
script
>
...
...
src/components/message/message-elements/image-element.vue
View file @
ef808ca
...
...
@@ -55,9 +55,7 @@ export default {
this
.
$bus
.
$emit
(
'image-loaded'
,
event
)
},
handlePreview
()
{
this
.
$bus
.
$emit
(
'image-preview'
,
{
url
:
this
.
payload
.
imageInfoArray
[
0
].
url
})
this
.
$bus
.
$emit
(
'image-preview'
,
{
url
:
this
.
payload
.
imageInfoArray
[
0
].
url
})
}
}
}
...
...
src/components/message/message-elements/video-element.vue
View file @
ef808ca
<
template
>
<message-bubble
:isMine=
isMine
:message=
message
>
<video
:src=
"payload.videoUrl"
controls
class=
"video"
@
error=
"videoError"
:src=
"payload.videoUrl"
controls
class=
"video"
@
error=
"videoError"
></video>
<el-progress
v-if=
"showProgressBar"
:percentage=
"percentage"
:color=
"percentage => (percentage === 100 ? '#67c23a' : '#409eff')"
v-if=
"showProgressBar"
:percentage=
"percentage"
:color=
"percentage => (percentage === 100 ? '#67c23a' : '#409eff')"
/>
</message-bubble>
</
template
>
<
script
>
import
MessageBubble
from
'../message-bubble'
import
{
Progress
}
from
'element-ui'
import
{
Progress
}
from
'element-ui'
export
default
{
name
:
'VideoElement'
,
components
:
{
...
...
@@ -47,7 +48,7 @@ export default {
},
methods
:
{
videoError
(
e
)
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
'视频出错,错误原因:'
+
e
.
target
.
error
.
message
})
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
'视频出错,错误原因:'
+
e
.
target
.
error
.
message
})
},
}
}
...
...
src/components/message/message-item.vue
View file @
ef808ca
...
...
@@ -90,7 +90,7 @@
<avatar
class=
"group-member-avatar"
:src=
"avatar"
@
click
.
native=
"showGroupMemberProfile"
/>
</div>
<div
class=
"col-2"
>
<!-- 消息主体 -->
<!-- 消息主体 -->
<message-header
v-if=
"showMessageHeader"
:message=
"message"
/>
<div
class=
"content-wrapper"
>
<message-status-icon
v-if=
"isMine"
:message=
"message"
/>
...
...
src/components/user/login.vue
View file @
ef808ca
<
template
>
<div
class=
"login-wrapper"
>
<img
class=
"logo"
:src=
"logo"
/>
<img
class=
"logo"
:src=
"logo"
/>
<el-form
ref=
"login"
:rules=
"rules"
:model=
"form"
label-width=
"0"
style=
"width:100%;"
@
keydown
.
enter
.
native=
"submit"
ref=
"login"
:rules=
"rules"
:model=
"form"
label-width=
"0"
style=
"width:100%;"
@
keydown
.
enter
.
native=
"submit"
>
<!-- Github登录方式 -->
<el-form-item
prop=
"userID"
>
<el-select
v-model=
"form.userID"
class=
"user-selector"
>
<el-option
v-for=
"index in 30"
:key=
"index"
:label=
"`user$
{index-1}`"
:value="`user${index-1}`"
v-for=
"index in 30"
:key=
"index"
:label=
"`user$
{index-1}`"
:value="`user${index-1}`"
>
</el-option>
</el-select>
</el-form-item>
...
...
@@ -35,19 +35,20 @@
</el-form-item>
-->
</el-form>
<el-button
type=
"primary"
@
click=
"submit"
style=
"width:100%; margin-top: 6px;"
:loading=
"loading"
>
登录
</el-button>
type=
"primary"
@
click=
"submit"
style=
"width:100%; margin-top: 6px;"
:loading=
"loading"
>
登录
</el-button>
</div>
</
template
>
<
script
>
import
{
Form
,
FormItem
,
Select
,
Option
}
from
'element-ui'
import
{
Form
,
FormItem
,
Option
,
Select
}
from
'element-ui'
import
logo
from
'../../assets/image/logo.png'
import
{
errorMap
}
from
'../../utils/common
'
import
md5
from
'md5'
import
Helper
from
'../../utils/helper
'
export
default
{
name
:
'Login'
,
components
:
{
...
...
@@ -72,10 +73,10 @@ export default {
},
rules
:
{
userID
:
[
{
required
:
true
,
message
:
'请输入 userID'
,
trigger
:
'blur'
},
{
validator
:
checkUserID
,
trigger
:
'blur'
}
{
required
:
true
,
message
:
'请输入 userID'
,
trigger
:
'blur'
},
{
validator
:
checkUserID
,
trigger
:
'blur'
}
],
password
:
[{
required
:
true
,
message
:
'请输入密码'
,
trigger
:
'blur'
}]
password
:
[{
required
:
true
,
message
:
'请输入密码'
,
trigger
:
'blur'
}]
},
logo
:
logo
,
registerVisible
:
false
,
...
...
@@ -93,33 +94,33 @@ export default {
login
()
{
this
.
loading
=
true
this
.
tim
.
login
({
userID
:
this
.
form
.
userID
,
userSig
:
window
.
genTestUserSig
(
this
.
form
.
userID
).
userSig
})
.
then
(()
=>
{
this
.
loading
=
false
this
.
$store
.
commit
(
'toggleIsLogin'
,
true
)
this
.
$store
.
commit
(
'startComputeCurrent'
)
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'success'
,
message
:
'登录成功'
})
this
.
$store
.
commit
({
type
:
'GET_USER_INFO'
,
.
login
({
userID
:
this
.
form
.
userID
,
userSig
:
window
.
genTestUserSig
(
this
.
form
.
userID
).
userSig
,
sdkAppID
:
window
.
genTestUserSig
(
''
).
SDKAppID
userSig
:
Helper
.
getSignature
(
this
.
form
.
userID
)
})
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'success'
,
message
:
'登录成功'
.
then
(()
=>
{
this
.
loading
=
false
this
.
$store
.
commit
(
'toggleIsLogin'
,
true
)
this
.
$store
.
commit
(
'startComputeCurrent'
)
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'success'
,
message
:
'登录成功'
})
this
.
$store
.
commit
({
type
:
'GET_USER_INFO'
,
userID
:
this
.
form
.
userID
,
userSig
:
Helper
.
getSignature
(
this
.
form
.
userID
),
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'
})
})
})
},
}
}
...
...
@@ -134,27 +135,34 @@ export default {
background
$
white
color
$
black
border-radius
5px
box-shadow
:
0
11px
20px
0
rgba
(
0
,
0
,
0
,
0
.3
)
box-shadow
:
0
11px
20px
0
rgba
(
0
,
0
,
0
,
0
.3
)
.row-div
display
flex
justify-content
center
align-items
center
flex-direction
row
.logo
width
110px
height
110px
.loginBox
width
320px
margin
0
0
20px
0
.send-code
width
112px
.login-im-btn
width
100
%
.loginFooter
color
:
#8c8a8ac7
text-align
:
center
padding
:
0
0
20px
0
cursor
:
pointer
.login-wrapper
{
display
:
flex
;
align-items
:
center
;
...
...
src/index.vue
View file @
ef808ca
...
...
@@ -71,14 +71,11 @@ export default {
this
.
loading
=
false
this
.
$store
.
commit
(
'toggleIsLogin'
,
true
)
this
.
$store
.
commit
(
'startComputeCurrent'
)
this
.
$store
.
commit
({
type
:
'GET_USER_INFO'
,
this
.
$store
.
commit
(
'GET_USER_INFO'
,
{
userID
:
user
.
id
,
userSig
:
user
.
sign
,
sdkAppID
:
window
.
genTestUserSig
(
''
).
SDKAppID
sdkAppID
:
process
.
env
.
VUE_APP_API_KEY
})
Helper
.
contactList
().
then
(
res
=>
this
.
$store
.
commit
(
'updateFriendList'
,
res
.
data
))
// Helper.groupList({size: 20}).then(res => this.$store.commit('updateGroupList', res.data))
// this.$store.commit('showMessage', {type: 'success', message: '登录成功'})
})
.
catch
(
error
=>
{
...
...
@@ -142,15 +139,14 @@ export default {
if
(
isSDKReady
)
{
this
.
tim
.
getMyProfile
()
.
then
(({
data
})
=>
{
this
.
$store
.
commit
(
'updateCurrentUserProfile'
,
data
)
})
.
catch
(
error
=>
{
this
.
$store
.
commit
(
'showMessage'
,
{
type
:
'error'
,
message
:
error
.
message
})
})
.
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'
}).
then
(
res
=>
this
.
$store
.
commit
(
'updateSchemeList'
,
res
.
data
))
Helper
.
contactList
({
type
:
'user'
}).
then
(
res
=>
this
.
$store
.
commit
(
'updateUserList'
,
res
.
data
))
// 登录trtc calling
this
.
trtcCalling
.
login
({
sdkAppID
:
this
.
sdkAppID
,
userID
:
this
.
userID
,
userSig
:
this
.
userSig
})
//
this.trtcCalling.login({sdkAppID: this.sdkAppID, userID: this.userID, userSig: this.userSig})
}
},
kickedOutReason
(
type
)
{
...
...
src/store/modules/conversation.js
View file @
ef808ca
import
tim
from
'tim'
import
TIM
from
'tim-js-sdk'
import
_
from
'loadsh'
import
store
from
'..'
import
{
titleNotify
}
from
'../../utils'
import
{
filterCallingMessage
}
from
'../../utils/common'
import
{
titleNotify
}
from
'../../utils'
import
{
filterCallingMessage
}
from
'../../utils/common'
const
conversationModules
=
{
state
:
{
currentConversation
:
{},
currentMessageList
:
[],
nextReqMessageID
:
''
,
isCompleted
:
false
,
// 当前会话消息列表是否已经拉完了所有消息
conversationList
:
[],
callingInfo
:
{
memberList
:
[],
type
:
'C2C'
,
//C2C,GROUP
},
audioCall
:
false
},
getters
:
{
toAccount
:
state
=>
{
if
(
!
state
.
currentConversation
||
!
state
.
currentConversation
.
conversationID
)
{
return
''
}
switch
(
state
.
currentConversation
.
type
)
{
case
'C2C'
:
return
state
.
currentConversation
.
conversationID
.
replace
(
'C2C'
,
''
)
case
'GROUP'
:
return
state
.
currentConversation
.
conversationID
.
replace
(
'GROUP'
,
''
)
default
:
return
state
.
currentConversation
.
conversationID
}
},
currentConversationType
:
state
=>
{
if
(
!
state
.
currentConversation
||
!
state
.
currentConversation
.
type
)
{
return
''
}
return
state
.
currentConversation
.
type
state
:
{
currentConversation
:
{},
currentMessageList
:
[],
nextReqMessageID
:
''
,
isCompleted
:
false
,
// 当前会话消息列表是否已经拉完了所有消息
conversationList
:
[],
callingInfo
:
{
memberList
:
[],
type
:
'C2C'
,
//C2C,GROUP
},
audioCall
:
false
},
totalUnreadCount
:
state
=>
{
const
result
=
state
.
conversationList
.
reduce
((
count
,
conversation
)
=>
{
// 当前会话不计算总未读
if
(
!
store
.
getters
.
hidden
&&
state
.
currentConversation
.
conversationID
===
conversation
.
conversationID
)
{
return
count
getters
:
{
toAccount
:
state
=>
{
if
(
!
state
.
currentConversation
||
!
state
.
currentConversation
.
conversationID
)
{
return
''
}
switch
(
state
.
currentConversation
.
type
)
{
case
'C2C'
:
return
state
.
currentConversation
.
conversationID
.
replace
(
'C2C'
,
''
)
case
'GROUP'
:
return
state
.
currentConversation
.
conversationID
.
replace
(
'GROUP'
,
''
)
default
:
return
state
.
currentConversation
.
conversationID
}
},
currentConversationType
:
state
=>
{
if
(
!
state
.
currentConversation
||
!
state
.
currentConversation
.
type
)
{
return
''
}
return
state
.
currentConversation
.
type
},
totalUnreadCount
:
state
=>
{
const
result
=
state
.
conversationList
.
reduce
((
count
,
conversation
)
=>
{
// 当前会话不计算总未读
if
(
!
store
.
getters
.
hidden
&&
state
.
currentConversation
.
conversationID
===
conversation
.
conversationID
)
{
return
count
}
return
count
+
conversation
.
unreadCount
},
0
)
titleNotify
(
result
)
return
result
},
// 用于当前会话的图片预览
imgUrlList
:
state
=>
{
return
state
.
currentMessageList
.
filter
(
message
=>
(
message
.
type
===
TIM
.
TYPES
.
MSG_IMAGE
||
(
message
.
type
===
TIM
.
TYPES
.
MSG_CUSTOM
&&
_
.
get
(
message
,
'payload.data'
,
'custom'
)
===
'image'
))
&&
!
message
.
isRevoked
)
// 筛选出没有撤回并且类型是图片类型的消息
.
map
(
message
=>
message
.
payload
.
imageInfoArray
[
0
].
url
||
message
.
payload
.
description
)
}
return
count
+
conversation
.
unreadCount
},
0
)
titleNotify
(
result
)
return
result
},
// 用于当前会话的图片预览
imgUrlList
:
state
=>
{
return
state
.
currentMessageList
.
filter
(
message
=>
message
.
type
===
TIM
.
TYPES
.
MSG_IMAGE
&&
!
message
.
isRevoked
)
// 筛选出没有撤回并且类型是图片类型的消息
.
map
(
message
=>
message
.
payload
.
imageInfoArray
[
0
].
url
)
}
},
mutations
:
{
/**
* 显示trtcCalling 群通话成员列表
* @param {Object} state
* @param {Conversation} setCallingList
*/
mutations
:
{
/**
* 显示trtcCalling 群通话成员列表
* @param {Object} state
* @param {Conversation} setCallingList
*/
setCallingList
(
state
,
value
)
{
state
.
callingInfo
.
memberList
=
value
.
memberList
state
.
callingInfo
.
type
=
value
.
type
},
setCallingList
(
state
,
value
)
{
state
.
callingInfo
.
memberList
=
value
.
memberList
state
.
callingInfo
.
type
=
value
.
type
},
/**
* 显示trtcCalling 语音通话
* @param {Object} state
* @param {Conversation} showAudioCall
*/
/**
* 显示trtcCalling 语音通话
* @param {Object} state
* @param {Conversation} showAudioCall
*/
showAudioCall
(
state
,
value
)
{
state
.
audioCall
=
value
},
showAudioCall
(
state
,
value
)
{
state
.
audioCall
=
value
},
/**
* 更新当前会话
* 调用时机: 切换会话时
* @param {Object} state
* @param {Conversation} conversation
*/
updateCurrentConversation
(
state
,
conversation
)
{
state
.
currentConversation
=
conversation
state
.
currentMessageList
=
[]
state
.
nextReqMessageID
=
''
state
.
isCompleted
=
false
},
/**
* 更新会话列表
* 调用时机:触发会话列表更新事件时。CONVERSATION_LIST_UPDATED
* @param {Object} state
* @param {Conversation[]} conversationList
*/
updateConversationList
(
state
,
conversationList
)
{
state
.
conversationList
=
conversationList
},
/**
* 重置当前会话
* 调用时机:需要重置当前会话时,例如:当前会话是一个群组,正好被踢出群时(被踢群事件触发),重置当前会话
* @param {Object} state
*/
resetCurrentConversation
(
state
)
{
state
.
currentConversation
=
{}
},
/**
* 将消息插入当前会话列表
* 调用时机:收/发消息事件触发时
* @param {Object} state
* @param {Message[]|Message} data
* @returns
*/
pushCurrentMessageList
(
state
,
data
)
{
// 还没当前会话,则跳过
if
(
!
state
.
currentConversation
.
conversationID
)
{
return
}
if
(
Array
.
isArray
(
data
))
{
// 筛选出当前会话的消息
const
result
=
data
.
filter
(
item
=>
item
.
conversationID
===
state
.
currentConversation
.
conversationID
)
state
.
currentMessageList
=
[...
state
.
currentMessageList
,
...
result
]
filterCallingMessage
(
state
.
currentMessageList
)
}
else
if
(
data
.
conversationID
===
state
.
currentConversation
.
conversationID
)
{
state
.
currentMessageList
=
[...
state
.
currentMessageList
,
data
]
filterCallingMessage
(
state
.
currentMessageList
)
}
},
/**
* 从当前消息列表中删除某条消息
* @param {Object} state
* @param {Message} message
*/
removeMessage
(
state
,
message
)
{
const
index
=
state
.
currentMessageList
.
findIndex
(({
ID
})
=>
ID
===
message
.
ID
)
if
(
index
>=
0
)
{
state
.
currentMessageList
.
splice
(
index
,
1
)
}
/**
* 更新当前会话
* 调用时机: 切换会话时
* @param {Object} state
* @param {Conversation} conversation
*/
updateCurrentConversation
(
state
,
conversation
)
{
state
.
currentConversation
=
conversation
state
.
currentMessageList
=
[]
state
.
nextReqMessageID
=
''
state
.
isCompleted
=
false
},
/**
* 更新会话列表
* 调用时机:触发会话列表更新事件时。CONVERSATION_LIST_UPDATED
* @param {Object} state
* @param {Conversation[]} conversationList
*/
updateConversationList
(
state
,
conversationList
)
{
state
.
conversationList
=
conversationList
},
/**
* 重置当前会话
* 调用时机:需要重置当前会话时,例如:当前会话是一个群组,正好被踢出群时(被踢群事件触发),重置当前会话
* @param {Object} state
*/
resetCurrentConversation
(
state
)
{
state
.
currentConversation
=
{}
},
/**
* 将消息插入当前会话列表
* 调用时机:收/发消息事件触发时
* @param {Object} state
* @param {Message[]|Message} data
* @returns
*/
pushCurrentMessageList
(
state
,
data
)
{
// 还没当前会话,则跳过
if
(
!
state
.
currentConversation
.
conversationID
)
{
return
}
if
(
Array
.
isArray
(
data
))
{
// 筛选出当前会话的消息
const
result
=
data
.
filter
(
item
=>
item
.
conversationID
===
state
.
currentConversation
.
conversationID
)
state
.
currentMessageList
=
[...
state
.
currentMessageList
,
...
result
]
filterCallingMessage
(
state
.
currentMessageList
)
}
else
if
(
data
.
conversationID
===
state
.
currentConversation
.
conversationID
)
{
state
.
currentMessageList
=
[...
state
.
currentMessageList
,
data
]
filterCallingMessage
(
state
.
currentMessageList
)
}
},
/**
* 从当前消息列表中删除某条消息
* @param {Object} state
* @param {Message} message
*/
removeMessage
(
state
,
message
)
{
const
index
=
state
.
currentMessageList
.
findIndex
(({
ID
})
=>
ID
===
message
.
ID
)
if
(
index
>=
0
)
{
state
.
currentMessageList
.
splice
(
index
,
1
)
}
},
reset
(
state
)
{
Object
.
assign
(
state
,
{
currentConversation
:
{},
currentMessageList
:
[],
nextReqMessageID
:
''
,
isCompleted
:
false
,
// 当前会话消息列表是否已经拉完了所有消息
conversationList
:
[]
})
}
},
reset
(
state
)
{
Object
.
assign
(
state
,
{
currentConversation
:
{},
currentMessageList
:
[],
nextReqMessageID
:
''
,
isCompleted
:
false
,
// 当前会话消息列表是否已经拉完了所有消息
conversationList
:
[]
})
}
},
actions
:
{
/**
* 获取消息列表
* 调用时机:打开某一会话时或下拉获取历史消息时
* @param {Object} context
* @param {String} conversationID
*/
getMessageList
(
context
,
conversationID
)
{
if
(
context
.
state
.
isCompleted
)
{
context
.
commit
(
'showMessage'
,
{
message
:
'已经没有更多的历史消息了哦'
,
type
:
'info'
})
return
}
const
{
nextReqMessageID
,
currentMessageList
}
=
context
.
state
tim
.
getMessageList
({
conversationID
,
nextReqMessageID
,
count
:
15
}).
then
(
imReponse
=>
{
// 更新messageID,续拉时要用到
context
.
state
.
nextReqMessageID
=
imReponse
.
data
.
nextReqMessageID
context
.
state
.
isCompleted
=
imReponse
.
data
.
isCompleted
// 更新当前消息列表,从头部插入
context
.
state
.
currentMessageList
=
[...
imReponse
.
data
.
messageList
,
...
currentMessageList
]
filterCallingMessage
(
context
.
state
.
currentMessageList
)
actions
:
{
/**
* 获取消息列表
* 调用时机:打开某一会话时或下拉获取历史消息时
* @param {Object} context
* @param {String} conversationID
*/
getMessageList
(
context
,
conversationID
)
{
if
(
context
.
state
.
isCompleted
)
{
context
.
commit
(
'showMessage'
,
{
message
:
'已经没有更多的历史消息了哦'
,
type
:
'info'
})
return
}
const
{
nextReqMessageID
,
currentMessageList
}
=
context
.
state
tim
.
getMessageList
({
conversationID
,
nextReqMessageID
,
count
:
15
}).
then
(
imReponse
=>
{
// 更新messageID,续拉时要用到
context
.
state
.
nextReqMessageID
=
imReponse
.
data
.
nextReqMessageID
context
.
state
.
isCompleted
=
imReponse
.
data
.
isCompleted
// 更新当前消息列表,从头部插入
context
.
state
.
currentMessageList
=
[...
imReponse
.
data
.
messageList
,
...
currentMessageList
]
filterCallingMessage
(
context
.
state
.
currentMessageList
)
})
},
/**
* 切换会话
* 调用时机:切换会话时
* @param {Object} context
* @param {String} conversationID
*/
checkoutConversation
(
context
,
conversationID
)
{
context
.
commit
(
'resetCurrentMemberList'
)
// 1.切换会话前,将切换前的会话进行已读上报
if
(
context
.
state
.
currentConversation
.
conversationID
)
{
const
prevConversationID
=
context
.
state
.
currentConversation
.
conversationID
tim
.
setMessageRead
({
conversationID
:
prevConversationID
})
}
// 2.待切换的会话也进行已读上报
tim
.
setMessageRead
({
conversationID
})
// 3. 获取会话信息
return
tim
.
getConversationProfile
(
conversationID
).
then
(({
data
})
=>
{
// 3.1 更新当前会话
context
.
commit
(
'updateCurrentConversation'
,
data
.
conversation
)
// 3.2 获取消息列表
context
.
dispatch
(
'getMessageList'
,
conversationID
)
// 3.3 拉取第一页群成员列表
if
(
data
.
conversation
.
type
===
TIM
.
TYPES
.
CONV_GROUP
)
{
return
context
.
dispatch
(
'getGroupMemberList'
,
data
.
conversation
.
groupProfile
.
groupID
)
})
},
/**
* 切换会话
* 调用时机:切换会话时
* @param {Object} context
* @param {String} conversationID
*/
checkoutConversation
(
context
,
conversationID
)
{
context
.
commit
(
'resetCurrentMemberList'
)
// 1.切换会话前,将切换前的会话进行已读上报
if
(
context
.
state
.
currentConversation
.
conversationID
)
{
const
prevConversationID
=
context
.
state
.
currentConversation
.
conversationID
tim
.
setMessageRead
({
conversationID
:
prevConversationID
})
}
// 2.待切换的会话也进行已读上报
tim
.
setMessageRead
({
conversationID
})
// 3. 获取会话信息
return
tim
.
getConversationProfile
(
conversationID
).
then
(({
data
})
=>
{
// 3.1 更新当前会话
context
.
commit
(
'updateCurrentConversation'
,
data
.
conversation
)
// 3.2 获取消息列表
context
.
dispatch
(
'getMessageList'
,
conversationID
)
// 3.3 拉取第一页群成员列表
if
(
data
.
conversation
.
type
===
TIM
.
TYPES
.
CONV_GROUP
)
{
context
.
dispatch
(
'getGroupUnMemberList'
,
data
.
conversation
.
groupProfile
.
groupID
)
return
context
.
dispatch
(
'getGroupMemberList'
,
data
.
conversation
.
groupProfile
.
groupID
)
}
return
Promise
.
resolve
()
})
}
return
Promise
.
resolve
()
})
}
}
}
export
default
conversationModules
...
...
src/store/modules/friend.js
View file @
ef808ca
...
...
@@ -9,10 +9,16 @@ const friendModules = {
getters
:
{},
mutations
:
{
updateFriendList
(
state
,
friendList
)
{
// state.friendList = friendList
state
.
userList
=
friendList
.
user
state
.
adminList
=
friendList
.
admin
state
.
schemeList
=
friendList
.
scheme
state
.
friendList
=
friendList
},
updateAdminList
(
state
,
friendList
)
{
state
.
adminList
=
friendList
},
updateSchemeList
(
state
,
friendList
)
{
state
.
schemeList
=
friendList
},
updateUserList
(
state
,
friendList
)
{
state
.
userList
=
friendList
},
reset
(
state
)
{
Object
.
assign
(
state
,
{
friendList
:
[],
createGroupModelVisible
:
false
})
...
...
src/store/modules/group.js
View file @
ef808ca
import
tim
from
'tim'
import
Helper
from
'../../utils/helper'
const
groupModules
=
{
state
:
{
groupList
:
[],
currentMemberList
:
[],
createGroupModelVisible
:
false
},
getters
:
{
hasGroupList
:
state
=>
state
.
groupList
.
length
>
0
},
mutations
:
{
updateGroupList
(
state
,
groupList
)
{
state
.
groupList
=
groupList
},
updateCreateGroupModelVisible
(
state
,
visible
)
{
state
.
createGroupModelVisible
=
visible
},
updateCurrentMemberList
(
state
,
memberList
)
{
state
.
currentMemberList
=
[...
state
.
currentMemberList
,
...
memberList
]
},
deleteGroupMemeber
(
state
,
userID
)
{
state
.
currentMemberList
=
state
.
currentMemberList
.
filter
((
member
)
=>
member
.
userID
!==
userID
)
},
deleteGroupMemberList
(
state
,
userIDList
)
{
state
.
currentMemberList
=
state
.
currentMemberList
.
filter
((
member
)
=>
!
userIDList
.
includes
(
member
.
userID
))
},
resetCurrentMemberList
(
state
)
{
state
.
currentMemberList
=
[]
},
reset
(
state
)
{
Object
.
assign
(
state
,
{
state
:
{
groupList
:
[],
currentMemberList
:
[],
currentUnMemberList
:
[],
currentUnMemberPage
:
1
,
createGroupModelVisible
:
false
})
}
},
actions
:
{
updateGroupList
(
context
,
groupList
)
{
context
.
commit
(
'updateGroupList'
,
groupList
)
},
getGroupMemberList
(
context
,
groupID
)
{
return
tim
.
getGroupMemberList
({
groupID
:
groupID
,
offset
:
context
.
state
.
currentMemberList
.
length
,
count
:
30
}).
then
((
imResponse
)
=>
{
context
.
commit
(
'updateCurrentMemberList'
,
imResponse
.
data
.
memberList
)
return
imResponse
})
getters
:
{
hasGroupList
:
state
=>
state
.
groupList
.
length
>
0
},
mutations
:
{
updateGroupList
(
state
,
groupList
)
{
state
.
groupList
=
groupList
},
updateCreateGroupModelVisible
(
state
,
visible
)
{
state
.
createGroupModelVisible
=
visible
},
updateCurrentMemberList
(
state
,
memberList
)
{
state
.
currentMemberList
=
[...
state
.
currentMemberList
,
...
memberList
]
},
updateCurrentUnMemberList
(
state
,
memberList
)
{
state
.
currentUnMemberList
=
[...
state
.
currentUnMemberList
,
...
memberList
]
state
.
currentUnMemberPage
=
state
.
currentUnMemberPage
+
1
},
deleteGroupMember
(
state
,
userID
)
{
state
.
currentMemberList
=
state
.
currentMemberList
.
filter
((
member
)
=>
member
.
userID
!==
userID
)
},
deleteGroupMemberList
(
state
,
userIDList
)
{
state
.
currentMemberList
=
state
.
currentMemberList
.
filter
((
member
)
=>
!
userIDList
.
includes
(
member
.
userID
))
},
resetCurrentMemberList
(
state
)
{
state
.
currentMemberList
=
[]
state
.
currentUnMemberList
=
[]
state
.
currentUnMemberPage
=
1
},
reset
(
state
)
{
Object
.
assign
(
state
,
{
groupList
:
[],
currentMemberList
:
[],
createGroupModelVisible
:
false
})
}
},
actions
:
{
updateGroupList
(
context
,
groupList
)
{
context
.
commit
(
'updateGroupList'
,
groupList
)
},
getGroupMemberList
(
context
,
groupID
)
{
return
tim
.
getGroupMemberList
({
groupID
:
groupID
,
offset
:
context
.
state
.
currentMemberList
.
length
,
count
:
30
}).
then
((
imResponse
)
=>
{
context
.
commit
(
'updateCurrentMemberList'
,
imResponse
.
data
.
memberList
)
return
imResponse
})
},
getGroupUnMemberList
(
context
,
groupID
)
{
Helper
.
groupMemberList
(
groupID
,
{
page
:
context
.
state
.
currentUnMemberPage
,
size
:
20
}).
then
(
res
=>
{
context
.
commit
(
'updateCurrentUnMemberList'
,
res
.
data
)
})
}
}
}
}
export
default
groupModules
...
...
src/store/modules/user.js
View file @
ef808ca
import
tim
from
'../../tim'
import
Helper
from
'../../utils/helper'
const
user
=
{
state
:
{
...
...
@@ -36,7 +37,7 @@ const user = {
login
(
context
,
userID
)
{
tim
.
login
({
userID
,
userSig
:
window
.
genTestUserSig
(
userID
).
userSig
userSig
:
Helper
.
getSignature
(
userID
)
}).
then
(()
=>
{
context
.
commit
(
'toggleIsLogin'
,
true
)
context
.
commit
(
'startComputeCurrent'
)
...
...
src/tim.js
View file @
ef808ca
...
...
@@ -2,9 +2,7 @@ import TIM from 'tim-js-sdk'
import
COSSDK
from
'cos-js-sdk-v5'
// 初始化 SDK 实例
const
tim
=
TIM
.
create
({
SDKAppID
:
window
.
genTestUserSig
(
''
).
SDKAppID
})
const
tim
=
TIM
.
create
({
SDKAppID
:
parseInt
(
process
.
env
.
VUE_APP_API_KEY
)})
window
.
setLogLevel
=
tim
.
setLogLevel
...
...
src/trtc-calling.js
View file @
ef808ca
import
TRTCCalling
from
'trtc-calling-js'
let
options
=
{
SDKAppID
:
window
.
genTestUserSig
(
''
).
SDKAppID
// 接入时需要将0替换为您的云通信应用的 SDKAppID
}
let
options
=
{
SDKAppID
:
parseInt
(
process
.
env
.
VUE_APP_API_KEY
)}
const
trtcCalling
=
new
TRTCCalling
(
options
)
...
...
src/utils/helper.js
View file @
ef808ca
import
request
from
'./request'
export
default
class
Helper
{
constructor
()
{
static
getKey
()
{
return
parseInt
(
process
.
env
.
VUE_APP_API_KEY
)
}
static
getSecret
()
{
return
process
.
env
.
VUE_APP_API_SECRET
}
static
getExpire
()
{
return
parseInt
(
process
.
env
.
VUE_APP_API_EXPIRETIME
)
}
static
getUrlKey
(
name
)
{
return
decodeURIComponent
((
new
RegExp
(
'[?|&]'
+
name
+
'='
+
'([^&;]+?)(&|#|;|$)'
).
exec
(
location
.
href
)
||
[,
''
])[
1
].
replace
(
/
\+
/g
,
'%20'
))
||
null
}
...
...
@@ -12,6 +23,11 @@ export default class Helper {
return
this
.
getUrlKey
(
'token'
)
}
static
getSignature
(
userID
)
{
const
generator
=
new
window
.
LibGenerateTestUserSig
(
this
.
getKey
(),
this
.
getSecret
(),
this
.
getExpire
())
return
generator
.
genTestUserSig
(
userID
)
}
/**
*
* @returns {Promise<never>|Promise<{sign, id}>}
...
...
@@ -19,18 +35,22 @@ export default class Helper {
static
verifyToken
()
{
return
request
.
get
(
'auth'
).
then
(
res
=>
{
const
{
esm_id
}
=
res
.
data
return
Promise
.
resolve
({
id
:
esm_id
,
sign
:
window
.
genTestUserSig
(
esm_id
).
userSig
})
return
Promise
.
resolve
({
id
:
esm_id
,
sign
:
this
.
getSignature
(
esm_id
)
})
})
}
static
contactList
()
{
return
request
.
get
(
'im/contacts'
)
static
contactList
(
params
=
{}
)
{
return
request
.
get
(
'im/contacts'
,
{
params
}
)
}
static
groupList
(
params
=
{})
{
return
request
.
get
(
'im/groups'
,
{
params
})
}
static
groupMemberList
(
group
,
params
=
{})
{
return
request
.
get
(
`im/groups/
${
group
}
/members`
,
{
params
})
}
static
joinGroup
(
id
,
member
)
{
return
request
.
post
(
`im/groups/
${
id
}
/members`
,
{
member
})
}
...
...
src/utils/request.js
View file @
ef808ca
...
...
@@ -5,7 +5,7 @@ import tim from '../tim'
const
service
=
axios
.
create
({
baseURL
:
'http://spread_dev.hikoon.com/mapi'
,
baseURL
:
process
.
env
.
VUE_APP_API_URL
,
// withCredentials: true, // send cookies when cross-domain requests
timeout
:
5000
// request timeout
})
...
...
vue.config.js
View file @
ef808ca
const
path
=
require
(
'path'
)
function
resolve
(
dir
)
{
return
path
.
join
(
__dirname
,
dir
)
return
path
.
join
(
__dirname
,
dir
)
}
module
.
exports
=
{
publicPath
:
'./'
,
assetsDir
:
'./'
,
productionSourceMap
:
false
,
chainWebpack
:
config
=>
{
config
.
resolve
.
alias
.
set
(
'@'
,
resolve
(
'src'
))
.
set
(
'tim'
,
resolve
(
'src/tim.js'
))
// 删除预加载
config
.
plugins
.
delete
(
'preload'
)
config
.
plugins
.
delete
(
'prefetch'
)
// 压缩代码
config
.
optimization
.
minimize
(
true
)
// 分割代码
config
.
optimization
.
splitChunks
({
chunks
:
'all'
})
},
css
:
{
extract
:
true
,
sourceMap
:
false
,
loaderOptions
:
{
stylus
:
{
'resolve url'
:
true
,
// 自定义主题场景
import
:
[
path
.
resolve
(
__dirname
,
'./src/assets/css/base.styl'
)]
}
publicPath
:
'./'
,
assetsDir
:
'./'
,
productionSourceMap
:
false
,
chainWebpack
:
config
=>
{
config
.
resolve
.
alias
.
set
(
'@'
,
resolve
(
'src'
))
.
set
(
'tim'
,
resolve
(
'src/tim.js'
))
// 删除预加载
config
.
plugins
.
delete
(
'preload'
)
config
.
plugins
.
delete
(
'prefetch'
)
// 压缩代码
config
.
optimization
.
minimize
(
true
)
// 分割代码
config
.
optimization
.
splitChunks
({
chunks
:
'all'
})
},
css
:
{
extract
:
true
,
sourceMap
:
false
,
loaderOptions
:
{
stylus
:
{
'resolve url'
:
true
,
// 自定义主题场景
import
:
[
path
.
resolve
(
__dirname
,
'./src/assets/css/base.styl'
)]
}
}
}
}
}
...
...
yarn.lock
View file @
ef808ca
...
...
@@ -1249,6 +1249,11 @@ acorn@^7.1.1:
resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
add@^2.0.6:
version "2.0.6"
resolved "https://registry.npmjs.org/add/-/add-2.0.6.tgz#248f0a9f6e5a528ef2295dbeec30532130ae2235"
integrity sha1-JI8Kn25aUo7yKV2+7DBTITCuIjU=
address@^1.0.3:
version "1.1.2"
resolved "https://registry.npmjs.org/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6"
...
...
@@ -5100,6 +5105,11 @@ loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4
emojis-list "^3.0.0"
json5 "^1.0.1"
loadsh@^0.0.4:
version "0.0.4"
resolved "https://registry.npmjs.org/loadsh/-/loadsh-0.0.4.tgz#5314babd12bb13315dde024a4ca70758c5489d2d"
integrity sha512-U+wLL8InpfRalWrr+0SuhWgGt10M4OyAk6G8xCYo2rwpiHtxZkWiFpjei0vO463ghW8LPCdhqQxXlMy2qicAEw==
locate-path@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
...
...
@@ -8689,6 +8699,11 @@ yargs@^16.0.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"
yarn@^1.22.10:
version "1.22.10"
resolved "https://registry.npmjs.org/yarn/-/yarn-1.22.10.tgz#c99daa06257c80f8fa2c3f1490724e394c26b18c"
integrity sha512-IanQGI9RRPAN87VGTF7zs2uxkSyQSrSPsju0COgbsKQOOXr5LtcVPeyXWgwVa0ywG3d8dg6kSYKGBuYK021qeA==
yorkie@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/yorkie/-/yorkie-2.0.0.tgz#92411912d435214e12c51c2ae1093e54b6bb83d9"
...
...
Please
register
or
sign in
to post a comment