PageRtcLive.vue 29 KB

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