Newer
Older
DH_Apicture / src / views / RongyunCommunication / index.vue
@chenke chenke 23 days ago 17 KB 优化
<template>
  <!-- 接听来电提醒 -->
  <el-dialog
    v-model="allData.showTip"
    id="tipModal"
    append-to-body
    :close-on-click-modal="false"
    class="responseDialog"
    :z-index="9999"
  >
    <template #header>
      <div class="tipsHeader">来电提示</div>
    </template>
    <div style="line-height: 80px; text-align: center; font-size: 16px; color: #fff">
      收到来自 {{ allData.fromCalluser }} 的{{ useRongyunStore.mediaType == 2 ? '视频' : '语音' }}邀请,是否接听???
    </div>
    <template #footer>
      <div class="dialog-footer">
        <el-button size="small" @click="hungup()">挂断</el-button>
        <el-button size="small" type="primary" @click="accept">确 定 </el-button>
      </div>
    </template>
  </el-dialog>
  <!-- 视图渲染弹窗 -->
  <el-dialog
    v-model="allData.showVideo"
    center
    id="ryAcceptModal"
    append-to-body
    :close-on-click-modal="false"
    :show-close="false"
    :z-index="9999"
  >
    <template #header>
      <div class="titleRy">
        远程会商
        <img @click="hungup()" src="/src/assets/images/rongYunImg/gb_btn.png" class="rybtn" />
      </div>
    </template>

    <div class="rong-container-app" id="rongContainer">
      <div id="videoViewAPP" class="rong-video-box-app"></div>
      <div id="videoActionAPP" class="rong-action-app">
        <img class="hunupBtn" id="hunup" src="/src/assets/images/rongYunImg/call-off.png" alt="" @click="hungup()" />
      </div>
    </div>
  </el-dialog>
  <div class="voiceDilog" v-if="allData.showVoice">
    <div class="voiceHeader">
      <img class="vioceIcon" src="/src/assets/images/rongYunImg/voice.png" alt="" />
      请开启声音权限
    </div>
    <el-button class="submit" type="primary" @click="allData.showVoice = false">确定</el-button>
  </div>
</template>
<script setup>
import { ref, reactive, toRefs, onMounted, nextTick } from 'vue';
import { getToken } from '@/utils/auth';
import { listrcloudUnitUser, getUserStatus, queryToken, hangUp } from '@/views/RongyunCommunication/rongyunjs/rongyunApi.js';
import { getInfo } from '@/api/login';
import rongyunStore from '@/store/modules/rongyunStore';
const useRongyunStore = rongyunStore();
import bus from '@/utils/util';
import * as RongIMLib from '@rongcloud/imlib-next';
// 导入 RTCLib、CallLib
import { installer as rtcInstaller, RCRTCClient, RCTrack, RCFrameRate, RCResolution } from '@rongcloud/plugin-rtc';
import useAppStore from '@/store/modules/app';
const appStore = useAppStore();

import {
  installer as callInstaller,
  RCCallClient,
  RCCallSession,
  RCCallErrorCode,
  RCCallLanguage,
  RCCallEndReason,
  RCCallMediaType,
  RCCallSessionState,
} from '@rongcloud/plugin-call';
const { proxy } = getCurrentInstance();
const audio = new Audio();
const successUrl = 'https://192.168.100.18:10000/image/newfiber-standard-region-project/ring.mp3';

const allData = reactive({
  showVoice: true,
  // 实例化一个音频播放器对象

  tokenRy: '',
  appkey: 'pkfcgjjue28x8',
  navi: 'https://jingkai.wh-nf.cn:11444',
  phone: '',
  userName: '',
  showTip: false,
  fromCalluser: null,
  showVideo: false,
  styleRY: {
    width: '900px',
    height: '600px',
  },
  conversationType: null, //接收类型
  remoteUser: [], //房间人员列表
  idList: [], //视频id-dom列表
  timer: null,
  acceptType: '',
});
const GetpromoterThridUserId = ref('');

const {
  showVoice,
  tokenRy,
  appkey,
  navi,
  phone,
  userName,
  showTip,
  fromCalluser,
  showVideo,
  styleRY,
  conversationType,
  remoteUser,
  idList,
  timer,
} = toRefs(allData);
onMounted(() => {
  bus.off('showRy');
  bus.on('showRy', e => {
    console.log('打开融云弹框');
    if (getToken()) {
      GetuserInfo();
    }
  });
  bus.off('rystatus');
  bus.on('rystatus', e => {
    console.log('拨打调用', e);
    if (getToken()) {
      reconnect();
    }
  });
  console.log('getToken()', getToken());

  if (getToken()) {
    GetuserInfo();
  }
});
// 播放音频
const PlayAudio = () => {
  let music1 = new Audio(); //建立一个music1对象
  music1 = 'https://jingkai.wh-nf.cn:8900/resources/videos/ring.mp3'; //通过require引入音频
  this.$refs.audio.src = music1; //此处的audio为代码ref="audio"中的audio
  this.$refs.audio.play(); //play()为播放函数
};
// 重连融云
const reconnect = () => {
  allData.tokenRy && connectIM();
  useRongyunStore.SET_online(false);
  proxy.$modal.msgWarning('视频会商已离线,重新连接中!');
};
const getStaus = (time = 0) => {
  clearInterval(allData.timer);
  allData.timer = setInterval(async () => {
    useRongyunStore.SET_online(false);

    let params = {
      registerThridUserId: allData.phone + '_web',
    };

    let res = await getUserStatus(params);
    console.log('轮询,', res);
    let flag = null;
    if (res.code == 200) {
      flag = JSON.parse(res.data);
    }
    if (flag != 1) {
      allData.tokenRy && connectIM();
      proxy.$modal.msgWarning('视频会商已离线,重新连接中!');
    } else {
      useRongyunStore.SET_online(true);
    }
  }, time);
};

const GetuserInfo = () => {
  console.log('1111111111111');
  getInfo().then(res => {
    console.log('当前登陆人信息', res);
    localStorage.setItem('userNo', res.data.user.userName);
    allData.phone = res.data.user.phonenumber;
    getQueryToken();
  });
};

// 获取融云token
const getQueryToken = async () => {
  let params = {
    registerThridUserId: allData.phone + '_web',
  };
  let res = await queryToken(params);

  if (res.code == 200) {
    allData.tokenRy = res.data && res.data[0]?.thridToken;

    if (allData.tokenRy) {
      useRongyunStore.SET_haveRYtoken(true);
      getStaus(60000);
      allData.tokenRy && connectIM();
    }
  } else {
    useRongyunStore.SET_haveRYtoken(false);
    useRongyunStore.SET_online(false);
    proxy.$modal.msgWarning('获取通讯token失败');
  }
};
// 获取元素
const getDom = key => {
  return document.querySelector(key);
};
const connectEvents = Events => {
  /**
   * 正在链接的事件状态
   */
  RongIMLib.addEventListener(Events.CONNECTING, () => {
    console.log('正在链接...');
  });

  /**
   * 链接到服务器会触发这个事件
   */
  RongIMLib.addEventListener(Events.CONNECTED, () => {
    console.log('连接成功');
  });

  /**
   * 手动调用 disconnect 方法或者用户被踢下线 会触发这个事件
   */
  RongIMLib.addEventListener(Events.DISCONNECT, code => {
    console.log('连接中断,需要业务层进行重连处理 ->', code);
  });

  /**
   * 链接出问题时,内部进行重新链接,会触发这个事件
   */
  RongIMLib.addEventListener(Events.SUSPEND, code => {
    console.log('链接中断,SDK 会尝试重连,业务层无需关心');
    // 5.1.2 版本开始,事件回调中会引起中断的 code 状态码
    console.log(`code -> ${code}`);
  });
};
// IM 实例
const connectIM = () => {
  console.log('初始化connectIM', allData.appkey);
  console.log('初始化connectIM22', allData.navi);
  console.log('初始化connectIM22', allData.tokenRy);
  RongIMLib.init({
    appkey: allData.appkey,
    navigators: [allData.navi],
  });

  initRTC();
  initCall();
  const token = allData.tokenRy;
  RongIMLib.connect(token)
    .then(data => {
      console.log('*-*-', data);
      // 监听融云状态
      connectEvents(RongIMLib.Events);
      useRongyunStore.SET_online(true);
      proxy.$message.success(`用户 ${data.data.userId} IM 链接成功 ✌🏻`);
    })
    .catch(error => {
      console.log(error);
      useRongyunStore.SET_online(false);
      proxy.$modal.msgWarning('IM 链接失败,请检查网络后再试');
    });
};
// RTC
const initRTC = () => {
  let rtcClient = RongIMLib.installPlugin(rtcInstaller);
  useRongyunStore.SET_RTC(rtcClient);
};
// Rcall
const initCall = () => {
  console.log('aaaa');
  console.log(callInstaller, 'callInstaller');
  console.log('useRongyunStore.rtcClient', useRongyunStore.rtcClient);
  console.log(toRaw(useRongyunStore.rtcClient), 'useRongyunStore.rtcClient');
  let callClient = RongIMLib.installPlugin(callInstaller, {
    rtcClient: toRaw(useRongyunStore.rtcClient),
    /**
     * 被动收到邀请 (收到一个远端发起的新会话), 会产生一个新的 session 对象 (必填)
     */

    onSession: (session, extra) => {
      console.log('来电拉来电拉', session, extra);
      allData.conversationType = session.getConversationType();
      allData.remoteUser = session.getRemoteUsers();
      allData.acceptType = session;
      useRongyunStore.SET_CALLSESSION(session);
      useRongyunStore.SET_MediaType(session.getMediaType());
      registerCallSessionEvent(toRaw(useRongyunStore.callSession));
      let callerId = session.getCallerId();
      queryformUserName(callerId);
      GetpromoterThridUserId.value = callerId;
      audio.autoplay = true;
      audio.muted = false;
      audio.loop = true;
      audio.src = successUrl;
      proxy.$modal.msgWarning(`收到 ${session.getCallerId()} 的通话邀请`);
      allData.showTip = true;
      console.log('allData.showTip', allData.showTip);
    },
    /**
     *  以下三条只要满足一条,就会触发onSessionClose
     *  1、本端用户自己主动挂断
     *  2、服务端把本端用户踢出 RTC 房间
     *  3、房间里小于2个人
     *
     *  @param {RCCallSession} session 被结束的 session 对象
     *  @param summaryInfo 结束一个 session 的后汇总信息
     */
    onSessionClose: (session, summaryInfo) => {
      console.log('通话已结束', summaryInfo);
      audio.pause();
      proxy.$modal.msgWarning('通话已结束');
      allData.showTip = false;
      //清除拨号界面的video视图
      bus.emit('removeEle');
      allData.showVideo = false;
    },
  });
  console.log(callClient, 'callClient');
  useRongyunStore.SET_CALL(callClient);
};
/**
 * CallSession 事件
 */
const getCallSessionEvent = () => {
  return {
    onRinging: sender => {
      proxy.$modal.msgWarning(` ${sender.userId} 振铃`);
    },
    onAccept: sender => {
      proxy.$modal.msgWarning(` ${sender.userId} 已接听`);
    },
    onHungup: (sender, reason) => {
      proxy.$modal.msgWarning(` ${sender.userId} 已挂断`);
      const videoViewDom = getDom('#videoViewAPP');
      const videoDom = getDom(`#video-${sender.userId}`);
      videoDom && videoViewDom.removeChild(videoDom);
      const itemdomList = document.getElementsByClassName('video-item');
      if (itemdomList.length <= 1) {
        restore();
        removeVideoEl();
        allData.showVideo = false;
      }
    },
    onTrackReady: track => {
      appendVideoEl(track);
      // 暂停
      // 当本端资源或远端资源已获取, 该函数有 2 个参数:track 是本端资源或远端资源, session 是通话实例。这时用户可以用拿到的 track 播放音频、视频。
      // 当本端资源或远端资源已获取, 该函数有 2 个参数:track 是本端资源或远端资源, session 是通话实例。这时用户可以用拿到的 track 播放音频、视频。
      if (!track.isLocalTrack()) {
        //
        audio.pause();
        proxy.$modal.msgWarning('通话已建立');
      }
    },
    onMemberModify: (sender, invitedUsers, session) => {
      console.log('触发邀请监听1111', sender, invitedUsers, session);
      console.log('触发邀请监听1111', allData.userList);

      // 群组通话中有其他人被邀请加入, 该函数有 3 个参数: sender 是发送者,invitedUsers 是被邀请的用户列表, session 是通话实例。这时用户可以在 UI 层提示‘xxx加入通话’。
    },
    onMediaModify: sender => {
      // 通话类型改变时触发, 该函数有3个参数: sender 是发送者,mediaType 通话类型, session 是通话实例。这时用户可以在 UI 层提示‘已降级成音频通话’。
    },
    onAudioMuteChange: muteUser => {
      // 对方静音后触发, 该函数有2个参数: muteUser 是已静音的用户, session 是通话实例。这时用户可以在 UI 层提示‘xxx已静音’。
      proxy.$modal.msgWarning(` ${muteUser.userId} 已静音`);
    },
    onVideoMuteChange: muteUser => {
      // 对方禁用视频后触发, 该函数有2个参数: muteUser 是已禁用视频的用户, session 是通话实例。这时用户可以在 UI 层提示‘xxx已禁用视频’。
      proxy.$modal.msgWarning(` ${muteUser.userId} 已禁用视频`);
    },
  };
};
/**
 * callSession 事件注册
 */
const registerCallSessionEvent = session => {
  const events = getCallSessionEvent();
  session.registerSessionListener(events);
};
/**
 * 接听当前 callSession
 */
const accept = () => {
  toRaw(useRongyunStore.callSession)
    .accept()
    .then(({ code }) => {
      if (code === RCCallErrorCode.SUCCESS) {
        proxy.$modal.msgWarning('接听成功');
        allData.showTip = false;
        allData.showVideo = true;
      } else {
        proxy.$modal.msgWarning(`接听失败,错误原因:${code}`);
        hungupApi(code);
      }
    });
};
/**
 * 挂断当前 callSession
 */
const hungup = () => {
  toRaw(useRongyunStore.callSession)
    .hungup()
    .then(({ code }) => {
      if (code === RCCallErrorCode.SUCCESS) {
        // proxy.$modal.msgWarning("挂断成功");
        removeVideoEl();
        restore();
        allData.idList = [];
        allData.showTip = false;
        allData.showVideo = false;
      } else {
        proxy.$modal.msgWarning(`挂断失败,错误原因:${code}`);
        removeVideoEl();
        allData.showTip = false;
        allData.showVideo = false;
        hungupApi(code);
      }
    });
};

// 接听或者挂断失败后都调 融合通讯通话
const hungupApi = code => {
  console.log('调取了挂断接口xxxx', GetpromoterThridUserId.value);
  let params = {
    promoterThridUserId: GetpromoterThridUserId.value, //发起人
    answerThridUserId: allData.phone + '_web', //接听人 当前登录人
    updateBy: localStorage.getItem('userNo'),
    answerType: code || null,
  };
  console.log('调取了挂断接口xxxx', params);
  hangUp(params).then(res => {
    console.log('调取了挂断接口xxxx', res);
  });
};

/**
 * video 视图渲染
 */
const appendVideoEl = async track => {
  const container = getDom('#videoViewAPP');
  const uid = track.getUserId();
  let mediaType = toRaw(useRongyunStore.mediaType);
  let videoTpl = null;
  let params = {
    phone: uid.split('_')[0],
  };
  let res = await listrcloudUnitUser(params);
  let data = res.data[0];
  if (res.code == 200) {
    const node = document.createElement('div');
    node.setAttribute('id', `video-${uid}`);
    if (allData.idList.findIndex(i => i == `video-${uid}`) == -1) {
      allData.idList.push(`video-${uid}`);
    }
    if (mediaType == 1) {
      videoTpl = `<span class="video-user-id">${data.name} :${uid} </span><span class="video-media-type"></span><video id="${uid}"></video>`;
    } else {
      videoTpl = `<span class="video-user-id">${data.name} :${uid} </span><video id="${uid}"></video>`;
    }
    node.innerHTML = videoTpl;
    node.classList.add('video-item');
    let length = allData.remoteUser.length + 1;
    console.log('什么东西', allData.conversationType, length);

    // 根据人数判断渲染不同的视图样式
    if (allData.phone + '_web' == uid && length <= 2) {
      node.classList.add('first-child');
    }

    if (length > 2 && length <= 4) {
      node.classList.add('video-item-4');
    }
    if (length > 4 && length <= 8) {
      node.classList.add('video-item-8');
    }

    if (track.isAudioTrack()) {
      if (mediaType == 1) {
        container.appendChild(node);
      }

      track.play();
    } else {
      container.appendChild(node);
      let videoEl = document.getElementById(uid);
      track.play(videoEl);
    }

    const targetElements = document.querySelectorAll('.video-item');
    console.log('targetElements', targetElements);

    targetElements.forEach(target => {
      target.classList.remove('video-item-4');
      target.classList.remove('video-item-8');

      if (length > 2 && length <= 4) {
        target.classList.add('video-item-4');
      }
      if (length > 4 && length <= 8) {
        target.classList.add('video-item-8');
      }
    });
  }
};
//关闭视频弹窗
const close = () => {
  // hungup();
};

//还原
const restore = () => {
  allData.styleRY = {
    width: '900px',
    height: '600px',
  };
  const dom1 = getDom('#videoViewAPP');
  if (!dom1) return false;
  dom1.style = '';
  allData.idList.forEach((item, index) => {
    let videodom = getDom(`#${item}`);
    if (videodom) {
      videodom.style = null;
    }

    const titledom = getDom(`#${item} .video-user-id`);
    if (titledom) {
      titledom.style = null;
    }
  });
};

// 通过userPhone匹配用户名称
const queryformUserName = async callerId => {
  console.log('callerId匹配用户名称', callerId);

  let params = {
    phone: callerId.split('_')[0],
  };
  let res = await listrcloudUnitUser(params);
  console.log('res获取用户', res);
  if (res && res.code == 200) {
    let name = res.data[0].name;
    allData.fromCalluser = `${name}`;
  }
};
const removeVideoEl = () => {
  if (!getDom('#videoViewAPP')) return false;
  getDom('#videoViewAPP').innerHTML = '';
  getDom('#videoViewAPP').style = '';
};

onBeforeUnmount(() => {
  RongIMLib.disconnect().then(() => console.log('断开链接成功'));
});
</script>
<style lang="scss">
@import '@/views/RongyunCommunication/rongyuncss/index.scss';
</style>
<style lang="scss" scoped>
.rybtn {
  cursor: pointer;
  position: absolute;
  right: 45px;
  top: 52px;
}
</style>