|
|
@@ -1,29 +1,788 @@
|
|
|
<!-- -->
|
|
|
<template>
|
|
|
- <div class="">
|
|
|
- 实时通信
|
|
|
+ <div class="realTime_box">
|
|
|
+ <el-card :style="'height:' + fullHeight + 'px'">
|
|
|
+ <div class="card_box">
|
|
|
+ <!-- 组织 -->
|
|
|
+ <div
|
|
|
+ class="userManger_left"
|
|
|
+ :style="'height:' + (fullHeight - 100) + 'px'"
|
|
|
+ >
|
|
|
+ <el-tree
|
|
|
+ :data="data"
|
|
|
+ :props="defaultProps"
|
|
|
+ @node-click="handleNodeClick"
|
|
|
+ ></el-tree>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 表格 -->
|
|
|
+ <div
|
|
|
+ class="userManger_right"
|
|
|
+ :style="'height:' + (fullHeight - 100) + 'px'"
|
|
|
+ >
|
|
|
+ <!-- 搜索 -->
|
|
|
+ <el-row>
|
|
|
+ <el-col>
|
|
|
+ <!-- 组织搜索 -->
|
|
|
+ <div class="search_box">
|
|
|
+ <el-input
|
|
|
+ size="mini"
|
|
|
+ placeholder="请输入用户姓名"
|
|
|
+ v-model.trim="nameVal"
|
|
|
+ @change="searchData"
|
|
|
+ clearable
|
|
|
+ >
|
|
|
+ </el-input>
|
|
|
+ <el-input
|
|
|
+ size="mini"
|
|
|
+ placeholder="请输入手机号"
|
|
|
+ v-model.trim="phoneVal"
|
|
|
+ @change="searchData"
|
|
|
+ clearable
|
|
|
+ >
|
|
|
+ </el-input>
|
|
|
+ <div class="btn_box">
|
|
|
+ <el-button type="primary" size="mini" @click="searchData"
|
|
|
+ >搜索</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-table :data="tableData" stripe style="width: 100%">
|
|
|
+ <el-table-column prop="ind" label="序号" width="180">
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="real_name" label="组织成员" width="250">
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="mobile" label="手机号" width="250">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span>{{ scope.row.mobile || "无" }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="address" label="职位" width="320">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span v-for="(item, index) in scope.row.org_list" :key="index"
|
|
|
+ >{{ item.org_name }}、</span
|
|
|
+ >
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="280">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span>
|
|
|
+ <img
|
|
|
+ @click="msgAxios(scope.row)"
|
|
|
+ src="../../assets/images/realTime/xiaoxi.png"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </span>
|
|
|
+ <!-- <span>
|
|
|
+ <img src="../../assets/images/realTime/B.png" alt="">
|
|
|
+ </span> -->
|
|
|
+ <span>
|
|
|
+ <img
|
|
|
+ @click="videoAxios(scope.row)"
|
|
|
+ src="../../assets/images/realTime/shipin.png"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 分页 -->
|
|
|
+ <el-pagination
|
|
|
+ v-if="tableData.length !== 0"
|
|
|
+ @current-change="changeList"
|
|
|
+ background
|
|
|
+ layout="prev, pager, next, jumper"
|
|
|
+ :current-page="page"
|
|
|
+ :total="pageSum"
|
|
|
+ >
|
|
|
+ </el-pagination>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 视频通话 -->
|
|
|
+ <el-dialog
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ :close-on-press-escape="false"
|
|
|
+ :before-close="handleClose"
|
|
|
+ :modal="false"
|
|
|
+ v-dialogDrag
|
|
|
+ :title="videoTle"
|
|
|
+ :visible.sync="videoVisible"
|
|
|
+ width="40%"
|
|
|
+ >
|
|
|
+ <div class="video_box">
|
|
|
+ <div class="host_video" v-if="videoShow">
|
|
|
+ <img
|
|
|
+ v-if="audioShow"
|
|
|
+ src="../../assets/images/realTime/8.png"
|
|
|
+ alt=""
|
|
|
+ class=""
|
|
|
+ />
|
|
|
+ <img
|
|
|
+ v-else
|
|
|
+ src="../../assets/images/realTime/13.png"
|
|
|
+ alt=""
|
|
|
+ class=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="host_video" v-else>
|
|
|
+ <video
|
|
|
+ style="width: 100%; height: 100%"
|
|
|
+ ref="localVideo"
|
|
|
+ autoplay
|
|
|
+ playsinline
|
|
|
+ :muted="true"
|
|
|
+ ></video>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 副视频画面 -->
|
|
|
+ <div v-if="audioShow" class="deputy_video" v-drag>
|
|
|
+ <video
|
|
|
+ style="width: 100%; height: 100%"
|
|
|
+ ref="remoteVideo"
|
|
|
+ autoplay
|
|
|
+ playsinline
|
|
|
+ :muted="true"
|
|
|
+ ></video>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 操作 -->
|
|
|
+ <div class="operate">
|
|
|
+ <!-- <div style="margin: 0 10px 0 0">
|
|
|
+ <img
|
|
|
+ v-if="microphone"
|
|
|
+ src="../../assets/images/realTime/10.png"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ <img v-else src="../../assets/images/realTime/9.png" alt="" />
|
|
|
+ </div> -->
|
|
|
+ <div v-if="audioShow" style="margin: 0 10px 0 0">
|
|
|
+ <img
|
|
|
+ v-if="camera"
|
|
|
+ @click="notPlugFlow"
|
|
|
+ src="../../assets/images/realTime/12.png"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ <img @click="PlugFlow" v-else src="../../assets/images/realTime/11.png" alt="" />
|
|
|
+ </div>
|
|
|
+ <el-button
|
|
|
+ type="danger"
|
|
|
+ style="padding: 2px 10px; margin: -2px 10px 0 0"
|
|
|
+ @click="notLogin"
|
|
|
+ size="mini"
|
|
|
+ >挂断</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 文本聊天框 -->
|
|
|
+ <el-dialog
|
|
|
+ custom-class="msgFrame"
|
|
|
+ :title="tltData"
|
|
|
+ v-dialogDrag
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ :modal="false"
|
|
|
+ :close-on-press-escape="false"
|
|
|
+ :visible.sync="dialogVisible"
|
|
|
+ width="30%"
|
|
|
+ >
|
|
|
+ <!-- 聊天内容 -->
|
|
|
+ <ul class="ul_list test-5" id="msgBox">
|
|
|
+ <!-- 查看更多 -->
|
|
|
+ <!-- <li class="">
|
|
|
+ <div
|
|
|
+ v-if="iconShow"
|
|
|
+ style="color: #0400ff; cursor: pointer; text-align: center"
|
|
|
+ @click="moreMsg"
|
|
|
+ >
|
|
|
+ 查看更多消息
|
|
|
+ </div>
|
|
|
+ </li> -->
|
|
|
+
|
|
|
+ <li class="list" v-for="(item, index) in msgList.msg_list" :key="index">
|
|
|
+ <!-- me -->
|
|
|
+ <div class="list_msgBox1" v-if="item.send_real_name == userName">
|
|
|
+ <div
|
|
|
+ style="
|
|
|
+ background: #60fba5;
|
|
|
+ font-weight: 550;
|
|
|
+ color: #000;
|
|
|
+ padding: 12px 15px 0 15px;
|
|
|
+ line-height: 25px;
|
|
|
+ border-radius: 8px;
|
|
|
+ "
|
|
|
+ >
|
|
|
+ {{ item.msg_info }}
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ style="
|
|
|
+ width: 0;
|
|
|
+ height: 0;
|
|
|
+ border-top: 6px solid transparent;
|
|
|
+ border-left: 10px solid #60fba5;
|
|
|
+ border-bottom: 5px solid transparent;
|
|
|
+ margin: 23px 0 0 0;
|
|
|
+ "
|
|
|
+ ></div>
|
|
|
+ <div>
|
|
|
+ <img
|
|
|
+ src="../../../static/images/realTime/7.png"
|
|
|
+ alt=""
|
|
|
+ class=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- you -->
|
|
|
+ <div
|
|
|
+ v-else-if="item.recv_user_id == this.getUserObj.user_id"
|
|
|
+ class="list_msgBox2"
|
|
|
+ >
|
|
|
+ <div>
|
|
|
+ <img
|
|
|
+ src="../../../static/images/realTime/6.png"
|
|
|
+ alt=""
|
|
|
+ class=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ style="
|
|
|
+ width: 0;
|
|
|
+ height: 0;
|
|
|
+ border-top: 5px solid transparent;
|
|
|
+ border-right: 10px solid #eae9eb;
|
|
|
+ border-bottom: 6px solid transparent;
|
|
|
+ margin: 24px 0 0 0;
|
|
|
+ "
|
|
|
+ ></div>
|
|
|
+ <div
|
|
|
+ style="
|
|
|
+ background: #eae9eb;
|
|
|
+ padding: 12px 15px 0 15px;
|
|
|
+ line-height: 25px;
|
|
|
+ border-radius: 8px;
|
|
|
+ font-weight: 550;
|
|
|
+ color: #000;
|
|
|
+ "
|
|
|
+ >
|
|
|
+ {{ item.msg_info }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+
|
|
|
+ <!-- 发送框 -->
|
|
|
+ <el-input
|
|
|
+ style="border: 0"
|
|
|
+ resize="none"
|
|
|
+ type="textarea"
|
|
|
+ v-model="input"
|
|
|
+ @keyup.enter.native="submit()"
|
|
|
+ @keydown.native="pushKeyword($event)"
|
|
|
+ maxlength="30"
|
|
|
+ show-word-limit
|
|
|
+ placeholder="按下enter按键发送消息"
|
|
|
+ ></el-input>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
+import { color } from "highcharts";
|
|
|
+import { ZegoExpressEngine } from "zego-express-engine-webrtc";
|
|
|
|
|
|
export default {
|
|
|
//import引入的组件需要注入到对象中才能使用
|
|
|
components: {},
|
|
|
data() {
|
|
|
//这里存放数据
|
|
|
- return {};
|
|
|
+ return {
|
|
|
+ fullHeight: document.documentElement.clientHeight - 116, //
|
|
|
+
|
|
|
+ // 搜索
|
|
|
+ nameVal: "",
|
|
|
+ phoneVal: "",
|
|
|
+
|
|
|
+ // 表格
|
|
|
+ tableData: [],
|
|
|
+ org_id: "", //组织id
|
|
|
+
|
|
|
+ // 树形图
|
|
|
+ data: [],
|
|
|
+ defaultProps: {
|
|
|
+ children: "childrens",
|
|
|
+ label: "org_name",
|
|
|
+ },
|
|
|
+
|
|
|
+ // 分页
|
|
|
+ pageSum: 0,
|
|
|
+ page: 1,
|
|
|
+
|
|
|
+ // 视频通话弹框
|
|
|
+ videoVisible: false,
|
|
|
+ videoShow: true, //主视频是否展示画面
|
|
|
+ audioShow: true, // 判断当前是语音通话还是视频通话 true为视频 false为语音
|
|
|
+ microphone: true, // 是否打开麦克风
|
|
|
+ camera: true, // 是否打开摄像头
|
|
|
+ appID: 2672645646, //项目唯一标识 AppID
|
|
|
+ server: "1e8344b2a193220e5e96338ba53c3dcc", // 接入服务器地址Server
|
|
|
+ videoUrl: "wss://webliveroom2672645646-api.imzego.com/ws", // 请求
|
|
|
+ zg: null,
|
|
|
+ // UserID: "sample" + Math.floor(Math.random() * 10000000000000).toString(),
|
|
|
+ UserID: "user00002",
|
|
|
+ StreamID: "web-4796754531236",
|
|
|
+ // StreamID: "web-" + Math.floor(Math.random() * 10000000000000).toString(),
|
|
|
+ localStream: null,
|
|
|
+ Token:
|
|
|
+ "03AAAAAGHyVbgAEGdqdmp0cnpia2lvcnd2aGUAsEZBIPxO1xCGkPt7alN2ldHRSJ/di1xoXhw5hxlwTyXUFb4FUPCg6xbKyjEK8ne34apzy0JiJw7V5apRQSCrxv3k+fYYVtM8IgaXza1yD77x50HIAe3raJLvCGDn56jC5ElN//QdspBKkjHBQ0GFHKAlRN5oYDYja7sv3wKsCGRAQW26cxnbVm8SUOU/r71kB4C+qXrb7UE1/IgdkS87RJtJfwiafpOvya0nK9wTTZOY",
|
|
|
+ RoomID: "00002",
|
|
|
+ videoTle: "正在和云飞-卢万里视频通话",
|
|
|
+
|
|
|
+ // 文本聊天框
|
|
|
+ tltData: "",
|
|
|
+ dialogVisible: false,
|
|
|
+ input: "", //发送框
|
|
|
+ iconShow: true,
|
|
|
+ // 文本消息功能
|
|
|
+ url: "ws://192.168.1.17:12345/api/api_gateway?method=control_center.real_time.im_message",
|
|
|
+ websock: null,
|
|
|
+ getUserObj: {}, // 获取到当前点击的行数据
|
|
|
+ msgList: [], //当前点击的账号消息列表
|
|
|
+ userName: "",
|
|
|
+ };
|
|
|
},
|
|
|
//监听属性 类似于data概念
|
|
|
computed: {},
|
|
|
//监控data中的数据变化
|
|
|
- watch: {},
|
|
|
+ watch: {
|
|
|
+ fullHeight(val) {
|
|
|
+ //监控浏览器高度变化
|
|
|
+ if (!this.timer) {
|
|
|
+ this.fullHeight = val;
|
|
|
+ this.timer = true;
|
|
|
+ let that = this;
|
|
|
+ setTimeout(function () {
|
|
|
+ //防止过度调用监测事件,导致卡顿
|
|
|
+ that.timer = false;
|
|
|
+ }, 400);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 聊天列表
|
|
|
+ msgList(val) {
|
|
|
+ // 实现打开聊天框后滚动条定位到最下方
|
|
|
+ this.$nextTick(() => {
|
|
|
+ var div = document.getElementById("msgBox");
|
|
|
+ div.scrollTop = div.scrollHeight;
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 聊天框
|
|
|
+ dialogVisible(val) {
|
|
|
+ if (val == false) {
|
|
|
+ this.msgList = [];
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 音视频弹框
|
|
|
+ videoVisible(val) {
|
|
|
+ if (val == false) {
|
|
|
+ this.notPlugFlow(); // 停止推流
|
|
|
+ this.notTensile(); // 停止拉流
|
|
|
+ this.notLogin(); //退出房间
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
//方法集合
|
|
|
- methods: {},
|
|
|
+ methods: {
|
|
|
+ //动态获取浏览器高度
|
|
|
+ get_boderHeight() {
|
|
|
+ const that = this;
|
|
|
+ window.onresize = () => {
|
|
|
+ return (() => {
|
|
|
+ window.fullHeight = document.documentElement.clientHeight;
|
|
|
+ that.fullHeight = window.fullHeight;
|
|
|
+ })();
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ // 树形图
|
|
|
+ handleNodeClick(data) {
|
|
|
+ console.log(data);
|
|
|
+ this.org_id = data.id;
|
|
|
+ this.userListData();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 搜索
|
|
|
+ searchData() {
|
|
|
+ this.userListData();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 分页
|
|
|
+ changeList(page) {},
|
|
|
+
|
|
|
+ // 获取左侧组织列表
|
|
|
+ organizationData() {
|
|
|
+ this.$axios({
|
|
|
+ method: "POST",
|
|
|
+ url: "/api/api_gateway?method=sysmenage.usermanager.org_list",
|
|
|
+ data: this.qs.stringify({
|
|
|
+ page: this.page,
|
|
|
+ page_item: "100000000",
|
|
|
+ org_name: "",
|
|
|
+ }),
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ if (res.data.data.page_list.length !== 0) {
|
|
|
+ var obj = {
|
|
|
+ org_name: "全部",
|
|
|
+ id: "",
|
|
|
+ };
|
|
|
+ var data = res.data.data.page_list;
|
|
|
+ this.data = [obj, ...data]; // 左侧组织列表
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ console.log(err);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取右侧用户列表
|
|
|
+ userListData() {
|
|
|
+ this.$axios({
|
|
|
+ method: "POST",
|
|
|
+ url: "/api/api_gateway?method=sysmenage.usermanager.user_list",
|
|
|
+ data: this.qs.stringify({
|
|
|
+ page: this.page,
|
|
|
+ page_item: "10",
|
|
|
+ real_name: this.nameVal, //用户名称
|
|
|
+ mobile: this.phoneVal, // 电话
|
|
|
+ org_id: this.org_id,
|
|
|
+ }),
|
|
|
+ }).then((res) => {
|
|
|
+ if (res.data.data.page_item !== 0) {
|
|
|
+ var data = res.data.data.page_list;
|
|
|
+ var list = [];
|
|
|
+ data.forEach((item, index) => {
|
|
|
+ item.ind = index + 1;
|
|
|
+ list.push(item);
|
|
|
+ });
|
|
|
+ this.tableData = list;
|
|
|
+ this.pageSum = res.data.data.page_item;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 文本消息
|
|
|
+ msgAxios(data) {
|
|
|
+ this.getUserObj = data;
|
|
|
+ this.userName = localStorage.getItem("usernme");
|
|
|
+ console.log(this.userName);
|
|
|
+ this.tltData = "与" + data.real_name + "的对话";
|
|
|
+ var obj = {};
|
|
|
+ obj = {
|
|
|
+ action: "list",
|
|
|
+ recv_user_id: data.user_id,
|
|
|
+ data: {
|
|
|
+ msg_status: false,
|
|
|
+ msg_info: "",
|
|
|
+ },
|
|
|
+ };
|
|
|
+ console.log(data);
|
|
|
+ this.websock.send(JSON.stringify(obj));
|
|
|
+ this.dialogVisible = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 视频消息
|
|
|
+ videoAxios(data) {
|
|
|
+ this.getUserObj = data;
|
|
|
+ this.userName = localStorage.getItem("username");
|
|
|
+ this.videoTle = "正在和" + data.real_name + "视频通话";
|
|
|
+
|
|
|
+
|
|
|
+ // 先获取当前用户的房间号和登录所需的Token
|
|
|
+ var obj = {}
|
|
|
+ obj = {
|
|
|
+ action: 'send_video',
|
|
|
+ recv_user_id: data.user_id,
|
|
|
+ data: {
|
|
|
+ msg_status: false,
|
|
|
+ msg_info: '',
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.websock.send(JSON.stringify(obj))
|
|
|
+
|
|
|
+ // 登录房间
|
|
|
+ // this.zg.loginRoom(
|
|
|
+ // this.RoomID,
|
|
|
+ // this.Token,
|
|
|
+ // { userID: this.UserID, userName: this.UserID },
|
|
|
+ // { userUpdate: true }
|
|
|
+ // ).then((result) => {
|
|
|
+ // if (result == true) {
|
|
|
+ // this.plugFlow(); //推流
|
|
|
+ // this.videoVisible = true
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ },
|
|
|
+ // 音视频推流
|
|
|
+ async plugFlow() {
|
|
|
+ this.videoShow = false
|
|
|
+ const localStream = await this.zg.createStream();
|
|
|
+ // stream 为 MediaStream 对象,开发者可通过赋值给 video 或 audio 的 srcObject 属性进行渲染
|
|
|
+ this.$refs["localVideo"].srcObject = localStream;
|
|
|
+ this.localStream = localStream;
|
|
|
+ // localStream 为创建流获取的 MediaStream 对象
|
|
|
+ this.zg.startPublishingStream(this.StreamID, localStream);
|
|
|
+ },
|
|
|
+ // 音视频停止推流
|
|
|
+ notPlugFlow() {
|
|
|
+ this.videoShow = true
|
|
|
+ this.zg.stopPublishingStream(this.streamID);
|
|
|
+ this.zg.destroyStream(this.localStream);
|
|
|
+ },
|
|
|
+ // 拉流
|
|
|
+ async tensile(streamID) {
|
|
|
+ const remoteStream = await this.zg.startPlayingStream(streamID);
|
|
|
+ // remoteVideo 为本地 <video> 或 <audio> 对象
|
|
|
+ this.$refs["remoteVideo"].srcObject = remoteStream;
|
|
|
+ },
|
|
|
+ notTensile(streamID) {
|
|
|
+ this.zg.stopPlayingStream(streamID);
|
|
|
+ },
|
|
|
+ // 退出房间
|
|
|
+ notLogin() {
|
|
|
+ this.zg.logoutRoom(this.RoomID);
|
|
|
+ this.videoVisible = false
|
|
|
+ },
|
|
|
+
|
|
|
+ // 当音视频通话关闭时的回调
|
|
|
+ handleClose(done) {
|
|
|
+ this.$confirm("目前正在音视频通话中,确认关闭?")
|
|
|
+ .then((_) => {
|
|
|
+ done();
|
|
|
+ })
|
|
|
+ .catch((_) => {});
|
|
|
+ },
|
|
|
+
|
|
|
+ // 发送消息
|
|
|
+ async submit() {
|
|
|
+ if (this.input.split(" ").join("").length == 0) {
|
|
|
+ this.$message({
|
|
|
+ message: "不能发送空白消息!",
|
|
|
+ type: "warning",
|
|
|
+ duration: 1500,
|
|
|
+ });
|
|
|
+ this.input = "";
|
|
|
+ } else {
|
|
|
+ try {
|
|
|
+ var obj = {};
|
|
|
+ obj = {
|
|
|
+ action: "send",
|
|
|
+ recv_user_id: this.getUserObj.user_id,
|
|
|
+ data: {
|
|
|
+ msg_status: false,
|
|
|
+ msg_info: this.input,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ var v = JSON.stringify(obj);
|
|
|
+ this.websock.send(v);
|
|
|
+ this.input = "";
|
|
|
+ } catch (error) {
|
|
|
+ console.log(">>> sendMsg, error: ", error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // var obj = {};
|
|
|
+ // obj = {
|
|
|
+ // action: "send",
|
|
|
+ // recv_user_id: "167",
|
|
|
+ // data: {
|
|
|
+ // msg_status: false,
|
|
|
+ // msg_info: this.input,
|
|
|
+ // },
|
|
|
+ // };
|
|
|
+ // var v = JSON.stringify(obj);
|
|
|
+ // this.websock.send(v);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 取消回车换行行为
|
|
|
+ pushKeyword(event) {
|
|
|
+ if (event.keyCode === 13) {
|
|
|
+ event.preventDefault(); // 阻止浏览器默认换行操作
|
|
|
+ this.keyword = "";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 更多消息
|
|
|
+ moreMsg() {},
|
|
|
+
|
|
|
+ // 文本消息功能初始化
|
|
|
+ msgInit() {
|
|
|
+ if (typeof WebSocket === "undefined") {
|
|
|
+ alert("您的浏览器不支持socket!");
|
|
|
+ } else {
|
|
|
+ console.log(location.host);
|
|
|
+ console.log(window.WebSocket);
|
|
|
+ this.websock = new window.WebSocket(
|
|
|
+ this.url + "&token=" + localStorage.getItem("session")
|
|
|
+ );
|
|
|
+ // window.s = this.websock
|
|
|
+
|
|
|
+ this.websock.onopen = (event) => {
|
|
|
+ console.log("WebSocket:已连接");
|
|
|
+ console.log(event);
|
|
|
+ };
|
|
|
+ this.websock.onmessage = (event) => {
|
|
|
+ console.log("WebSocket:消息");
|
|
|
+ // console.log(JSON.parse(event.data));
|
|
|
+ var data = JSON.parse(event.data);
|
|
|
+ if (data.action == "none") {
|
|
|
+ // 获取聊天记录
|
|
|
+ console.log(data.data[0]);
|
|
|
+ if (data.data[0] !== undefined) {
|
|
|
+ data.data[0].msg_list = data.data[0].msg_list.reverse();
|
|
|
+ this.msgList = data.data[0];
|
|
|
+ }
|
|
|
+ } else if (data.action == "list") {
|
|
|
+ // 返回list为发送消息成功后需要再次调用聊天列表
|
|
|
+ var obj = {};
|
|
|
+ obj = {
|
|
|
+ action: "list",
|
|
|
+ recv_user_id: this.getUserObj.user_id,
|
|
|
+ data: {
|
|
|
+ msg_status: false,
|
|
|
+ msg_info: "",
|
|
|
+ },
|
|
|
+ };
|
|
|
+ this.websock.send(JSON.stringify(obj));
|
|
|
+ } else if (data.action == 'recv_video') {
|
|
|
+ // 获取当前点击用户的房间号以及登录房间所需的Token
|
|
|
+ console.log(JSON.parse(event.data));
|
|
|
+ }
|
|
|
+ };
|
|
|
+ this.websock.onerror = (event) => {
|
|
|
+ console.log("WebSocket:发生错误 ");
|
|
|
+ console.log(event);
|
|
|
+ };
|
|
|
+ this.websock.onclose = (event) => {
|
|
|
+ console.log("WebSocket:已关闭");
|
|
|
+ console.log(event);
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 音视频消息功能初始化
|
|
|
+ videoInit() {
|
|
|
+ this.zg = new ZegoExpressEngine(this.appID, this.videoUrl);
|
|
|
+ this.soundOn(); // 监听房间
|
|
|
+ this.detection(); // 检测是否兼容当前浏览器
|
|
|
+ },
|
|
|
+ // 监听房间
|
|
|
+ soundOn() {
|
|
|
+ // 房间状态更新回调
|
|
|
+ this.zg.on(
|
|
|
+ "roomStateUpdate",
|
|
|
+ (roomID, state, errorCode, extendedData) => {
|
|
|
+ if (state == "CONNECTED") {
|
|
|
+ // 与房间连接成功,只有当房间状态是连接成功时,才能进行推流、拉流等操作。
|
|
|
+ // 接下来的“预览并推流”的代码写在这里
|
|
|
+ console.log("房间连接成功");
|
|
|
+ }
|
|
|
+ if (state == "DISCONNECTED") {
|
|
|
+ // 与房间断开了连接
|
|
|
+ console.log("与房间断开连接");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (state == "CONNECTING") {
|
|
|
+ // 与房间尝试连接中
|
|
|
+ console.log("与房间尝试连接中");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ this.zg.on("roomUserUpdate", (roomID, updateType, userList) => {
|
|
|
+ // 其他用户进出房间的通知
|
|
|
+ console.log(updateType);
|
|
|
+ console.log(userList);
|
|
|
+ console.log("有其他用户进出房间");
|
|
|
+ });
|
|
|
+
|
|
|
+ this.zg.on(
|
|
|
+ "roomStreamUpdate",
|
|
|
+ async (roomID, updateType, streamList, extendedData) => {
|
|
|
+ console.log(roomID);
|
|
|
+ console.log(updateType);
|
|
|
+ console.log(streamList);
|
|
|
+ console.log(extendedData);
|
|
|
+ // 房间内其他用户音视频流变化的通知
|
|
|
+ console.log("有其他用户开启或关闭音频");
|
|
|
+ if (updateType == "ADD") {
|
|
|
+ // 流新增,开始拉流
|
|
|
+ this.tensile(streamList[0].streamID);
|
|
|
+ } else if (updateType == "DELETE") {
|
|
|
+ // 流删除,停止拉流
|
|
|
+ this.notTensile(streamList[0].streamID);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ this.zg.on("publisherStateUpdate", (result) => {
|
|
|
+ // 推流状态更新回调
|
|
|
+ console.log("推流状态更新");
|
|
|
+ });
|
|
|
+
|
|
|
+ this.zg.on("publishQualityUpdate", (streamID, stats) => {
|
|
|
+ // 推流质量回调
|
|
|
+ console.log("推流质量更新");
|
|
|
+ });
|
|
|
+
|
|
|
+ // this.zg.on("IMRecvBroadcastMessage", (roomID, chatData) => {
|
|
|
+ // console.log("IMRecvBroadcastMessage", roomID, chatData);
|
|
|
+ // console.log(">>>>>>>>>>>>>>>>>>>>>接收到文本消息了");
|
|
|
+ // var list = {
|
|
|
+ // id: "2", //模拟数据中使用id来区分当前是发送人还是接收人 1为接收人 2为发送人
|
|
|
+ // msg: chatData[0].message, // 文本消息
|
|
|
+ // img: "../../../static/img/6.png", // 头像url
|
|
|
+ // };
|
|
|
+ // this.msgList = [...this.msgList, list];
|
|
|
+ // // let message = {
|
|
|
+ // // ID: 'zego' + chatData[0].fromUser.userID + chatData[0].sendTime,
|
|
|
+ // // name: chatData[0].fromUser.userName,
|
|
|
+ // // time: format(chatData[0].sendTime),
|
|
|
+ // // content: chatData[0].message + '(广播发送)'
|
|
|
+ // // }
|
|
|
+ // });
|
|
|
+ },
|
|
|
+ // 检测是否兼容当前浏览器
|
|
|
+ async detection() {
|
|
|
+ const result = await this.zg.checkSystemRequirements();
|
|
|
+ // 返回的 result 为兼容性检测结果。 webRTC 为 true 时表示支持 webRTC,其他属性含义可以参考接口 API 文档
|
|
|
+ console.log(result);
|
|
|
+ if (result.webRTC == true) {
|
|
|
+ console.log("兼容");
|
|
|
+ } else {
|
|
|
+ console.log("不兼容");
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
//生命周期 - 创建完成(可以访问当前this实例)
|
|
|
created() {},
|
|
|
//生命周期 - 挂载完成(可以访问DOM元素)
|
|
|
- mounted() {},
|
|
|
+ mounted() {
|
|
|
+ this.organizationData(); //获取左侧组织列表
|
|
|
+ this.userListData(); // 获取右侧用户列表
|
|
|
+
|
|
|
+ this.msgInit(); // 文本消息功能初始化
|
|
|
+ this.videoInit(); // 视频消息功能初始化
|
|
|
+ },
|
|
|
beforeCreate() {}, //生命周期 - 创建之前
|
|
|
beforeMount() {}, //生命周期 - 挂载之前
|
|
|
beforeUpdate() {}, //生命周期 - 更新之前
|
|
|
@@ -34,4 +793,190 @@ export default {
|
|
|
};
|
|
|
</script>
|
|
|
<style lang='less' scoped>
|
|
|
+.realTime_box {
|
|
|
+ .card_box {
|
|
|
+ display: flex;
|
|
|
+ width: 100%;
|
|
|
+ // 树形图
|
|
|
+ .userManger_left {
|
|
|
+ width: 19%;
|
|
|
+ margin: 0 15px 0 0;
|
|
|
+ padding: 5px;
|
|
|
+ border: 1px solid #eeeeee;
|
|
|
+ border-radius: 5px;
|
|
|
+ overflow: hidden;
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 搜索和表格
|
|
|
+ .userManger_right {
|
|
|
+ width: 80%;
|
|
|
+ // border: 1px solid red;
|
|
|
+
|
|
|
+ // 搜索
|
|
|
+ .search_box {
|
|
|
+ display: flex;
|
|
|
+ /deep/.el-input {
|
|
|
+ width: 20%;
|
|
|
+ margin: 0 15px 0 0;
|
|
|
+ }
|
|
|
+ .btn_box {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ a {
|
|
|
+ text-decoration: none;
|
|
|
+ }
|
|
|
+ .reset {
|
|
|
+ color: #1890ff;
|
|
|
+ }
|
|
|
+ .delete {
|
|
|
+ color: #f56c6c;
|
|
|
+ }
|
|
|
+ .line {
|
|
|
+ display: inline-block;
|
|
|
+ width: 1px;
|
|
|
+ background: rgba(0, 0, 0, 0.09);
|
|
|
+ margin: 0 11px;
|
|
|
+ height: 14px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /deep/.el-select {
|
|
|
+ width: 80%;
|
|
|
+ }
|
|
|
+
|
|
|
+ /deep/.el-cascader {
|
|
|
+ width: 80%;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 视频通话
|
|
|
+ .video_box {
|
|
|
+ border: 1px solid #000;
|
|
|
+ // margin: 15px 0 0 0;
|
|
|
+ background: #2c2c2c;
|
|
|
+ height: 325px;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ // 主视频画面
|
|
|
+ .host_video {
|
|
|
+ width: 100%;
|
|
|
+ height: 300px;
|
|
|
+ display: table-cell;
|
|
|
+ vertical-align: middle;
|
|
|
+ text-align: center;
|
|
|
+ img {
|
|
|
+ margin: 0 atuo;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 副视频画面
|
|
|
+ .deputy_video {
|
|
|
+ width: 90px;
|
|
|
+ height: 90px;
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ right: 0;
|
|
|
+ background: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 操作
|
|
|
+ .operate {
|
|
|
+ height: 25px;
|
|
|
+ background: #000;
|
|
|
+ padding: 5px 0 5px 0;
|
|
|
+ margin: -13px 0 0 0px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 聊天内容 */
|
|
|
+ .ul_list {
|
|
|
+ height: 350px;
|
|
|
+ // margin-left: -41px;
|
|
|
+ overflow: hidden;
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .list_msgBox1 {
|
|
|
+ display: flex;
|
|
|
+ margin-top: 22px;
|
|
|
+ justify-content: end;
|
|
|
+ }
|
|
|
+ .list_msgBox2 {
|
|
|
+ display: flex;
|
|
|
+ margin-top: 22px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .test-5::-webkit-scrollbar {
|
|
|
+ /*滚动条整体样式*/
|
|
|
+ width: 10px; /*高宽分别对应横竖滚动条的尺寸*/
|
|
|
+ height: 1px;
|
|
|
+ }
|
|
|
+ .test-5::-webkit-scrollbar-thumb {
|
|
|
+ /*滚动条里面小方块*/
|
|
|
+ border-radius: 10px;
|
|
|
+ background-color: skyblue;
|
|
|
+ background-image: -webkit-linear-gradient(
|
|
|
+ 45deg,
|
|
|
+ rgba(255, 255, 255, 0.2) 25%,
|
|
|
+ transparent 25%,
|
|
|
+ transparent 50%,
|
|
|
+ rgba(255, 255, 255, 0.2) 50%,
|
|
|
+ rgba(255, 255, 255, 0.2) 75%,
|
|
|
+ transparent 75%,
|
|
|
+ transparent
|
|
|
+ );
|
|
|
+ }
|
|
|
+ .test-5::-webkit-scrollbar-track {
|
|
|
+ /*滚动条里面轨道*/
|
|
|
+ box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
|
|
|
+ background: #ededed;
|
|
|
+ border-radius: 10px;
|
|
|
+ }
|
|
|
+ .list {
|
|
|
+ /* border: 1px solid red; */
|
|
|
+ width: 100%;
|
|
|
+ height: 100px;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ElementUI 样式 */
|
|
|
+ // 聊天框
|
|
|
+ /deep/.el-dialog {
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+ /deep/.el-dialog__header {
|
|
|
+ background: #f2f2f2;
|
|
|
+ border-bottom: 1px solid #cacaca;
|
|
|
+ }
|
|
|
+ /deep/.el-dialog__title {
|
|
|
+ font-weight: 550;
|
|
|
+ font-size: 15px;
|
|
|
+ line-height: 0;
|
|
|
+ float: left;
|
|
|
+ }
|
|
|
+ /deep/.el-dialog__headerbtn {
|
|
|
+ top: 10px;
|
|
|
+ right: 10px;
|
|
|
+ }
|
|
|
+ /deep/.el-dialog__headerbtn .el-dialog__close {
|
|
|
+ font-size: 20px;
|
|
|
+ line-height: 15px;
|
|
|
+ }
|
|
|
+ /deep/.el-dialog__body {
|
|
|
+ padding: 0;
|
|
|
+ // margin-top: -15px;
|
|
|
+ }
|
|
|
+ /deep/.el-textarea__inner {
|
|
|
+ border: 0;
|
|
|
+ border-top: 1px solid #dcdfe6;
|
|
|
+ border-radius: 0;
|
|
|
+ height: 95px;
|
|
|
+ }
|
|
|
+
|
|
|
+ // /deep/.el-dialog__body {
|
|
|
+ // padding: 0;
|
|
|
+ // }
|
|
|
+}
|
|
|
</style>
|