tpl_tonghua.html 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title><?=$da['title']?></title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0"/>
  7. <link rel="stylesheet" type="text/css" href="web/res/css/webimcss.css"/>
  8. <link rel="stylesheet" type="text/css" href="web/res/fontawesome/css/font-awesome.min.css">
  9. <link rel="shortcut icon" href="favicon.ico" />
  10. <script type="text/javascript" src="js/jquery.js"></script>
  11. <script type="text/javascript" src="js/js.js"></script>
  12. <script type="text/javascript" src="js/base64-min.js"></script>
  13. <script type="text/javascript" src="mode/agora/AgoraRTC_N-4.7.1.js"></script>
  14. <script type="text/javascript" src="mode/plugin/jquery-rockmodels.js"></script>
  15. <script>
  16. adminid = <?=$da['adminid']?>;
  17. var localAudioTrack=false,localVideoTrack = false,remoteAudioTrack=false,remoteVideoTrack=false;
  18. function initbody(){
  19. c.init();
  20. }
  21. function bodyunload(){
  22. c.bodyunload(false);
  23. }
  24. var c = {
  25. iscall:<?=$ars['iscall']?>,
  26. type:0,
  27. callshu:30,
  28. id:<?=$ars['id']?>,
  29. nwwin:false,
  30. init:function(){
  31. this.typearr = ['语音','视频'];
  32. this.name = '<?=$ars['name']?>';
  33. this.playobj = get('notify_sound_tonghua');
  34. js.initbtn(this);
  35. //接收端
  36. if(!this.iscall){
  37. this.type = <?=$thrs['type']?>;
  38. this.channel = '<?=$thrs['channel']?>';
  39. this.jieshoucall();
  40. }else{
  41. $('#calldiv').show();
  42. }
  43. if(nwjsgui){
  44. this.nwwin = nw.Window.get();
  45. this.nwwin.on('close', function(){
  46. c.bodyunload(this);
  47. });
  48. }
  49. },
  50. hujiao:function(o1,lx){
  51. if(this.hujiaobo)return;
  52. js.loading('请求中...');
  53. this.hujiaobo = true;
  54. this.type = lx;
  55. js.ajax('tonghua|thinit',{id:this.id,type:lx},function(ret){
  56. c.hujiaoback(ret);
  57. }, 'get', function(str){
  58. js.msgerror(str);
  59. c.stateupdate(str);
  60. c.hujiaobo=false;
  61. });
  62. },
  63. stateupdate(str, bo){
  64. $('#wiatling').html(str);
  65. $('#wiatlings').html(str);
  66. document.title = str;
  67. if(bo)this.showtoast(str);
  68. },
  69. showtoast:function(str){
  70. js.msg('success',str);
  71. },
  72. hujiaoback:function(ret){
  73. this.thcan = ret.data;
  74. this.channel = this.thcan.channel;
  75. $('#backbtn').hide();
  76. $('#hujiaobtn').remove();
  77. $('#cancelbtn').show();
  78. this.initagoraRtc();
  79. this.callstartplay();
  80. this.callstrimes = js.now('time');
  81. this.callmiashue();
  82. this.hujiaobool = true;
  83. },
  84. callstartplay:function(){
  85. this.playobj.src='web/res/sound/call.mp3';
  86. if(this.playobj.play)this.playobj.play();
  87. },
  88. callstopplay:function(){
  89. if(this.playobj.pause)this.playobj.pause();
  90. },
  91. cancalpayls:function(){
  92. this.playobj.src='web/res/sound/gua.mp3';
  93. this.playobj.loop='';
  94. if(this.playobj.play)this.playobj.play();
  95. },
  96. callmiashue:function(){
  97. clearTimeout(this.callmiashuetime);
  98. var sj = parseInt((js.now('time')-this.callstrimes)*0.001);
  99. if(sj>this.callshu){
  100. this.cancelhus(5);
  101. return;
  102. }
  103. if(sj%2==0 && sj>0 && !this.ztpandbool){
  104. this.ztpandbool = true;
  105. js.ajax('tonghua|state',{channel:this.channel}, function(ret){
  106. var zt = ret.data.state;
  107. c.ztpandbool = false;
  108. if(!c.calljutong && (zt=='tongyi' || zt=='jujue'))c.callbackss(zt);
  109. },'get', function(st1){
  110. c.ztpandbool = false;
  111. js.msg();
  112. });
  113. }
  114. this.stateupdate(''+this.typearr[this.type]+'通话呼叫中已呼叫'+sj+'秒...');
  115. this.callmiashuetime = setTimeout(function(){c.callmiashue()},1000);
  116. },
  117. initagoraRtc:async function(){
  118. client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
  119. client.on("user-published", async (user, mediaType) => {
  120. await client.subscribe(user, mediaType);
  121. if (mediaType === "video") {
  122. remoteVideoTrack = user.videoTrack;
  123. remoteVideoTrack.play('remote_stream');
  124. }
  125. if (mediaType === "audio") {
  126. remoteAudioTrack = user.audioTrack;
  127. remoteAudioTrack.play();
  128. }
  129. });
  130. client.on("user-joined", (user) => {
  131. //showSuccess('有人来('+JSON.stringify(user)+')');
  132. });
  133. client.on("user-left", (user, reason) => {
  134. //showAlert('有人退出['+reason+']('+JSON.stringify(user)+')');
  135. c.guaduanok(false);
  136. });
  137. },
  138. cancelhu:function(){
  139. this.cancelhus(3);
  140. },
  141. closewin:function(bo){
  142. if(bo){
  143. if(this.nwwin){
  144. this.nwwin.close(true);
  145. }else{
  146. window.close();
  147. }
  148. }else{
  149. setTimeout(function(){c.closewin(true)},2000);
  150. }
  151. },
  152. cancelhus:function(zt){
  153. $('#cancelbtn').hide();
  154. this.hujiaobool = false;
  155. clearTimeout(this.callmiashuetime);
  156. var ss1='';if(zt==5)ss1='无人接听';
  157. js.loading(''+ss1+'取消呼叫中...');
  158. this.stateupdate(''+ss1+'取消呼叫中...');
  159. this.callstopplay();
  160. js.ajax('tonghua|cancel',{channel:this.thcan.channel,state:zt},function(ret){
  161. c.stateupdate(''+ss1+'已取消呼叫', true);
  162. c.closewin();
  163. }, 'get', function(str){
  164. $('#cancelbtn').show();
  165. js.msgerror(str);
  166. c.stateupdate(str);
  167. });
  168. },
  169. //接通后显示视频
  170. localvadio:async function(){
  171. if(this.localvadiobool)return;
  172. this.localvadiobool = true;
  173. this.isjietong = true;
  174. this.showtoast(''+this.typearr[this.type]+'已接通');
  175. this.stateupdate('与'+this.name+''+this.typearr[this.type]+'通话中(00:00)');
  176. $('#backbtn').hide();
  177. this.starttime = js.now('time');
  178. this.showmian();
  179. $('#calldiv').remove();
  180. $('#canceldiv').show();
  181. if(this.type==1){
  182. $('#shipindiv').show();
  183. $('#yuyindiv').hide();
  184. $('#local_stream').show();
  185. $('#remote_stream').show();
  186. }
  187. await client.join(this.thcan.appid, this.thcan.channel, this.thcan.token, this.thcan.uid);
  188. // 通过麦克风采集的音频创建本地音频轨道对象。
  189. localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
  190. await client.publish(localAudioTrack);
  191. if(this.type==1){
  192. // 通过摄像头采集的视频创建本地视频轨道对象。
  193. localVideoTrack = await AgoraRTC.createCameraVideoTrack();
  194. // 将这些音视频轨道对象发布到频道中。
  195. await client.publish(localVideoTrack);
  196. localVideoTrack.play('local_stream'); //播放视频
  197. }
  198. },
  199. showmian:function(){
  200. var sj = parseInt((js.now('time')-this.starttime)*0.001);
  201. this.tonghuasj = sj;
  202. var fz = 0;
  203. if(sj>59)fz = parseInt(sj/60);
  204. var ms = sj-fz*60;
  205. this.stateupdate(''+this.typearr[this.type]+'通话中('+xy10(fz)+':'+xy10(ms)+')');
  206. if(sj>0 && sj%2==0 && !this.showmiaobool){
  207. this.showmiaobool = true;
  208. js.ajax('tonghua|stateth',{channel:this.channel}, function(ret){
  209. var zt = ret.data.state;
  210. c.showmiaobool = false;
  211. if(zt=='jiesu')c.callbackss(zt);
  212. },'get', function(st1){
  213. c.showmiaobool = false;
  214. js.msg();
  215. });
  216. }
  217. this.showmiantime = setTimeout(function(){c.showmian()},1000);
  218. },
  219. guaduan:function(){
  220. this.guaduanok(true);
  221. },
  222. guaduanok:function(bo){
  223. if(this.guaduanbool)return;
  224. this.guaduanbool = true;
  225. if(bo){
  226. this.showtoast('挂断中...');
  227. js.ajax('tonghua|jiesu',{channel:this.thcan.channel,toid:this.id}, function(ret){
  228. c.guaduanokok();
  229. },'get', function(str){
  230. c.guaduanokok();
  231. });
  232. }else{
  233. this.guaduanokok();
  234. }
  235. },
  236. guaduanokok:function(){
  237. clearTimeout(this.showmiantime);
  238. if(localAudioTrack)localAudioTrack.close();
  239. if(localVideoTrack)localVideoTrack.close();
  240. client.unpublish();
  241. client.leave();
  242. this.stateupdate('通话已结束', true);
  243. $('#canceldiv').remove();
  244. this.cancalpayls();
  245. this.closewin();
  246. },
  247. payerstart:function(){
  248. this.playobj.src='web/res/sound/mi.mp3';
  249. if(this.playobj.play)this.playobj.play();
  250. },
  251. payerend:function(){
  252. this.callstopplay();
  253. },
  254. qiehysq:function(){
  255. if(!this.yuancjinb){
  256. remoteAudioTrack.setVolume(0);
  257. this.yuancjinb = true;
  258. $('#jingyinclltxt').html('开启声音');
  259. get('jingyincll').className='icon-volume-off';
  260. }else{
  261. remoteAudioTrack.setVolume(100);
  262. this.yuancjinb = false;
  263. $('#jingyinclltxt').html('静音');
  264. get('jingyincll').className='icon-volume-up';
  265. }
  266. },
  267. //接电话端处理初始化
  268. jieshoucall:function(){
  269. $('#backbtn').hide();
  270. $('#anjiandiv').show();
  271. js.ajax('tonghua|receopen',{channel:this.channel});
  272. this.jieshoutimes(-1);
  273. this.isyaoqbool = true;
  274. this.payerstart();
  275. },
  276. jieshoutimes:function(i1){
  277. var str = this.typearr[this.type];
  278. var sys = this.callshu - <?=$thrs['sytime']?> -i1;
  279. if(sys<0){
  280. this.stateupdate('超时自动取消', true);
  281. this.jiedianha(false,3);
  282. }else{
  283. if(i1%2==0 && i1>0 && !this.ztpandbool){
  284. this.ztpandbool = true;
  285. js.ajax('tonghua|state',{channel:this.channel}, function(ret){
  286. var zt = ret.data.state;
  287. c.ztpandbool = false;
  288. if(zt=='cancel' || zt=='tongyi' || zt=='jujue')c.callbackss(zt);
  289. },'get', function(st1){
  290. c.ztpandbool = false;
  291. js.msg();
  292. });
  293. }
  294. this.stateupdate('邀请与您'+str+'通话('+sys+')...');
  295. this.jieshoutimesa = setTimeout(function(){c.jieshoutimes(i1+1)},1000);
  296. }
  297. },
  298. jiedianha:function(o1,lx){
  299. clearTimeout(this.jieshoutimesa);
  300. this.ismybool = true;
  301. this.isyaoqbool = false;
  302. $('#anjiandiv').hide();
  303. this.payerend();
  304. if(lx==1){
  305. this.stateupdate('接通中...');
  306. this.initagoraRtc();
  307. js.ajax('tonghua|jietong',{channel:this.channel,state:1},function(ret){
  308. c.jietongback(ret);
  309. }, 'get', function(str){
  310. js.msgerror(str);
  311. c.stateupdate(str);
  312. $('#anjiandiv').show();
  313. });
  314. }
  315. if(lx==2){
  316. this.stateupdate('拒绝中...');
  317. js.ajax('tonghua|jie',{channel:this.channel,state:2},function(ret){
  318. var ms2 = '已拒绝通话';
  319. if(ret.data.satype)ms2 = ret.data.satype;
  320. c.jiequxian(ms2);
  321. },'get', function(str){
  322. js.msgerror(str);
  323. c.stateupdate(str);
  324. $('#anjiandiv').show();
  325. });
  326. }
  327. if(lx==3){
  328. this.closewin();
  329. }
  330. },
  331. jiequxian:function(s1){
  332. this.stateupdate(s1, true);
  333. this.closewin();
  334. },
  335. jietongback:function(ret){
  336. this.thcan = ret.data;
  337. if(ret.data.satype){
  338. this.jiequxian(ret.data.satype);
  339. }else{
  340. this.stateupdate(''+this.typearr[this.type]+'通话中...');
  341. this.localvadio();//被叫端接通
  342. }
  343. },
  344. bodyunload:function(win){
  345. var lx = '';
  346. if(this.isjietong){
  347. this.guaduan();
  348. lx = '挂断中...';
  349. }else{
  350. if(this.hujiaobool){
  351. this.cancelhu();
  352. lx='取消中...';
  353. }
  354. if(this.isyaoqbool){
  355. this.jiedianha(false,2);
  356. lx='邀请中..';
  357. }
  358. }
  359. if(!lx){
  360. win.close(true);
  361. }
  362. },
  363. callbackss:function(lx){
  364. this.callstopplay();
  365. clearTimeout(this.callmiashuetime);
  366. clearTimeout(this.jieshoutimesa);
  367. if(lx=='jujue'){
  368. this.calljutong = true;
  369. this.hujiaobool = false;
  370. if(this.iscall){
  371. $('#cancelbtn').remove();;
  372. this.stateupdate('对方拒绝通话', true);
  373. this.closewin();
  374. }
  375. if(!this.iscall && !this.ismybool){
  376. this.stateupdate('已在另端拒绝', true);
  377. $('#anjiandiv').remove();
  378. this.closewin();
  379. }
  380. }
  381. if(lx=='tongyi'){
  382. this.calljutong = true;
  383. this.hujiaobool = false;
  384. if(this.iscall){
  385. this.stateupdate('接通中...');
  386. this.localvadio(); //主叫端接通
  387. }
  388. if(!this.iscall && !this.ismybool){
  389. this.stateupdate('已在另端接通', true);
  390. $('#anjiandiv').remove();
  391. this.closewin();
  392. }
  393. }
  394. //----以下是接收端处理----
  395. //呼叫已经取消
  396. if(lx=='cancel' && get('anjiandiv')){
  397. $('#anjiandiv').remove();
  398. clearTimeout(this.jieshoutimesa);
  399. this.stateupdate('对方已取消', true);
  400. this.closewin();
  401. }
  402. //对方挂电话
  403. if(lx=='jiesu'){
  404. this.guaduanok(false);
  405. }
  406. }
  407. }
  408. js.ajax=function(lex,ds,fun,lxss,efun){
  409. var lexa = lex.split('|');
  410. if(!lxss)lxss='type';
  411. var cans = {
  412. url:js.apiurl(lexa[0],lexa[1]),
  413. data:ds,
  414. type:lxss,
  415. dataType:'json',
  416. success:function(ret){
  417. js.unloading();
  418. if(ret.success){
  419. if(fun)fun(ret);
  420. }else{
  421. if(efun)efun(ret.msg)
  422. }
  423. },
  424. error:function(e){
  425. js.unloading();
  426. if(efun)efun('处理出错:'+e.responseText+'');
  427. }
  428. }
  429. $.ajax(cans);
  430. }
  431. js.initbtn = function(obj){
  432. var o = $("[clickevt]"),i,o1,cl;
  433. for(i=0; i<o.length; i++){
  434. o1 = $(o[i]);
  435. cl = o1.attr('clickadd');
  436. if(cl!='true'){
  437. o1.click(function(eo){
  438. var cls = $(this).attr('clickevt');
  439. if(typeof(cls)=='string'){
  440. cls=cls.split(',');
  441. obj[cls[0]](this, cls[1], cls[2], eo);
  442. }
  443. return false;
  444. });
  445. }
  446. }
  447. o.attr('clickadd','true');
  448. }
  449. function showAlert(str,col){
  450. var obj = $('div[temp="div"]'),hei=0;
  451. for(var i=0;i<obj.length;i++)hei+=$(obj[i]).height()+15;
  452. if(!col)col='red';
  453. var str = '<div temp="div" onclick="$(this).remove()" style="background:rgba(0,0,0,0.8);position:fixed;left:0px;top:'+hei+'px;padding:5px;color:'+col+'">'+str+'</div>';
  454. $('body').append(str);
  455. }
  456. function showSuccess(str){
  457. showAlert(str,'white');
  458. }
  459. </script>
  460. </head>
  461. <body style="overflow:hidden;background:#555555">
  462. <div id="local_stream" style="width:100px;height:150px;right:0px;top:0px;border:0px red solid;position:fixed;z-index:2;display:none"></div>
  463. <div id="remote_stream" style="width:100%;height:100%;left:0px;top:0px;border:0px red solid;position:fixed;z-index:1;display:none"></div>
  464. <div align="left" style="padding:0px 10px;height:60px;overflow:hidden;display:none;position:fixed;z-index:9;left:0;top:0" id="shipindiv">
  465. <table style="margin-top:10px"><tr>
  466. <td><img id="tonghuafaces" src="<?=$ars['face']?>" width="40px" height="40px" style="border-radius:50%"></td>
  467. <td width="5"></td>
  468. <td style="color:white"><?=$ars['name']?></td>
  469. <td width="10"></td>
  470. <td><div id="wiatlings" style="color:#888888;font-size:14px">等待呼叫</div></td>
  471. </tr></table>
  472. </div>
  473. <div align="center" style="position:fixed;z-index:9;left:0;top:0;width:100%" id="yuyindiv">
  474. <div style="margin-top:50px"><img id="tonghuaface" src="<?=$ars['face']?>" width="100px" height="100px" style="border-radius:50%"></div>
  475. <div style="color:white"><?=$ars['name']?></div>
  476. <div id="wiatling" style="color:#888888;font-size:14px;margin-top:5px">等待呼叫</div>
  477. </div>
  478. <div align="center" id="calldiv" style="position:fixed;bottom:50px;width:100%;display:none;z-index:9">
  479. <div id="hujiaobtn">
  480. <div style="color:#888888;font-size:12px">请选择通话类型</div>
  481. <table><tr>
  482. <td align="center">
  483. <div class="webbtn" clickevt="hujiao,0" align="center" style="width:90px;height:90px;background:#ff6600;color:white;line-height:90px;border-radius:50%;font-size:16px;margin-top:10px;padding:0"><i class="icon-volume-up"></i> 语音</div>
  484. </td>
  485. <td width="50"></td>
  486. <td align="center">
  487. <div class="webbtn" clickevt="hujiao,1" align="center" style="width:90px;height:90px;background:#339933;color:white;line-height:90px;border-radius:50%;font-size:16px;padding:0;margin-top:20px"><i class="icon-facetime-video"></i> 视频</div>
  488. </td>
  489. </tr></table>
  490. </div>
  491. <div id="cancelbtn" style="display:none">
  492. <div class="webbtn" clickevt="cancelhu" style="width:80px;height:80px;background:#FF6666;color:white;line-height:80px;border-radius:50%;font-size:40px;padding:0;margin-top:20px;transform:rotate(135deg);"><i class="icon-phone"></i></div>
  493. <div style="color:#888888;font-size:12px;margin-top:5px">取消</div>
  494. </div>
  495. </div>
  496. <div align="center" id="canceldiv" style="position:fixed;bottom:0px;width:100%;display:none;height:120px;overflow:hidden;z-index:9">
  497. <table style="margin-top:10px"><tr>
  498. <td align="center">
  499. <div class="webbtn" clickevt="guaduan" style="width:80px;height:80px;background:#FF6666;color:white;line-height:80px;border-radius:50%;font-size:40px;padding:0;margin-top:20px;margin:0;transform:rotate(135deg);"><i class="icon-phone"></i></div>
  500. <div style="color:#888888;font-size:12px;margin-top:5px">挂断</div>
  501. </td>
  502. <td width="30"></td>
  503. <td align="center">
  504. <div class="webbtn" clickevt="qiehysq" style="width:80px;height:80px;background:white;color:#000000;line-height:80px;border-radius:50%;font-size:40px;padding:0;margin-top:20px;margin:0"><i id="jingyincll" class="icon-volume-up"></i></div>
  505. <div id="jingyinclltxt" style="color:#888888;font-size:12px;margin-top:5px">静音</div>
  506. </td>
  507. </tr></table>
  508. </div>
  509. <div align="center" id="anjiandiv" style="position:fixed;bottom:50px;width:100%;display:none;z-index:9">
  510. <div>
  511. <table><tr>
  512. <td align="center">
  513. <div class="webbtn" clickevt="jiedianha,2" style="width:80px;height:80px;background:#FF6666;color:white;line-height:80px;border-radius:50%;font-size:40px;padding:0;margin-top:20px;transform:rotate(135deg);"><i class="icon-phone"></i></div>
  514. <div style="color:#888888;font-size:12px;margin-top:5px">拒绝</div>
  515. </td>
  516. <td width="50"></td>
  517. <td align="center">
  518. <div class="webbtn" clickevt="jiedianha,1" style="width:80px;height:80px;background:#339933;color:white;line-height:80px;border-radius:50%;font-size:40px;padding:0;margin-top:20px"><i class="icon-phone"></i></div>
  519. <div style="color:#888888;font-size:12px;margin-top:5px">接听</div>
  520. </td>
  521. </tr></table>
  522. </div>
  523. </div>
  524. <audio id="notify_sound_tonghua" hidden="true" loop="loop" autoplay="autoplay" src=""></audio>
  525. </body>
  526. </html>