PageRtcLive.vue 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. <template>
  2. <div id="PageRtcLive">
  3. <div class="member_number">
  4. <div class="members"></div>
  5. <span>{{ user_list.length }}观看</span>
  6. </div>
  7. <chat ref="chat$" v-show="chatShow" :chatList="chatList" :user_info="user_info"></chat>
  8. <div class="videoBox userVideo" id="userVideo" v-show="!hideVideoTop">
  9. <img v-if="!userVideoShow" :src="require('@/assets/images/rtcLive/avatar_small@2x.png')" alt="" />
  10. <img v-if="!userVideoShow" class="loadingTip" :src="require('@/assets/images/rtcLive/loading@2x.png')" alt="" />
  11. <div class="micBox">
  12. <i v-if="hideMicTop" class="iconfont iconscene_mic_off1"></i>
  13. <i v-else class="speak_mic"></i>
  14. </div>
  15. </div>
  16. <div v-show="mode == '1' && !hideVideoBottom" class="videoBox myVideo" id="myVideo">
  17. <img v-if="!myVideoShow" :src="require('@/assets/images/rtcLive/avatar_small@2x.png')" alt="" />
  18. <img v-if="!myVideoShow" class="loadingTip" :src="require('@/assets/images/rtcLive/loading@2x.png')" alt="" />
  19. <div class="micBox">
  20. <i v-if="hideMic" class="iconfont iconscene_mic_off1"></i>
  21. <i v-else class="speak_mic"></i>
  22. </div>
  23. </div>
  24. <!-- </div> -->
  25. <!-- <input type="text" autocomplete="off"> -->
  26. <div class="contorlBar" v-if="!showInput">
  27. <div v-if="connectStatus == 1" :class="{ disabled: !user_info.IsWords }" class="saySomething" @click="onFocus">
  28. <!-- <i class="speakIcon"
  29. :class="{'dis':!user_info.IsWords}"></i> -->
  30. <span v-if="user_info.IsWords"> 说点什么 </span>
  31. <span v-if="!user_info.IsWords">已被禁言</span>
  32. <div class="disSpeakBtn" @click.stop="chatShow = !chatShow" :class="{ dis: !chatShow }"></div>
  33. </div>
  34. <div style="text-align: right; width: 100%" v-if="connectStatus == 0">连接中...</div>
  35. <div v-if="connectStatus == 1" class="contorl_btn">
  36. <div v-if="isBrushes && user_info.Role == 'leader'" @click="onDrawUndo" class="brushesBack" :class="{ disabled: !canUndo }"></div>
  37. <div v-if="user_info.Role == 'leader'" @click="onDraw(!isBrushes)" :class="{ brushesed: isBrushes }" class="brushes"></div>
  38. <div
  39. v-if="(user_list.length < 2 && mode == '1') || (mode == '2' && user_list.length < 30)"
  40. class="invitation"
  41. @click="openDialog('dialogShare', shareLink)"
  42. ></div>
  43. <div v-if="mode == '2' && role == 'leader'" class="members" @click="openMember"></div>
  44. <div v-if="audioDevices.length != 0 && !disableMic" @click="changeMedia('audio', hideMic)" :class="{ mic_off: hideMic }" class="mic_on"></div>
  45. <div v-if="audioDevices.length == 0 || disableMic" class="mic_no"></div>
  46. <div
  47. v-if="(role == 'leader' && videoDevices.length != 0) || (mode == '1' && videoDevices.length != 0)"
  48. @click="changeMedia('video', hideVideo)"
  49. :class="{ video_off: hideVideo }"
  50. class="video_on"
  51. ></div>
  52. <div v-if="(videoDevices.length == 0 && mode == '1') || (role == 'leader' && videoDevices.length == 0)" class="video_no"></div>
  53. <div class="exit" @click="openDialog('dialogIndex')"></div>
  54. </div>
  55. </div>
  56. <div class="layer" v-if="showInput" @click="closeInput">
  57. <div class="inputBox" @click.stop>
  58. <div class="msgBox">
  59. <input id="input_msg" type="text" maxlength="200" v-model.trim="text" :placeholder="`说点什么~`" />
  60. <span class="iconsend_icon" :class="{ disable: text == '' }" @click.stop="sendText">发送</span>
  61. </div>
  62. </div>
  63. </div>
  64. <!-- 成员 -->
  65. <div class="layer" v-if="showMember" @click.self="closeMember">
  66. <div class="memberContent animated" :class="animateActive ? 'fadeInUpBig' : 'fadeOutDownBig'">
  67. <div class="blurBox"></div>
  68. <div class="content">
  69. <div class="memberHeader">
  70. <span> 成员管理({{ user_list.length }})</span>
  71. <i class="iconfont"></i>
  72. </div>
  73. <div class="memberList">
  74. <div class="memberItem">
  75. <div class="userMsg">
  76. <div class="avatar">
  77. <img :src="require('@/assets/images/rtcLive/avatar_small@2x.png')" alt="" />
  78. </div>
  79. <div class="name" v-if="user_info.Role == 'leader'">{{ user_info.Nickname }} (主持人,我)</div>
  80. <div class="name" v-else>{{ user_info.Nickname }} (我)</div>
  81. </div>
  82. <div class="button" v-if="user_info.Role == 'leader'">
  83. <!-- <div class="outBtn iconfont iconremove"></div> -->
  84. <!-- <div v-if="audioDevices.length>0" class="micBtn iconfont" @click="changeMedia('audio',hideMic)" :class="user_info.muted ?'iconmic_off':'iconmic_on'"></div>
  85. <div v-else class="micBtn iconfont iconmic_off"></div> -->
  86. <div class="micBtn mute_all_mic" :class="{ open_all_mic: !all_mute_mic }" ></div>
  87. </div>
  88. </div>
  89. <div v-show="user_info.UserId != i.UserId && i.Role != 'leader'" class="memberItem" v-for="i in user_list" :key="i.UserId">
  90. <div class="userMsg">
  91. <div class="avatar">
  92. <img :src="require('@/assets/images/rtcLive/avatar_small@2x.png')" alt="" />
  93. </div>
  94. <div class="name">{{ i.Nickname }}</div>
  95. </div>
  96. <div class="button" v-if="user_info.Role == 'leader'">
  97. <div class="micBtn" :class="i.IsWords ? 'ban_speak_on' : 'ban_speak_off'" @click="userCanSpeak(i)"></div>
  98. <div class="outBtn icon_remove" @click="userGetOut(i.UserId)"></div>
  99. <div class="micBtn" :class="i.IsMuted ? 'mute_one_mic_off' : 'mute_one_mic_on'" @click="onMemberMuted(i)"></div>
  100. </div>
  101. </div>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. </div>
  107. </template>
  108. <script setup>
  109. import { onMounted, watch, defineEmits, ref, reactive, computed, nextTick } from "vue";
  110. import { useApp, getApp } from "@/app";
  111. import { useStore } from "vuex";
  112. import { Scrollbar, Dialog } from "@/global_components/";
  113. import common from "@/utils/common";
  114. import { mapGetters } from "vuex";
  115. import chat from "./chat/chat.vue";
  116. import browser from "@/utils/browser";
  117. const emit = defineEmits(["openDialog"]);
  118. const store = useStore();
  119. let chatAutoScroll = () => {
  120. let el = document.getElementById("chat");
  121. let client_h = document.getElementById("chat").clientHeight;
  122. let all = document.getElementById("contents").clientHeight;
  123. el.scrollTo(0, client_h + all);
  124. };
  125. let createSocket = (config) => {
  126. var socket = io(process.env.VUE_SOCKET_URL, {
  127. path: "/ws-sync",
  128. transports: ["websocket"],
  129. });
  130. return socket;
  131. };
  132. store.commit("rtc/setSocket", createSocket());
  133. let getUrl = (href, queryArr) => {
  134. queryArr.forEach((item) => {
  135. if (!browser.hasURLParam(item.key)) {
  136. href += `&${item.key}=${item.val}`;
  137. } else {
  138. href = browser.replaceQueryString(href, item.key, item.val);
  139. }
  140. });
  141. return href;
  142. };
  143. const connectStatus = ref(0);
  144. const showPaint = ref(true);
  145. const isBrushes = ref(false);
  146. const hideVideo = ref(false);
  147. const hideVideoBottom = ref(false);
  148. const hideVideoTop = ref(true);
  149. const hideMic = ref(false);
  150. const hideMicTop = ref(false);
  151. const showInput = ref(false);
  152. const showMember = ref(false);
  153. const animateActive = ref(false);
  154. const socket = computed(() => store.getters["rtc/socket"]);
  155. const myVideoShow = ref(false);
  156. const userVideoShow = ref(false);
  157. const user_info = ref({});
  158. const user_list = ref([]);
  159. const mode = ref(browser.getURLParam("mode"));
  160. const role = ref(browser.getURLParam("role"));
  161. const isJoined = ref(false);
  162. const paint = reactive({});
  163. const chatList = ref([]);
  164. const text = ref("");
  165. const shareLink = ref("");
  166. const canUndo = ref(false);
  167. const audioDevices = ref([1]);
  168. const videoDevices = ref([1]);
  169. const disableMic = ref(false);
  170. const chatShow = ref(true);
  171. const all_mute_mic = ref(true);
  172. const chat$ = ref(null);
  173. const setUserWords = (res) => {
  174. if (user_info.value.Role == "leader") {
  175. user_list.value = res.members.reduce(function (tempArr, item) {
  176. if (tempArr.findIndex((ele) => ele.UserId === item.UserId) === -1) {
  177. tempArr.push(item);
  178. }
  179. return tempArr;
  180. }, []);
  181. }
  182. if (res.userId == user_info.value.UserId) {
  183. user_info.value.IsWords = res.words;
  184. }
  185. };
  186. const setUserMuted = (res) => {
  187. if (user_info.value.Role == "leader") {
  188. user_list.value = res.members.reduce(function (tempArr, item) {
  189. if (tempArr.findIndex((ele) => ele.UserId === item.UserId) === -1) {
  190. tempArr.push(item);
  191. }
  192. return tempArr;
  193. }, []);
  194. }
  195. if (res.userId == user_info.value.UserId) {
  196. user_info.value.IsMuted = res.muted;
  197. }
  198. };
  199. //用戶加入
  200. const setUserJoin = async (res) => {
  201. console.log("有人进来了", res);
  202. // self.user_info = res.user;
  203. user_list.value = res.members.reduce(function (tempArr, item) {
  204. if (tempArr.findIndex((ele) => ele.UserId === item.UserId) === -1) {
  205. tempArr.push(item);
  206. }
  207. return tempArr;
  208. }, []);
  209. // self.chekcLeaderInfo();
  210. let name = res.user.Nickname;
  211. if (res.user.Role == "leader") {
  212. name = "主持人";
  213. Dialog.toast({ content: `主持人进入房间` });
  214. }
  215. let data = {
  216. role: res.user.Role,
  217. mode: mode.value,
  218. Nickname: name,
  219. UserId: res.user.UserId,
  220. text: "进入房间",
  221. };
  222. chatList.value.push(data);
  223. await nextTick();
  224. try {
  225. chatAutoScroll();
  226. } catch (error) {}
  227. };
  228. const onDrawUndo = async () => {
  229. let app = await getApp();
  230. app.Connect.paint.undo();
  231. canUndo.value = app.Connect.paint.records.length > 0;
  232. console.log(app.Connect.paint.records, "app.Connect.paint.records");
  233. };
  234. // 画笔开启
  235. const onDraw = async (status) => {
  236. isBrushes.value = status;
  237. if (isBrushes.value) {
  238. await getApp().Connect.paint.show({ role: role.value, paint: role.value == "leader" ? true : false });
  239. if (role.value == "leader") {
  240. socket.value.emit("action", { type: "user-paint", open: true });
  241. }
  242. } else {
  243. await getApp().Connect.paint.hide();
  244. if (role.value == "leader") {
  245. socket.value.emit("action", { type: "user-paint", open: false });
  246. }
  247. }
  248. };
  249. //打开输入框
  250. const onFocus = () => {
  251. showInput.value = true;
  252. nextTick(() => {
  253. let input_msg = document.getElementById("input_msg");
  254. input_msg.focus();
  255. });
  256. };
  257. //发弹幕
  258. const sendText = async () => {
  259. if (text.value == "") {
  260. return;
  261. }
  262. let data = {
  263. role: role.value,
  264. mode: mode.value,
  265. Nickname: user_info.value.Nickname,
  266. UserId: user_info.value.UserId,
  267. text: text.value,
  268. };
  269. socket.value &&
  270. socket.value.emit("action", {
  271. type: "danmumsg",
  272. data,
  273. });
  274. chatList.value.push(data);
  275. await nextTick();
  276. try {
  277. chatAutoScroll();
  278. let input_msg = document.getElementById("input_msg");
  279. input_msg.blur();
  280. } catch (error) {}
  281. closeInput();
  282. };
  283. //接收消息
  284. const setReceiveMsg = async (res) => {
  285. console.log(res);
  286. if (res.role == "leader") {
  287. res.Nickname = "主持人";
  288. }
  289. chatList.value.push(res);
  290. await nextTick();
  291. try {
  292. chatAutoScroll();
  293. } catch (error) {}
  294. };
  295. // 关闭输入框
  296. const closeInput = () => {
  297. showInput.value = false;
  298. text.value = "";
  299. };
  300. // 开启成员
  301. const openMember = () => {
  302. showMember.value = true;
  303. animateActive.value = true;
  304. };
  305. // 关闭成员
  306. const closeMember = () => {
  307. animateActive.value = false;
  308. let t = setTimeout(() => {
  309. clearTimeout(t);
  310. showMember.value = false;
  311. }, 200);
  312. };
  313. const openDialog = (str, link) => {
  314. emit("openDialog", str, link);
  315. };
  316. const onMemberMuted = (item) => {
  317. item.IsMuted = !item.IsMuted;
  318. socket.value.emit("action", { type: "users-muted", muted: item.IsMuted, userId: item.UserId });
  319. };
  320. const userCanSpeak = (item) => {
  321. item.IsWords = !item.IsWords;
  322. socket.value.emit("action", { type: "users-words", words: item.IsWords, userId: item.UserId });
  323. };
  324. const startFollow = (app) => {
  325. app.Connect.follow.start({ follow: role.value == "customer" });
  326. if (role.value == "customer") {
  327. socket.value.emit("action", { type: "user-init" });
  328. }
  329. socket.value.on("connect", () => {
  330. socket.value.emit("join", {
  331. userId: browser.getURLParam("userId") || common.uuid(12),
  332. roomId: browser.getURLParam("roomId") || common.uuid(12),
  333. role: role.value || "leader",
  334. nickname: browser.getURLParam("name") || common.uuid(12),
  335. });
  336. });
  337. // 加入房间成功
  338. socket.value.on("join", (data) => {
  339. connectStatus.value = 1;
  340. isJoined.value = true;
  341. user_info.value = data.user;
  342. user_list.value = data.members.reduce(function (tempArr, item) {
  343. if (tempArr.findIndex((ele) => ele.UserId === item.UserId) === -1) {
  344. tempArr.push(item);
  345. }
  346. return tempArr;
  347. }, []);
  348. //更新分享链接
  349. shareLink.value = getUrl(window.location.href, [
  350. {
  351. key: "mode",
  352. val: mode.value,
  353. },
  354. {
  355. key: "name",
  356. val: "",
  357. },
  358. {
  359. key: "userId",
  360. val: "",
  361. },
  362. {
  363. key: "role",
  364. val: "customer",
  365. },
  366. {
  367. key: "roomId",
  368. val: user_info.value.RoomId,
  369. },
  370. ]);
  371. let tmp = "";
  372. if (user_info.value.Role == "leader") {
  373. tmp = getUrl(window.location.href, [
  374. {
  375. key: "roomId",
  376. val: user_info.value.RoomId,
  377. },
  378. {
  379. key: "userId",
  380. val: user_info.value.UserId,
  381. },
  382. ]);
  383. } else {
  384. tmp = getUrl(window.location.href, [
  385. {
  386. key: "userId",
  387. val: user_info.value.UserId,
  388. },
  389. ]);
  390. }
  391. history.replaceState(null, null, tmp);
  392. });
  393. socket.value.on("action", (data) => {
  394. if (data.type == "error") {
  395. Dialog.toast({ content: `房间未找到`, type: "error" });
  396. } else if (data.type == "danmumsg") {
  397. setReceiveMsg(data.data);
  398. } else if (data.type == "user-init") {
  399. app.Connect.follow.sync();
  400. } else if (data.type == "user-paint") {
  401. onDraw(data.open);
  402. if (role.value == "customer") {
  403. if (data.open) {
  404. Dialog.toast({ content: `主持人开启画笔` });
  405. } else {
  406. Dialog.toast({ content: `主持人关闭画笔` });
  407. }
  408. }
  409. } else if (data.type == "user-join") {
  410. setUserJoin(data);
  411. } else if (data.type == "users-muted") {
  412. setUserMuted(data);
  413. //閉麥
  414. } else if (data.type == "users-words") {
  415. setUserWords(data);
  416. //禁言
  417. }
  418. });
  419. // 同屏带看
  420. socket.value.on("sync", (data) => {
  421. app.Connect.follow.receive(data);
  422. });
  423. // 画笔
  424. socket.value.on("paint", (data) => {
  425. app.Connect.paint.receive(data);
  426. });
  427. };
  428. onMounted(() => {
  429. useApp().then((app) => {
  430. startFollow(app);
  431. app.Connect.follow.on("data", (data) => {
  432. if (isJoined.value) {
  433. socket.value.emit("sync", data);
  434. }
  435. });
  436. app.Connect.paint.on("data", (data) => {
  437. canUndo.value = app.Connect.paint.records.length > 0;
  438. socket.value.emit("paint", data);
  439. });
  440. });
  441. });
  442. </script>
  443. <style scoped lang="scss">
  444. #PageRtcLive {
  445. position: absolute;
  446. left: 0;
  447. bottom: 0;
  448. // height: 7.31rem;
  449. width: 100%;
  450. z-index: 999;
  451. // background: rgba(0, 0, 0, 0.1);
  452. padding: 0 0.44rem;
  453. box-sizing: border-box;
  454. // pointer-events: none;
  455. .member_number {
  456. // width: 1.67rem;
  457. height: 0.5rem;
  458. background: rgba(0, 0, 0, 0.3);
  459. border-radius: 0.25rem;
  460. position: fixed;
  461. top: 0.56rem;
  462. right: 0.44rem;
  463. padding: 0.07rem 0.17rem;
  464. display: flex;
  465. align-items: center;
  466. justify-content: center;
  467. .members {
  468. width: 0.42rem;
  469. height: 0.42rem;
  470. background: url(~@/assets/images/rtcLive/members@2x.png);
  471. background-size: 100% 100%;
  472. margin-right: 0.07rem;
  473. }
  474. span {
  475. font-size: 0.24rem;
  476. color: #fff;
  477. }
  478. }
  479. .videoBox {
  480. width: 1.94rem;
  481. height: 1.94rem;
  482. border-radius: 50%;
  483. overflow: hidden;
  484. position: fixed;
  485. .loadingTip {
  486. position: absolute;
  487. z-index: 101;
  488. left: 0;
  489. top: 0;
  490. animation: Rotate 1.5s infinite;
  491. @keyframes Rotate {
  492. 0% {
  493. transform: rotate(0deg);
  494. }
  495. 100% {
  496. transform: rotate(360deg);
  497. }
  498. }
  499. }
  500. > img {
  501. width: 1.94rem;
  502. height: 1.94rem;
  503. }
  504. .videoPlayer {
  505. width: 1.94rem;
  506. height: 1.94rem;
  507. position: relative;
  508. z-index: 2;
  509. }
  510. &.userVideo {
  511. top: 0.69rem;
  512. left: 0.53rem;
  513. // background-size: ;
  514. }
  515. &.myVideo {
  516. bottom: 2.72rem;
  517. right: 0.69rem;
  518. }
  519. .micBox {
  520. width: 100%;
  521. height: 0.44rem;
  522. background: rgba(0, 0, 0, 0.3);
  523. position: absolute;
  524. left: 0;
  525. bottom: 0;
  526. z-index: 100;
  527. display: flex;
  528. align-items: center;
  529. justify-content: center;
  530. .speak_mic {
  531. display: block;
  532. background-size: 13.3344rem auto;
  533. width: 0.22rem;
  534. height: 0.22rem;
  535. background-image: url(~@/assets/images/rtcLive/speed.png);
  536. // width: 0.69rem;
  537. // height: 0.69rem;
  538. animation: myAnimation 3s steps(59) infinite;
  539. }
  540. .iconscene_mic_off1 {
  541. font-size: 0.22rem;
  542. color: #f56c6c;
  543. }
  544. }
  545. }
  546. .contorlBar {
  547. width: 9.51rem;
  548. height: 1.173333rem;
  549. background: rgba(0, 0, 0, 0.5);
  550. border-radius: 0.67rem;
  551. border: 0.03rem solid rgba(255, 255, 255, 0.1);
  552. margin: 0.67rem auto 0;
  553. // position: absolute;
  554. position: fixed;
  555. z-index: 9999;
  556. left: 50%;
  557. transform: translateX(-50%);
  558. padding: 0 0.266667rem;
  559. box-sizing: border-box;
  560. bottom: 0.94rem;
  561. display: flex;
  562. align-items: center;
  563. justify-content: space-between;
  564. .saySomething {
  565. color: #fff;
  566. // font-size: 0.42rem;
  567. height: 0.8rem;
  568. position: relative;
  569. display: flex;
  570. align-items: center;
  571. justify-content: center;
  572. background: rgba(0, 0, 0, 0.5);
  573. padding: 0 0.2rem 0 0.2rem;
  574. border-radius: 0.64rem;
  575. width: 100%;
  576. display: flex;
  577. align-items: center;
  578. justify-content: space-between;
  579. .disSpeakBtn {
  580. width: 0.533333rem;
  581. height: 0.533333rem;
  582. background: url(~@/assets/images/rtcLive/pop-up_screen_on@2x.png) no-repeat;
  583. background-size: 100% 100%;
  584. cursor: pointer;
  585. &.dis {
  586. background: url(~@/assets/images/rtcLive/pop-up_screen_off@2x.png) no-repeat;
  587. background-size: 100% 100%;
  588. }
  589. }
  590. .speakIcon {
  591. width: 0.32rem;
  592. height: 0.32rem;
  593. background: url(~@/assets/images/rtcLive/Input_norma@2x.png);
  594. background-size: 100% 100%;
  595. display: block;
  596. margin-right: 0.1rem;
  597. &.dis {
  598. background: url(~@/assets/images/rtcLive/Input_disabled@2x.png);
  599. background-size: 100% 100%;
  600. }
  601. }
  602. span {
  603. font-size: 0.266667rem;
  604. }
  605. // &::after {
  606. // content: "";
  607. // position: absolute;
  608. // width: 0.04rem;
  609. // height: 0.44rem;
  610. // background: #ffffff;
  611. // border-radius: 0.03rem;
  612. // top: 50%;
  613. // transform: translateY(-50%);
  614. // right: -0.28rem;
  615. // }
  616. }
  617. .contorl_btn {
  618. display: flex;
  619. align-items: center;
  620. justify-content: space-between;
  621. margin-left: 0.2rem;
  622. > div {
  623. // width: 0.56rem;
  624. // height: 0.56rem;
  625. width: 0.65rem;
  626. height: 0.65rem;
  627. // font-size: 0.56rem;
  628. // background: #FD5151;
  629. margin-right: 0.33rem;
  630. // &.iconexit {
  631. // // width: 0.56rem;
  632. // // height: 0.56rem;
  633. // color: #fd5151;
  634. // // background: #fff;
  635. // // border-radius: 50%;
  636. // // overflow: hidden;
  637. // }
  638. &.brushesBack {
  639. background: url(~@/assets/images/rtcLive/revocation@2x.png);
  640. background-size: 100% 100%;
  641. }
  642. &.brushes {
  643. // background: url(~@/assets/images/rtcLive/brushes@2x.png);
  644. background: url(~@/assets/images/rtcLive/brushes@2x.png);
  645. background-size: 100% 100%;
  646. }
  647. &.brushesed {
  648. background: url(~@/assets/images/rtcLive/brushes_selected@2_1.png);
  649. background-size: 100% 100%;
  650. }
  651. &.invitation {
  652. background: url(~@/assets/images/rtcLive/invitation@2x.png);
  653. background-size: 100% 100%;
  654. }
  655. &.members {
  656. background: url(~@/assets/images/rtcLive/members@2x.png);
  657. background-size: 100% 100%;
  658. }
  659. &.mic_on {
  660. background: url(~@/assets/images/rtcLive/mic_on@2x.png);
  661. background-size: 100% 100%;
  662. }
  663. &.mic_no {
  664. background: url(~@/assets/images/rtcLive/mic_off_50@2x.png);
  665. background-size: 100% 100%;
  666. }
  667. &.mic_off {
  668. background: url(~@/assets/images/rtcLive/mic_off@2x.png);
  669. background-size: 100% 100%;
  670. }
  671. &.video_on {
  672. background: url(~@/assets/images/rtcLive/video_on@2x.png);
  673. background-size: 100% 100%;
  674. }
  675. &.video_no {
  676. background: url(~@/assets/images/rtcLive/video_off_50@2x.png);
  677. background-size: 100% 100%;
  678. }
  679. &.video_off {
  680. background: url(~@/assets/images/rtcLive/video_off@2x.png);
  681. background-size: 100% 100%;
  682. }
  683. &.exit {
  684. background: url(~@/assets/images/rtcLive/exit@2x.png);
  685. background-size: 100% 100%;
  686. }
  687. &:last-child {
  688. margin-right: 0;
  689. }
  690. }
  691. }
  692. }
  693. .layer {
  694. width: 100vw;
  695. height: 100vh;
  696. background: rgba(0, 0, 0, 0.1);
  697. z-index: 10000;
  698. position: fixed;
  699. bottom: 0;
  700. left: 0;
  701. // right: unset;
  702. // top: unset;
  703. .inputBox {
  704. width: 100vw;
  705. height: 1.39rem;
  706. // background: #f2f2f2;
  707. border: 1px solid rgba(255, 255, 255, 0.1);
  708. background: rgba(0, 0, 0, 0.5);
  709. position: absolute;
  710. bottom: 0;
  711. left: 0;
  712. padding: 0 0.44rem;
  713. box-sizing: border-box;
  714. display: flex;
  715. align-items: center;
  716. justify-content: center;
  717. .msgBox {
  718. width: 9.53rem;
  719. height: 0.94rem;
  720. position: absolute;
  721. > input {
  722. width: 9.53rem;
  723. height: 0.94rem;
  724. background: rgba(0, 0, 0, 0.5);
  725. border-radius: 0.56rem;
  726. font-size: 0.42rem;
  727. padding: 0 1.6rem 0 0.44rem;
  728. box-sizing: border-box;
  729. border: none;
  730. outline: none;
  731. color: #fff;
  732. resize: none;
  733. line &::placeholder {
  734. color: rgba(255, 255, 255, 0.5);
  735. }
  736. }
  737. .iconfont {
  738. // width: 0.56rem;
  739. // height: 0.56rem;
  740. // background: #ed5d18;
  741. font-size: 0.56rem;
  742. position: absolute;
  743. top: 50%;
  744. transform: translateY(-50%);
  745. right: 0.78rem;
  746. color: #fff;
  747. &.active {
  748. color: #ed5d18;
  749. }
  750. }
  751. .iconsend_icon {
  752. position: absolute;
  753. top: 50%;
  754. transform: translateY(-50%);
  755. // right: 0.78rem;
  756. right: 0.106667rem;
  757. width: 1.28rem;
  758. height: 0.693333rem;
  759. background: #ed5d18;
  760. color: #fff;
  761. font-size: 0.32rem;
  762. text-align: center;
  763. line-height: 0.693333rem;
  764. border-radius: 0.533333rem;
  765. // width: 0.67rem;
  766. // height: 0.67rem;
  767. // background-image: url(~@/assets/images/rtcLive/send_selected@2x.png);
  768. // background-size: 100% 100%;
  769. }
  770. }
  771. }
  772. .memberContent {
  773. height: auto;
  774. width: 100%;
  775. // background: #ffffff;
  776. border-radius: 0.28rem 0.28rem 0px 0px;
  777. position: absolute;
  778. left: 0;
  779. bottom: 0;
  780. &.animated {
  781. animation-duration: 0.3s;
  782. }
  783. .blurBox {
  784. background: rgba(0, 0, 0, 0.9);
  785. border-radius: 0.14rem 0.14rem 0px 0px;
  786. filter: blur(1px);
  787. position: absolute;
  788. width: 100%;
  789. height: 100%;
  790. z-index: 1;
  791. top: 0;
  792. left: 0;
  793. }
  794. .content {
  795. position: relative;
  796. width: 100%;
  797. height: 100%;
  798. z-index: 2;
  799. top: 0;
  800. left: 0;
  801. }
  802. .memberHeader {
  803. width: 100%;
  804. height: 1.28rem;
  805. text-align: center;
  806. line-height: 1.28rem;
  807. > span {
  808. font-size: 0.42rem;
  809. color: #fff;
  810. }
  811. }
  812. .memberList {
  813. width: 100%;
  814. height: 8.33rem;
  815. border-top-style: solid;
  816. border-top-color: rgba(0, 0, 0, 0.1);
  817. border-top-width: 1px;
  818. border-bottom-style: solid;
  819. border-bottom-color: rgba(0, 0, 0, 0.1);
  820. border-bottom-width: 1px;
  821. box-sizing: border-box;
  822. overflow-y: auto;
  823. &::-webkit-scrollbar {
  824. display: none;
  825. }
  826. .memberItem {
  827. width: 100%;
  828. height: 1.39rem;
  829. display: flex;
  830. align-items: center;
  831. justify-content: space-between;
  832. padding: 0.19rem 0.44rem;
  833. .userMsg {
  834. display: flex;
  835. align-items: center;
  836. justify-content: center;
  837. .avatar {
  838. width: 1rem;
  839. height: 1rem;
  840. border-radius: 50%;
  841. // overflow: hidden;
  842. margin-right: 0.28rem;
  843. > img {
  844. // width: 100%;
  845. // height: 100%;
  846. width: 1rem;
  847. height: 1rem;
  848. }
  849. }
  850. .name {
  851. font-size: 0.39rem;
  852. color: #fff;
  853. }
  854. }
  855. .button {
  856. display: flex;
  857. align-items: center;
  858. justify-content: center;
  859. > div {
  860. // width: 0.56rem;
  861. // height: 0.56rem;
  862. // background: #fc6970;
  863. font-size: 0.65rem;
  864. color: #fff;
  865. &.micBtn {
  866. width: 0.65rem;
  867. height: 0.65rem;
  868. margin-right: 0.3rem;
  869. &.mute_all_mic {
  870. background-image: url(~@/assets/images/rtcLive/mic_all_on@2x.png);
  871. background-size: 100% 100%;
  872. }
  873. &.open_all_mic {
  874. background-image: url(~@/assets/images/rtcLive/mic_all_off@2x.png);
  875. background-size: 100% 100%;
  876. }
  877. &.mute_one_mic_on {
  878. background-image: url(~@/assets/images/rtcLive/mic_on@2x.png);
  879. background-size: 100% 100%;
  880. }
  881. &.mute_one_mic_off {
  882. background-image: url(~@/assets/images/rtcLive/mic_off@2x.png);
  883. background-size: 100% 100%;
  884. }
  885. &.ban_speak_on {
  886. background-image: url(~@/assets/images/rtcLive/chat_on@2x.png);
  887. background-size: 100% 100%;
  888. }
  889. &.ban_speak_off {
  890. background-image: url(~@/assets/images/rtcLive/chat_off@2x.png);
  891. background-size: 100% 100%;
  892. }
  893. }
  894. &.outBtn {
  895. margin-right: 0.3rem;
  896. width: 0.65rem;
  897. height: 0.65rem;
  898. &.icon_remove {
  899. background-image: url(~@/assets/images/rtcLive/remove@2x.png);
  900. background-size: 100% 100%;
  901. }
  902. }
  903. }
  904. }
  905. }
  906. }
  907. .memberBottom {
  908. width: 100%;
  909. padding: 0 0.44rem;
  910. box-sizing: border-box;
  911. display: flex;
  912. align-items: center;
  913. justify-content: center;
  914. padding: 0.28rem 0;
  915. box-sizing: border-box;
  916. > div {
  917. width: 4.61rem;
  918. height: 1.11rem;
  919. color: #ed5d18;
  920. border-radius: 0.11rem;
  921. border: 0.03rem solid #ed5d18;
  922. display: flex;
  923. align-items: center;
  924. justify-content: center;
  925. font-size: 0.39rem;
  926. &.mute_all {
  927. margin-right: 0.31rem;
  928. }
  929. }
  930. }
  931. }
  932. }
  933. .chat__area-layoutBox {
  934. display: block;
  935. width: 100%;
  936. height: auto;
  937. position: fixed;
  938. bottom: 0;
  939. left: 0;
  940. right: unset;
  941. top: unset;
  942. background: #fff;
  943. // padding-bottom: 0.821256rem;
  944. .chat__area-layoutBox_bg {
  945. width: 100vw;
  946. height: 100vh;
  947. position: fixed;
  948. z-index: 1;
  949. top: 0;
  950. left: 0;
  951. }
  952. .chat__area-l-content {
  953. display: -webkit-box;
  954. display: -ms-flexbox;
  955. display: flex;
  956. -webkit-box-orient: horizontal;
  957. -webkit-box-direction: normal;
  958. -ms-flex-direction: row;
  959. flex-direction: row;
  960. -webkit-box-align: center;
  961. -ms-flex-align: center;
  962. align-items: center;
  963. -webkit-box-pack: center;
  964. -ms-flex-pack: center;
  965. justify-content: center;
  966. min-height: 0.821256rem;
  967. padding: 0.241546rem 0;
  968. width: 100%;
  969. position: relative;
  970. z-index: 100;
  971. textarea {
  972. width: calc(100% - 0.96618rem);
  973. -ms-flex-preferred-size: calc(100% - 0.96618rem);
  974. flex-basis: calc(100% - 0.96618rem);
  975. background: none;
  976. border: none;
  977. border-radius: 0;
  978. color: #000;
  979. font-size: 0.386473rem;
  980. line-height: 0.483092rem;
  981. padding: 0 0.241546rem;
  982. resize: none;
  983. -webkit-user-select: text;
  984. caret-color: #ff4500;
  985. overflow: hidden !important;
  986. }
  987. }
  988. }
  989. @keyframes myAnimation {
  990. 0% {
  991. background-position: 0px 0px;
  992. background-size: 13.3344rem auto;
  993. }
  994. 100.00% {
  995. background-position: -13.1104rem 0px;
  996. background-size: 13.3344rem auto;
  997. }
  998. }
  999. }
  1000. </style>