apicloud基于融云实现即时通讯

427 阅读2分钟

rongcloud.js 这个是我对融云模块的封装整合

链接融云的步骤login -> 初始化IM -> 链接

下面要使用的一些资源链接链接:pan.baidu.com/s/1tOcHOA1d… 提取码:ubs7

rongcloud.js

var appKey = "你的appkey";
var appSecret = "你的appSecret";
var statusDesc = {
    CONNECTED: "连接成功",
    CONNECTING: "连接中",
    DISCONNECTED: "断开连接",
    KICKED: "用户账户在其他设备登录,本机会被踢掉线",
    NETWORK_UNAVAILABLE: "网络不可用",
    SERVER_INVALID: "服务器异常或无法连接",
    TOKEN_INCORRECT: "Token 不正确",
}
var disConnectReasonDesc = {
    1: '己方取消已发出的通话请求',
    2: '己方拒绝收到的通话请求',
    3: '己方挂断',
    4: '己方忙碌',
    5: '己方未接听',
    6: '当前引擎不支持',
    7: '己方网络出错',
    8: '己方摄像头初始化错误,可能是没有打开使用摄像头权限',
    9: '其他端已经接听',
    11: '对方取消已发出的通话请求',
    12: '对方拒绝收到的通话请求',
    13: '通话过程对方挂断',
    14: '对方忙碌',
    15: '对方未接听',
    16: '对方引擎不支持',
    17: '对方网络错误',
    18: 'im ipc服务已断开',
}

function RongCloud() {
    this.appReception = true
    this.nowTargetId = ''
    this.rong = api.require('rongCloud2');
    this.messageType = {
        'RC:VSTMsg': '[视频通话]',
        'RC:ImgMsg': '[图片]',
        'RC:VcMsg': '[语音消息]'
    }
}

function stringifyParse(stringify) {
    return JSON.parse(stringify)
}

function date_format(micro_second) {
    // 总秒数
    var second = Math.floor(micro_second / 1000);
    // 天数
    // var day = Math.floor(second / 3600 / 24);
    // 小时
    var hr = Math.floor(second / 3600 % 24);
    // 分钟
    var min = Math.floor(second / 60 % 60);
    // 秒
    var sec = Math.floor(second % 60);
    return (hr < 10 ? '0' + hr : hr) + ":" + (min < 10 ? '0' + min : min) + ":" + (sec < 10 ? '0' + sec : sec);
};
RongCloud.prototype.login = function (id, zh, tx, callback) {
    //获取token
    var userId = id;
    //会员id
    var name = zh;
    //会员昵称
    var portraitUri = tx;
    //会员头像

    var nonce = Math.floor(Math.random() * 1000000);
    //随机数
    var timestamp = Date.now();
    //时间戳
    var signature = sha1("" + appSecret + nonce + timestamp);
    //数据签名(通过哈希加密计算)
    api.ajax({
        url: "http://api.cn.ronghub.com/user/getToken.json",
        method: "post",
        headers: {
            "RC-App-Key": appKey,
            "RC-Nonce": "" + nonce,
            "RC-Timestamp": "" + timestamp,
            "RC-Signature": "" + signature,
            "Content-Type": "application/x-www-form-urlencoded"
        },
        data: {
            values: {
                userId: userId,
                name: name,
                portraitUri: portraitUri
            }
        }
    }, function (ret, err) {
        if (ret) {
            callback(ret)
        } else {
            api.toast({
                msg: '通讯链接失败🔗~',
                duration: 3000,
                location: 'bottom'
            });
        }
    });

}
RongCloud.prototype.stopVideo = function () {
    var that = this
    api.stopPlay();
    clearInterval(that.timer)
}
RongCloud.prototype.startVideo = function () {
    var that = this
    api.startPlay({
        path: 'widget://image/chat/voice.amr' //声音放在call文件夹里面,如果要改位置,注意这里也要更改
    }, function (ret, err) { });
    that.timer = setInterval(function () {
        api.startPlay({
            path: 'widget://image/chat/voice.amr' //声音放在call文件夹里面,如果要改位置,注意这里也要更改
        }, function (ret, err) { });
    }, 5000)
}

RongCloud.prototype.removeConversation = function (targetId, winName, functionName) {
    var that = this;
    that.rong.removeConversation({
        conversationType: 'PRIVATE',
        targetId: targetId
    }, function (ret, err) {
        api.execScript({
            name: winName,
            script: 'vm.' + functionName + '('+ JSON.stringify(ret) +')'
        });
    });
}
RongCloud.prototype.init = function (callback) {
    var that = this;
    that.rong.init({}, function (ret, err) {
        if (ret.status == 'success') {
            that.rong.setConnectionStatusListener(function (ret, err) {
                mineAlert(statusDesc[ret.result.connectionStatus])
            });
            that.setCallListener()
            apiAddEventListener('removeConversation', function (ret, err) {
                that.removeConversation(ret.value.targetId, ret.value.winName, ret.value.functionName)
            });
            apiAddEventListener('pause', function (ret, err) {
                that.appReception = true
            });
            apiAddEventListener('resume', function (ret, err) {
                that.appReception = false
            });
            apiAddEventListener('setNowTargetId', function (ret, err) {
                if (ret.value.targetId) {
                    that.nowTargetId = ret.value.targetId
                } else {
                    that.nowTargetId = ''
                }
            });
            apiAddEventListener('startVideo', function (ret, err) {
                that.startVideo()
            });
            apiAddEventListener('stopVideo', function (ret, err) {
                that.stopVideo()
            });
            apiAddEventListener('noticeclicked', function (ret, err) {
                if (ret.value) {
                    var value = JSON.parse(ret.value);
                    if (ret.type == 0) {
                        newOpenWindow(pageUrl.chat, {
                            targetId: value.message.targetId
                        })
                        //APICloud推送内容
                    } else if (ret.type == 1) {
                        newOpenWindow(pageUrl.chat, {
                            targetId: value.message ? value.message.targetId : value.targetId
                        })
                        //开发者自定义消息
                    }
                }
            });
            that.rong.setOnReceiveMessageListener(function (ret) {
                apiSendEvent('receiveMessage', ret.result)
                if ((ret.result.message.targetId == that.nowTargetId) && that.appReception) {
                    that.setMessageReceivedStatus({
                        messageId: ret.result.message.messageId,
                        receivedStatus: 'READ'
                    }, function () {
                        apiSendEvent('getConversationList')
                    })
                } else {
                    apiSendEvent('notificationYN', ret.result)
                    apiSendEvent('getConversationList')
                }
                // console.log(JSON.stringify(ret))
            });
            apiAddEventListener('notificationYN', function (ret) {
                api.notification();
                api.notification({
                    notify: {
                        title: '湃安心理',
                        content: ret.value.message.objectName == 'RC:TxtMsg' ? ret.value.message.content.text : ('您有一条' + that.messageType[ret.value.message.objectName] + '消息'),
                        extra: ret.value
                    }
                });
            })
        }
        callback(ret, err)
    });
}
RongCloud.prototype.setCallListener = function () {
    var that = this;
    //收到来电的事件
    that.rong.addCallReceiveListener({
        target: 'didReceiveCall'
    }, function (ret, err) {
        var callId = ret.callSession.callId;
        var uid = ret.callSession.targetId;
        // //这里就是进入视频界面,uid、callId在这里不需要更改。callStatus是按钮状态,3表示来电显示。
        newOpenWindow(pageUrl.showVideo, {
            uid: uid,
            callId: callId,
            callStatus: 3,
            mediaType: ret.callSession.mediaType
        })
        console.log('来电' + JSON.stringify(ret))
        //播放声音
        api.startPlay({
            path: 'widget://image/chat/voice.amr' //声音放在call文件夹里面,如果要改位置,注意这里也要更改
        }, function (ret, err) { });
        that.timer = setInterval(function () {
            api.startPlay({
                path: 'widget://image/chat/voice.amr' //声音放在call文件夹里面,如果要改位置,注意这里也要更改
            }, function (ret, err) { });
        }, 5000)
    });

    // //通话已接通的事件
    that.rong.addCallSessionListener({
        target: 'didConnect'
    }, function (ret) {
        console.log('通话已接通的事件' + JSON.stringify(ret))
        //关闭声音
        api.stopPlay();
        clearInterval(that.timer)
    });

    // //对端用户加入了通话的事件
    that.rong.addCallSessionListener({
        target: 'remoteUserDidJoin'
    }, function (ret) {
        console.log('对端用户加入了通话的事件' + JSON.stringify(ret))
        that.rong.getCallSession(function (ret) {
            console.log('对话信息' + JSON.stringify(ret))
            apiSendEvent('myRemoteUserDidJoin', ret)
            //电话接通执行的代码放在这里,不能放到上面的didConnect里面。
            // api.execScript({
            //     name: 'showVideo_win',
            //     frameName: 'showVideo_frm',
            //     script: 'window.rootVue.setCallStatus('+2+');'  //showVideo_win页面也在call文件夹里,这里更改callStatus为2,即接通
            // });
            //callerUserId 拨打电话的用户ID
            //selfUserId  自己的ID
            //targetId    对方的ID
            // api.execScript({
            //     name: 'showVideo_win',
            //     script: 'window.rootVue.showVideo("'+ret.selfUserId+'","'+ret.targetId+'");'  //这里的selfUserId和targetId也不要动,就这么写。
            // });
            //重新打开showVideo_frm,将按钮的frame提到video的前面来
            // api.execScript({
            //     name: 'showVideo_win',
            //     script: 'openFram();'
            // });
        });
        //关闭声音
        api.stopPlay();
        clearInterval(that.timer)
    });
    // //对端用户正在振铃的事件
    that.rong.addCallSessionListener({
        target: 'remoteUserDidRing'
    }, function (ret) {
        console.log('对端用户正在振铃的事件' + JSON.stringify(ret))
    });
    // //对端用户切换了媒体类型的事件
    that.rong.addCallSessionListener({
        target: 'remoteUserDidChangeMediaType'
    }, function (ret) {
        console.log('对端用户切换了媒体类型的事件' + JSON.stringify(ret))
    });
    // //对端用户开启或关闭了摄像头的状态的事件
    that.rong.addCallSessionListener({
        target: 'remoteUserDidDisableCamera'
    }, function (ret) {
        console.log('对端用户开启或关闭了摄像头的状态的事件' + JSON.stringify(ret))
    });
    // //通话已结束的事件
    that.rong.addCallSessionListener({
        target: 'didDisconnect'
    }, function (ret) {
        console.log('通话已结束的事件' + JSON.stringify(ret))
        api.stopPlay();
        clearInterval(that.timer)
        apiSendEvent('didDisconnect', {
            targetId: ret.userId,
            messageDirection: ret.callerUserId == ret.userId ? 'RECEIVE' : 'SEND',
            objectName: 'RC:VSTMsg',
            sentTime: new Date().getTime(),
            content: {
                activeTime: ret.startTime,
                endTime: ret.endTime,
                hangupReason: ret.disConnectReason,
                mediaType: ret.mediaType,
            }
        })
        api.closeWin({
            name: 'showVideo'
        });
        mineAlert(disConnectReasonDesc[ret.disConnectReason])
    });
    //对端用户挂断
    that.rong.addCallSessionListener({
        target: 'remoteUserDidLeft'
    }, function (ret) {
        console.log('对端用户挂断' + JSON.stringify(ret))
        api.stopPlay();
        clearInterval(that.timer)
        api.closeWin({
            name: 'showVideo'
        });
        mineAlert(disConnectReasonDesc[ret.disConnectReason])

    });
}
////////////////////////////视频语音 监听/////////////////////////////
RongCloud.prototype.connect = function (token, callback) {
    var that = this;
    that.rong.connect({
        token: token
    }, function (ret, err) {

        callback(ret, err)
    });
}

RongCloud.prototype.startCall = function (params, callback) {
    var that = this;
    newHasPermission('该功能需要您授权麦克风和相机权限', [{
        name: 'microphone',
        failDesc: '授权麦克风权限失败'
    }, {
        name: 'camera',
        failDesc: '授权相机权限失败'
    }], function () {
        that.rong.startCall(params, function (ret, err) {
            // api.startPlay({
            //     path: 'widget://image/chat/voice.amr' //声音放在call文件夹里面,如果要改位置,注意这里也要更改
            // }, function (ret, err) {});
            // that.timer = setInterval(function () {
            //     api.startPlay({
            //         path: 'widget://image/chat/voice.amr' //声音放在call文件夹里面,如果要改位置,注意这里也要更改
            //     }, function (ret, err) {});
            // }, 5000)
            callback(ret, err)
        });
    })

}
RongCloud.prototype.setVideoView = function (params) {
    var that = this;
    if (!params.rect) {
        params.rect = {
            x: 0,
            y: 0,
            w: api.winWidth,
            h: api.winHeight
        }
    }
    if (!params.userId) {
        mineAlert("缺少打开视频对象")
        return false
    }
    that.rong.setVideoView({
        rect: params.rect,
        userId: params.userId,
        bg: '#ff0000',
        renderModel: 'hidden',
        fixedOn: api.frameName,
        fixed: true
    });
}
RongCloud.prototype.accept = function (params) {
    var that = this;
    newHasPermission('该功能需要您授权麦克风和相机权限', [{
        name: 'microphone',
        failDesc: '授权麦克风权限失败'
    }, {
        name: 'camera',
        failDesc: '授权相机权限失败'
    }], function () {
        params.mediaType ? '' : (params.mediaType = 'video');
        that.rong.accept(params);
    })

}
RongCloud.prototype.hangup = function () {
    var that = this;
    that.rong.hangup();
    that.stopVideo()
}
RongCloud.prototype.getConversationList = function (callback) {
    var that = this;
    that.rong.getConversationList(function (ret, err) {
        callback(ret)
    })
}

RongCloud.prototype.setMessageReceivedStatus = function (params, callback) {
    var that = this;
    params.conversationType = 'PRIVATE'
    that.rong.setMessageReceivedStatus(params, function (ret, err) {
        callback(ret)
    })
}
RongCloud.prototype.clearMessagesUnreadStatus = function (params, callback) {
    var that = this;
    params.conversationType = 'PRIVATE'
    that.rong.clearMessagesUnreadStatus(params, function (ret, err) {
        callback(ret)
    })
}
RongCloud.prototype.sendTextMessage = function (params, callback) {
    var that = this;
    // PRIVATE (单聊)
    // DISCUSSION (讨论组)
    // GROUP (群组)
    // CHATROOM(聊天室)
    // CUSTOMER_SERVICE (客服)
    // SYSTEM (系统)
    params.conversationType = 'PRIVATE'
    if (!params.targetId) {
        mineAlert("缺少发送对象")
        return false
    }
    if (!params.text) {
        mineAlert("请输入要发送的内容")
        return false
    }
    that.rong.sendTextMessage(params, callback)
}

RongCloud.prototype.sendVoiceMessage = function (params, callback) {
    var that = this;

    params.conversationType = 'PRIVATE'
    if (!params.targetId) {
        mineAlert("缺少发送对象")
        return false
    }
    if (!params.voicePath) {
        mineAlert("缺少发送内容")
        return false
    }
    // conversationType: 'PRIVATE',
    // targetId: '9527',
    // oldestMessageId: 688,
    // count: 20
    that.rong.sendVoiceMessage(params, callback)
}
RongCloud.prototype.sendImageMessage = function (params, callback) {
    var that = this;

    params.conversationType = 'PRIVATE'
    if (!params.targetId) {
        mineAlert("缺少发送对象")
        return false
    }
    if (!params.imagePath) {
        mineAlert("缺少发送内容")
        return false
    }
    // function(ret, err) {
    //     if (ret.status == 'prepare')
    //         api.toast({ msg: JSON.stringify(ret.result.message) });
    //     else if (ret.status == 'progress')
    //         api.toast({ msg: ret.result.progress });
    //     else if (ret.status == 'success')
    //         api.toast({ msg: ret.result.message.messageId });
    //     else if (ret.status == 'error')
    //         api.toast({ msg: err.code });
    // }
    that.rong.sendImageMessage(params, callback);
}
RongCloud.prototype.sendSightMessage = function (params, callback) {
    var that = this;

    params.conversationType = 'PRIVATE'
    if (!params.targetId) {
        mineAlert("缺少发送对象")
        return false
    }
    if (!params.sightPath) {
        mineAlert("缺少发送内容")
        return false
    }
    // conversationType: 'PRIVATE',
    // targetId: '9527',
    // thumbPath: 'fs:///xxx/xxx/picture.jpg',
    // sightPath:'',
    // duration: 10, 
    // extra: ''
    // function(ret, err) {
    //     if (ret.status == 'prepare')
    //         api.toast({ msg: JSON.stringify(ret.result.message) });
    //     else if (ret.status == 'progress')
    //         api.toast({ msg: ret.result.progress });
    //     else if (ret.status == 'success')
    //         api.toast({ msg: ret.result.message.messageId });
    //     else if (ret.status == 'error')
    //         api.toast({ msg: err.code });
    // }
    that.rong.sendSightMessage(params, callback);
}
RongCloud.prototype.getHistoryMessages = function (params, callback) {
    var that = this;
    params.conversationType = 'PRIVATE'
    if (!params.targetId) {
        mineAlert("缺少发送对象")
        return false
    }
    that.rong.getHistoryMessages(params, callback);
}
RongCloud.prototype.getConnectionStatus = function (callback) {
    this.rong.getConnectionStatus(callback);
}
RongCloud.prototype.getUnreadCount = function (params, callback) {
    params.conversationType = 'PRIVATE'
    this.rong.getUnreadCount(params, callback);
}
RongCloud.prototype.setMuted = function (muted) {
    var that = this;
    that.rong.setMuted({
        muted: muted
    }, function (ret) { })
}
RongCloud.prototype.setSpeakerEnabled = function (speakerEnabled) {
    var that = this;
    that.rong.setSpeakerEnabled({
        speakerEnabled: speakerEnabled
    }, function (ret) {

    })
}

RongCloud.prototype.logout = function (callback) {
    var that = this;
    that.rong.logout(function (ret, err) {
        callback(ret)
    })
}






function encodeUTF8(s) {
    var i, r = [],
        c, x;
    for (i = 0; i < s.length; i++)
        if ((c = s.charCodeAt(i)) < 0x80) r.push(c);
        else if (c < 0x800) r.push(0xC0 + (c >> 6 & 0x1F), 0x80 + (c & 0x3F));
        else {
            if ((x = c ^ 0xD800) >> 10 == 0) //对四字节UTF-16转换为Unicode
                c = (x << 10) + (s.charCodeAt(++i) ^ 0xDC00) + 0x10000,
                    r.push(0xF0 + (c >> 18 & 0x7), 0x80 + (c >> 12 & 0x3F));
            else r.push(0xE0 + (c >> 12 & 0xF));
            r.push(0x80 + (c >> 6 & 0x3F), 0x80 + (c & 0x3F));
        };
    return r;
}
// 字符串加密成 hex 字符串
function sha1(s) {
    var data = new Uint8Array(encodeUTF8(s))
    var i, j, t;
    var l = ((data.length + 8) >>> 6 << 4) + 16,
        s = new Uint8Array(l << 2);
    s.set(new Uint8Array(data.buffer)), s = new Uint32Array(s.buffer);
    for (t = new DataView(s.buffer), i = 0; i < l; i++) s[i] = t.getUint32(i << 2);
    s[data.length >> 2] |= 0x80 << (24 - (data.length & 3) * 8);
    s[l - 1] = data.length << 3;
    var w = [],
        f = [
            function () {
                return m[1] & m[2] | ~m[1] & m[3];
            },
            function () {
                return m[1] ^ m[2] ^ m[3];
            },
            function () {
                return m[1] & m[2] | m[1] & m[3] | m[2] & m[3];
            },
            function () {
                return m[1] ^ m[2] ^ m[3];
            }
        ],
        rol = function (n, c) {
            return n << c | n >>> (32 - c);
        },
        k = [1518500249, 1859775393, -1894007588, -899497514],
        m = [1732584193, -271733879, null, null, -1009589776];
    m[2] = ~m[0], m[3] = ~m[1];
    for (i = 0; i < s.length; i += 16) {
        var o = m.slice(0);
        for (j = 0; j < 80; j++)
            w[j] = j < 16 ? s[i + j] : rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1),
                t = rol(m[0], 5) + f[j / 20 | 0]() + m[4] + w[j] + k[j / 20 | 0] | 0,
                m[1] = rol(m[1], 30), m.pop(), m.unshift(t);
        for (j = 0; j < 5; j++) m[j] = m[j] + o[j] | 0;
    };
    t = new DataView(new Uint32Array(m).buffer);
    for (var i = 0; i < 5; i++) m[i] = t.getUint32(i << 2);

    var hex = Array.prototype.map.call(new Uint8Array(new Uint32Array(m).buffer), function (e) {
        return (e < 16 ? "0" : "") + e.toString(16);
    }).join("");
    return hex;
}
vm.rong.login(用户的唯一标识, 用户姓名, 用户头像,
    function (res) {
        if (res.code == 200 && res.token) {
            var token = res.token
            apiAddEventListener('rongLogout', function (ret) {
                vm.rong.logout(function (ret) {

                })
            });
            vm.rong.init(function (ret, err) {
                vm.rong.connect(token, function (ret, err) {
                    if (ret.status == 'success') {
                        onlineAndOffline(1, function () {

                        })
                        apiSendEvent('getConversationList'); // 重新登录后刷新消息菜单的列表
                        // apiAddEventListener('setConversationList', function (ret) {
                        //     vm.rong.getConversationList(function (ret) {
                        //         apiSendEvent('getConversationList', ret);
                        //     })
                        // });
                        // apiAddEventListener('setHistoryMessages', function (ret) {
                        //     vm.rong.getHistoryMessages(ret.value,function (ret) {
                        //         apiSendEvent('getHistoryMessages', ret);
                        //     })
                        // });
                    } else {
                        mineAlert("通讯登录错误,请重新登录")
                    }
                })
            })
        } else {
            mineAlert("通讯链接失败🔗")
        }
    }
)

这里聊天界面

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport"
        content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0" />
    <meta name="format-detection" content="telephone=no,email=no,date=no,address=no">
    <title></title>
    <link rel="stylesheet" type="text/css" href="../../css/aui.css" />
    <link rel="stylesheet" type="text/css" href="../../css/common.css" />
    <link rel="stylesheet" type="text/css" href="../../css/aui-flex.css" />
    <link rel="stylesheet" type="text/css" href="../../css/index.css" />
    <style>
        html,
        body {
            background: #EBEBEB;
        }

        input,
        textarea {
            /* -webkit-user-select: auto; */
            /*webkit浏览器*/
            /* margin: 0px;
            padding: 0px;
            outline: none; */
        }

        .emoji:active {
            background: rgba(0, 0, 0, 0.09);
        }

        .backgroundR {
            background: rgba(0, 0, 0, 0.09);
        }

        .aui-chat .aui-chat-content {
            color: #444
        }

        .aui-chat .aui-chat-left .aui-chat-content {
            background-color: #fff;
        }

        .aui-chat .aui-chat-left .aui-chat-arrow {
            background: #fff !important;
        }

        .aui-chat .aui-chat-right .aui-chat-content {
            background-color: #4070FF;
            color: #fff
        }

        .aui-chat .aui-chat-right .aui-chat-arrow {
            background: #4070FF !important;
        }

        .van-image {
            display: flex;
            align-content: flex-start;
        }
    </style>
</head>

<body>
    <div v-cloak id="app">
        <van-overlay :custom-style="{'height':'calc( 100vh - ' + keyboardHeight + 'px )'}" :show="recordingStatus">

        </van-overlay>
        <div @touchstart="emojiShow = false;addShow = false;recordStatus = false;blur()"
            :style="{'height': '100vh','overflow':(chatBoxStatus ? 'hidden' : 'auto')}" id="chatBox">
            <!-- translateStatus &&  -->
            <div :style="{'transform': 'translateY('+ (((emojiShow || recordStatus || focusStatus || addShow)) ? -keyboardHeight : 0) +'px)'}"
                id="chat" class="box_relative">
                <van-pull-refresh pulling-text="下拉查看更多历史记录..." loosing-text="释放即可加载..." v-model="isLoading"
                    @refresh="onRefresh">
                    <section id="chat1" @click="emojiShow = false;addShow = false" class="aui-chat">
                        <div v-if="showTop">
                            <div
                                class="aui-margin-t-10 aui-margin-b-10 aui-chat-header aui-flex-col aui-flex-center aui-flex-middle">
                                <div class=" color_999 aui-font-size-13 aui-padded-l-5 aui-padded-r-5">
                                    ~没有更多历史消息了~
                                </div>
                            </div>
                        </div>
                        <template :key="index" v-for="(item,index) in messagesList">
                            <div>
                                <div class="aui-chat-header aui-flex-col aui-flex-center aui-flex-middle">
                                    <div class="bg_CCC color_fff aui-font-size-13 aui-padded-l-5 aui-padded-r-5"
                                        style="border-radius: 0.21rem;">
                                        {{dateFtt1(item.sentTime)}}
                                    </div>
                                </div>
                            </div>
                            <div
                                :class="['aui-chat-item', item.messageDirection == 'RECEIVE' ? 'aui-chat-left' : 'aui-chat-right']">
                                <div class="aui-chat-media">
                                    <van-image round width="2rem" height='2rem' fit="cover"
                                        :src="item.messageDirection == 'RECEIVE' ? otherInfo.headPortrait : userInfo.headPortrait">
                                    </van-image>
                                </div>
                                <div class="aui-chat-inner">
                                    <div class="aui-chat-name">{{item.messageDirection == 'RECEIVE' ? otherInfo.nickName : userInfo.name}}</div>
                                    <div class="aui-chat-content">
                                        <div :style="item.objectName == 'RC:VSTMsg' ? 'width:auto':''"
                                            class="aui-chat-arrow"></div>
                                        <template v-if="item.objectName == 'RC:TxtMsg'">
                                            <template
                                                v-if="item.content.extra && stringifyParse(item.content.extra).type && stringifyParse(item.content.extra).type == 'call'">
                                                <div @click="startCall" style="flex-wrap: nowrap;"
                                                    class="aui-flex-col aui-flex-middle">
                                                    <img style="width: 0.85rem;" class="aui-margin-r-5"
                                                        :src=" item.messageDirection == 'RECEIVE' ? '../../image/chat/callyou.png' : '../../image/chat/callme.png'" />
                                                    <div></div>
                                                    {{item.content ?
                                                    item.content.text : ''}}
                                                </div>
                                            </template>
                                            <div v-else>
                                                {{item.content ?
                                                item.content.text : ''}}
                                            </div>
                                        </template>
                                        <template v-else-if="item.objectName == 'RC:VSTMsg'">
                                            <div @click="startCall" style="flex-wrap: nowrap;"
                                                class="aui-flex-col aui-flex-middle">
                                                <img style="width: 0.85rem;" class="aui-margin-r-5"
                                                    :src=" item.messageDirection == 'RECEIVE' ? '../../image/chat/callyou.png' : '../../image/chat/callme.png'" />
                                                <div style="white-space: nowrap;"
                                                    v-if="item.content.hangupReason != 11 && item.content.activeTime != 0 && item.content.endTime != 0">
                                                    通话结束{{date_format(item.content.endTime - item.content.activeTime)}}
                                                </div>
                                                <div v-else>
                                                    {{disConnectReasonDesc[item.content.hangupReason]}}
                                                </div>
                                            </div>

                                        </template>
                                        <template v-else-if="item.objectName == 'RC:ImgMsg'">
                                            <div class="box_relative">
                                                <div v-if="item.progress && (item.progress != 100 || item.fail == 1)"
                                                    class="box_absolute aui-flex-col aui-flex-middle aui-font-size-14 color_fff aui-flex-center"
                                                    style="z-index:100;left: 0;width: 100%;top: 0;height: 100%;background: rgba(0, 0, 0, 0.39);">
                                                    {{item.progress}}%
                                                </div>
                                                <van-image @click="chatPhoto(index)" fit="cover"
                                                    :src="item.content ? item.content.imageUrl : ''">
                                                </van-image>
                                            </div>

                                        </template>
                                        <template v-if="item.objectName == 'RC:VcMsg'">
                                            <div class="aui-flex-col aui-flex-middle aui-flex-center"
                                                @click="startPlay(index,item.content.voicePath)">
                                                <img style="width: 1.2rem;" class="aui-margin-r-5"
                                                    :src="item.start ? '../../image/chat/playing.gif' : item.messageDirection == 'RECEIVE' ? '../../image/chat/stop.png' : '../../image/chat/myS.png'" />
                                                {{item.content ? item.content.duration : ''}}s
                                            </div>
                                        </template>
                                    </div>
                                    <div v-if="item.fail == 1" class="aui-chat-status">
                                        <i class="aui-iconfont aui-icon-info aui-text-danger"></i>
                                    </div>
                                    <div v-if="item.loading == 1" class="aui-chat-status">
                                        <van-loading size="0.78rem"></van-loading>
                                    </div>
                                </div>
                            </div>
                        </template>
                        <!-- "{'height': 'calc( 5rem + ' + ((emojiShow) ? keyboardHeight : 0 ) + 'px )'}" -->
                        <div class="aui-chat-item aui-font-size-15" :style="{'height': 'calc( 5rem )'}">
                        </div>


                    </section>
                </van-pull-refresh>

            </div>
            <!--   -->
        </div>
        <footer @touchstart="chatBoxStatus = true" @touchmove="touchmove" @touchend="chatBoxStatus = false" id="textBox"
            ref="footer" style="bottom: 0;left: 0;width: 100%;" class="bg_EBEBEB box_fixed footer">
            <div class="aui-flex-col aui-flex-between aui-padded-r-10 aui-padded-l-10 aui-flex-middle"
                style="flex-wrap: nowrap;border-top: 1px solid #e2e2e2;border-bottom: 1px solid #e2e2e2;">
                <div @click="recordStatus = !recordStatus">
                    <img style="width: 1.36rem;"
                        :src="recordStatus ? '../../image/chat/auido_acitve.png' : '../../image/chat/audio.png'" />
                </div>
                <div class="aui-flex-col aui-flex-auto aui-padded-10">
                    <div class="bg_F5F5F5 aui-padded-10" style="border-radius: 0.32rem;width: 100%;height:100%;">
                        <textarea @click="showList = [0,current];emojiShow = false" @blur="blur" @focus="focus"
                            ref="textarea" v-model="content" id="textarea" class="message"
                            style="height: 1.5em;"></textarea>
                    </div>
                </div>
                <div style="flex-wrap: nowrap;" class="aui-flex-col aui-flex-middle">
                    <div class="aui-flex-col aui-flex-middle"
                        @click="setTimeout(function(){emojiShow = !emojiShow},10) ">
                        <img style="width: 1.36rem;"
                            :src="emojiShow ? '../../image/chat/expression_active.png' : '../../image/chat/expression.png'" />
                    </div>
                    <div class="aui-flex-auto" v-if="content">
                        <van-button @click="sendTextMessage" class="aui-margin-l-10"
                            style="height:1.496rem;width: auto;" block :color="themeColor" type="primary">
                            <span class="aui-font-size-15 color_fff ">发送</span>
                        </van-button>
                    </div>
                    <div v-else @click="setTimeout(function(){addShow = !addShow},10) "
                        class="aui-flex-col aui-flex-middle aui-padded-l-10">
                        <img style="width: 1.36rem;"
                            :src="addShow ? '../../image/chat/add_active.png' : '../../image/chat/add.png'" />
                    </div>
                </div>
            </div>
            <!-- <transition name="van-slide-up"> -->
            <div :style="'height:calc(' + keyboardHeight + 'px );'" v-show="recordStatus">
                <div class="aui-flex-col aui-padded-30">
                    <div class="aui-flex-row aui-flex-middle aui-flex-center" style="margin-top: 10%;width: 100%;">
                        <div class="aui-text-center aui-margin-b-10 aui-font-size-14 color_666">{{recordingStatus ?
                            '释放发送' : '按住说话'}}</div>
                        <div :class="recordingStatus ? 'backgroundR' : 'bg_fff'" @touchstart="startRecord"
                            @touchend="stopRecord(sendRecord)"
                            class="aui-shadow aui-flex-col aui-flex-middle aui-flex-center"
                            style="height: 4.2rem;width: 4.2rem;border-radius: 50%;">
                            <img style="width: 60%;" src="../../image/record.png" />
                        </div>
                    </div>
                </div>
            </div>
            <div :style="'height:calc(' + keyboardHeight + 'px );'" v-show="addShow">
                <div class="aui-flex-col aui-padded-30">
                    <div @click="selectPic1(1,sendImage)" style="width: 3.4rem;height:3.4rem;border-radius: 0.45rem;"
                        class="aui-margin-r-15 emoji aui-flex-col aui-flex-center aui-flex-middle bg_fff">
                        <img style="width: 56%;" src="../../image/crame.png" />
                    </div>
                    <div @click="selectPic1(2,sendImage,3)" style="width: 3.4rem;height:3.4rem;border-radius: 0.45rem;"
                        class="emoji aui-margin-r-15  aui-flex-col aui-flex-center aui-flex-middle bg_fff">
                        <img style="width: 56%;" src="../../image/photo2.png" />
                    </div>
                    <!-- <div @click="startCall" style="width: 3.4rem;height:3.4rem;border-radius: 0.45rem;"
                        class="emoji aui-flex-col aui-flex-center aui-flex-middle bg_fff">
                        <img style="width: 56%;" src="../../image/videoPlay.png" />
                    </div> -->
                </div>
            </div>

            <!-- </transition> -->

            <!-- <transition name="van-slide-up"> -->

            <div id="emojiBox1" ref="emojiBox" @click="stop" class="">
                <van-swipe :touchable="touchable" v-show="emojiShow" ref="swipe" @change="onChange">
                    <template v-for="(item,index) in emojiconfig" :key="index">
                        <van-swipe-item :style="'height:calc(' + keyboardHeight + 'px - 1.96rem);overflow: scroll;'"
                            class="content">
                            <template v-if="showList.indexOf(index) != -1">
                                <div style="line-height: 2.2rem;font-size: 1.25rem;"
                                    class="aui-text-center aui-flex-col">
                                    <div :value="items" class="emoji" style="width: 12.5%;height: 2.2rem"
                                        v-for="(items,i) in item.alias">
                                        {{items}}
                                    </div>
                                </div>
                            </template>
                        </van-swipe-item>
                    </template>
                    <template slot="indicator">
                        <div id="myTab" style="flex-wrap: nowrap;overflow-y: scroll;" class="aui-flex-col">
                            <div :key="index" v-for="(item,index) in emojiconfig">
                                <van-button :class="'tab' + index" style="height:1.96rem" @click="current = index"
                                    :color="current == index ? themeColor : ''" type="default">
                                    {{item.name}}</van-button>
                            </div>
                        </div>
                    </template>
                </van-swipe>
            </div>
            <!-- </transition> -->
        </footer>
    </div>

</body>
<script type="text/javascript" src="../../script/api.js"></script>
<script type="text/javascript" src="../../script/vue.js"></script>
<script type="text/javascript" src="../../script/jq.js"></script>
<script type="text/javascript" src="../../script/common.js"></script>
<script type="text/javascript" src="../../script/component.js"></script>
<script type="text/javascript" src="../../script/vant.min.js"></script>
<script type="text/javascript" src="../../script/js/emojisort.js"></script>
<script type="text/javascript" src="../../script/js/textarea.js"></script>
<script type="text/javascript" src="../../script/rongcloud.js"></script>
<script type="text/javascript">
    if (!HTMLElement.prototype.addTapEvent) {
        HTMLElement.prototype.addTapEvent = function (callback) {
            var tapStartTime = 0,
                tapEndTime = 0,
                tapTime = 250, //tap等待时间,在此事件下松开可触发方法
                tapStartClientX = 0,
                tapStartClientY = 0,
                tapEndClientX = 0,
                tapEndClientY = 0,
                tapScollHeight = 0, //水平或垂直方向移动超过15px测判定为取消(根据chrome浏览器默认的判断取消点击的移动量)
                cancleClick = false;
            this.addEventListener('touchstart', function (event) {
                tapStartTime = event.timeStamp;
                var touch = event.changedTouches[0];
                tapStartClientX = touch.clientX;
                tapStartClientY = touch.clientY;
                cancleClick = false;
            })
            this.addEventListener('touchmove', function () {
                var touch = event.changedTouches[0];
                tapEndClientX = touch.clientX;
                tapEndClientY = touch.clientY;
                if ((Math.abs(tapEndClientX - tapStartClientX) > tapScollHeight) || (Math.abs(tapEndClientY - tapStartClientY) > tapScollHeight)) {
                    cancleClick = true;
                }
            })
            this.addEventListener('touchend', function (event) {
                tapEndTime = event.timeStamp;
                if (!cancleClick && (tapEndTime - tapStartTime) <= tapTime) {
                    callback(event);
                }
            })
        }
    }
    var emojiconfigElement = []
    for (var key in emojiconfig) {
        emojiconfigElement.push(emojiconfig[key])
    }

    var innerHeight = window.innerHeight
    var vm = new Vue({
        el: "#app",
        data: function () {
            return {
                showTop: false,
                rong: null,
                targetId: "",
                count: 8,
                messagesList: [],
                content: "",
                textareaHeight: 0,
                footHeight: 0,
                keyboardHeight: 346,
                textBoxRect: {},
                emojiShow: false,
                emojiconfig: emojiconfigElement,
                current: 0,
                showList: [0],
                touchable: true,
                textBoxRect: {},
                textarea: null,
                focusStatus: false,
                addShow: false,
                chatBoxStatus: false,
                recordStatus: false,
                recordingStatus: false,
                isLoading: false,
                fontSize: null,
                translateStatus: true,
                userInfo:{},
                otherInfo:{}
            }
        },
        watch: {
            translateStatus: function (newValue) {
                console.log(newValue)
                if (!newValue) {
                    vm.$nextTick(function () {
                        chatBox.scrollTo(0, chat1.offsetHeight)
                    })
                }
            },
            current: function (newValue) {
                if (vm.showList.indexOf(newValue) == -1) {
                    vm.showList.push(newValue)
                }
                this.$refs.swipe.swipeTo(newValue)
                this.offsetLeft()
            },
            addShow: function (newValue) {
                if (newValue) {
                    vm.emojiShow = false
                    vm.recordStatus = false
                }
            },
            recordStatus: function (newValue) {
                if (newValue) {
                    vm.emojiShow = false
                    vm.addShow = false
                }
            },
            emojiShow: function (newValue) {
                // if(newValue)this.$refs.swipe.resize();
                this.$nextTick(function () {
                    if (newValue) {
                        vm.addShow = false
                        vm.recordStatus = false
                        vm.$refs.swipe.resize();
                        vm.$refs.swipe.swipeTo(vm.current)
                        vm.offsetLeft()
                        // window.scrollTo(0, window.scrollY + vm.keyboardHeight + vm.footHeight)
                        console.log(window.scrollY)
                        console.log(vm.keyboardHeight, vm.footHeight)
                    } else {
                        if (window.scrollY + innerHeight < chat.offsetHeight) {
                            // window.scrollTo(0, window.scrollY - (vm.keyboardHeight + vm.footHeight))
                        }

                    }

                })
            },
            footHeight: {
                handler: function () {
                    this.$nextTick(function () {
                        // vm.textareaHeight = this.$refs.footer.offsetHeight
                    })
                },
                // 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法
                immediate: true
            },
            keyboardHeight: function (newValue) {
            }
        },
        mixins: [mix],
        mounted: function () {
            // this.$nextTick(function () {
            //     vm.init()
            // })
        },
        methods: {
            chatPhoto(index) {
                var imageUrlList = []
                var findIndex = 0
                vm.messagesList.forEach(function (ele, i) {
                    if (ele.objectName == 'RC:ImgMsg') {
                        imageUrlList.push(vm.messagesList[i].content.imageUrl)
                    }
                })
                findIndex = imageUrlList.findIndex(function (ele) {
                    return ele == vm.messagesList[index].content.imageUrl
                })
                photoBrowser(imageUrlList, findIndex)
            },
            startRecord: function () {
            // 自定义申请权限的方法
                hasPermission('发送语音消息需要使用麦克风录制音频权限', 'microphone', function (flag) {
                    if (flag) {
                        vm.recordingStatus = true
                        var savePath = 'fs://paxl_' + (+new Date()) + '.amr';
                        api.startRecord({
                            path: savePath
                        });
                    }
                })
                // api.notification();

            },
            startPlay(index, voicePath) {
                vm.messagesList.forEach(function (ele) {
                    if (ele.start) {
                        Vue.set(ele, 'start', false)
                    }
                })
                api.stopPlay()
                vm.messagesList[index].start = true
                Vue.set(vm.messagesList, index, vm.messagesList[index])
                api.startPlay({
                    path: voicePath
                }, function (ret, err) {
                    if (ret) {
                        vm.messagesList[index].start = false
                        Vue.set(vm.messagesList, index, vm.messagesList[index])
                    } else {
                        mineAlert("播放失败")
                    }
                });
            },
            sendRecord: function (ret, err) {
                if (ret.duration <= 1) {
                    mineAlert("按键时间太短")
                    return false
                }
                vm.sendVoiceMessage({ duration: ret.duration, voicePath: ret.path })
                return false
            },
            stopRecord: function (callback) {
                vm.recordingStatus = false
                api.stopRecord(callback);
            },
            touchmove: function () {
                // event.preventDefault()
                event.stopPropagation()
                // console.log(event.target)
                // chat.style.overflow="hidden"
                // event.cancelBubble()

            },
            insertText: function (val) {
                var textarea = this.$refs.textarea
                var str = val;
                var startPos;
                var endPos;
                if (document.selection) {
                    var sel = document.selection.createRange();
                    sel.text = str;
                } else if (typeof textarea.selectionStart === 'number' && typeof textarea.selectionEnd === 'number') {
                    startPos = textarea.selectionStart;
                    endPos = textarea.selectionEnd;
                    var tmpStr = textarea.value;
                    textarea.value = tmpStr.substring(0, startPos) + str + tmpStr.substring(endPos, tmpStr.length);
                } else {
                    textarea.value += str;
                }
                textarea.focus();
                this.content = textarea.value
                if (api.systemType != "ios") {
                    textarea.focus();
                    textarea.selectionStart = startPos + str.length;
                    textarea.selectionEnd = endPos + str.length;
                    textarea.blur();
                }
            },
            onChange(index) {
                this.current = index;
            },
            offsetLeft: function () {
                let offsetLeft = 0
                if (this.emojiconfig.length / 2 + 1 >= this.current) {
                    offsetLeft = $('.tab' + this.current)[0].offsetLeft - $('.tab1')[0].offsetLeft * 1.25
                } else {
                    offsetLeft = $('.tab' + this.current)[0].offsetLeft
                }
                $('#myTab').animate({ scrollLeft: (offsetLeft) }, 200);
            },
            stop: function (e) {
                if (api.systemType != "ios") {
                    let target = e.target ? e.target : e.srcElement
                    let value = target.getAttribute('value')
                    value && vm.insertText(value)
                }
            },
            focus: function () {
                vm.countKeyboardHeight()
                vm.$nextTick(function () {
                    vm.focusStatus = true
                    vm.addShow = false
                    vm.recordStatus = false
                    if (window.scrollY + innerHeight < chat.offsetHeight) {
                        // window.scrollTo(0, window.scrollY + vm.keyboardHeight + vm.footHeight)
                    }
                })
            },
            blur: function () {
                vm.$nextTick(function () {
                    this.$refs.textarea.blur()
                    vm.focusStatus = false
                    if (window.scrollY + innerHeight < chat.offsetHeight) {
                        // window.scrollTo(0, window.scrollY - (vm.keyboardHeight + vm.footHeight))
                    }
                })
            },
            toBottom() {
                setTimeout(function () {
                    vm.$nextTick(function () {
                        chatBox.scrollTo(0, chat1.offsetHeight)
                    })
                }, 300)

            },
            countKeyboardHeight: function () {
                vm.$nextTick(function () {

                    if (api.systemType == "ios") {
                        vm.$refs.emojiBox.addTapEvent(function (e) {
                            // console.log(event)
                            let target = e.target ? e.target : e.srcElement
                            let value = target.getAttribute('value')
                            value && vm.insertText(value)
                        })
                        vm.touchable = false
                        var textBoxRect = textBox.getBoundingClientRect()
                        if (vm.textBoxRect.y - textBoxRect.y > 0) {
                            vm.keyboardHeight = vm.textBoxRect.y - textBoxRect.y
                        }
                    }
                })
            },
            init: function () {
                var fontSize = parseInt(window.getComputedStyle(document.getElementsByTagName('html')[0]).fontSize)
                fontSize = (isNaN(fontSize) ? 20 : fontSize);
                vm.fontSize = fontSize
                autoTextarea(textarea, 0, fontSize * 3, function (height) {
                    vm.footHeight = height
                })
                vm.getHistoryMessages(function () {
                    vm.$nextTick(function () {
                        vm.toBottom()
                        if (api.systemType != "ios") {
                            const h = api.winHeight
                            window.onresize = function () { // 如果当前窗口小于一开始记录的窗口高度,那就让当前窗口等于一开始窗口的高度
                                var keyboardHeight = h - api.winHeight
                                if (keyboardHeight > 0) {
                                    setTimeout(function () {
                                        vm.keyboardHeight = keyboardHeight
                                    }, 0)
                                }
                            }
                        } else {
                            vm.textBoxRect = textBox.getBoundingClientRect()
                        }
                    })
                })
                chatBox.onscroll = function () {
                    var windowH = document.documentElement.clientHeight;
                    var documentH = chat1.offsetHeight;
                    var scrollH = chatBox.scrollTop;
                    console.log(windowH, documentH, scrollH)
                    if (windowH + scrollH >= documentH - 20) {
                        //do something
                        vm.translateStatus = false
                    } else {
                        vm.translateStatus = true
                    }
                }
                vm.clearMessagesUnreadStatus()
                // vm.getUnreadCount()
            },
            getUnreadCount() {
                // 统计当前聊天对象的所有未读消息
                var obj = {
                    targetId: vm.targetId,
                }
                vm.rong.getUnreadCount(obj, function (ret) {
                    // alert(JSON.stringify(ret))
                })
            },
            clearMessagesUnreadStatus() {
                // 清除当前聊天对象的所有未读消息
                var obj = {
                    targetId: vm.targetId,
                }
                vm.rong.clearMessagesUnreadStatus(obj, function (ret) {
                    // alert(JSON.stringify(ret))
                })
            },
            startCall() {
                return false
                var params = {
                    targetId: vm.targetId + '',
                    mediaType: 'video',
                    conversationType: 'PRIVATE',
                    userIdList: [vm.targetId + '']
                }
                vm.rong.startCall(params, function (ret) {
                    vm.sendTextMessage(1, "发起了视频通话", { type: 'call' })
                    apiSendEvent('startVideo')
                    newOpenWindow(pageUrl.showVideo, { uid: vm.targetId, callId: ret.callSession.callId, callStatus: 1, mediaType: params.mediaType })
                })
            },
            getHistoryMessages(callback) {
                var obj = {
                    targetId: vm.targetId,
                    oldestMessageId: vm.messagesList.length > 0 ? vm.messagesList[0].messageId : -1,
                    count: vm.count,
                }
                vm.rong.getHistoryMessages(obj, function (ret) {
                    if (ret.result) {
                        ret.result.reverse()
                        vm.messagesList = [].concat(ret.result, vm.messagesList)
                        console.log(JSON.stringify(vm.messagesList))
                    } else {
                        vm.showTop = true
                    }

                    if (!!callback) {
                        callback(ret)
                    }
                })
            },
            sendImage(ret) {
                if (typeof ret == "string") {
                    vm.sendImageMessage(ret)
                } else {
                    ret.forEach(function (element) {
                        vm.sendImageMessage(element)
                    });
                }
            },
            sendVoiceMessage(params) {
                var obj = {
                    targetId: vm.targetId,
                    voicePath: params.voicePath,
                    duration: params.duration,
                    extra: {
                    }
                }
                var length = 0
                vm.rong.sendVoiceMessage(obj, function (ret) {
                    // alert(JSON.stringify(ret.result))
                    var data = ret
                    switch (ret.status) {
                        case 'prepare':
                            data.result.message.loading = 1
                            vm.messagesList.push(data.result.message)
                            length = vm.messagesList.length
                            vm.toBottom()
                            break;
                        case 'progress':
                            vm.messagesList[length - 1].progress = ret.result.progress
                            break;
                        case 'success':
                            vm.messagesList[length - 1].loading = 0
                            break;
                        case 'error':
                            vm.messagesList[length - 1].fail = 1
                            vm.messagesList[length - 1].loading = 0
                            mineAlert("发送失败")
                            break;
                    }

                    // alert(JSON.stringify(ret))
                })
            },
            sendImageMessage(imagePath) {
                var obj = {
                    targetId: vm.targetId,
                    imagePath: imagePath,
                    extra: {
                    }
                }
                var length = 0
                vm.rong.sendImageMessage(obj, function (ret) {
                    // alert(JSON.stringify(ret.result))
                    var data = ret
                    switch (ret.status) {
                        case 'prepare':
                            data.result.message.loading = 1
                            vm.messagesList.push(data.result.message)
                            length = vm.messagesList.length
                            vm.toBottom()
                            break;
                        case 'progress':
                            vm.messagesList[length - 1].progress = ret.result.progress
                            break;
                        case 'success':
                            vm.messagesList[length - 1].loading = 0
                            break;
                        case 'error':
                            vm.messagesList[length - 1].fail = 1
                            vm.messagesList[length - 1].loading = 0
                            mineAlert("发送失败")
                            break;
                    }

                    // alert(JSON.stringify(ret))
                })
            },
            sendTextMessage(a, text, params) {

                var obj = {
                    targetId: vm.targetId,
                    text: a == 1 ? text : vm.content,
                    extra: {
                        ...params,
                    }
                }
                var length = 0
                vm.rong.sendTextMessage(obj, function (ret) {
                    // alert(JSON.stringify(ret.status))
                    // alert(JSON.stringify(ret.result))
                    var data = ret
                    switch (ret.status) {
                        case 'prepare':
                            data.result.message.loading = 1
                            vm.content = ""
                            if (vm.fontSize) {
                                textarea.style.height = vm.fontSize + 'px'
                            }
                            vm.messagesList.push(data.result.message)
                            length = vm.messagesList.length
                            vm.toBottom()
                            break;
                        case 'success':
                            vm.messagesList[length - 1].loading = 0
                            break;
                        case 'error':
                            vm.messagesList[length - 1].fail = 1
                            vm.messagesList[length - 1].loading = 0
                            mineAlert("发送失败")
                            break;
                    }

                    // alert(JSON.stringify(ret))
                })
            },
            onRefresh: function () {
                vm.getHistoryMessages(function () {
                    vm.isLoading = false
                })
            }
        }
    })
    apiready = function () {
        getLoginInfo(function (res) {
                vm.userInfo = res
            })
        apiAddEventListener('upDateUserInfo', function () {
            getLoginInfo(function (res) {
                vm.userInfo = res
            })
        })
        vm.targetId = api.pageParam.targetId
        getAccount(vm.targetId,function(res){
            vm.otherInfo = res
        })
        vm.rong = new RongCloud()
        apiSendEvent('setNowTargetId', { targetId: vm.targetId });
        vm.rong.getConnectionStatus(function (ret) {
            // alert(JSON.stringify(ret))
            // alert(statusDesc[ret.result.connectionStatus])
            if (ret.result.connectionStatus == 'CONNECTED') {

            } else {
                mineAlert("聊天初始化失败,请重新登录")
            }
        })

        apiAddEventListener('didDisconnect', function (ret) {
            vm.messagesList.push(ret.value)
            vm.toBottom()
        });
        apiAddEventListener('receiveMessage', function (ret) {
            if (ret.value.message.senderUserId == vm.targetId) {
                vm.messagesList.push(ret.value.message)
                vm.toBottom()
            }
        });
        vm.init();
        // api.setRefreshHeaderInfo({
        //     bgColor: '#ccc',
        //     textColor: '#fff',
        //     textDown: '下拉加载更多...',
        //     textUp: '松开加载...',
        //     textLoading: "加载中..."
        // }, function (ret, err) {
        //     //在这里从服务器加载数据,加载完成后调用方法恢复组件到默认状态
        //     // 

        // });
    }

</script>

</html>

e8bb4e873be588801956da8b3ab3486.jpg

视频通话界面

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport"
        content="maximum-scale=1.0, minimum-scale=1.0, user-scalable=0, initial-scale=1.0, width=device-width" />
    <meta name="format-detection" content="telephone=no, email=no, date=no, address=no">
    <title></title>
</head>

<body>
    <div id="app">

    </div>
</body>
<script type="text/javascript" src="../../script/api.js"></script>
<script type="text/javascript" src="../../script/vue.js"></script>
<script type="text/javascript" src="../../script/common.js"></script>
<script type="text/javascript" src="../../script/vant.min.js"></script>
<script type="text/javascript" src="../../script/rongcloud.js"></script>
<script>


    //初始化vue
    var vm = new Vue({
        el: '#app',
        data: function () {
            return {
                uid: '',
                callId: '',
                mediaType:""
            }
        },
        methods: {
            //打开视频
            showVideo: function (uid1, uid2) {   //uid自己的id,uid2别人的id
                rong.setVideoView({
                    rect: {
                        x: 0,
                        y: 0,
                        w: api.winWidth,
                        h: api.winHeight
                    },
                    userId: uid2,
                    bg: '#ff0000',
                    renderModel: 'hidden',
                    fixed: true
                });
                //打开自己的视频
                rong.setVideoView({
                    rect: {
                        x: api.winWidth - 130,
                        y: api.safeArea.top + 20,
                        w: 110,
                        h: 180
                    },
                    userId: uid1,
                    bg: '#ff0000',
                    renderModel: 'hidden',
                    fixed: true
                });
            },
            //重新打开视频
            resetVideoView: function (uid) {
                var rong = api.require('rongCloud2');
                rong.resetVideoView({
                    userId: uid
                });
            }
        },
        // mounted: function () {
        //     setTimeout(function () {
        //         openFram();
        //     }, 500)
        // }
    });
    apiready = function () {
        vm.callStatus = api.pageParam.callStatus
        vm.callId = api.pageParam.callId
        vm.mediaType = api.pageParam.mediaType
        vm.uid = api.pageParam.uid
        open_frame(api.pageParam.url, api.pageParam.name, false,{callId:api.pageParam.callId,callStatus:api.pageParam.callStatus,mediaType:api.pageParam.callStatus,uid:vm.uid});
        api.addEventListener({
            name: 'keyback'
        }, function (ret, err) {
            api.execScript({
                frameName: api.pageParam.name,
                script: 'window.vm.hangup();'
            });
        });
     
    }

</script>

</html>

悬浮在通话界面上的操作按钮 区分了是拨打用户还是被拨打用户

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport"
        content="maximum-scale=1.0, minimum-scale=1.0, user-scalable=0, initial-scale=1.0, width=device-width" />
    <meta name="format-detection" content="telephone=no, email=no, date=no, address=no">
    <title></title>
    <link rel="stylesheet" type="text/css" href="../../css/aui.css" />
    <link rel="stylesheet" type="text/css" href="../../css/common.css" />
    <link rel="stylesheet" type="text/css" href="../../css/aui-flex.css" />
    <link rel="stylesheet" type="text/css" href="../../script/index.css" />
    <style>
        html {
            background-color: rgba(0, 0, 0, 0.49)
        }

        body {
            background: transparent;
            height: 100vh;
        }
    </style>
</head>

<body>
    <!--
        callStatus===1、拨打电话,应该显示接听电话人的头像
        callStatus===3、接听电话,应该显示拨打电话人的头像
    -->
    <div id="app" style="height: 100%;" class="aui-flex-row aui-flex-between" v-cloak>
        <div class="aui-clearfix ">
            <div style="margin-top: 13.6vh;" class="aui-flex-row aui-flex-center aui-flex-middle">
                <van-image fit='cover' style="border-radius: 0.24rem;overflow: hidden" width='4.71rem' height='4.71rem'
                    :src="headPortrait">
                </van-image>
                <div class="aui-margin-t-10 aui-text-center color_fff aui-font-size-18 aui-font-weight">
                    {{name}}
                </div>
            </div>
        </div>
        <div style="padding-bottom: 5vh;" class="nor_box color_fff aui-font-size-13">
            <template v-if="start">
                <div class="aui-padded-l-15 aui-padded-r-15 aui-flex-col aui-flex-between">
                    <div @click='muted = !muted' class="aui-text-center ">
                        <img style="width: 3.3rem;"
                            :src="muted ? '../../image/chat/call3-close.png' : '../../image/chat/call3-on.png'" />
                        <div class="aui-margin-t-5">
                            静音
                        </div>
                    </div>
                    <div @click="hangup" class="aui-text-center ">
                        <img style="width: 3.3rem;" src="../../image/chat/call2.png" />
                        <div class="aui-margin-t-5">
                            挂断
                        </div>
                    </div>
                    <div @click='speakerEnabled = !speakerEnabled' class="aui-text-center ">
                        <img style="width: 3.3rem;"
                            :src="speakerEnabled ? '../../image/chat/call1-on.png' :'../../image/chat/call1-close.png'" />
                        <div class="aui-margin-t-5">
                            免提
                        </div>
                    </div>
                </div>
            </template>
            <template v-else>
                <template v-if="callStatus == 1">
                    <div class="aui-padded-l-15 aui-padded-r-15 aui-flex-col aui-flex-center">
                        <div @click="hangup" class="aui-text-center ">
                            <img style="width: 3.3rem;" src="../../image/chat/call2.png" />
                            <div class="aui-margin-t-5">
                                挂断
                            </div>
                        </div>
                    </div>
                </template>
                <template v-else>
                    <div class="aui-padded-l-15 aui-padded-r-15 aui-flex-col aui-flex-between">
                        <div @click="hangup" class="aui-text-center ">
                            <img style="width: 3.3rem;" src="../../image/chat/call2.png" />
                            <div class="aui-margin-t-5">
                                挂断
                            </div>
                        </div>
                        <div @click="accept" class="aui-text-center ">
                            <img style="width: 3.3rem;" src="../../image/chat/call4.png" />
                            <div class="aui-margin-t-5">
                                接听
                            </div>
                        </div>
                    </div>
                </template>
            </template>

        </div>
    </div>
</body>
<script type="text/javascript" src="../../script/api.js"></script>
<script type="text/javascript" src="../../script/vue.js"></script>
<script type="text/javascript" src="../../script/common.js"></script>
<script type="text/javascript" src="../../script/vant.min.js"></script>
<script type="text/javascript" src="../../script/rongcloud.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: function () {
            return {
                rong: null,
                mediaType: "",
                callId: "",
                callStatus: "1",
                muted: false,
                speakerEnabled: false,
                start: false,
                uid:"",
                headPortrait: "",
                name: ""
            }
        },
        watch: {
            muted: function (newValue) {
                vm.rong.setMuted(newValue, function () { })
            },
            speakerEnabled: function (newValue) {
                vm.rong.setSpeakerEnabled(newValue, function () { })
            }
        },
        methods: {
            init: function () {

            },
            accept: function () {
                vm.rong.accept({ mediaType: vm.mediaType, callId: vm.callId })
            },
            hangup() {
                vm.rong.hangup()
                apiSendEvent('stopVideo');
                api.closeWin();
            }
        }
    });
    apiready = function () {
        vm.callStatus = api.pageParam.callStatus
        vm.callId = api.pageParam.callId
        vm.mediaType = api.pageParam.mediaType
        vm.rong = new RongCloud()
        vm.uid = api.pageParam.uid
        getAccount(vm.uid, function (res) {
            if (res) {
                vm.name = res.nickName
                vm.headPortrait = res.headPortrait
            }
        })
        vm.init()
        apiAddEventListener('myRemoteUserDidJoin', function (ret) {
            vm.start = true
            vm.rong.setVideoView({
                userId: ret.value.targetId,
            });
            //打开自己的视频
            vm.rong.setVideoView({
                rect: {
                    x: api.winWidth - 130,
                    y: api.safeArea.top + 20,
                    w: 110,
                    h: 180
                },
                userId: ret.value.selfUserId,
            });
            myOpenFrame('callphone_frm',api.pageParam)
        });
    }
</script>

</html>