realTime.vue 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696
  1. <!-- -->
  2. <template>
  3. <div class="realTime_box">
  4. <!-- 搜索 -->
  5. <el-row>
  6. <el-col>
  7. <!-- 组织搜索 -->
  8. <div class="search_box">
  9. <el-input
  10. size="mini"
  11. placeholder="请输入用户姓名"
  12. v-model.trim="nameVal"
  13. @change="searchData"
  14. clearable
  15. >
  16. </el-input>
  17. <el-input
  18. size="mini"
  19. placeholder="请输入手机号"
  20. v-model.trim="phoneVal"
  21. @change="searchData"
  22. clearable
  23. >
  24. </el-input>
  25. <div class="btn_box">
  26. <el-button type="info" size="mini" @click="searchData"
  27. >搜索</el-button
  28. >
  29. </div>
  30. </div>
  31. </el-col>
  32. </el-row>
  33. <el-card style="margin-top: 15px">
  34. <div class="card_box" style="margin-top: 15px">
  35. <!-- 组织 -->
  36. <div
  37. class="userManger_left"
  38. :style="'height:' + 26 * 25 + 'px;' + 'overflow-y: auto'"
  39. >
  40. <el-tree
  41. :data="data"
  42. :props="defaultProps"
  43. v-loading="loading2"
  44. @node-click="handleNodeClick"
  45. ></el-tree>
  46. </div>
  47. <!-- 表格 -->
  48. <div class="userManger_right">
  49. <el-table
  50. v-loading="loading"
  51. :data="tableData"
  52. stripe
  53. :height="48 * 13"
  54. style="width: 100%; overflow-y: auto"
  55. >
  56. <el-table-column prop="ind" label="序号" width="180">
  57. <template slot-scope="scope">
  58. <span>{{ (page - 1) * 20 + scope.row.ind }}</span>
  59. </template>
  60. </el-table-column>
  61. <el-table-column prop="real_name" label="成员" width="330">
  62. </el-table-column>
  63. <el-table-column prop="mobile" label="手机号" width="250">
  64. <template slot-scope="scope">
  65. <span>{{ scope.row.mobile || '无' }}</span>
  66. </template>
  67. </el-table-column>
  68. <el-table-column
  69. :show-overflow-tooltip="true"
  70. prop="address"
  71. label="职位"
  72. width="320"
  73. >
  74. <template slot-scope="scope">
  75. <span v-for="(item, index) in scope.row.org_list" :key="index"
  76. >{{ item.org_name }}
  77. <span v-if="index !== scope.row.org_list.length - 1">、</span>
  78. </span>
  79. </template>
  80. </el-table-column>
  81. <el-table-column label="操作" width="200" fixed="right">
  82. <template slot-scope="scope">
  83. <span
  84. style="
  85. height: 30px;
  86. display: inline-block;
  87. margin: 0 0 0 0;
  88. position: absolute;
  89. left: 0;
  90. top: 11px;
  91. "
  92. >
  93. <el-badge v-if="scope.row.unread" is-dot class="item">
  94. <img
  95. @click="msgAxios(scope.row)"
  96. src="../../assets/images/realTime/xiaoxi.png"
  97. alt=""
  98. />
  99. </el-badge>
  100. <img
  101. v-else
  102. @click="msgAxios(scope.row)"
  103. src="../../assets/images/realTime/xiaoxi.png"
  104. alt=""
  105. />
  106. </span>
  107. <span style="position: absolute; top: 12px; left: 60px">
  108. <img
  109. @click="videoAxios(scope.row)"
  110. src="../../assets/images/realTime/shipin.png"
  111. alt=""
  112. />
  113. </span>
  114. </template>
  115. </el-table-column>
  116. </el-table>
  117. <!-- 分页 -->
  118. <el-pagination
  119. v-if="tableData.length !== 0"
  120. @current-change="changeList"
  121. background
  122. layout="prev, pager, next, jumper"
  123. :current-page="page"
  124. :total="pageSum"
  125. :page-size="20"
  126. >
  127. </el-pagination>
  128. </div>
  129. </div>
  130. </el-card>
  131. <!-- 视频通话 -->
  132. <el-dialog
  133. :close-on-click-modal="false"
  134. :close-on-press-escape="false"
  135. :before-close="handleClose"
  136. :modal="false"
  137. v-dialogDrag
  138. :fullscreen="zoomShow"
  139. :title="videoTle"
  140. :visible.sync="videoVisible"
  141. width="600px"
  142. >
  143. <!-- <div class="video_box"> -->
  144. <div :class="zoomShow == false ? 'video_box' : 'video_box-big'">
  145. <!-- 最大化、最小化 -->
  146. <div
  147. style="
  148. position: absolute;
  149. right: 42px;
  150. color: #9fa2a7;
  151. top: -28px;
  152. font-size: 13px;
  153. "
  154. >
  155. <!-- 最小化 -->
  156. <span
  157. style="font-size: 25px; cursor: pointer"
  158. class="iconfont icon-zuixiaohua"
  159. @click="zoomOperate('small')"
  160. ></span>
  161. <!-- 最大化 -->
  162. <span
  163. style="font-size: 25px; cursor: pointer"
  164. class="iconfont icon-zuidahua"
  165. @click="zoomOperate('big')"
  166. ></span>
  167. </div>
  168. <!-- 最大化、最小化 -->
  169. <div class="host_video" v-if="videoShow">
  170. <img
  171. src="../../assets/images/realTime/8.png"
  172. alt=""
  173. class="video_img"
  174. />
  175. <!-- <img
  176. v-if="audioShow"
  177. src="../../assets/images/realTime/8.png"
  178. alt=""
  179. class=""
  180. style="margin: 120px atuo;"
  181. />
  182. <img
  183. v-else
  184. src="../../assets/images/realTime/13.png"
  185. alt=""
  186. class=""
  187. /> -->
  188. </div>
  189. <div class="host_video" v-else>
  190. <!-- <video
  191. style="width: 100%; height: 100%"
  192. ref="localVideo"
  193. autoplay
  194. playsinline
  195. :muted="true"
  196. ></video> -->
  197. <!-- <video
  198. style="width: 100%; height: 100%"
  199. :ref="idName1"
  200. autoplay
  201. playsinline
  202. :muted="true"
  203. ></video> -->
  204. <video
  205. style="width: 100%; height: 100%"
  206. :ref="idName"
  207. autoplay
  208. playsinline
  209. :muted="false"
  210. ></video>
  211. </div>
  212. <!-- 副视频画面 -->
  213. <div v-if="audioShow" @click="switchWindow" class="deputy_video" v-drag>
  214. <!-- <video
  215. style="width: 100%; height: 100%"
  216. ref="remoteVideo"
  217. autoplay
  218. playsinline
  219. :muted="true"
  220. ></video> -->
  221. <!-- <video
  222. style="width: 100%; height: 100%"
  223. :ref="idName"
  224. autoplay
  225. playsinline
  226. :muted="true"
  227. ></video> -->
  228. <video
  229. style="width: 100%; height: 100%"
  230. :ref="idName1"
  231. autoplay
  232. playsinline
  233. :muted="false"
  234. ></video>
  235. </div>
  236. <!-- 操作 -->
  237. <div class="operate">
  238. <!-- <div style="margin: 0 10px 0 0">
  239. <img
  240. v-if="microphone"
  241. src="../../assets/images/realTime/10.png"
  242. alt=""
  243. />
  244. <img v-else src="../../assets/images/realTime/9.png" alt="" />
  245. </div> -->
  246. <!-- <div v-if="audioShow" style="margin: 0 10px 0 0">
  247. <img
  248. v-if="camera"
  249. @click="notPlugFlow"
  250. src="../../assets/images/realTime/12.png"
  251. alt=""
  252. />
  253. <img
  254. @click="openVideo"
  255. v-else
  256. src="../../assets/images/realTime/11.png"
  257. alt=""
  258. />
  259. </div> -->
  260. <el-button
  261. type="danger"
  262. style="padding: 2px 10px; margin: -2px 10px 0 0"
  263. @click="notLogin"
  264. size="mini"
  265. >挂断</el-button
  266. >
  267. </div>
  268. </div>
  269. </el-dialog>
  270. <!-- 文本聊天框 -->
  271. <el-dialog
  272. custom-class="msgFrame"
  273. :title="tltData"
  274. v-dialogDrag
  275. :close-on-click-modal="false"
  276. :modal="false"
  277. :close-on-press-escape="false"
  278. :visible.sync="dialogVisible"
  279. width="500px"
  280. >
  281. <!-- 聊天内容 -->
  282. <ul class="ul_list test-5" id="msgBox">
  283. <!-- 查看更多 -->
  284. <!-- <li class="">
  285. <div
  286. v-if="iconShow"
  287. style="color: #0400ff; cursor: pointer; text-align: center"
  288. @click="moreMsg"
  289. >
  290. 查看更多消息
  291. </div>
  292. </li> -->
  293. <li class="list" v-for="(item, index) in msgList.msg_list" :key="index">
  294. <!-- me -->
  295. <div class="list_msgBox1" v-if="item.is_right == true">
  296. <!-- <div class="el-icon-loading"></div> -->
  297. <div
  298. style="
  299. background: #60fba5;
  300. font-weight: 550;
  301. color: #000;
  302. padding: 12px 15px 0 15px;
  303. line-height: 25px;
  304. border-radius: 8px;
  305. "
  306. >
  307. {{ item.msg_info }}
  308. </div>
  309. <div
  310. style="
  311. width: 0;
  312. height: 0;
  313. border-top: 6px solid transparent;
  314. border-left: 10px solid #60fba5;
  315. border-bottom: 5px solid transparent;
  316. margin: 23px 0 0 0;
  317. "
  318. ></div>
  319. <div
  320. style="
  321. width: 45px;
  322. height: 45px;
  323. border-radius: 10px;
  324. line-height: 45px;
  325. text-align: center;
  326. font-size: 16px;
  327. background-image: linear-gradient(#a7fbc6, #60fba5);
  328. color: #fff;
  329. "
  330. >
  331. </div>
  332. </div>
  333. <!-- you -->
  334. <div v-else-if="item.is_right == false" class="list_msgBox2">
  335. <div
  336. style="
  337. width: 45px;
  338. height: 45px;
  339. border-radius: 10px;
  340. line-height: 45px;
  341. text-align: center;
  342. font-size: 16px;
  343. background-image: linear-gradient(#addbff, #5cacff);
  344. color: #fff;
  345. "
  346. >
  347. {{ getUserObj.real_name.slice(0, 1) }}
  348. </div>
  349. <div
  350. style="
  351. width: 0;
  352. height: 0;
  353. border-top: 5px solid transparent;
  354. border-right: 10px solid #eae9eb;
  355. border-bottom: 6px solid transparent;
  356. margin: 24px 0 0 0;
  357. "
  358. ></div>
  359. <div
  360. style="
  361. background: #eae9eb;
  362. padding: 12px 15px 0 15px;
  363. line-height: 25px;
  364. border-radius: 8px;
  365. font-weight: 550;
  366. color: #000;
  367. "
  368. >
  369. {{ item.msg_info }}
  370. </div>
  371. </div>
  372. </li>
  373. </ul>
  374. <!-- 发送框 -->
  375. <el-input
  376. style="border: 0"
  377. resize="none"
  378. type="textarea"
  379. v-model="input"
  380. @keyup.enter.native="submit()"
  381. @keydown.native="pushKeyword($event)"
  382. maxlength="30"
  383. show-word-limit
  384. placeholder="按下enter按键发送消息"
  385. ></el-input>
  386. </el-dialog>
  387. <el-dialog
  388. title="视频通话通知"
  389. :close-on-click-modal="false"
  390. :modal="false"
  391. :close-on-press-escape="false"
  392. :visible.sync="videoNoticeDialogVisible"
  393. @close="handleCloseNoticeDialog"
  394. width="500px"
  395. >
  396. <div style="padding:40px 20px;">{{ videoNoticeTitle }}</div>
  397. <span slot="footer" class="dialog-footer">
  398. <el-button @click="handleCloseNoticeDialog">取 消</el-button>
  399. <el-button type="primary" @click="confrimNoticeClick">确 定</el-button>
  400. </span>
  401. </el-dialog>
  402. </div>
  403. </template>
  404. <script>
  405. import { mapState, mapMutations } from 'vuex';
  406. import { color } from 'highcharts';
  407. import { ZegoExpressEngine } from 'zego-express-engine-webrtc';
  408. export default {
  409. //import引入的组件需要注入到对象中才能使用
  410. components: {},
  411. data() {
  412. //这里存放数据
  413. return {
  414. fullHeight: document.documentElement.clientHeight - 116, //
  415. // 搜索
  416. nameVal: '',
  417. phoneVal: '',
  418. // 表格
  419. tableData: [],
  420. websockMsgList: [], // websocket传递来的数组数据
  421. loading: false, // 加载
  422. org_id: '', //组织id
  423. // 树形图
  424. data: [],
  425. loading2: false,
  426. defaultProps: {
  427. children: 'childrens',
  428. label: 'org_name'
  429. },
  430. // 分页
  431. pageSum: 0,
  432. page: 1,
  433. // 视频通话弹框
  434. idName: 'remoteVideo', // ref 副视频
  435. idName1: 'localVideo', // ref 主视频
  436. videoVisible: false,
  437. videoShow: true, //主视频是否展示画面
  438. audioShow: true, // 判断当前是语音通话还是视频通话 true为视频 false为语音
  439. microphone: true, // 是否打开麦克风
  440. camera: true, // 是否打开摄像头
  441. // appID: 2672645646, //项目唯一标识 AppID
  442. appID: 3215939266, //项目唯一标识 AppID
  443. // server: "1e8344b2a193220e5e96338ba53c3dcc", // 接入服务器地址Server
  444. // videoUrl: "wss://webliveroom2672645646-api.imzego.com/ws", // 请求 - 测试
  445. videoUrl: 'wss://webliveroom3215939266-api.imzego.com/ws', // 请求 - 正式
  446. zg: null,
  447. // UserID: "sample" + Math.floor(Math.random() * 10000000000000).toString(),
  448. UserID: 'user00002',
  449. // UserID: "168",
  450. // StreamID: "web-4796754531236",
  451. StreamID: 'web-' + Math.floor(Math.random() * 10000000000000).toString(),
  452. localStream: null,
  453. Token: '',
  454. RoomID: '',
  455. videoTle: '正在和云飞-卢万里视频通话',
  456. timer: null, // 接听
  457. // 文本聊天框
  458. tltData: '',
  459. dialogVisible: false,
  460. input: '', //发送框
  461. iconShow: true,
  462. // 文本消息功能
  463. url:
  464. // "ws://192.168.1.17:12345/api/api_gateway?method=control_center.real_time.im_message",
  465. // "ws" +
  466. // "https" +
  467. this.$wsUrl +
  468. '/api/api_gateway?method=control_center.real_time.im_message',
  469. websock: null,
  470. getUserObj: {}, // 获取到当前点击的行数据
  471. msgList: [], //当前点击的账号消息列表
  472. userName: '',
  473. // 心跳、重连机制
  474. ws: null, //建立的连接
  475. lockReconnect: false, //是否真正建立连接
  476. timeout: 5 * 1000, //30秒一次心跳
  477. timeoutObj: null, //心跳心跳倒计时
  478. serverTimeoutObj: null, //心跳倒计时
  479. timeoutnum: null, //断开 重连倒计时
  480. // 视频通话窗口缩放
  481. zoomShow: false, // 默认最小化
  482. // websocket断开加载框
  483. fullscreenLoading: null,
  484. // 消息发送加载
  485. msgSetTime: null,
  486. socketTimeoutLogs: [],
  487. currentVideoCallUserID: '',
  488. videoNoticeTitle: '',
  489. videoNoticeDialogVisible: false,
  490. currentVideoNoticeData: null,
  491. isNoticeDialogConfirm: false
  492. };
  493. },
  494. //监听属性 类似于data概念
  495. computed: {
  496. ...mapState({
  497. isVideoCallRefused: state => state.isVideoCallRefused,
  498. isVideoTalking: state => state.isVideoTalking
  499. })
  500. },
  501. //监控data中的数据变化
  502. watch: {
  503. fullHeight(val) {
  504. //监控浏览器高度变化
  505. if (!this.timer) {
  506. this.fullHeight = val;
  507. this.timer = true;
  508. let that = this;
  509. setTimeout(function() {
  510. //防止过度调用监测事件,导致卡顿
  511. that.timer = false;
  512. }, 400);
  513. }
  514. },
  515. // 聊天列表
  516. msgList(val) {
  517. // 实现打开聊天框后滚动条定位到最下方
  518. this.$nextTick(() => {
  519. var div = document.getElementById('msgBox');
  520. div.scrollTop = div.scrollHeight;
  521. });
  522. },
  523. // 聊天框
  524. dialogVisible(val) {
  525. if (val == false) {
  526. console.log('update table read status');
  527. this.updateTableUnreadStatus();
  528. this.msgList = [];
  529. }
  530. },
  531. // 音视频弹框
  532. videoVisible(val) {
  533. if (val == false) {
  534. this.notPlugFlow(); // 停止推流
  535. this.notTensile(); // 停止拉流
  536. this.notLogin(); //退出房间
  537. }
  538. },
  539. // 给表格文本消息增加提示,数据从webscoket中获取
  540. tableData(val) {
  541. var that = this;
  542. this.updateTableUnreadStatus();
  543. },
  544. deep: true,
  545. // websocket列表变化
  546. websockMsgList(val) {
  547. console.log(
  548. '-----------------有变化了啊---------------------------',
  549. val
  550. );
  551. // var that = this
  552. // for (var i = 0; i < this.tableData.length; i++) {
  553. // let sdhkj = this.tableData[i];
  554. // for (var k = 0; k < val.length; k++) {
  555. // let sdjaks = val[k];
  556. // if (sdhkj.real_name == sdjaks.real_name && sdjaks.unread !== 0 && sdjaks.unread) {
  557. // this.tableData[i]['unread'] = sdjaks.unread
  558. // }
  559. // }
  560. // }
  561. this.userListData(); // 获取右侧用户列表
  562. },
  563. isVideoCallRefused(val) {
  564. console.warn(val, 'isVideoCallRefused video');
  565. if (val) {
  566. if (this.videoNoticeDialogVisible) {
  567. this.$message({
  568. message: '对方已挂断',
  569. type: 'warning',
  570. duration: 1500
  571. });
  572. this.videoNoticeDialogVisible = false;
  573. } else {
  574. this.$message({
  575. message: '对方正忙,请稍后再试!',
  576. type: 'warning',
  577. duration: 1500
  578. });
  579. }
  580. this.notLogin();
  581. }
  582. }
  583. },
  584. //方法集合
  585. methods: {
  586. ...mapMutations([
  587. 'updateVideoSelfRoomInfo',
  588. 'updateIsRefusedCall',
  589. 'updateVideoInfo',
  590. 'updateTalkingStatus'
  591. ]),
  592. updateTableUnreadStatus() {
  593. for (var i = 0; i < this.tableData.length; i++) {
  594. let sdhkj = this.tableData[i];
  595. for (var k = 0; k < this.websockMsgList.length; k++) {
  596. let sdjaks = this.websockMsgList[k];
  597. if (sdhkj.real_name == sdjaks.real_name) {
  598. this.tableData[i]['unread'] = Number(sdjaks.unread) || 0;
  599. }
  600. }
  601. }
  602. },
  603. //动态获取浏览器高度
  604. get_boderHeight() {
  605. const that = this;
  606. window.onresize = () => {
  607. return (() => {
  608. window.fullHeight = document.documentElement.clientHeight;
  609. that.fullHeight = window.fullHeight;
  610. })();
  611. };
  612. },
  613. // 树形图
  614. handleNodeClick(data) {
  615. console.log(data);
  616. this.org_id = data.id;
  617. this.userListData();
  618. },
  619. // 搜索
  620. searchData() {
  621. this.page = 1;
  622. this.userListData();
  623. },
  624. // 分页
  625. changeList(page) {
  626. this.page = page;
  627. this.loading = true;
  628. this.tableData = [];
  629. this.userListData();
  630. },
  631. // 获取左侧组织列表
  632. organizationData() {
  633. this.$axios({
  634. method: 'POST',
  635. url: '/api/api_gateway?method=sysmenage.usermanager.org_list',
  636. data: this.qs.stringify({
  637. page: this.page,
  638. page_item: '100000000',
  639. org_name: '',
  640. is_mails: 1
  641. })
  642. })
  643. .then(res => {
  644. if (res.data.data.page_list.length !== 0) {
  645. var obj = {
  646. org_name: '全部',
  647. id: ''
  648. };
  649. var data = res.data.data.page_list;
  650. this.data = [obj, ...data]; // 左侧组织列表
  651. }
  652. this.loading2 = false;
  653. })
  654. .catch(err => {
  655. this.loading2 = false;
  656. });
  657. },
  658. // 获取右侧用户列表
  659. userListData() {
  660. this.$axios({
  661. method: 'POST',
  662. url: '/api/api_gateway?method=sysmenage.usermanager.user_list',
  663. data: this.qs.stringify({
  664. page: this.page,
  665. page_item: '20',
  666. real_name: this.nameVal, //用户名称
  667. mobile: this.phoneVal, // 电话
  668. org_id: this.org_id,
  669. is_mails: 1
  670. })
  671. })
  672. .then(res => {
  673. if (res.data.data.total_item !== 0) {
  674. var data = res.data.data.page_list;
  675. var list = [];
  676. data.forEach((item, index) => {
  677. item.ind = index + 1;
  678. list.push(item);
  679. });
  680. this.tableData = list;
  681. this.pageSum = res.data.data.total_item;
  682. this.loading = false;
  683. }
  684. })
  685. .catch(err => {
  686. this.loading = false;
  687. });
  688. },
  689. // 文本消息
  690. msgAxios(data) {
  691. this.getUserObj = data;
  692. this.redtf = data;
  693. this.userName = localStorage.getItem('username');
  694. console.log(this.userName);
  695. this.tltData = '与' + data.real_name + '的对话';
  696. var obj = {};
  697. obj = {
  698. action: 'list',
  699. recv_user_id: data.user_id,
  700. data: {
  701. msg_status: false,
  702. msg_info: ''
  703. }
  704. };
  705. this.websock.send(JSON.stringify(obj)); // 获取聊天记录
  706. // var readObj = {};
  707. // readObj = {
  708. // action: "read",
  709. // send_user_id: data.user_id,
  710. // data: {
  711. // msg_status: false,
  712. // msg_info: "",
  713. // },
  714. // };
  715. // this.websock.send(JSON.stringify(readObj)); // 消息已读
  716. this.dialogVisible = true;
  717. },
  718. // 视频消息
  719. videoAxios(data) {
  720. this.getUserObj = data;
  721. this.userName = localStorage.getItem('username');
  722. this.videoTle = '正在和' + data.real_name + '视频通话';
  723. this.UserID = localStorage.getItem('userID');
  724. console.warn(data.user_id, '------------------------------ vidoe ');
  725. // 先获取当前用户的房间号和登录所需的Token
  726. var obj = {};
  727. obj = {
  728. action: 'send_video',
  729. recv_user_id: data.user_id,
  730. data: {
  731. msg_status: false,
  732. msg_info: ''
  733. }
  734. };
  735. // obj = {
  736. // action: 'reject_video', // 动作标识,必填
  737. // recv_user_id: data.user_id, // 接收人用户id, 非必填
  738. // data: {}
  739. // };
  740. console.warn(obj, '------------------------------ vidoe ');
  741. this.currentVideoCallUserID = data.user_id;
  742. // console.log('gdahjdgjasgd', data.user_id)
  743. this.websock.send(JSON.stringify(obj));
  744. // // 登录房间
  745. // this.zg.loginRoom(
  746. // this.RoomID,
  747. // this.Token,
  748. // { userID: this.UserID, userName: this.UserID },
  749. // { userUpdate: true }
  750. // ).then((result) => {
  751. // if (result == true) {
  752. // this.plugFlow(); //推流
  753. // this.videoVisible = true
  754. // }
  755. // });
  756. },
  757. // 打开视频画面
  758. openVideo() {
  759. this.plugFlow();
  760. },
  761. // 音视频推流
  762. async plugFlow() {
  763. this.videoShow = false;
  764. this.camera = true;
  765. const localStream = await this.zg.createStream();
  766. // stream 为 MediaStream 对象,开发者可通过赋值给 video 或 audio 的 srcObject 属性进行渲染
  767. this.$refs['localVideo'].srcObject = localStream;
  768. this.localStream = localStream;
  769. // localStream 为创建流获取的 MediaStream 对象
  770. this.zg.startPublishingStream(this.StreamID, localStream);
  771. },
  772. // 音视频停止推流
  773. notPlugFlow() {
  774. this.videoShow = true;
  775. this.camera = false;
  776. this.zg.stopPublishingStream(this.StreamID);
  777. this.zg.destroyStream(this.localStream);
  778. },
  779. // 拉流
  780. async tensile(streamID) {
  781. var playOption = { videoDecodeType: 'H264', playType: 'video' };
  782. const remoteStream = await this.zg.startPlayingStream(
  783. streamID,
  784. playOption
  785. );
  786. // remoteVideo 为本地 <video> 或 <audio> 对象
  787. this.$refs['remoteVideo'].srcObject = remoteStream;
  788. },
  789. notTensile(streamID) {
  790. this.zg.stopPlayingStream(streamID);
  791. },
  792. // 切换视频窗口
  793. switchWindow() {
  794. // 副视频画面 remoteVideo
  795. // 主视频画面 localVideo
  796. this.idName = this.idName == 'remoteVideo' ? 'localVideo' : 'remoteVideo';
  797. this.idName =
  798. this.idName1 == 'remoteVideo' ? 'localVideo' : 'remoteVideo';
  799. },
  800. // 退出房间
  801. notLogin() {
  802. this.updateTalkingStatus(false);
  803. this.updateIsRefusedCall(false);
  804. clearTimeout(this.timer);
  805. this.zg.logoutRoom(this.RoomID);
  806. this.videoVisible = false;
  807. this.hangUp();
  808. },
  809. // 当音视频通话关闭时的回调
  810. handleClose(done) {
  811. var that = this;
  812. this.$confirm('目前正在音视频通话中,确认关闭?')
  813. .then(_ => {
  814. done();
  815. that.notLogin(); // 退出房间
  816. this.currentVideoCallUserID = '';
  817. })
  818. .catch(_ => {});
  819. },
  820. // 发送消息
  821. async submit() {
  822. if (this.input.split(' ').join('').length == 0) {
  823. if (document.getElementsByClassName('el-message').length == 0) {
  824. this.$message({
  825. message: '不能发送空白消息!',
  826. type: 'warning',
  827. duration: 1500
  828. });
  829. }
  830. this.input = '';
  831. } else {
  832. try {
  833. var obj = {};
  834. obj = {
  835. action: 'send',
  836. recv_user_id: this.getUserObj.user_id,
  837. data: {
  838. msg_status: false,
  839. msg_info: this.input
  840. }
  841. };
  842. var v = JSON.stringify(obj);
  843. this.websock.send(v);
  844. this.input = '';
  845. this.msgSetTime = setTimeout(() => {
  846. // 设定十秒内没有接收到服务器返回的list数据就表明消息没有发送成
  847. if (document.getElementsByClassName('el-message').length == 0) {
  848. this.$message({
  849. message: '消息发送失败,请刷新界面重试!',
  850. type: 'warning',
  851. duration: 1500
  852. });
  853. }
  854. }, 10000);
  855. } catch (error) {
  856. console.log('>>> sendMsg, error: ', error);
  857. }
  858. }
  859. },
  860. // 取消回车换行行为
  861. pushKeyword(event) {
  862. if (event.keyCode === 13) {
  863. event.preventDefault(); // 阻止浏览器默认换行操作
  864. this.keyword = '';
  865. return false;
  866. }
  867. },
  868. // 更多消息
  869. moreMsg() {},
  870. // 文本消息功能初始化
  871. async msgInit() {
  872. var that = this;
  873. if (typeof WebSocket === 'undefined') {
  874. alert('您的浏览器不支持socket!');
  875. } else {
  876. console.log(this.url, 'msg int 00000000000000000 12313441');
  877. this.websock = new window.WebSocket(
  878. this.url + '&token=' + localStorage.getItem('session')
  879. );
  880. this.websock.onopen = event => {
  881. console.log('WebSocket:已连接');
  882. console.log(event);
  883. // 发送消息 - 获取对话列表
  884. var obj1 = {};
  885. obj1 = {
  886. action: 'list',
  887. recv_user_id: '',
  888. data: {
  889. msg_status: false,
  890. msg_info: ''
  891. }
  892. };
  893. this.start(); //开启心跳
  894. if (this.fullscreenLoading !== null) {
  895. this.websock.send(JSON.stringify(obj1));
  896. }
  897. // this.fullscreenLoading.close(); // 加载关闭
  898. };
  899. this.websock.onmessage = event => {
  900. var data = JSON.parse(event.data);
  901. console.warn('WebSocket:消息---------------------------', data);
  902. if (data.action == 'none') {
  903. // 获取聊天记录
  904. var datArr = data.data; // 总数据
  905. this.websockMsgList = datArr; // 把数据定义在data中
  906. if (datArr.length !== 0) {
  907. for (var i = 0; i < datArr.length; i++) {
  908. if (this.getUserObj.user_id == datArr[i].user_id) {
  909. data.data[i].msg_list = data.data[i].msg_list.reverse();
  910. that.msgList = data.data[i];
  911. console.log(data.data[i]);
  912. }
  913. }
  914. }
  915. // if (data.data[0] !== undefined) {
  916. // data.data[0].msg_list = data.data[0].msg_list.reverse();
  917. // this.msgList = data.data[0];
  918. // }
  919. } else if (data.action == 'list') {
  920. console.log('消息发送成功了----------------------------------');
  921. clearTimeout(this.msgSetTime); // 清除发送失败定时器
  922. // 返回list为发送消息成功后需要再次调用聊天列表
  923. var obj = {};
  924. obj = {
  925. action: 'list',
  926. // recv_user_id: this.getUserObj.user_id,
  927. recv_user_id: '',
  928. data: {
  929. msg_status: false,
  930. msg_info: ''
  931. }
  932. };
  933. this.websock.send(JSON.stringify(obj));
  934. } else if (data.action == 'recv_video') {
  935. console.warn('recv_video', data.data, this.isVideoCallRefused);
  936. if (this.isVideoCallRefused) {
  937. this.updateIsRefusedCall(false);
  938. return;
  939. }
  940. this.updateIsRefusedCall(false);
  941. if (this.isVideoTalking) {
  942. // 占线中
  943. var obj = {
  944. action: 'occupy', // 动作标识,必填
  945. recv_user_id: data.data.user_id, // 接收人用户id, 非必填
  946. data: {}
  947. };
  948. this.websock.send(JSON.stringify(obj));
  949. return;
  950. }
  951. this.updateTalkingStatus(true);
  952. // 获取当前点击用户的房间号以及登录房间所需的Token
  953. // console.log(JSON.parse(event.data));
  954. console.log(data);
  955. var data = JSON.parse(event.data);
  956. this.RoomID = data.data.room_id; // 房间号
  957. this.Token = data.data.room_token; // Token
  958. this.videoNoticeDialogVisible = true;
  959. this.currentVideoNoticeData = data.data;
  960. //TODO 提示弹窗,确认后登录房间
  961. // const confrimInstance = this.$confirm(
  962. // `${data.data.real_name}邀请你进行视频通话...`
  963. // )
  964. // .then(_ => {
  965. // this.videoTle = '正在和' + data.data.real_name + '视频通话';
  966. // this.loginRoom();
  967. // })
  968. // .catch(_ => {
  969. // console.log('------------------------ confirm catch', _);
  970. // const socketData = {
  971. // action: 'reject_video', // 动作标识,必填
  972. // recv_user_id: data.data.user_id, // 接收人用户id, 非必填
  973. // data: {}
  974. // };
  975. // console.warn('send reject_video', socketData);
  976. // this.websock.send(JSON.stringify(socketData));
  977. // });
  978. this.videoNoticeTitle = `${data.data.real_name}邀请你进行视频通话...`;
  979. console.log('confirm instance', this.$confirm.done);
  980. //
  981. } else if (data.action == 'send_video_rsp') {
  982. console.warn('recv_video---------------- response', data.data);
  983. if (this.isVideoCallRefused) {
  984. this.updateIsRefusedCall(false);
  985. this.updateTalkingStatus(false);
  986. return;
  987. }
  988. this.updateIsRefusedCall(false);
  989. this.updateVideoSelfRoomInfo(data.data);
  990. this.RoomID = data.data.room_id; // 房间号
  991. this.Token = data.data.room_token; // Token
  992. console.warn(
  993. 'into romm ready ------------------',
  994. data.data.room_token
  995. );
  996. console.warn('into romm ------------------');
  997. this.updateTalkingStatus(true);
  998. // 唤起视频弹窗
  999. this.loginRoom();
  1000. } else if (data.action == 'reject_video_rsp') {
  1001. // 被拒绝后挂断视频通话
  1002. this.updateIsRefusedCall(true);
  1003. } else if (data.action == 'occupy_rsp') {
  1004. console.warn('----------------------- is refused');
  1005. this.currentVideoCallUserID = '';
  1006. // 占线中,挂断发起通话
  1007. this.updateIsRefusedCall(true);
  1008. } else if (data.action == 'ok') {
  1009. // 心跳机制 - 当前状态是websocket连接没有问题
  1010. this.start(); // 心跳机制
  1011. } else if (data.action == 'error') {
  1012. if (data.code == 403) {
  1013. this.websock.close(); // 关闭socket
  1014. localStorage.removeItem('session');
  1015. this.$message({
  1016. message:
  1017. (data.data && data.data.error_info) ||
  1018. '账号异地登陆,请重新登陆',
  1019. type: 'warning',
  1020. duration: 2500
  1021. });
  1022. setTimeout(() => {
  1023. this.$router.push('/Login');
  1024. }, 3000);
  1025. }
  1026. }
  1027. };
  1028. this.websock.onerror = event => {
  1029. console.log('WebSocket:发生错误 ', Date.now());
  1030. this.socketTimeoutLogs.push(Date.now());
  1031. console.log(event);
  1032. if (that.timeoutnum !== null) {
  1033. setTimeout(() => {
  1034. that.websock.close(); // 先关闭
  1035. clearTimeout(that.timeoutObj); //清除时间
  1036. that.reconnect(); // 重连
  1037. }, 5000);
  1038. }
  1039. };
  1040. this.websock.onclose = event => {
  1041. console.log('WebSocket:已关闭');
  1042. console.log(event);
  1043. console.log(that.timeoutnum);
  1044. if (that.timeoutnum !== null) {
  1045. // this.openFullScreen2();
  1046. setTimeout(() => {
  1047. // that.websock.close(); // 先关闭
  1048. clearTimeout(that.timeoutObj); //清除时间
  1049. // that.reconnect(); // 重连
  1050. }, 5000);
  1051. }
  1052. };
  1053. }
  1054. },
  1055. confrimNoticeClick() {
  1056. this.isNoticeDialogConfirm = true;
  1057. this.videoNoticeDialogVisible = false;
  1058. if (!this.currentVideoNoticeData) {
  1059. return;
  1060. }
  1061. this.videoTle =
  1062. '正在和' + this.currentVideoNoticeData.real_name + '视频通话';
  1063. this.loginRoom();
  1064. },
  1065. handleCloseNoticeDialog() {
  1066. console.warn('close notice dialog', this.isNoticeDialogConfirm);
  1067. this.videoNoticeDialogVisible = false;
  1068. if (!this.isNoticeDialogConfirm) {
  1069. this.cancleNoticeClik();
  1070. }
  1071. this.isNoticeDialogConfirm = false;
  1072. },
  1073. cancleNoticeClik() {
  1074. const socketData = {
  1075. action: 'reject_video', // 动作标识,必填
  1076. recv_user_id: this.currentVideoNoticeData.user_id, // 接收人用户id, 非必填
  1077. data: {}
  1078. };
  1079. console.warn('send reject_video', socketData);
  1080. this.websock.send(JSON.stringify(socketData));
  1081. this.updateTalkingStatus(false);
  1082. this.currentVideoNoticeData = null;
  1083. },
  1084. loginRoom() {
  1085. const userID = localStorage.getItem('userID');
  1086. console.warn(`userID:${userID};userName:${this.userName}`);
  1087. // 登录房间
  1088. this.zg
  1089. .loginRoom(
  1090. this.RoomID,
  1091. this.Token,
  1092. { userID: userID, userName: this.userName },
  1093. { userUpdate: true }
  1094. )
  1095. .then(result => {
  1096. console.log(result);
  1097. if (result == true) {
  1098. console.log('0000000000000000000000000000000000000登录成功');
  1099. this.plugFlow(); //推流
  1100. this.videoVisible = true;
  1101. }
  1102. });
  1103. },
  1104. // 音视频消息功能初始化
  1105. videoInit() {
  1106. this.zg = new ZegoExpressEngine(this.appID, this.videoUrl);
  1107. this.soundOn(); // 监听房间
  1108. this.detection(); // 检测是否兼容当前浏览器
  1109. },
  1110. // 监听房间
  1111. soundOn() {
  1112. // 房间状态更新回调
  1113. this.zg.on(
  1114. 'roomStateUpdate',
  1115. (roomID, state, errorCode, extendedData) => {
  1116. if (state == 'CONNECTED') {
  1117. // 与房间连接成功,只有当房间状态是连接成功时,才能进行推流、拉流等操作。
  1118. // 接下来的“预览并推流”的代码写在这里
  1119. console.log('房间连接成功');
  1120. //定时器
  1121. this.timer = setTimeout(() => {
  1122. if (document.getElementsByClassName('el-message').length == 0) {
  1123. this.$message({
  1124. message: '没人接听,请稍后重试',
  1125. type: 'warning',
  1126. duration: 2500
  1127. });
  1128. }
  1129. this.videoVisible = false;
  1130. // }, 5000);
  1131. }, 30000);
  1132. }
  1133. if (state == 'DISCONNECTED') {
  1134. // 与房间断开了连接
  1135. console.log('与房间断开连接');
  1136. }
  1137. if (state == 'CONNECTING') {
  1138. // 与房间尝试连接中
  1139. console.log('与房间尝试连接中');
  1140. }
  1141. }
  1142. );
  1143. this.zg.on('roomUserUpdate', (roomID, updateType, userList) => {
  1144. // 其他用户进出房间的通知
  1145. console.log(updateType);
  1146. console.log(userList);
  1147. console.log('有其他用户进出房间');
  1148. if (updateType == 'DELETE') {
  1149. if (document.getElementsByClassName('el-message').length == 0) {
  1150. this.$message({
  1151. message: '对方已挂断,结束通话!',
  1152. type: 'warning',
  1153. duration: 1500
  1154. });
  1155. }
  1156. setTimeout(() => {
  1157. this.notLogin(); // 退出房间
  1158. }, 2000);
  1159. } else if (updateType == 'ADD') {
  1160. clearTimeout(this.timer); // 关闭无人接听回调
  1161. }
  1162. });
  1163. this.zg.on(
  1164. 'roomStreamUpdate',
  1165. async (roomID, updateType, streamList, extendedData) => {
  1166. console.log(roomID);
  1167. console.log(updateType);
  1168. console.log(streamList);
  1169. console.log(extendedData);
  1170. // 房间内其他用户音视频流变化的通知
  1171. console.log('有其他用户开启或关闭音频');
  1172. if (updateType == 'ADD') {
  1173. // 流新增,开始拉流
  1174. console.log('这是拉流的ID', streamList);
  1175. this.tensile(streamList[0].streamID);
  1176. } else if (updateType == 'DELETE') {
  1177. // 流删除,停止拉流
  1178. this.notTensile(streamList[0].streamID);
  1179. }
  1180. }
  1181. );
  1182. this.zg.on('publisherStateUpdate', result => {
  1183. // 推流状态更新回调
  1184. console.log('推流状态更新');
  1185. console.log(result);
  1186. });
  1187. this.zg.on('publishQualityUpdate', (streamID, stats) => {
  1188. // 推流质量回调
  1189. console.log('推流质量更新');
  1190. console.log(streamID, stats);
  1191. });
  1192. this.zg.on('playerStateUpdate', result => {
  1193. // 拉流状态回调
  1194. console.log('拉流状态的回调');
  1195. console.log(result);
  1196. });
  1197. this.zg.on('playQualityUpdate', (streamID, stats) => {
  1198. // 拉流成功后回调
  1199. console.log('拉流质量回调');
  1200. console.log(streamID);
  1201. console.log(stats);
  1202. });
  1203. },
  1204. // 检测是否兼容当前浏览器
  1205. async detection() {
  1206. const result = await this.zg.checkSystemRequirements();
  1207. // 返回的 result 为兼容性检测结果。 webRTC 为 true 时表示支持 webRTC,其他属性含义可以参考接口 API 文档
  1208. console.log(result);
  1209. if (result.webRTC == true) {
  1210. console.log('兼容');
  1211. } else {
  1212. console.log('不兼容');
  1213. }
  1214. },
  1215. // 心跳机制
  1216. start() {
  1217. //开启心跳
  1218. var self = this;
  1219. self.timeoutObj && clearTimeout(self.timeoutObj);
  1220. self.serverTimeoutObj && clearTimeout(self.serverTimeoutObj);
  1221. self.timeoutObj = setTimeout(function() {
  1222. //这里发送一个心跳,后端收到后,返回一个心跳消息,
  1223. console.log('心跳中。。。', self.websock.readyState);
  1224. if (self.websock.readyState == 1) {
  1225. //如果连接正常
  1226. var obj1 = {};
  1227. obj1 = {
  1228. action: 'keepalive',
  1229. type: 'PC',
  1230. recv_user_id: '',
  1231. data: {
  1232. msg_status: false,
  1233. msg_info: ''
  1234. }
  1235. };
  1236. self.websock.send(JSON.stringify(obj1));
  1237. } else {
  1238. //否则重连
  1239. self.reconnect();
  1240. }
  1241. self.serverTimeoutObj = setTimeout(function() {
  1242. //超时关闭
  1243. console.log('又进入了?');
  1244. self.websock.close();
  1245. self.reconnect(); // 重连
  1246. }, self.timeout);
  1247. }, self.timeout);
  1248. },
  1249. reset() {
  1250. //重置心跳
  1251. var that = this;
  1252. clearTimeout(that.timeoutObj); //清除时间
  1253. clearTimeout(that.serverTimeoutObj); //清除时间
  1254. that.start(); //重启心跳
  1255. },
  1256. // 重连机制
  1257. reconnect() {
  1258. var that = this;
  1259. console.log('进入重连了');
  1260. clearTimeout(that.timeoutObj); //清除时间
  1261. if (that.lockReconnect) {
  1262. return;
  1263. }
  1264. that.lockReconnect = true;
  1265. // 没连接上会一直重连,设置延迟避免请求过多
  1266. that.timeoutnum && clearTimeout(that.timeoutnum);
  1267. that.timeoutnum = setTimeout(function() {
  1268. that.msgInit(); //新连接
  1269. that.lockReconnect = false;
  1270. }, 5000);
  1271. },
  1272. // 视频通话窗口最小化、最大化
  1273. zoomOperate(ref) {
  1274. if (ref == 'small') {
  1275. // 最小化
  1276. this.zoomShow = false;
  1277. } else if (ref == 'big') {
  1278. // 最大化
  1279. this.zoomShow = true;
  1280. }
  1281. },
  1282. // websocket断开加载框
  1283. openFullScreen2() {
  1284. // this.fullscreenLoading = this.$loading({
  1285. // lock: true,
  1286. // text: "通信异常,连接中...",
  1287. // spinner: "el-icon-loading",
  1288. // background: "rgba(0, 0, 0, 0.7)",
  1289. // });
  1290. },
  1291. hangUp() {
  1292. if (!this.currentVideoCallUserID) {
  1293. return;
  1294. }
  1295. if (this.zg) {
  1296. this.zg.logoutRoom(this.RoomID);
  1297. }
  1298. const socketData = {
  1299. action: 'reject_video', // 动作标识,必填
  1300. recv_user_id: this.currentVideoCallUserID, // 接收人用户id, 非必填
  1301. data: {}
  1302. };
  1303. console.warn('send reject_video', socketData);
  1304. this.websock.send(JSON.stringify(socketData));
  1305. },
  1306. handleTextDialogClose() {
  1307. console.log('text dialog close ');
  1308. }
  1309. },
  1310. //生命周期 - 创建完成(可以访问当前this实例)
  1311. created() {
  1312. this.loading = true;
  1313. this.loading2 = true;
  1314. this.organizationData(); //获取左侧组织列表
  1315. this.userListData(); // 获取右侧用户列表
  1316. },
  1317. //生命周期 - 挂载完成(可以访问DOM元素)
  1318. mounted() {
  1319. // this.loading = true;
  1320. // this.loading2 = true;
  1321. // this.organizationData(); //获取左侧组织列表
  1322. // this.userListData(); // 获取右侧用户列表
  1323. // console.log("---------------------------");
  1324. // console.log(this.websock);
  1325. // console.log("---------------------------");
  1326. if (this.websock == null) {
  1327. this.msgInit(); // 文本消息功能初始化
  1328. }
  1329. this.videoInit(); // 视频消息功能初始化
  1330. window.socketTimeoutLogs = this.socketTimeoutLogs;
  1331. },
  1332. beforeCreate() {}, //生命周期 - 创建之前
  1333. beforeMount() {}, //生命周期 - 挂载之前
  1334. beforeUpdate() {}, //生命周期 - 更新之前
  1335. updated() {}, //生命周期 - 更新之后
  1336. beforeDestroy() {
  1337. console.log('即时通讯挂断 销毁页面');
  1338. this.hangUp();
  1339. // var that = this;
  1340. // clearTimeout(that.timeoutnum); // 清除重连
  1341. // clearTimeout(that.timeoutObj); // 清除心跳
  1342. // that.websock.close(); // 关闭websocket
  1343. }, //生命周期 - 销毁之前
  1344. destroyed() {
  1345. console.log('我进入到销毁里喽');
  1346. this.updateTalkingStatus(false);
  1347. this.updateIsRefusedCall(false);
  1348. var that = this;
  1349. clearTimeout(that.timeoutnum); // 清除重连
  1350. clearTimeout(that.timeoutObj); // 清除心跳
  1351. that.websock.close(); // 关闭websocket
  1352. that.websock = null; // 清空
  1353. console.log(that.websock);
  1354. }, //生命周期 - 销毁完成
  1355. activated() {} //如果页面有keep-alive缓存功能,这个函数会触发
  1356. };
  1357. </script>
  1358. <style lang="less" scoped>
  1359. .realTime_box {
  1360. // 搜索
  1361. .search_box {
  1362. display: flex;
  1363. /deep/.el-input {
  1364. width: 20%;
  1365. margin: 0 15px 0 0;
  1366. }
  1367. .btn_box {
  1368. display: flex;
  1369. justify-content: start;
  1370. }
  1371. }
  1372. .card_box {
  1373. display: flex;
  1374. width: 100%;
  1375. // 树形图
  1376. .userManger_left {
  1377. width: 19%;
  1378. margin: 0 15px 0 0;
  1379. padding: 5px;
  1380. border: 1px solid #eeeeee;
  1381. border-radius: 5px;
  1382. overflow: hidden;
  1383. overflow-y: auto;
  1384. }
  1385. // 搜索和表格
  1386. .userManger_right {
  1387. width: 80%;
  1388. // border: 1px solid red;
  1389. a {
  1390. text-decoration: none;
  1391. }
  1392. .reset {
  1393. color: #1890ff;
  1394. }
  1395. .delete {
  1396. color: #f56c6c;
  1397. }
  1398. .line {
  1399. display: inline-block;
  1400. width: 1px;
  1401. background: rgba(0, 0, 0, 0.09);
  1402. margin: 0 11px;
  1403. height: 14px;
  1404. }
  1405. }
  1406. }
  1407. /deep/.el-select {
  1408. width: 80%;
  1409. }
  1410. /deep/.el-cascader {
  1411. width: 80%;
  1412. }
  1413. // 视频通话 - 最小化
  1414. .video_box {
  1415. border: 1px solid #000;
  1416. background: #2c2c2c;
  1417. height: 325px;
  1418. position: relative;
  1419. // 主视频画面
  1420. .host_video {
  1421. height: 326px;
  1422. vertical-align: middle;
  1423. text-align: center;
  1424. position: relative;
  1425. .video_img {
  1426. margin: 120px auto;
  1427. position: absolute;
  1428. top: 0;
  1429. right: 0;
  1430. bottom: 0;
  1431. left: 0;
  1432. margin: auto;
  1433. }
  1434. }
  1435. // 副视频画面
  1436. .deputy_video {
  1437. width: 90px;
  1438. height: 90px;
  1439. position: absolute;
  1440. top: 0;
  1441. right: 0;
  1442. background: #fff;
  1443. }
  1444. // 操作
  1445. .operate {
  1446. height: 25px;
  1447. width: 100%;
  1448. background: #000;
  1449. padding: 5px 0 5px 0;
  1450. margin: -13px 0 0 0px;
  1451. position: absolute;
  1452. bottom: 0;
  1453. left: 0;
  1454. display: flex;
  1455. justify-content: flex-end;
  1456. }
  1457. }
  1458. // 视频通话 - 最大化
  1459. .video_box-big {
  1460. border: 1px solid #000;
  1461. background: #2c2c2c;
  1462. height: 100%;
  1463. position: relative;
  1464. // 主视频画面
  1465. .host_video {
  1466. height: 100%;
  1467. vertical-align: middle;
  1468. text-align: center;
  1469. position: relative;
  1470. .video_img {
  1471. margin: 120px auto;
  1472. position: absolute;
  1473. top: 0;
  1474. right: 0;
  1475. bottom: 0;
  1476. left: 0;
  1477. margin: auto;
  1478. }
  1479. }
  1480. // 副视频画面
  1481. .deputy_video {
  1482. width: 190px;
  1483. height: 190px;
  1484. position: absolute;
  1485. top: 0;
  1486. right: 0;
  1487. background: #fff;
  1488. }
  1489. // 操作
  1490. .operate {
  1491. height: 25px;
  1492. width: 100%;
  1493. background: #000;
  1494. padding: 5px 0 5px 0;
  1495. margin: -13px 0 0 0px;
  1496. position: absolute;
  1497. bottom: 3%;
  1498. left: 0;
  1499. display: flex;
  1500. justify-content: flex-end;
  1501. }
  1502. }
  1503. /* 聊天内容 */
  1504. .ul_list {
  1505. height: 350px;
  1506. // margin-left: -41px;
  1507. overflow: hidden;
  1508. overflow-y: auto;
  1509. }
  1510. .list_msgBox1 {
  1511. padding: 0 10px;
  1512. display: flex;
  1513. margin-top: 22px;
  1514. justify-content: flex-end;
  1515. }
  1516. .list_msgBox2 {
  1517. padding: 0 10px;
  1518. display: flex;
  1519. margin-top: 22px;
  1520. }
  1521. .test-5::-webkit-scrollbar {
  1522. /*滚动条整体样式*/
  1523. width: 10px; /*高宽分别对应横竖滚动条的尺寸*/
  1524. height: 1px;
  1525. }
  1526. .test-5::-webkit-scrollbar-thumb {
  1527. /*滚动条里面小方块*/
  1528. border-radius: 10px;
  1529. background-color: skyblue;
  1530. background-image: -webkit-linear-gradient(
  1531. 45deg,
  1532. rgba(255, 255, 255, 0.2) 25%,
  1533. transparent 25%,
  1534. transparent 50%,
  1535. rgba(255, 255, 255, 0.2) 50%,
  1536. rgba(255, 255, 255, 0.2) 75%,
  1537. transparent 75%,
  1538. transparent
  1539. );
  1540. }
  1541. .test-5::-webkit-scrollbar-track {
  1542. /*滚动条里面轨道*/
  1543. box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
  1544. background: #ededed;
  1545. border-radius: 10px;
  1546. }
  1547. .list {
  1548. /* border: 1px solid red; */
  1549. width: 100%;
  1550. height: 100px;
  1551. }
  1552. /* ElementUI 样式 */
  1553. // 聊天框
  1554. /deep/.el-dialog {
  1555. overflow: hidden;
  1556. }
  1557. /deep/.el-dialog__header {
  1558. background: #f2f2f2;
  1559. border-bottom: 1px solid #cacaca;
  1560. }
  1561. /deep/.el-dialog__title {
  1562. font-weight: 550;
  1563. font-size: 15px;
  1564. line-height: 0;
  1565. float: left;
  1566. }
  1567. /deep/.el-dialog__headerbtn {
  1568. top: 10px;
  1569. right: 10px;
  1570. }
  1571. /deep/.el-dialog__headerbtn .el-dialog__close {
  1572. font-size: 20px;
  1573. line-height: 15px;
  1574. }
  1575. /deep/.el-dialog__body {
  1576. padding: 0;
  1577. // margin-top: -15px;
  1578. height: 100%;
  1579. }
  1580. /deep/.el-textarea__inner {
  1581. border: 0;
  1582. border-top: 1px solid #dcdfe6;
  1583. border-radius: 0;
  1584. height: 95px;
  1585. }
  1586. /deep/.el-card {
  1587. overflow: hidden;
  1588. overflow-y: auto;
  1589. }
  1590. }
  1591. /deep/.el-button--info {
  1592. background-color: #409eff;
  1593. border-color: #409eff;
  1594. }
  1595. </style>