Newer
Older
XinYang_SanWei+RongYun / src / views / call / index copy.vue
@张强云笔记本 张强云笔记本 on 17 Dec 2021 18 KB 融云通话接入
<!-- 呼叫页面 -->
<template>
  <div id="rong-template-call">
    <div class="rong-box rong-call-box">
      <div class="rong-info">
        <p>当前拨号用户: <span>{{params.userId}} - {{$route.params.userId}}</span></p>
        <!-- <p>群组 id: <span>{{params.groupId}}- {{$route.params.groupId}}</span></p> -->
        <!-- <el-button @click="test()">群聊测试</el-button> -->
      </div>
      <div class="rong-type-box" style="display:none;">
        <!-- <div class="rong-type-box" v-if="callStep === CallStep.READY_TO_CALL"> -->
        <label for="">通话类型: </label>
        <select name="" id="" v-model="callType">
          <option value="1">单人</option>
          <option value="3">群组</option>
        </select>
      </div>
      <div class="rong-video-box">
        <div class="rong-video-list">
          <div class="rong-video-min" v-for="user in minUserList" v-video="user" :talktype="user.talkType"></div>
        </div>
        <div v-if="maxUser" class="rong-video-max" v-video="maxUser" :talktype="maxUser.talkType"></div>
      </div>
      <div class="rong-call-btns">
        <template v-if="callStep === CallStep.READY_TO_CALL">
          <button class="rong-call-video" title="点击进行视频通话" @click="inputCall(false)"></button>
          <button class="rong-call-audio" title="点击进行音频通话" @click="inputCall(true)"></button>
        </template>
        <template v-else-if="callStep === CallStep.CALLING">
          <button class="rong-call-hungup" title="点击挂断" @click="hungup"></button>
          <button v-if="callType == 3" class="rong-call-invite" title="点击邀请" @click="invite"></button>
          <button class="rong-call-mute" title="点击开启/关闭音频" :closed="isMuted" @click="mute"></button>
          <button class="rong-call-video" closed title="点击开启/关闭视频" :closed="callInfo.mediaType !== 2"
            @click="setVideo"></button>
        </template>
        <template v-else-if="callStep === CallStep.INVITED_TO_ANSWER">
          <button class="rong-call-accept" @click="accept"></button>
          <button class="rong-call-hungup" @click="reject"></button>
        </template>
      </div>
    </div>

    <!-- 群聊 -->
    <el-dialog title="群聊用户" :visible.sync="dialogVisible" width="30%">

      <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选当前用户
      </el-checkbox>
      <div style="margin: 15px 0;"></div>

      <el-checkbox-group v-model="checkedCities" @change="handleCheckedCitiesChange">
        <el-checkbox v-for="userId in cities" :label="userId" :key="userId">{{userId}}</el-checkbox>
      </el-checkbox-group>

      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="sureMemer()">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
  import {
    getPeoplesMembers
  } from '@/services';
  var RongIMLib = window.RongIMLib,
    RongCallLib = window.RongCallLib,
    win = window,
    RongCall = window.RongCall,
    setting = RongCall.setting,
    utils = RongCall.utils;

  var dialog = RongCall.dialog,
    ConversationType = RongIMLib.ConversationType,
    MediaType = RongIMLib.VoIPMediaType;
  var isAutoClose = false
  // 通话阶段
  var CallStep = {
    READY_TO_CALL: 1, // 准备拨打(最初状态)
    INVITED_TO_ANSWER: 2, // 被邀请接听, 其他人拨打, 己方选择接听或拒绝
    CALLING: 3 // 拨打中
  };

  var CallName = {};
  CallName[MediaType.MEDIA_AUDIO] = '语音';
  CallName[MediaType.MEDIA_VEDIO] = '视频';

  // 将消息转化为调用 CallLib 需要参数
  function messageToCallInfo(message) {
    return {
      conversationType: message.conversationType,
      targetId: message.targetId,
      mediaType: message.content.mediaType
    };
  }

  // 获取挂断原因
  function getHungupReason(reason, message) {
    var reasonPrompt;
    var senderUserId = message.senderUserId;
    switch (reason) {
      case 8:
        reasonPrompt = '其他设备已处理';
        break;
      case 11:
        reasonPrompt = `${senderUserId} 已取消`;
        break;
      case 12:
        reasonPrompt = `${senderUserId} 已拒绝`;
        break;
      case 13:
        reasonPrompt = `${senderUserId} 已挂断`;
        break;
      case 14:
        reasonPrompt = `${senderUserId} 忙碌中`;
        break;
      case 15:
        reasonPrompt = `${senderUserId} 未接听`;
        break;
      default:
        reasonPrompt = '未知原因挂断';
    }
    return reasonPrompt;
  }

  // 己方挂断后的提示
  function getSummaryText(status, message) {
    var senderUserId = message.senderUserId;
    var text;
    switch (status) {
      case 1:
        text = '己方已取消';
        break;
      case 2:
        text = '己方已拒绝';
        break;
      case 3:
        text = '己方挂断';
        break;
      case 4:
        text = `收到 ${senderUserId} 的音视频邀请, 但己方忙碌中, 不处理`;
        break;
      case 5:
        text = '己方未接听';
        break;
      default:
        text = '未知原因';
    }
    return text;
  }

  function mediaTypeToTalkType(mediaType) {
    return mediaType === MediaType.MEDIA_AUDIO ? 0 : 1;
  }

  var commandEvents = {
    // 监听其他人邀请自己
    InviteMessage: function (message, context) {
      var conversationType = message.conversationType === ConversationType.PRIVATE ? '单聊' : '群聊';
      context.$message(
        `${message.senderUserId} 邀请您进行${CallName[message.content.mediaType]}通话(${conversationType})`);
      context.callInfo = messageToCallInfo(message);
      context.callStep = CallStep.INVITED_TO_ANSWER;
    },
    MemberModifyMessage: function (message, context) {
      if (message.content.inviteUserIds.indexOf(context.selfUserId) !== -1) {
        var conversationType = message.conversationType === ConversationType.PRIVATE ? '单聊' : '群聊';
        context.$message(
          `${message.senderUserId} 邀请您进行${CallName[message.content.mediaType]}通话(${conversationType})`);
        context.callInfo = messageToCallInfo(message);
        context.callStep = CallStep.INVITED_TO_ANSWER;
      }
    },
    HungupMessage: function (message, context) {
      var reason = getHungupReason(message.content.reason, message);
      context.$message(reason);
      var params = {
        conversationType: message.conversationType,
        targetId: message.targetId
      };
      isAutoClose = true
      if (message.content.reason) {
        RongCallLib.hungup(params, function (error) {
          // 置为最初的准备拨打状态
          context.callStep = CallStep.READY_TO_CALL;
        });
      }
    },
    MediaModifyMessage: function (message, context) {
      var senderUserId = message.senderUserId,
        mediaType = message.content.mediaType;
      context.userList.forEach(function (user) {
        if (user.userId === senderUserId) {
          user.talkType = mediaTypeToTalkType(mediaType);
        }
      });
    },
    SummaryMessage: function (message, context) {
      // 每次拨通或者挂断都会触发此方法
      var status = message.content.status;

      if (!isAutoClose) {
        var promptText = getSummaryText(status, message);
        context.$message(promptText);
        if (status === 5) { // 自己未接听, 回到初始状态
          context.callStep = CallStep.READY_TO_CALL;
        }
      }

      if (status === 15) {
        context.callStep = CallStep.READY_TO_CALL;
      }
    }
  };

  var videoChangedEvents = {
    added: function (detail, context) {
      context.userList.push(detail);
    },
    removed: function (detail, context) {
      context.userList = utils.removeArray(detail, context.userList, 'userId');
    },
    leave: function (detail, context) {
      context.userList = [];
    }
  };

  async function getMembers(currentUserList, selfUserId) {
    let members = await getPeoplesMembers();
    console.log('members', members)
    members = members.filter(function (user) {
      var currentUserIds = currentUserList.map(function (user) {
        return user.id || user.userId;
      });
      return user.id !== selfUserId && currentUserIds.indexOf(user.id) === -1;
    });
    console.log('members', members)
    return win.Promise.resolve(members);
  }

  function call(callParams) {
    var context = this;
    RongCallLib.call(callParams, function (error) {
      // 置为通话中状态
      context.callStep = error ? context.callStep : CallStep.CALLING;
    });
    context.callInfo = callParams;
  }

  function accept() {
    var context = this;
    var callInfo = context.callInfo; // callInfo 在监听到 InviteMessage 时赋值, 格式见 messageToCallInfo 方法
    RongCallLib.accept(callInfo, function (error) {
      // 置为通话中状态
      context.callStep = error ? context.callStep : CallStep.CALLING;
    });
  }

  function invite() {
    var context = this;
    var callInfo = context.callInfo,
      inviteParams = {
        conversationType: ConversationType.GROUP,
        targetId: callInfo.targetId,
        inviteUserIds: [],
        mediaType: callInfo.mediaType
      };
    getMembers(context.userList, context.selfUserId).then(function (members) {
      dialog.selectUser({
        userList: members,
        confirmed: function (selectedUserList) {
          var selectedIds = selectedUserList.map(function (user) {
            return user.id;
          });
          inviteParams.inviteUserIds = selectedIds;
          RongCallLib.invite(inviteParams);
        }
      });
    }).catch(function () {
      context.$message('获取群组成员失败');
    });
  }

  function reject() {
    var context = this;
    var callInfo = context.callInfo; // callInfo 在监听到 InviteMessage 时赋值, 格式见 messageToCallInfo 方法
    RongCallLib.reject(callInfo, function (error) {
      // 置为最初的准备拨打状态
      context.callStep = error ? context.callStep : CallStep.READY_TO_CALL;
    });
  }

  function hungup() {
    var context = this;
    var callInfo = context.callInfo;
    RongCallLib.hungup(callInfo, function (error) {
      // 置为最初的准备拨打状态
      context.callStep = error ? context.callStep : CallStep.READY_TO_CALL;
    });
  }

  function mute() {
    var isMuted = this.isMuted;
    var event = isMuted ? RongCallLib.unmute : RongCallLib.mute;
    event();
    this.isMuted = !isMuted;
  }

  function setVideo() {
    var callInfo = this.callInfo,
      mediaType = callInfo.mediaType;
    var event = mediaType === MediaType.MEDIA_AUDIO ? RongCallLib.audioToVideo : RongCallLib.videoToAudio;
    event();
    this.callInfo.mediaType = mediaType === MediaType.MEDIA_AUDIO ? MediaType.MEDIA_VEDIO : MediaType.MEDIA_AUDIO;
  }

  export default {
    name: 'rong-template-call',
  props: ["userNo"],
    data() {
      return {
        userList: [],
        selectUserId: '',
        selectUserShow: true,
        userId: this.$route.params.userId ? this.$route.params.userId : '1',
        params: '',
        callStep: CallStep.READY_TO_CALL,
        callType: ConversationType.PRIVATE, // 通话类型, 默认为单聊
        /**
         * 通话信息. 给 callInfo 赋值的地方有:
         * 1. 发送 call 成功后, 存储当前通话信息
         * 2. 接收到 InviteMessage 后, 存储通话信息
         */
        callInfo: {},
        targetId: '',
        isMuted: false,
        dialogVisible: false,
        callBool: false,
        checkAll: false,
        checkedCities: [],
        cities: [],
        isIndeterminate: true
      };
    },
    directives: {
      video: function (el, binding) {
        var user = binding.value;
        var video = user.data;
        el.appendChild(video);
        video.play();
      }
    },
    computed: {
      CallStep: function () {
        return CallStep;
      },
      // 大窗口用户
      maxUser: function () {
        var context = this;
        var maxUser;
        context.userList.forEach(function (user) {
          if (user.userId === context.selfUserId) {
            maxUser = user;
          }
        });
        if (maxUser) {
          maxUser.talkType = mediaTypeToTalkType(context.callInfo.mediaType);
        }
        return maxUser;
      },
      // 小窗口用户列表
      minUserList: function () {
        var context = this,
          maxUser = context.maxUser || {};
        return context.userList.filter(function (user) {
          return user.userId !== maxUser.userId;
        });
      },
      selfUserId: function () {
        return this.params.userId;
      }
    },
    methods: {
      async test() {
        let {
          members
        } = await getPeoplesMembers();
        let newMemers = [];
        members = members.map(items => {
          if (items.id !== this.targetId) {
            newMemers.push(items.id || items.userId)
          }
        })
        this.cities = newMemers;
        this.dialogVisible = true;
      },
      handleCheckAllChange(val) {
        this.checkedCities = val ? this.cities : [];
        this.isIndeterminate = false;
      },
      handleCheckedCitiesChange(value) {
        let checkedCount = value.length;
        this.checkAll = checkedCount === this.cities.length;
        this.isIndeterminate = checkedCount > 0 && checkedCount < this.cities.length;
      },
      sureMemer() {
        // 群聊
        var context = this;
        var params = context.params,
          groupId = params.groupId;

        var callParams = {
          conversationType: ConversationType.GROUP,
          targetId: groupId,
          inviteUserIds: [],
          mediaType: mediaType
        };
        getMembers(context.userList, context.selfUserId).then(function (members) {
          dialog.selectUser({
            userList: members,
            confirmed: function (selectedUserList) {
              var selectedIds = selectedUserList.map(function (user) {
                return user.id;
              });
              callParams.inviteUserIds = selectedIds;
              context.call(callParams);
            }
          });
        }).catch(function () {
          context.$message('获取群组成员失败');
        });

      },
      inputCall(bool) {
        // 输入用户id
        var targetId = this.userNo || "";

        if (targetId !== '') {
          // url中有参数phone,则进行直接呼叫用户
          this.callBool = bool;
          this.startCall();
          return false
        }

        this.$prompt('请输入用户id', '温馨提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          inputErrorMessage: '用户id'
        }).then(({
          value
        }) => {
          // 用户id
          this.targetId = value;
          this.callBool = bool;
          this.startCall();
        })
      },
      /**
       * @param {boolean} isOnlyAudio 是否仅以音频发起
       */
      startCall: function (isOnlyAudio = this.callBool) {
        var mediaType = isOnlyAudio ? MediaType.MEDIA_AUDIO : MediaType.MEDIA_VEDIO;
        if (this.callType == ConversationType.GROUP) {
          this.startGroupCall(mediaType);
        } else {
          // 视频
          this.startPrivateCall(mediaType);
        }
      },
      startPrivateCall: function (mediaType) {
        var targetId = this.$route.query.phone || "";
        if (targetId === '') {
          targetId = this.targetId;
        }

        targetId && this.call({
          conversationType: ConversationType.PRIVATE,
          targetId: targetId,
          inviteUserIds: [targetId],
          mediaType: mediaType
        });
      },
      startGroupCall: function (mediaType) {
        var context = this;
        var params = context.params,
          groupId = params.groupId;

        var callParams = {
          conversationType: ConversationType.GROUP,
          targetId: groupId,
          inviteUserIds: [],
          mediaType: mediaType
        };
        getMembers(context.userList, context.selfUserId).then(function (members) {
          dialog.selectUser({
            userList: members,
            confirmed: function (selectedUserList) {
              var selectedIds = selectedUserList.map(function (user) {
                return user.id;
              });
              callParams.inviteUserIds = selectedIds;
              context.call(callParams);
            }
          });
        }).catch(function () {
          context.$message('获取群组成员失败');
        });
      },
      async login(callBack) {
        var userId = this.userId;
        let _this = this;
        var loginDetail

        let result = await this.$axios.login({
          userId
        });

        if (result.code !== 200) {
          _this.$message('登录失败, 请检查 CallLib Demo Server 是否启动')
        } else {
          setting.token = result.token;
          this.targetId = result.userId;
          loginDetail = result;
          let RongCall = window.RongCall;
          
          RongCall.initIM(setting);

          _this.params = loginDetail
          callBack ? callBack(this) : null;
        }
      },
      initLib() {
        var context = this;

        // 初始化
        RongCallLib = RongCall.initCallLib(context.userId);
        // 注册命令(消息)监听
        RongCallLib.commandWatch(function (message) {
          var event = commandEvents[message.messageType];
          event && event(message, context);
          console.log('received message', message);
        });

        // 注册音视频节点监听
        RongCallLib.videoWatch(function (result) {
          var event = videoChangedEvents[result.type];
          event && event(result, context);
          console.log('video changed', result);
        });

        let phone = this.$route.query.phone || "";

        if (phone !== '') {
          // 默认视频通话
        context.$message('正在拨通视频,请稍后...')
          setTimeout(() => {
            this.startCall(false)
          }, 2000);
        }
      },
      call: call,
      accept: accept,
      invite: invite,
      reject: reject,
      hungup: hungup,
      mute: mute,
      setVideo: setVideo
    },
    mounted() {
      let params = this.userNo || 0;
      console.log(params)
      if (params.length !== 0) {
        // 有phone,直接进行拨打
        this.login(this.initLib);
      } else {
        // 通过login页面进入的场景
        this.initLib();
      }
    },
  }

</script>

<style scoped>
</style>