Commit 51bb7eaf 51bb7eaf832fe7246a051ddd711fb1103d21be47 by huhai

Merge branch 'develop'

2 parents be0413d9 5cf62a3a
......@@ -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'
......
......@@ -5,3 +5,5 @@ VUE_APP_API_URL='http://spread.hikoon.com/mapi'
VUE_APP_API_KEY=1400514886
VUE_APP_API_SECRET='9c0cbbb0f08e4087e1b06295cd32fc1f9f368c011539123517f769c59274147a'
VUE_APP_API_EXPIRETIME=604800
#VUE_APP_API_UNI_URL='https://spread.hikoon.com/api'
VUE_APP_API_UNI_URL='https://spread-dev.hikoon.com/api'
......
......@@ -8,9 +8,9 @@
"eslint:recommended"
],
"rules": {
"no-console": 'off',
"quotes": ["error", "single"],
"semi": ["error","never"],
// "no-console": 'off',
// "quotes": ["error", "single"],
// "semi": ["error","never"],
"space-before-blocks": "error",
"space-unary-ops": "error"
},
......
No preview for this file type
<template>
<div
class="conversation-item-container"
:class="{ 'choose': conversation.conversationID === currentConversation.conversationID }"
@click="selectConversation"
class="conversation-item-container"
: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"
v-if="conversation.type === TIM.TYPES.CONV_C2C"
>{{ conversation.userProfile.nick || conversation.userProfile.userID }}
</span>
<span :title="conversation.groupProfile.name || conversation.groupProfile.groupID"
v-else-if="conversation.type === TIM.TYPES.CONV_GROUP"
>{{ conversation.groupProfile.name || conversation.groupProfile.groupID }}
</span>
<span
v-else-if="conversation.type === TIM.TYPES.CONV_SYSTEM"
>系统通知
</span>
:title="
conversation.userProfile.nick ||
conversation.userProfile.userID
"
v-if="conversation.type === TIM.TYPES.CONV_C2C"
>{{
conversation.userProfile.nick ||
conversation.userProfile.userID
}}
</span>
<span
:title="
conversation.groupProfile.name ||
conversation.groupProfile.groupID
"
v-else-if="conversation.type === TIM.TYPES.CONV_GROUP"
>{{
conversation.groupProfile.name ||
conversation.groupProfile.groupID
}}
</span>
<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 }}
</span>
<span class="badge" v-if="showUnreadCount">
{{
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">
{{ messageForShow }}
</span>
<span class="remind" style="color: red" v-if="hasMessageAtMe"
>[有人提到我]</span
>
<span
class="text"
:title="conversation.lastMessage.messageForShow"
>
{{ messageForShow }}
</span>
</div>
</div>
<div class="date">
......@@ -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.currentConversation.conversationID !==
this.conversation.conversationID && this.conversation.unreadCount > 0
)
);
},
date() {
if (
!this.conversation.lastMessage ||
!this.conversation.lastMessage.lastTime
!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'
)
this.conversation.groupProfile.selfInfo.messageRemindType ===
"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 !==
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',
this.conversation.conversationID
)
"checkoutConversation",
this.conversation.conversationID
);
}
},
deleteConversation(event) {
// 停止冒泡,避免和点击会话的事件冲突
event.stopPropagation()
event.stopPropagation();
this.tim
.deleteConversation(this.conversation.conversationID)
.then(() => {
this.$store.commit('showMessage', {
message: `会话【${this.conversationName}】删除成功!`,
type: 'success'
})
this.popoverVisible = false
this.$store.commit('resetCurrentConversation')
})
.catch(error => {
this.$store.commit('showMessage', {
message: `会话【${this.conversationName}】删除失败!, error=${error.message}`,
type: 'error'
})
this.popoverVisible = false
})
.deleteConversation(this.conversation.conversationID)
.then(() => {
this.$store.commit("showMessage", {
message: `会话【${this.conversationName}】删除成功!`,
type: "success",
});
this.popoverVisible = false;
this.$store.commit("resetCurrentConversation");
})
.catch((error) => {
this.$store.commit("showMessage", {
message: `会话【${this.conversationName}】删除失败!, error=${error.message}`,
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>
......
......@@ -3,34 +3,42 @@
<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"
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="请输入群名片"
@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>
......@@ -42,119 +50,144 @@
<span class="label">禁言至:</span>
<span class="content">{{ muteUntil }}</span>
</div>
<el-button type="text" v-if="canChangeRole" @click="changeMemberRole">
{{
member.role === 'Admin' ? '取消管理员' : '设为管理员'
}}
</el-button>
<!-- <el-button type="text" v-if="canChangeRole" @click="changeMemberRole">-->
<!-- {{-->
<!-- member.role === 'Admin' ? '取消管理员' : '设为管理员'-->
<!-- }}-->
<!-- </el-button>-->
<!-- <el-button type="text" v-if="showKickout" style="color:red;" @click="kickoutGroupMember">踢出群组</el-button>-->
<el-button type="text" style="color:red;" @click="kickoutGroupMember">踢出群组</el-button>
<!-- <el-button type="text" style="color:red;" @click="kickoutGroupMember">踢出群组</el-button>-->
</div>
</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)
)
this.isOwner &&
["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() {
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
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)
.then(() => {
this.$store.commit('deleteGroupMember', this.member.userID)
this.$store.commit('updateCurrentUnMemberList', [{
Helper.groupMemberDelete(
this.currentConversation.groupProfile.groupID,
this.member.userID
)
.then(() => {
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,87 +206,92 @@ 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
})
})
.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() {
// console.log('Number(this.muteTime) is ',Number(this.muteTime))
let _muteTime = Number(this.muteTime)
if(_muteTime > 99999999) {
_muteTime = 99999999
}
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: _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) {
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
})
.then(() => {
this.nameCardPopoverVisible = false
this.$store.commit('showMessage', {
message: '修改成功'
})
})
.catch(error => {
this.$store.commit('showMessage', {
type: 'error',
message: error.message
})
})
}
}
}
.setGroupMemberNameCard({
groupID: this.currentConversation.groupProfile.groupID,
userID: this.member.userID,
nameCard: this.nameCard,
})
.then(() => {
this.nameCardPopoverVisible = false;
this.$store.commit("showMessage", {
message: "修改成功",
});
})
.catch((error) => {
this.$store.commit("showMessage", {
type: "error",
message: error.message,
});
});
},
},
};
</script>
<style lang="stylus" scoped>
......
<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)
.then(() => {
this.count += 30
})
this.$store
.dispatch("getGroupMemberList", this.groupProfile.groupID)
.then(() => {
this.count += 30;
});
},
}
}
},
};
</script>
<style lang="stylus" scoped>
......@@ -167,6 +188,4 @@ export default {
// text-align: center;
// line-height: 30px;
// }
</style>
......
<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">&nbsp;重新编辑</el-button>
{{ text }}
<el-button
type="text"
size="mini"
class="edit-button"
v-show="isEdit"
@click="reEdit"
>&nbsp;重新编辑</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>
......
<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>未命名音乐文件</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>
<template>
<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"/>
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"
v-else-if="this.payload.data === 'video'"
:isMine="isMine"
: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>
......
<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">
......@@ -55,11 +91,11 @@
</el-form-item>
<el-form-item label="建议">
<el-input
type="textarea"
:rows="2"
placeholder="请输入内容"
resize="none"
v-model="suggestion"
type="textarea"
:rows="2"
placeholder="请输入内容"
resize="none"
v-model="suggestion"
></el-input>
</el-form-item>
</el-form>
......@@ -69,41 +105,43 @@
</span>
</el-dialog>
<el-popover
trigger="manual"
v-model="showAtGroupMember"
placement="top"
style="max-height:500px;overflow-y:scroll;"
trigger="manual"
v-model="showAtGroupMember"
placement="top"
style="max-height: 500px; overflow-y: scroll"
>
<el-radio-group
v-model="atUserID"
style="display:flex;flex-decoration: column;"
v-for="member in memberList"
:key="member.userID"
@change="handleSelectAtUser"
v-model="atUserID"
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">
<textarea
ref="text-input"
rows="4"
resize="false"
v-model="messageContent"
class="text-input"
@focus="focus = true"
@blur="focus = false"
@keydown.enter.exact.prevent="handleEnter"
@keyup.ctrl.enter.prevent.exact="handleLine"
@keydown.up.stop="handleUp"
@keydown.down.stop="handleDown"
ref="text-input"
rows="4"
resize="false"
v-model="messageContent"
class="text-input"
@focus="focus = true"
@blur="focus = false"
@keydown.enter.exact.prevent="handleEnter"
@keyup.ctrl.enter.prevent.exact="handleLine"
@keydown.up.stop="handleUp"
@keydown.down.stop="handleDown"
>
</textarea>
<el-tooltip
class="item"
effect="dark"
content="按Enter发送消息,Ctrl+Enter换行"
placement="left-start"
class="item"
effect="dark"
content="按Enter发送消息,Ctrl+Enter换行"
placement="left-start"
>
<div class="btn-send" @click="sendTextMessage">
<div class="tim-icon-send"></div>
......@@ -111,16 +149,34 @@
</el-tooltip>
</div>
<input
type="file"
id="imagePicker"
ref="imagePicker"
accept=".jpg, .jpeg, .png, .gif, .bmp"
@change="sendImage"
style="display:none"
type="file"
id="imagePicker"
ref="imagePicker"
accept=".jpg, .jpeg, .png, .gif, .bmp"
@change="sendImage"
style="display: none"
/>
<input
type="file"
id="filePicker"
ref="filePicker"
@change="sendFile"
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"/>
<div class="calling-member-list" v-if="currentConversationType === TIM.TYPES.CONV_GROUP && showCallingMember">
<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
"
>
<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,286 +215,287 @@ 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
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
})
.catch(imError => {
this.$store.commit('showMessage', {
message: imError.message,
type: 'error'
})
})
.sendMessage(message)
.then(() => {
this.$refs.videoPicker.value = null;
})
.catch((imError) => {
this.$store.commit("showMessage", {
message: imError.message,
type: "error",
});
});
},
sendTextMessage() {
if (
this.messageContent === '' ||
this.messageContent.trim().length === 0
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 (
this.form.data.length === 0 &&
this.form.description.length === 0 &&
this.form.extension.length === 0
this.form.data.length === 0 &&
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: ''
})
})
.catch(error => {
this.$store.commit('showMessage', {
type: 'error',
message: error.message
})
})
this.surveyDialogVisible = false
.sendMessage(message)
.then(() => {
Object.assign(this, {
rate: 5,
suggestion: "",
});
})
.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
})
.catch(imError => {
this.$store.commit('showMessage', {
message: imError.message,
type: 'error'
})
})
.sendMessage(message)
.then(() => {
this.$refs.imagePicker.value = null;
})
.catch((imError) => {
this.$store.commit("showMessage", {
message: imError.message,
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
})
.catch(imError => {
this.$store.commit('showMessage', {
message: imError.message,
type: 'error'
})
})
.sendMessage(message)
.then(() => {
this.$refs.filePicker.value = null;
})
.catch((imError) => {
this.$store.commit("showMessage", {
message: imError.message,
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
onProgress: (percent) => {
this.$set(message, "progress", percent); // 手动给message 实例加个响应式属性: progress
},
});
this.$store.commit("pushCurrentMessageList", message);
this.tim
.sendMessage(message)
.then(() => {
this.$refs.videoPicker.value = null;
})
.catch((imError) => {
this.$store.commit("showMessage", {
message: imError.message,
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;
}
})
this.$store.commit('pushCurrentMessageList', message)
});
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(() => {
this.$refs.videoPicker.value = null
})
.catch(imError => {
this.$store.commit('showMessage', {
message: imError.message,
type: 'error'
})
})
}
}
}
.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 {
......
<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
`GROUP${event.data.message.payload.groupProfile.groupID}` ===
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.type === this.TIM.TYPES.MSG_TEXT &&
message.payload.text.includes('@')
)
(message) =>
message.type === this.TIM.TYPES.MSG_TEXT &&
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 &&
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)
})
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)
);
});
// 清理当前会话的群成员列表
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">
......
import request from './request'
import request from "./request";
export default class Helper {
static getKey() {
return parseInt(process.env.VUE_APP_API_KEY);
}
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
}
static getToken() {
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}>}
*/
static verifyToken() {
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})
}
static groupList(params = {}) {
return request.get('im/groups', {params})
}
static groupMemberList(group, params = {}) {
return request.get(`im/groups/${group}/members`, {params})
}
static groupMemberDelete(group, member) {
return request.delete(`im/groups/${group}/members/${member}`)
}
static joinGroup(id, member) {
return request.post(`im/groups/${id}/members`, {member})
}
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
);
}
static getToken() {
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}>}
*/
static verifyToken() {
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 });
}
static groupList(params = {}) {
return request.get("im/groups", { params });
}
static groupMemberList(group, params = {}) {
return request.get(`im/groups/${group}/members`, { params });
}
static groupMemberDelete(group, member) {
return request.delete(`im/groups/${group}/members/${member}`);
}
static joinGroup(id, member) {
return request.post(`im/groups/${id}/members`, { member });
}
}
......
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;
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
})
baseURL: process.env.VUE_APP_API_URL,
// withCredentials: true, // send cookies when cross-domain requests
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
case 401:
Store.commit('showMessage', {type: 'error', message: '身份信息已失效,请重新登录'})
tim.logout().then(() => {
Store.commit('user/toggleIsLogin')
Store.commit('user/stopComputeCurrent')
Store.commit('user/reset')
})
break
default:
return Promise.reject(response.data)
case 200:
return response.data;
case 401:
Store.commit("showMessage", {
type: "error",
message: "身份信息已失效,请重新登录",
});
tim.logout().then(() => {
Store.commit("user/toggleIsLogin");
Store.commit("user/stopComputeCurrent");
Store.commit("user/reset");
});
break;
default:
return Promise.reject(response.data);
}
}, error => {
return Promise.reject(error)
})
},
(error) => {
return Promise.reject(error);
}
);
export default service
export default service;
......