融云开发者文档地址
融云包括含UI SDK 集成 和 无UI SDK集成。
含UI SDK 集成:
优点:可以快速集成,不需要编写页面。缺点:消息可以直接发送,但是无法获取输入的消息。
无UI SDK 集成:
优点:可以获取消息,进行存储。 缺点: 需要手动编写页面,配置。
本篇文章主要介绍无UI SDK 集成。
前置操作:
创建融云开发者账号 ,获取 App Key(服务管理→基本信息→app key);创建测试用户,获取 用户ID(服务管理→基本信息→app key → 管理测试用户);获取用户ID 对应的token(北极星 → Server api调试→用户→获取token)。至此前置操作已完成,废话不多说,上代码。
<div class="flex">
<div class="left overflowY">
<div v-if="chatList.length > 0">
<div :class="chatIndex == index ? 'activeLeftItem' :'leftItem'" v-for="(item,index) in chatList" @click="handleChat(index,item)" :key="index">
<div class="flexC" style="width:60%;">
<div class="position">
<img style="width:50px;height:50px;border-radius:50%;margin-right:10px;" :src="item.latestMessage.content.user.portraitUri" alt="">
<div class="absolute" v-if="item.unreadMessageCount > 0">{{item.unreadMessageCount}}</div>
</div>
<div>
<div class="name mb5">{{item.latestMessage.content.user.name}}</div>
<div class="content">{{item.latestMessage.content.content}}</div>
</div>
</div>
<div class="time">{{item.latestMessage.sentTime}}</div>
</div>
</div>
<div v-else>
<el-empty description="暂无会话"></el-empty>
</div>
</div>
<div class="right" >
<div class="rightTop">
<div v-if="messageList.length > 0">
<div class="rightTopName">{{name}}</div>
<div style="height:80px;"></div>
<div style="padding:5px 20px;height:350px;" class="overflowY" id="overflowY">
<div v-for="(item,index) in messageList" :key="index" >
<div style="font-size:16px;" :class="item.messageDirection == 1 ? 'messageRight mb20 ' : 'mb10 moreHidden mb20' ">
<img style="width:40px;height:40px;border-radius:50%;" v-if="item.messageDirection == 2" :src="item.content.user ? item.content.user.portraitUri : '../../assets/avatar.png'" alt="">
<span v-if="item.messageType == 'RC:TxtMsg'" :class="item.messageDirection == 1 ? 'rightMessage moreHidden' : 'leftMessage moreHidden'">{{item.content.content}}</span>
<el-image v-if="item.messageType == 'RC:ImgMsg'" style="width:40px;height:40px;" fit="cover" :src="item.content.imageUri" :preview-src-list="[item.content.imageUri]"></el-image>
<span style="display:block;font-size:12px;color:#909399;" v-if="item.messageDirection == 2" :class="item.messageDirection == 1 ? 'textR' : ''">{{item.sentTime}}</span>
<span style="display:block;font-size:12px;color:#909399;" v-if="item.messageDirection == 1" :class="item.messageDirection == 1 ? 'textR' : ''">{{item.sentTime}}</span>
</div>
</div>
</div>
</div>
<div v-else style="height:430px;">
<el-empty description="暂无消息"></el-empty>
</div>
</div>
<div class="rightBottom">
<div>
<i class="el-icon-picture-outline" style="font-size:20px;"></i>
<el-popover
placement="top"
width="400"
trigger="click">
<span v-for="(item,index) in smallList" @click="getEm(item.emoji)" :key="index">
{{item.emoji}}
</span>
<i class="el-icon-help" slot="reference" style="font-size:20px;"></i>
</el-popover>
</div>
<el-input type="textarea" rows="4" v-model="content" style="width:80%;"></el-input>
<el-button size="mini" @click="submit">发送</el-button>
</div>
</div>
</div>
<script>
import * as RongIMLib from '@rongcloud/imlib-next'
import {timestampToTime} from "@/utils/time.js"
import { mapState,mapActions } from 'vuex'
export default {
data(){
return{
chatList:[],
chatIndex:"",
messageList:[],
name:"", //对方名称
avatar:"",//对方头像
userName:"", //自己名称
userPortrait:"",//自己头像
targetId:"",
content:"",
userId:"",
smallList:[]
}
},
mounted(){
this.initRongyun()
},
methods:{
...mapActions(["getUserDetail","txtMsg"]),
//毫秒转为日期
timestampToTime(timestamp){
var date = new Date(timestamp)
var Y = date.getFullYear() + '-';
var M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1):date.getMonth()+1) + '-';
var D = (date.getDate()< 10 ? '0'+date.getDate():date.getDate())+ ' ';
var h = (date.getHours() < 10 ? '0'+date.getHours():date.getHours())+ ':';
var m = (date.getMinutes() < 10 ? '0'+date.getMinutes():date.getMinutes()) + ':';
var s = date.getSeconds() < 10 ? '0'+date.getSeconds():date.getSeconds();
return Y+M+D+h+m+s;
},
getEm(emo){
this.content += emo
},
submit(){
if(!this.targetId){
this.$message({
message: '请选择会话!',
type: 'warning',
});
return
}
if(!this.content){
this.$message({
message: '请输入消息!',
type: 'warning',
});
return
}
const conversation = { conversationType: RongIMLib.ConversationType.PRIVATE, targetId: this.targetId }
// 实例化待发送消息,RongIMLib.TextMessage 为内置文本型消息
const message = new RongIMLib.TextMessage({
content: this.content,
extra: '',
user: {
id: this.targetId,
name: this.name,
portraitUri: this.avatar,
extra: ''
}})
RongIMLib.sendMessage(conversation, message,).then(res => {
if (res.code === RongIMLib.ErrorCode.SUCCESS) {
this.txtMsg({
reqType: "txtMsg", //接口标识
source: 3, //请求人身份来源 1-会员 2-司机 3-平台
toUserId: this.targetId, //发送给哪个人
toUserSource: 1, //接收信息人 身份 1-会员 2-司机 3-平台
content:this.content //发送内容
}).then((res)=>{
if(res.code == 0){
// 消息发送成功,可以根据返回结果中的 messageId 字段将列表中的该消息状态改为发送成功。
this.$message({
message: '发送成功!',
type: 'success',
});
this.getChatList()
this.getMessageList(this.targetId)
this.content = ""
}
})
} else {
// 消息发送失败,可以根据返回结果中的 messageId 字段将列表中的该消息状态改为发送失败。
console.log('消息发送失败', res.code, res.msg)
}
})
},
handleChat(i,item){
this.chatIndex = i
this.name = item.latestMessage.content.user.name
this.avatar = item.latestMessage.content.user.portraitUri
this.targetId = item.targetId
this.getMessageList(item.targetId)
const conversationType = RongIMLib.ConversationType.PRIVATE;
const targetId = item.targetId;
//清除当前会话未读状态
RongIMLib.clearMessagesUnreadStatus({ conversationType, targetId }).then(res => {
if (res.code === 0) {
console.log(res.code)
this.getChatList()
} else {
console.log(res.code, res.msg)
}
})
this.$nextTick(()=>{
var ele = document.getElementById("overflowY");
if(ele.scrollHeight>ele.clientHeight){
setTimeout(()=>{
//判断元素是否出现了滚动条
ele.scrollTop = ele.scrollHeight
},500)
}
})
},
// 获取消息列表
getMessageList(id){
const conversation = {
conversationType: RongIMLib.ConversationType.PRIVATE,
targetId: id
}
// 从当前时间开始向前查询
const option = {
timestamp: 0,
count: 99,
order: 0
}
RongIMLib.getHistoryMessages(conversation, option).then(res => {
if (res.code === 0) {
this.messageList = res.data.list.map((item)=>{
item.sentTime = timestampToTime(item.sentTime)
return item
})
console.log(res.data.list)
console.log(res.data.hasMore)
} else {
console.log(res.code, res.msg)
}
})
},
//获取会话列表
async getChatList(){
const startTime = 0;
const count = 10;
const order = 0
let res1 = await RongIMLib.getConversationList({
count: count,
startTime: startTime,
order: order
})
console.log(res1.data)
this.chatList = res1.data.map((item)=>{
item.latestMessage.sentTime = timestampToTime(item.latestMessage.sentTime)
return item
})
},
//融云初始化
async initRongyun(){
RongIMLib.init({ appkey: '您获取到的appKey' });
let token = 'userId转为的token'
//连接
let res = await RongIMLib.connect(token)
//连接成功后根据userId获取用户信息(由后端去请求)。
//[获取用户信息文档说明](https://doc.rongcloud.cn/imserver/server/v1/user/get)
this.userId = res.data.userId
this.getUserDetail({
reqType: "getUserDetail", //接口标识
userCode: res.data.userId
}).then((res)=>{
if(res.code == 0){
this.userName = res.data.rcUserInfo.userName
this.userPortrait = res.data.rcUserInfo.userPortrait
}
})
// 初始化Emo表情 html 引入 <script src="https://cdn.ronghub.com/RongEmoji-2.2.10.min.js"></script>
window.RongIMLib.RongIMEmoji.init();
var list = window.RongIMLib.RongIMEmoji.list;
this.smallList = list
//监听消息
const Events = RongIMLib.Events
RongIMLib.addEventListener(Events.MESSAGES, (evt)=>{
this.$router.push("/refres")
this.$notify({
title: '提示',
message: '收到一条来自' + evt.messages[0].content.user.name + "的新消息",
duration: 0
});
})
this.getChatList()
},
},
}
</script>
<style lang="scss" scoped>
.textR{
text-align: right;
}
.left{
width:35%;
background-color: #fff;
height:600px;
border-right: 1px solid #ddd;
.name{
font-size:16px;
}
.content{
width:350px;
color:#909399;
overflow: hidden;
text-overflow: ellipsis;//多出部分以省略号形式隐藏
white-space: nowrap;/* 禁止换行 normal可以换行 */
}
.time{
color:#909399;
}
.leftItem{
padding:10px;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
}
.activeLeftItem{
background:#eee;
justify-content: space-between;
padding:10px;
display: flex;
align-items: center;
cursor: pointer;
}
}
.right{
width:65%;
background:#fff;
.rightTopName{
z-index: 1000;
width:100%;
background:#fff;
height:30px;
padding:20px;
font-size: 25px;
border-bottom:1px solid #ddd;
border-top:1px solid #ddd;
position: fixed;
}
.rightBottom{
width:100%;
// height:120px;
// background:#fff;
padding:15px;
border-top:1px solid #ddd;
}
.messageRight{
text-align: right;
}
.leftMessage{
display: inline-block;
border-radius: 0 15px 15px;
background-color: rgba(0, 0, 0, 0.1);
padding: 10px 15px;
}
.rightMessage{
display: inline-block;
border-radius: 15px 0 15px 15px;
background-color: rgba(0, 0, 0, 0.1);
padding: 10px 15px;
}
}
.position{
position: relative;
}
.absolute{
position: absolute;
top:0;
left:45px;
color:#fff;
text-align: center;
width:15px;
line-height: 15px;
height:15px;
background:red;
border-radius: 50%;
}
</style>