meeting-demo.html 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8"/>
  5. <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no,user-scalable=no"/>
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
  7. <meta name="theme-color" content="#000000"/>
  8. <meta name="x5-fullscreen" content="true">
  9. <meta name="mobile-web-app-capable" content="yes">
  10. <meta http-equiv="Pragma" content="no-cache">
  11. <meta http-equiv="Cache-control" content="no-cache">
  12. <title>我的会议</title>
  13. <style>
  14. .select-text {
  15. -webkit-user-select: text;
  16. -moz-user-select: text;
  17. -ms-user-select: text;
  18. user-select: text;
  19. }
  20. .box {
  21. display: flex;
  22. flex-wrap: wrap;
  23. flex-direction: row;
  24. justify-content: space-around;
  25. background: center / contain repeat url(https://www.huaweicloud.com/content/dam/cloudbu-site/archive/china/zh-cn/product/cloud_communications/meeting/image/image-%E5%B8%AE%E5%8A%A9%E6%96%87%E6%A1%A3-2.png);
  26. }
  27. </style>
  28. </head>
  29. <body>
  30. <div id="root" style="position: absolute; width: 100%; height: 100%;"></div>
  31. <div class="box" style="display: flex; display: -webkit-flex; display:none;">
  32. <div class="title is-2" style="text-align: center; width: 100%;">华为云webSDK演示页面</div>
  33. <div style="width: 50%;">
  34. <div>
  35. <button id="get-sdk-version-button" class="button is-link" onclick=getSdkVersion()
  36. style="padding-left:15px;">获取SDK版本号
  37. </button>
  38. <button id="browser-check-button" class="button is-success" onclick=checkBrowserSupport()
  39. style="padding-left:15px;">检查浏览器兼容性
  40. </button>
  41. </div>
  42. <div>
  43. <input id="lang" autocomplete="off" class="input is-rounded" placeholder="en-US | zh-CN " type="text"
  44. style="width: 160px;" value = 'zh-CN'>
  45. <button id='setLangButton' type="submit" onclick = setLang() class="button is-link">设置语言</button>
  46. </div>
  47. <div style="width: 100%; margin-top: 8px;">
  48. <input id="token" autocomplete="off" class="input is-rounded" type="text" placeholder="token(可选:用于实名入会)"
  49. style="width: 220px;">
  50. <input id="confId" autocomplete="off" class="input is-rounded" placeholder="请输入会议ID" type="text"
  51. style="width: 140px;" value="">
  52. <input id="pwd" autocomplete="off" class="input is-rounded" placeholder="请输入会议密码" type="text"
  53. style="width: 150px;" value="">
  54. <input id="nickName" autocomplete="off" class="input is-rounded" placeholder="请输入姓名" type="text"
  55. style="width: 130px;" value="">
  56. <button type="submit" onclick=validateForm() id="join" class="button is-link">加入会议</button>
  57. <button class="button is-danger" onclick=clickLeaveConf() style="padding-left:15px;">离会</button>
  58. </div>
  59. <div id="leaveConfModal" class="modal">
  60. <div class="modal-background"></div>
  61. <div class="modal-card">
  62. <header class="modal-card-head">
  63. <p class="modal-card-title">提示</p>
  64. <button class="delete" aria-label="close" onclick=closeModals()></button>
  65. </header>
  66. <section class="modal-card-body">
  67. <div class="control">
  68. <label class="radio">
  69. <input type="radio" name="leaveConfConfirm" value="leave" checked>
  70. 离开会议
  71. </label>
  72. <label class="radio">
  73. <input type="radio" name="leaveConfConfirm" value="end">
  74. 结束会议
  75. </label>
  76. </div>
  77. </section>
  78. <footer class="modal-card-foot">
  79. <button class="button is-success" onclick=handleLeaveConfirm()>确认</button>
  80. <button class="button" onclick=closeModals()>取消</button>
  81. </footer>
  82. </div>
  83. </div>
  84. <div style="margin-top: 8px;">
  85. <button id="handup-button" class="button is-primary" onclick=handleHand()>举手</button>
  86. <button id="chat-button" class="button is-info" onclick=handleChatVisible() style="padding-left:15px;">聊天显示
  87. </button>
  88. <button id="attendee-button" class="button is-link" onclick=handleAttendeeListVisible()
  89. style="padding-left:15px;">与会者显示
  90. </button>
  91. <button id="control-button" class="button is-info" onclick=handleControlBarVisible()
  92. style="padding-left:15px;">会控条显示
  93. </button>
  94. <button id="title-button" class="button is-success" onclick=handleTitleVisible() style="padding-left:15px;">
  95. 标题隐藏
  96. </button>
  97. <button id="bullet-button" class="button is-success" onclick=handleBulletScreenVisible()
  98. style="padding-left:15px;">弹幕隐藏
  99. </button>
  100. <button id="share-button" class="button is-info" onclick=handleShareScreen()>共享</button>
  101. <button id="video-button" class="button is-warning" onclick=handleVideoMute() style="padding-left:15px;">
  102. 打开视频
  103. </button>
  104. <button id="audio-button" class="button is-primary" onclick=handleMuteAudio() style="padding-left:15px;">
  105. 取消静音
  106. </button>
  107. <button id="speaker-button" class="button is-danger" onclick=handleMuteSpeaker() style="padding-left:15px;">
  108. 关闭扬声器
  109. </button>
  110. </div>
  111. <div style="margin-top: 8px;">
  112. <input id='volumeInput' value class="input is-primary is-rounded" type="number" min="0" max="100" placeholder="请输入音量 "
  113. onchange=volumeChange(value) style="width:136px;padding-left:15px;"></input>
  114. <button id="conf-staus-button" class="button is-success" onclick=handleSetVolume()
  115. style="padding-left:15px;">
  116. 设置音量
  117. </button>
  118. <input id='changeNameInput' value class="input is-link is-rounded" type="text" placeholder="请输入姓名: " onchange=changingName(value)
  119. style="width:184px;padding-left:15px;"></input>
  120. <button id="chat-button" class="button is-info" onclick=handleChangeName() style="padding-left:15px;">修改名字
  121. </button>
  122. <input id='changeWidthInput' value=1280 class="input is-link is-rounded" type="number" min="300" max="2000" placeholder="宽度 "
  123. onchange=changingWith(value) style="width:100px;padding-left:15px;"></input>
  124. <input id='changeHeightInput' value=720 class="input is-link is-rounded" type="number" min="300" max="1000" placeholder="高度 "
  125. onchange=changingHeight(value) style="width:100px;padding-left:15px;"></input>
  126. <button id="chat-button" class="button is-info" onclick=handleChangeSize() style="padding-left:15px;">修改窗口宽高
  127. </button>
  128. </div>
  129. <div style="margin-top: 8px;">
  130. <span id="guest-url">
  131. <input value class="confViewInput input is-warning is-rounded" autocomplete="off" type="text" placeholder="请输入链接: "
  132. onchange=changingGuestUrl(value) style="width:700px;padding-left:15px;"></input>
  133. <button id="chat-button" class="button is-warning" onclick=handleGuestSharingUrl()
  134. style="padding-left:15px;">设置嘉宾链接</button>
  135. </span>
  136. </div>
  137. <div style="margin-top: 8px;">
  138. <span id="audience-url">
  139. <input value class="confViewInput input is-success is-rounded" autocomplete="off" type="text" placeholder="请输入链接: "
  140. onchange=changingAudienceUrl(value) style="width:700px;padding-left:15px;"></input>
  141. <button id="chat-button" class="button is-success" onclick=handleAudienceSharingUrl()
  142. style="padding-left:15px;">设置观众链接</button>
  143. </span>
  144. </div>
  145. <div style="margin-top: 8px;">
  146. <span id="leave-url">
  147. <input value class="confViewInput input is-success is-rounded" autocomplete="off" type="text" placeholder="请输入链接: "
  148. onchange=changingLeaveUrl(value) style="width:700px;padding-left:15px;"></input>
  149. <button id="chat-button" class="button is-success" onclick=handleLeaveUrl()
  150. style="padding-left:15px;">设置离会链接</button>
  151. </span>
  152. </div>
  153. <div style="margin-top: 8px;">
  154. <span id="record-content">
  155. <textarea name="record-content" rows="4" cols="80" value class=" confViewInput is-success is-rounded" autocomplete="off" type="text" placeholder="请输入内容: "
  156. onchange=changingStopRecordTip(value) style="width:700px;padding-left:15px;"></textarea>
  157. <button id="chat-button" class="button is-success" onclick=handleStopRecordTip()
  158. style="padding-left:15px;">设置停止录制内容</button>
  159. </span>
  160. </div>
  161. <div style="margin-top: 8px;">
  162. <div id="mode-select" class="select is-link">
  163. <select id='changeModeSelect' onchange=selectMode(value)>
  164. <option value="">--设置视图--</option>
  165. <option value="speaking">演讲者视图</option>
  166. <option value="gallery">画廊视图</option>
  167. <option value="single">单视图</option>
  168. </select>
  169. </div>
  170. <div class="select is-primary">
  171. <select id='getViewSelect' onchange=getViewStatus(value)>
  172. <option value="">--查看视图状态--</option>
  173. <option value="titleVisible">标题显示</option>
  174. <option value="bulletScreenVisible">弹幕显示</option>
  175. <option value="attendeeListVisible">与会者显示</option>
  176. <option value="chatVisible">聊天显示</option>
  177. <option value="viewMode">视图模式</option>
  178. <option value="controlBarVisible">会控条显示</option>
  179. <option value="guestSharingUrl">嘉宾分享链接</option>
  180. <option value="audienceSharingUrl">观众分享链接</option>
  181. <option value="stopRecordTip">停止录制内容</option>
  182. <option value="leaveUrl">离会后跳转链接</option>
  183. </select>
  184. </div>
  185. <div class="select is-danger">
  186. <select id='getConfStatusSelect' onchange=getConfStatus(value)>
  187. <option value="">--查看会控状态--</option>
  188. <option value="audioMute">静音状态</option>
  189. <option value="videoMute">视频状态</option>
  190. <option value="speakerMute">扬声器状态</option>
  191. <option value="volume">音量</option>
  192. <option value="handUp">举手状态</option>
  193. <option value="shareScreen">共享状态</option>
  194. <option value="userName">名称</option>
  195. <option value="role">获取角色</option>
  196. </select>
  197. </div>
  198. </div>
  199. <div style="margin-top: 8px;">
  200. <textarea id="meeting-config" name="meeting-config" rows="8" cols="80" placeholder="请输入自定义 config 的 参数(JSON 类型)"
  201. onchange=changingCustomConfig(value)></textarea>
  202. <div>
  203. <button id="formatConfig" class="button is-success" onclick=formatConfig() style="padding-left:15px;">
  204. 格式化参数
  205. </button>
  206. <button id="setServerConfigButton" class="button is-warning" onclick=invokeSetServerConfig()
  207. style="padding-left:15px;">setServerConfig
  208. </button>
  209. <button id="joinConfButton" class="button is-info" onclick=invokeJoinConf() style="padding-left:15px;">
  210. joinConf
  211. </button>
  212. <button id="leaveConfButton" class="button is-info" onclick=invokeLeaveConf()
  213. style="padding-left:15px;">leaveConf
  214. </button>
  215. <button id="setViewConfigButton" class="button is-success" onclick=invokeSetViewConfig()
  216. style="padding-left:15px;">setViewConfig
  217. </button>
  218. <button id="setConfConfigButton" class="button is-info" onclick=invokeSetConfConfig()
  219. style="padding-left:15px;">setConfConfig
  220. </button>
  221. </div>
  222. </div>
  223. </div>
  224. <article class="message is-danger" style="width: 40%;">
  225. <div class="message-header">
  226. <p>事件监听</p>
  227. <button class="button is-success is-small" onclick=clearMessagePanel()
  228. style="padding-left:15px;background-color: #c33a55;">清空
  229. </button>
  230. <!-- <button class="delete" aria-label="delete"></button> -->
  231. </div>
  232. <div id="message-body" class="message-body" style="height: 500px; overflow-y: auto; user-select: text;">
  233. </div>
  234. </article>
  235. </div>
  236. <div id="stream-pools" style="display: none"></div>
  237. </body>
  238. <script src="./react.development.js" crossorigin></script>
  239. <script src="./react-dom.development.js" crossorigin></script>
  240. <script src="./moment.min.js" crossorigin></script>
  241. <!-- SDK -->
  242. <script src='./HWMeeting.js'></script>
  243. <link rel="stylesheet" href="./bulma.min.css">
  244. <script>
  245. /**
  246. * 设置会议服务器地址, 不设置时默认使用中国站
  247. * 中国站: host: 'meeting.huaweicloud.com', port: '443'
  248. * 国际站: host: 'intl.meeting.huaweicloud.com', port: '443'
  249. * */
  250. HWMeeting.setServerConfig({
  251. host: 'meeting.huaweicloud.com',
  252. port: '443'
  253. });
  254. let listener;
  255. let role;
  256. function createListener() {
  257. listener = HWMeeting.createEventListener();
  258. HWMeeting.getEventList().forEach(event => {
  259. listener.on(event, (eventData) => {
  260. handleListeningEvents(event, JSON.stringify(eventData));
  261. if (event === "leave_conf_result") {
  262. handleConfLeaveEvent(eventData);
  263. }
  264. if (event === "conf_config_changed") {
  265. handleConfChangeEvent(eventData);
  266. }
  267. if (event === "view_config_changed") {
  268. handleViewChangeEvent(eventData);
  269. }
  270. if (event === "join_conf_result" && eventData?.retCode === "0") {
  271. // 同步按钮状态
  272. syncConfConfig();
  273. syncViewConfig();
  274. }
  275. });
  276. });
  277. }
  278. // 可视化事件结果
  279. function handleListeningEvents(event, eventDataJson) {
  280. let msgBody = document.getElementById("message-body");
  281. let newContent = document.createElement("div");
  282. newContent.textContent = `【事件回调】 | ${moment().format("YYYY-MM-DD HH:mm:ss")} | 事件内容: [${event}]: ${eventDataJson}`;
  283. newContent.class = 'select-text';
  284. newContent.style = " white-space: pre-wrap; word-wrap:break-word";
  285. // 添加文本节点 到这个新的 div 元素
  286. msgBody.appendChild(newContent);
  287. msgBody.scrollTop = msgBody.scrollHeight;
  288. console.warn("事件监听:", event, eventDataJson)
  289. }
  290. function clearMessagePanel() {
  291. let msgBody = document.getElementById("message-body");
  292. msgBody.innerHTML = '';
  293. }
  294. </script>
  295. <!-- 会控控制 -->
  296. <script>
  297. let width = 1280;
  298. let height = 720;
  299. let customConfig;
  300. const SUCCESS = true;
  301. const FAIL = false;
  302. const confConfig = {
  303. audioMute: {
  304. name: 'audioMute',
  305. value: true,
  306. },
  307. videoMute: {
  308. name: 'videoMute',
  309. value: true,
  310. },
  311. speakerMute: {
  312. name: 'speakerMute',
  313. value: false,
  314. },
  315. volume: {
  316. name: 'volume',
  317. value: 50,
  318. },
  319. handUp: {
  320. name: 'handUp',
  321. value: false,
  322. },
  323. shareScreen: {
  324. name: 'shareScreen',
  325. value: false,
  326. },
  327. userName: {
  328. name: 'userName',
  329. value: null,
  330. },
  331. role: {
  332. name: 'role',
  333. value: null,
  334. },
  335. }
  336. const buttonMap = {
  337. [confConfig.audioMute.name]: {
  338. element: document.getElementById("audio-button"),
  339. value: {
  340. true: "取消静音",
  341. false: "静音"
  342. }
  343. },
  344. [confConfig.videoMute.name]: {
  345. element: document.getElementById("video-button"),
  346. value: {
  347. true: "打开视频",
  348. false: "关闭视频"
  349. }
  350. },
  351. [confConfig.speakerMute.name]: {
  352. element: document.getElementById("speaker-button"),
  353. value: {
  354. true: "打开扬声器",
  355. false: "关闭扬声器"
  356. }
  357. },
  358. [confConfig.handUp.name]:
  359. {
  360. element: document.getElementById("handup-button"),
  361. value: {
  362. true: "放下",
  363. false: "举手"
  364. }
  365. },
  366. [confConfig.shareScreen.name]:
  367. {
  368. element: document.getElementById("share-button"),
  369. value: {
  370. true: "取消共享",
  371. false: "共享"
  372. }
  373. },
  374. }
  375. function syncConfConfig() {
  376. Object.keys(confConfig).forEach((key => {
  377. HWMeeting.getConfConfig(key).then((result) => {
  378. if (Object.prototype.hasOwnProperty.call(buttonMap, key)) {
  379. buttonMap[key].element.textContent = buttonMap[key].value[result.data[key]];
  380. confConfig[key].value = result.data[key];
  381. }
  382. }).catch((e) => {
  383. console.error('mark syncConfConfig', e)
  384. });
  385. }));
  386. }
  387. function handleConfLeaveEvent() {
  388. Array.from(document.querySelectorAll('.confViewInput')).forEach(node => {
  389. node.value = '';
  390. })
  391. }
  392. function handleConfChangeEvent(eventData) {
  393. const { configName, previousValue, currentValue } = eventData;
  394. if (Object.prototype.hasOwnProperty.call(buttonMap, configName)) {
  395. buttonMap[configName].element.textContent = buttonMap[configName].value[currentValue];
  396. confConfig[configName].value = currentValue;
  397. }
  398. }
  399. function handleShareScreen() {
  400. let params = { shareScreen: !confConfig.shareScreen.value };
  401. HWMeeting.setConfConfig(params).then((result) => {
  402. // 显示结果
  403. showPromiseResult("setConfConfig", params, SUCCESS, result);
  404. }).catch((e) => {
  405. // 显示结果
  406. showPromiseResult("setConfConfig", params, FAIL, e);
  407. });
  408. }
  409. function handleMuteAudio() {
  410. let params = { audioMute: !confConfig.audioMute.value };
  411. HWMeeting.setConfConfig(params).then((result) => {
  412. // 显示结果
  413. showPromiseResult("setConfConfig", params, SUCCESS, result);
  414. }).catch((e) => {
  415. // 显示结果
  416. showPromiseResult("setConfConfig", params, FAIL, e);
  417. });
  418. }
  419. function handleVideoMute() {
  420. let params = { videoMute: !confConfig.videoMute.value };
  421. HWMeeting.setConfConfig(params).then((result) => {
  422. // 显示结果
  423. showPromiseResult("setConfConfig", params, SUCCESS, result);
  424. }).catch((e) => {
  425. // 显示结果
  426. showPromiseResult("setConfConfig", params, FAIL, e);
  427. });
  428. }
  429. function handleMuteSpeaker() {
  430. let params = { speakerMute: !confConfig.speakerMute.value }
  431. HWMeeting.setConfConfig(params).then((result) => {
  432. // 显示结果
  433. showPromiseResult("setConfConfig", params, SUCCESS, result);
  434. }).catch((e) => {
  435. // 显示结果
  436. showPromiseResult("setConfConfig", params, FAIL, e);
  437. });
  438. }
  439. function handleHand() {
  440. let params = { handUp: !confConfig.handUp.value };
  441. HWMeeting.setConfConfig(params).then((result) => {
  442. // 显示结果
  443. showPromiseResult("setConfConfig", params, SUCCESS, result);
  444. }).catch((e) => {
  445. // 显示结果
  446. showPromiseResult("setConfConfig", params, FAIL, e);
  447. });
  448. }
  449. function getConfStatus(value) {
  450. if (value === "") {
  451. return;
  452. }
  453. HWMeeting.getConfConfig(value).then((data) => {
  454. // 显示结果
  455. showPromiseResult("getConfConfig", value, SUCCESS, data);
  456. }).catch((e) => {
  457. // 显示结果
  458. showPromiseResult("getConfConfig", value, FAIL, e);
  459. });
  460. }
  461. function getViewStatus(value) {
  462. if (value === "") {
  463. return;
  464. }
  465. HWMeeting.getViewConfig(value).then((data) => {
  466. // 显示结果
  467. showPromiseResult("getViewConfig", value, SUCCESS, data);
  468. }).catch((e) => {
  469. // 显示结果
  470. showPromiseResult("getViewConfig", value, FAIL, e);
  471. });
  472. }
  473. function handleSetVolume() {
  474. let params = { 'volume': Number(confConfig.volume.value) }
  475. HWMeeting.setConfConfig(params).then((result) => {
  476. // 显示结果
  477. showPromiseResult("setConfConfig", params, SUCCESS, result);
  478. }).catch((e) => {
  479. // 显示结果
  480. showPromiseResult("setConfConfig", params, FAIL, e);
  481. });
  482. }
  483. function handleChangeName() {
  484. let params = { userName: confConfig.userName.value }
  485. HWMeeting.setConfConfig(params).then((result) => {
  486. // 显示结果
  487. showPromiseResult("setConfConfig", params, SUCCESS, result);
  488. }).catch((e) => {
  489. // 显示结果
  490. showPromiseResult("setConfConfig", params, FAIL, e);
  491. });
  492. }
  493. function handleGetToken() {
  494. getToken();
  495. }
  496. function changingWith(e) {
  497. width = e;
  498. }
  499. function changingHeight(e) {
  500. height = e;
  501. }
  502. // confConfig
  503. function changingName(e) {
  504. confConfig.userName.value = e;
  505. }
  506. function volumeChange(e) {
  507. confConfig.volume.value = e;
  508. }
  509. // viewConfig
  510. function changingGuestUrl(e) {
  511. viewConfig.guestSharingUrl.value = e;
  512. }
  513. function changingAudienceUrl(e) {
  514. viewConfig.audienceSharingUrl.value = e;
  515. }
  516. function changingLeaveUrl(e) {
  517. viewConfig.leaveUrl.value = e;
  518. }
  519. function changingStopRecordTip(e) {
  520. viewConfig.stopRecordTip.value = e;
  521. }
  522. // 自定义参数
  523. function changingCustomConfig(value) {
  524. customConfig = value;
  525. }
  526. function parseConfJson(config) {
  527. if (typeof config === 'undefined' || config === null) {
  528. return config;
  529. }
  530. if (config === '') {
  531. return undefined;
  532. }
  533. try {
  534. return JSON.parse(config);
  535. } catch (err) {
  536. console.error(err);
  537. alert('JSON 格式错误' + JSON.stringify(err))
  538. }
  539. }
  540. function formatConfig() {
  541. const customConfigJson = parseConfJson(customConfig);
  542. if (customConfigJson) {
  543. document.getElementById("meeting-config").value = JSON.stringify(customConfigJson, null, 4);
  544. }
  545. }
  546. </script>
  547. <!-- UI控制: -->
  548. <script>
  549. const viewConfig = {
  550. titleVisible: {
  551. name: 'titleVisible',
  552. value: false
  553. },
  554. attendeeListVisible: {
  555. name: 'attendeeListVisible',
  556. value: false
  557. },
  558. chatVisible: {
  559. name: 'chatVisible',
  560. value: false
  561. },
  562. bulletScreenVisible: {
  563. name: 'bulletScreenVisible',
  564. value: false
  565. },
  566. controlBarVisible: {
  567. name: 'controlBarVisible',
  568. value: false
  569. },
  570. viewMode: {
  571. name: 'viewMode',
  572. value: null
  573. },
  574. guestSharingUrl: {
  575. name: 'guestSharingUrl',
  576. value: null
  577. },
  578. audienceSharingUrl: {
  579. name: 'audienceSharingUrl',
  580. value: null
  581. },
  582. stopRecordTip: {
  583. name: 'stopRecordTip',
  584. value: null
  585. },
  586. leaveUrl: {
  587. name: 'leaveUrl',
  588. value: null
  589. },
  590. }
  591. const viewButtonMap = {
  592. [viewConfig.titleVisible.name]: {
  593. element: document.getElementById("title-button"),
  594. value: {
  595. true: "标题隐藏",
  596. false: "标题显示"
  597. }
  598. },
  599. [viewConfig.attendeeListVisible.name]: {
  600. element: document.getElementById("attendee-button"),
  601. value: {
  602. true: "与会者隐藏",
  603. false: "与会者显示"
  604. }
  605. },
  606. [viewConfig.chatVisible.name]: {
  607. element: document.getElementById("chat-button"),
  608. value: {
  609. true: "聊天隐藏",
  610. false: "聊天显示"
  611. }
  612. },
  613. [viewConfig.bulletScreenVisible.name]: {
  614. element: document.getElementById("bullet-button"),
  615. value: {
  616. true: "弹幕隐藏",
  617. false: "弹幕显示"
  618. }
  619. },
  620. [viewConfig.controlBarVisible.name]: {
  621. element: document.getElementById("control-button"),
  622. value: {
  623. true: "会控条隐藏",
  624. false: "会控条显示"
  625. }
  626. },
  627. }
  628. function syncViewConfig() {
  629. Object.keys(viewConfig).forEach((key => {
  630. HWMeeting.getViewConfig(key).then((result) => {
  631. if (Object.prototype.hasOwnProperty.call(viewButtonMap, key)) {
  632. viewButtonMap[key].element.textContent = viewButtonMap[key].value[result.data[key]];
  633. viewConfig[key].value = result.data[key];
  634. }
  635. }).catch((e) => {
  636. console.error('syncViewConfig', key, e)
  637. });
  638. }));
  639. }
  640. function handleViewChangeEvent(eventData) {
  641. const { configName, previousValue, currentValue } = eventData;
  642. if (Object.prototype.hasOwnProperty.call(viewButtonMap, configName)) {
  643. viewButtonMap[configName].element.textContent = viewButtonMap[configName].value[currentValue];
  644. }
  645. viewConfig[configName].value = currentValue;
  646. }
  647. function clickLeaveConf() {
  648. const value = "role"
  649. HWMeeting.getConfConfig(value).then((data) => {
  650. // 显示结果
  651. showPromiseResult("getConfConfig", value, SUCCESS, data);
  652. if (data?.data?.role === "host") {
  653. openModals();
  654. } else {
  655. handleLeave({ isEndConf: false });
  656. }
  657. }).catch((e) => {
  658. // 显示结果
  659. showPromiseResult("getConfConfig", value, FAIL, e);
  660. });
  661. }
  662. function handleLeaveConfirm() {
  663. closeModals();
  664. const radioValue = document.querySelector('[name=leaveConfConfirm]:checked').value;
  665. const params = { isEndConf: radioValue === "end" };
  666. handleLeave(params);
  667. }
  668. function handleLeave(params) {
  669. HWMeeting.leaveConf(params).then((result) => {
  670. // 显示结果
  671. showPromiseResult("leaveConf", params, SUCCESS, result);
  672. }).catch((e) => {
  673. // 显示结果
  674. showPromiseResult("leaveConf", params, FAIL, e);
  675. })
  676. }
  677. function openModals() {
  678. document.getElementById("leaveConfModal").classList.add('is-active');
  679. }
  680. function closeModals() {
  681. document.getElementById("leaveConfModal").classList.remove('is-active')
  682. }
  683. function handleChatVisible() {
  684. let params = { chatVisible: !viewConfig.chatVisible.value };
  685. HWMeeting.setViewConfig(params).then((result) => {
  686. // 显示结果
  687. showPromiseResult("setViewConfig", params, SUCCESS, result);
  688. }).catch((e) => {
  689. // 显示结果
  690. showPromiseResult("setViewConfig", params, FAIL, e);
  691. });
  692. }
  693. function handleAttendeeListVisible() {
  694. let params = { attendeeListVisible: !viewConfig.attendeeListVisible.value };
  695. HWMeeting.setViewConfig(params).then((result) => {
  696. // 显示结果
  697. showPromiseResult("setViewConfig", params, SUCCESS, result);
  698. }).catch((e) => {
  699. // 显示结果
  700. showPromiseResult("setViewConfig", params, FAIL, e);
  701. });
  702. }
  703. function handleControlBarVisible() {
  704. let params = { controlBarVisible: !viewConfig.controlBarVisible.value };
  705. HWMeeting.setViewConfig(params).then((result) => {
  706. // 显示结果
  707. showPromiseResult("setViewConfig", params, SUCCESS, result);
  708. }).catch((e) => {
  709. // 显示结果
  710. showPromiseResult("setViewConfig", params, FAIL, e);
  711. });
  712. }
  713. function handleTitleVisible() {
  714. let params = { titleVisible: !viewConfig.titleVisible.value };
  715. HWMeeting.setViewConfig(params).then((result) => {
  716. // 显示结果
  717. showPromiseResult("setViewConfig", params, SUCCESS, result);
  718. }).catch((e) => {
  719. // 显示结果
  720. showPromiseResult("setViewConfig", params, FAIL, e);
  721. });
  722. }
  723. function handleBulletScreenVisible() {
  724. let params = { bulletScreenVisible: !viewConfig.bulletScreenVisible.value };
  725. HWMeeting.setViewConfig(params).then((result) => {
  726. // 显示结果
  727. showPromiseResult("setViewConfig", params, SUCCESS, result);
  728. }).catch((e) => {
  729. // 显示结果
  730. showPromiseResult("setViewConfig", params, FAIL, e);
  731. });
  732. }
  733. function selectMode(value) {
  734. if (value === "") {
  735. return;
  736. }
  737. let params = { viewMode: value };
  738. HWMeeting.setViewConfig(params).then((result) => {
  739. // 显示结果
  740. showPromiseResult("setViewConfig", params, SUCCESS, result);
  741. }).catch((e) => {
  742. // 显示结果
  743. showPromiseResult("setViewConfig", params, FAIL, e);
  744. })
  745. }
  746. // 修改sdk渲染框大小
  747. function handleChangeSize() {
  748. let sdkRoot = document.getElementById("root");
  749. width = Math.max(Math.min(width, 2000), 300);
  750. height = Math.max(Math.min(height, 1000), 300);
  751. sdkRoot.style.width = width + "px";
  752. sdkRoot.style.height = height + "px";
  753. }
  754. function handleGuestSharingUrl() {
  755. let params = { guestSharingUrl: viewConfig.guestSharingUrl.value }
  756. HWMeeting.setViewConfig(params).then((result) => {
  757. // 显示结果
  758. showPromiseResult("setViewConfig", params, SUCCESS, result);
  759. }).catch((e) => {
  760. // 显示结果
  761. showPromiseResult("setViewConfig", params, FAIL, e);
  762. });
  763. }
  764. function handleAudienceSharingUrl() {
  765. let params = { audienceSharingUrl: viewConfig.audienceSharingUrl.value };
  766. HWMeeting.setViewConfig(params).then((result) => {
  767. // 显示结果
  768. showPromiseResult("setViewConfig", params, SUCCESS, result);
  769. }).catch((e) => {
  770. // 显示结果
  771. showPromiseResult("setViewConfig", params, FAIL, e);
  772. });
  773. }
  774. function handleLeaveUrl() {
  775. let params = { leaveUrl: viewConfig.leaveUrl.value };
  776. HWMeeting.setViewConfig(params).then((result) => {
  777. // 显示结果
  778. showPromiseResult("setViewConfig", params, SUCCESS, result);
  779. }).catch((e) => {
  780. // 显示结果
  781. showPromiseResult("setViewConfig", params, FAIL, e);
  782. });
  783. }
  784. function handleStopRecordTip() {
  785. let params = { stopRecordTip: viewConfig.stopRecordTip.value };
  786. HWMeeting.setViewConfig(params).then((result) => {
  787. // 显示结果
  788. showPromiseResult("setViewConfig", params, SUCCESS, result);
  789. }).catch((e) => {
  790. // 显示结果
  791. showPromiseResult("setViewConfig", params, FAIL, e);
  792. });
  793. }
  794. function invokeSetConfConfig() {
  795. const customConfigObj = parseConfJson(customConfig);
  796. HWMeeting.setConfConfig(customConfigObj).then((result) => {
  797. // 显示结果
  798. showPromiseResult("setConfConfig", customConfigObj, SUCCESS, result);
  799. }).catch((e) => {
  800. // 显示结果
  801. showPromiseResult("setConfConfig", customConfigObj, FAIL, e);
  802. })
  803. }
  804. function invokeSetViewConfig() {
  805. const customConfigObj = parseConfJson(customConfig);
  806. HWMeeting.setViewConfig(customConfigObj).then((result) => {
  807. // 显示结果
  808. showPromiseResult("setViewConfig", customConfigObj, SUCCESS, result);
  809. }).catch((e) => {
  810. // 显示结果
  811. showPromiseResult("setViewConfig", customConfigObj, FAIL, e);
  812. })
  813. }
  814. function invokeJoinConf() {
  815. const customConfigObj = parseConfJson(customConfig);
  816. HWMeeting.joinConf(customConfigObj).then((result) => {
  817. // 显示结果
  818. showPromiseResult("joinConf", customConfigObj, SUCCESS, result);
  819. }).catch((e) => {
  820. // 显示结果
  821. showPromiseResult("joinConf", customConfigObj, FAIL, e);
  822. })
  823. }
  824. function invokeLeaveConf() {
  825. const customConfigObj = parseConfJson(customConfig);
  826. HWMeeting.leaveConf(customConfigObj).then((result) => {
  827. // 显示结果
  828. showPromiseResult("leaveConf", customConfigObj, SUCCESS, result);
  829. }).catch((e) => {
  830. // 显示结果
  831. showPromiseResult("leaveConf", customConfigObj, FAIL, e);
  832. })
  833. }
  834. function invokeSetServerConfig() {
  835. const customConfigObj = parseConfJson(customConfig);
  836. try {
  837. HWMeeting.setServerConfig(customConfigObj);
  838. // 显示结果
  839. showPromiseResult("setServerConfig", customConfigObj, SUCCESS);
  840. } catch (e) {
  841. // 显示结果
  842. showPromiseResult("setServerConfig", customConfigObj, FAIL, e);
  843. }
  844. }
  845. </script>
  846. <script>
  847. function validateForm() {
  848. let nickName = document.getElementById("nickName").value;
  849. let pwd = document.getElementById("pwd").value;
  850. let confId = document.getElementById("confId").value;
  851. let token = document.getElementById("token").value;
  852. console.warn(confId, pwd, nickName, token);
  853. HWMeeting.joinConf({ confId, pwd, nickName, token }).then((result) => {
  854. // 显示结果
  855. showPromiseResult("joinConf", { confId, pwd, nickName, token }, SUCCESS, result);
  856. }).catch((e) => {
  857. // 显示结果
  858. showPromiseResult("joinConf", { confId, pwd, nickName, token }, FAIL, e);
  859. })
  860. }
  861. function setLang() {
  862. let lang = document.getElementById('lang').value;
  863. if (lang == undefined || lang === null || lang === '') {
  864. return;
  865. }
  866. try {
  867. HWMeeting.setLang(lang);
  868. showPromiseResult("setLang", lang, SUCCESS);
  869. } catch (e) {
  870. showPromiseResult("setLang", lang, FAIL, e);
  871. }
  872. }
  873. // 可视化事件结果
  874. function showPromiseResult(event, params, isSuccess, result) {
  875. let msgBody = document.getElementById("message-body");
  876. let newContent = document.createElement("div");
  877. newContent.textContent = `【API调用】 | ${moment().format("YYYY-MM-DD HH:mm:ss")} | ${isSuccess ? 'SUCCESS' : 'FAIL'} | [api]: ${event} | [api-params]: ${JSON.stringify(params)} | [api-result]: ${JSON.stringify(result)}`
  878. newContent.class = 'select-text';
  879. newContent.style = " white-space: pre-wrap;";
  880. // 添加文本节点 到这个新的 div 元素
  881. msgBody.appendChild(newContent);
  882. msgBody.scrollTop = msgBody.scrollHeight;
  883. }
  884. function checkBrowserSupport() {
  885. const result = HWMeeting.checkSystemRequirements().then((result) => {
  886. // 显示结果
  887. showPromiseResult("checkSystemRequirements", null, SUCCESS, result);
  888. }).catch((e) => {
  889. // 显示结果
  890. showPromiseResult("checkSystemRequirements", null, FAIL, e);
  891. })
  892. }
  893. function getSdkVersion() {
  894. const result = HWMeeting.getVersion();
  895. // 显示结果
  896. showPromiseResult("getSdkVersion", null, SUCCESS, result);
  897. }
  898. //获取地址参数
  899. function getQueryString(name) {//name为传入参数
  900. let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
  901. let r = window.location.search.substr(1).match(reg);
  902. if (r != null) return unescape(r[2]); return null;
  903. }
  904. //进入该页面自动加入会议 李猛add 20230222
  905. function autoJoin() {
  906. let id = getQueryString("conferenceID");
  907. let password = getQueryString("password");
  908. let nickName = getQueryString("nickName");
  909. document.getElementById("confId").value = id;
  910. document.getElementById("pwd").value = password;
  911. document.getElementById("nickName").value = decodeURI(decodeURI(nickName));
  912. validateForm();
  913. }
  914. </script>
  915. <script>
  916. createListener();
  917. //进入该页面自动加入会议 李猛add 20230222
  918. autoJoin();
  919. </script>
  920. </html>