浏览代码

fix: 优化

shuisheng 2 年之前
父节点
当前提交
1333ebad50

+ 2 - 4
.vscode/settings.json

@@ -11,10 +11,8 @@
 
   // 保存时进行一些操作
   "editor.codeActionsOnSave": {
-    // "source.fixAll.eslint": false, // 运行eslint
-    "source.fixAll.eslint": true, // 运行eslint
-    "source.organizeImports": true // 整理import语句(包括import的成员),以及会删掉未使用的导入,注意:会删掉declare global {import utils from 'billd-utils';}的import utils from 'billd-utils';
-    // "source.sortImports": true // 对您的导入进行排序,然而,与organizeImports不同,它不会删除任何未使用的导入,也不会对import里面的成员进行排序
+    "source.fixAll.eslint": "explicit",
+    "source.organizeImports": "explicit"
   },
 
   // "eslint.autoFixOnSave": true, // 废弃,使用editor.codeActionsOnSave替代

+ 26 - 0
src/assets/constant.scss

@@ -8,6 +8,8 @@
   --light-primary-color: blue; //CSS 自定义属性(变量)
 }
 
+$layout-head-h: 60px;
+
 $video-ratio: calc(16 / 9);
 $w-1500: 1500px;
 $w-1475: 1475px;
@@ -32,3 +34,27 @@ $w-200: 200px;
 
 $theme-color-gold: #ffd700;
 $header-height: 60px;
+
+// 自定义滚动条:https://developer.mozilla.org/zh-CN/docs/Web/CSS/::-webkit-scrollbar
+%customScrollbar {
+  // 整个滚动条
+  &::-webkit-scrollbar {
+    width: 8px;
+    height: 0px;
+    background: rgba(0, 0, 0, 0);
+    border-radius: 0px;
+  }
+
+  // 滚动条轨道
+  &::-webkit-scrollbar-track {
+    box-shadow: rgba(0, 0, 0, 0);
+    border-radius: 0px;
+    background: rgba(0, 0, 0, 0);
+  }
+
+  // 滚动条上的滚动滑块
+  &::-webkit-scrollbar-thumb {
+    border-radius: 3px;
+    background: #e0e0e0;
+  }
+}

二进制
src/assets/img/msg-face.png


二进制
src/assets/img/msg-face.webp


二进制
src/assets/img/msg-img.png


二进制
src/assets/img/msg-img.webp


+ 60 - 43
src/components/Slider/index.vue

@@ -1,15 +1,16 @@
 <template>
-  <div class="slider-wrap">
+  <div class="slider-cpt-wrap">
     <div
       v-for="(slider, index) in sliderList"
       :key="'slider-' + index"
       class="slider"
+      :class="{ [direction]: 1 }"
       :style="{
-        '--width': widthMap[index] / 2,
-        '--speed': widthMap[index] / 2 / speed + 's',
-        width: widthMap[index] / 2 + 'px',
-        // background: 'red',
-        margin: '0 auto',
+        width: width + 'px',
+        '--container-width': widthMap[0],
+        '--speed':
+          width === 'auto' ? widthMap[0] / speed + 's' : width / speed + 's',
+        ...styles,
       }"
     >
       <div
@@ -32,7 +33,7 @@
           </div>
 
           <span class="txt">
-            <span class="msg">{{ slide.txt }}</span>
+            {{ slide.txt }}
           </span>
         </div>
       </div>
@@ -42,41 +43,41 @@
 
 <script lang="ts" setup>
 import { openToTarget } from 'billd-utils';
-import { nextTick, onMounted, ref } from 'vue';
-
-const props = defineProps({
-  list: {
-    type: Array,
-    require: true,
-    default() {
-      return [];
-    },
-  },
-  // 多少行
-  row: {
-    type: Number,
-    default: 3,
-  },
-  // 滚动速率 (px/s)
-  speed: {
-    type: Number,
-    default: 100,
-  },
-});
+import { CSSProperties, computed, nextTick, onMounted, ref } from 'vue';
+
+const props = withDefaults(
+  defineProps<{
+    list: any[];
+    width: number | 'auto';
+    speed: number;
+    customStyle?: CSSProperties;
+    direction?: 'l-r' | 'r-l';
+  }>(),
+  {
+    list: () => [],
+    // 宽度
+    width: document.documentElement.clientWidth,
+    // 滚动速率 (px/s)
+    speed: 100,
+    // @ts-ignore
+    customStyle: () => {},
+    direction: 'l-r',
+  }
+);
 
 const containerRef = ref<HTMLDivElement[]>([]);
 const sliderList = ref<any[]>([]);
 const widthMap = ref<Record<number, number>>({});
 const min = ref(0);
 
+const styles = computed(() => {
+  return {
+    ...props.customStyle,
+  } as CSSProperties;
+});
+
 onMounted(() => {
-  const res: any[] = [];
-  const count = Math.ceil(props.list.length / props.row);
-  for (let i = 0, len = props.list.length; i < len; i += count) {
-    const item = props.list.slice(i, i + count);
-    res.push([...item, ...item]);
-  }
-  sliderList.value = res;
+  sliderList.value = [[...props.list]];
   nextTick(() => {
     const res = {};
     containerRef.value.forEach((container, index) => {
@@ -101,6 +102,20 @@ onMounted(() => {
       }
     });
     widthMap.value = res;
+    if (props.width === 'auto') {
+      sliderList.value[0].push(...props.list);
+    } else if (widthMap.value[0] < props.width) {
+      const num = (Math.ceil(widthMap.value[0] / props.width) + 1) * 2;
+      for (let i = 0; i < num; i += 1) {
+        sliderList.value[0].push(...props.list);
+      }
+      // console.log(
+      //   '如果传入的宽度比一次展示的宽度要大,则一次滚动不完,则复制一份不够'
+      // );
+    } else if (widthMap.value[0] > props.width) {
+      sliderList.value[0].push(...props.list);
+      // console.log('如果传入的宽度比一次展示的宽度要小,则一次滚动即可');
+    }
   });
 });
 </script>
@@ -108,7 +123,7 @@ onMounted(() => {
 <style lang="scss" scoped>
 @keyframes left-right {
   0% {
-    transform: translateX(calc(var(--width) * -1px));
+    transform: translateX(calc(var(--container-width) * -1px));
   }
   100% {
     transform: translateX(0);
@@ -120,16 +135,19 @@ onMounted(() => {
     transform: translateX(0);
   }
   100% {
-    transform: translateX(calc(var(--width) * -1px));
+    transform: translateX(calc(var(--container-width) * -1px));
   }
 }
-.slider-wrap {
+.slider-cpt-wrap {
+  overflow: hidden;
+  padding: 2px 0;
   .slider {
-    overflow-x: scroll;
+    position: relative;
+    overflow: scroll;
 
     @extend %hideScrollbar;
 
-    &:nth-child(2n) {
+    &.l-r {
       .container {
         animation: left-right var(--speed) linear infinite;
         &:hover {
@@ -137,7 +155,7 @@ onMounted(() => {
         }
       }
     }
-    &:nth-child(2n-1) {
+    &.r-l {
       .container {
         animation: right-left var(--speed) linear infinite;
         &:hover {
@@ -152,7 +170,6 @@ onMounted(() => {
       .slide {
         display: flex;
         align-items: center;
-        flex-shrink: 0;
         box-sizing: border-box;
         padding-right: 30px;
         height: 40px;
@@ -176,7 +193,7 @@ onMounted(() => {
           }
         }
         .txt {
-          max-width: 130px;
+          // max-width: 130px;
           font-size: 14px;
 
           @extend %singleEllipsis;

+ 35 - 5
src/constant.ts

@@ -44,16 +44,13 @@ export const SRS_CB_URL_PARAMS = {
   randomId: 'randomid',
 };
 
-export const QINIU_BLOG = {
+export const QINIU_LIVE = {
   domain: 'resource.hsslive.cn',
   url: 'https://resource.hsslive.cn/',
   bucket: 'hssblog',
   prefix: {
-    'image/': 'image/',
-    'backupsDatabase/': 'backupsDatabase/',
-    'media/': 'media/',
-    'nuxt-blog-client/': 'nuxt-blog-client/',
     'billd-live/image/': 'billd-live/image/',
+    'billd-live/msg-image/': 'billd-live/msg-image/',
   },
 };
 
@@ -81,6 +78,39 @@ export const mediaTypeEnumMap = {
   [MediaTypeEnum.stopwatch]: '秒表',
 };
 
+export const sliderList2 = [
+  {
+    img: 'https://resource.hsslive.cn/billd-live/image/a4039f86e5352bcfccaddecc4b72a1df.webp',
+    txt: 'https://resource.hsslive.cn/billd-live/image',
+    link: 'https://ossrs.net',
+  },
+  // {
+  //   img: 'https://resource.hsslive.cn/billd-live/image/a4039f86e5352bcfccaddecc4b72a1df.webp',
+  //   txt: 'SRS',
+  //   link: 'https://ossrs.net',
+  // },
+  {
+    img: 'https://resource.hsslive.cn/image/c3c342f6852706e0b70d011e8753d2d6.webp',
+    txt: 'FFmpeg',
+    link: 'https://ffmpeg.org',
+  },
+  {
+    img: 'https://resource.hsslive.cn/image/0214acde5f5f5e3caf278ce446cc4414.webp',
+    txt: 'WebRTC',
+    link: 'https://github.com/webrtc',
+  },
+  // {
+  //   img: 'https://resource.hsslive.cn/billd-live/image/1277df4371045310acbc4bf2fc0811b8.webp',
+  //   txt: 'Vue3',
+  //   link: 'https://vuejs.org',
+  // },
+  // {
+  //   img: 'https://resource.hsslive.cn/image/dd907463af7fdec395e5f6d088b0308b.webp',
+  //   txt: 'Pinia',
+  //   link: 'https://pinia.vuejs.org',
+  // },
+];
+
 export const sliderList = [
   {
     img: 'https://resource.hsslive.cn/billd-live/image/a4039f86e5352bcfccaddecc4b72a1df.webp',

+ 4 - 0
src/interface.ts

@@ -211,10 +211,13 @@ export interface ILiveRoom {
   users?: IUser[];
   /** 分区信息 */
   area?: IArea;
+  /** 分区信息 */
+  areas?: IArea[];
   /** 直播信息 */
   live?: ILive;
   user_live_room?: IUserLiveRoom & { user: IUser };
   name?: string;
+  desc?: string;
   /** 1:使用cdn;2:不使用cdn */
   cdn?: number;
   /** 权重 */
@@ -226,6 +229,7 @@ export interface ILiveRoom {
   /** 拉流是否需要鉴权 */
   pull_is_should_auth?: LiveRoomPullIsShouldAuthEnum;
   cover_img?: string;
+  bg_img?: string;
   rtmp_url?: string;
   flv_url?: string;
   hls_url?: string;

+ 1 - 1
src/layout/pc/head/index.vue

@@ -439,7 +439,7 @@ function handleStartLive(key: LiveRoomTypeEnum) {
     align-items: center;
     justify-content: space-between;
     padding: 0 30px;
-    height: 60px;
+    height: $layout-head-h;
     box-shadow: inset 0 -1px #f1f2f3 !important;
     font-size: 15px;
     .badge {

+ 12 - 2
src/utils/index.ts

@@ -2,10 +2,15 @@
 import { getRangeRandom } from 'billd-utils';
 import sparkMD5 from 'spark-md5';
 
+export const getLiveRoomPageUrl = (liveRoomId: number) => {
+  return `${getHostnameUrl()}/pull/${liveRoomId}`;
+};
+
 export const getHostnameUrl = () => {
   // window.location.host,包含了域名的一个DOMString,可能在该串最后带有一个":"并跟上 URL 的端口号。
-  const { protocol, hostname } = window.location;
-  return `${protocol}//${hostname}`;
+  // window.location.hostname,包含了域名的一个DOMString
+  const { protocol, host } = window.location;
+  return `${protocol}//${host}`;
 };
 
 /**
@@ -302,6 +307,11 @@ export function videoToCanvas(data: {
   function drawCanvas() {
     canvas.width = w;
     canvas.height = h;
+    if (w > h) {
+      canvas.style.minWidth = '100%';
+    } else {
+      canvas.style.minHeight = '100%';
+    }
     ctx.drawImage(videoEl, 0, 0, w, h);
     timer = requestAnimationFrame(drawCanvas);
   }

+ 11 - 6
src/views/account/index.vue

@@ -14,18 +14,23 @@
       <span>直播间信息:</span>
       <span
         v-if="!userInfo?.live_rooms?.length"
-        class="link"
         @click="openLiveRoom"
       >
         未开通
       </span>
       <div v-else>
-        <div>直播间名字:{{ userInfo?.live_rooms?.[0].name }}</div>
         <div>
-          直播间地址:{{ getHostnameUrl() }}/pull/{{
-            userInfo?.live_rooms?.[0].id
-          }}
+          直播间地址:
+          <a
+            :href="getLiveRoomPageUrl(userInfo?.live_rooms?.[0].id!)"
+            class="link"
+            target="_blank"
+          >
+            {{ getLiveRoomPageUrl(userInfo?.live_rooms?.[0].id!) }}
+          </a>
         </div>
+        <div>直播间名称:{{ userInfo?.live_rooms?.[0].name }}</div>
+        <div>直播间简介:{{ userInfo?.live_rooms?.[0].desc }}</div>
         <div
           v-loading="keyLoading"
           class="rtmp-url"
@@ -69,7 +74,7 @@ import { SRS_CB_URL_PARAMS } from '@/constant';
 import { loginTip } from '@/hooks/use-login';
 import { IUser, LiveRoomTypeEnum } from '@/interface';
 import { routerName } from '@/router';
-import { getHostnameUrl } from '@/utils';
+import { getLiveRoomPageUrl } from '@/utils';
 
 const newRtmpUrl = ref();
 const keyLoading = ref(false);

+ 35 - 19
src/views/home/index.vue

@@ -2,29 +2,32 @@
   <div class="home-wrap">
     <div class="play-container">
       <div
-        v-if="configBg !== ''"
+        v-if="configBg && configBg !== ''"
         class="bg-img"
         :style="{ backgroundImage: `url(${configBg})` }"
       ></div>
       <video
-        v-if="configVideo !== ''"
+        v-if="configVideo && configVideo !== ''"
         class="bg-video"
         :src="configVideo"
         muted
         autoplay
+        loop
       ></video>
       <div
-        v-else
-        class="bg-img"
-      ></div>
-      <div class="slider-wrap">
+        v-for="(item, index) in interactionList"
+        :key="index"
+      >
         <Slider
-          v-if="interactionList.length"
-          :list="interactionList"
-          :row="2"
-          :speed="60"
+          v-if="item.length"
+          :list="item"
+          :width="docW"
+          :speed="120"
+          :direction="index % 2 === 0 ? 'l-r' : 'r-l'"
+          :customStyle="{ margin: '0 auto' }"
         ></Slider>
       </div>
+
       <div class="container">
         <div
           v-loading="videoLoading"
@@ -209,8 +212,9 @@ const configVideo = ref();
 const topLiveRoomList = ref<ILive[]>([]);
 const otherLiveRoomList = ref<ILive[]>([]);
 const currentLiveRoom = ref<ILive>();
-const interactionList = ref(sliderList);
+const interactionList = ref<any[]>([]);
 const remoteVideoRef = ref<HTMLDivElement>();
+const docW = document.documentElement.clientWidth;
 
 const {
   videoLoading,
@@ -222,6 +226,7 @@ const {
 } = usePull();
 
 onMounted(() => {
+  handleSlideList();
   getLiveRoomList();
   getBg();
 });
@@ -238,6 +243,17 @@ watch(
   }
 );
 
+function handleSlideList() {
+  const row = 3;
+  const res: any[] = [];
+  const count = Math.ceil(sliderList.length / row);
+  for (let i = 0, len = sliderList.length; i < len; i += count) {
+    const item = sliderList.slice(i, i + count);
+    res.push([...item]);
+  }
+  interactionList.value = res;
+}
+
 async function getBg() {
   try {
     const res = await fetchFindLiveConfigByKey('frontend_live_home_bg');
@@ -312,7 +328,7 @@ function joinRoom(data: { roomId: number }) {
   .play-container {
     position: relative;
     z-index: 1;
-    padding-bottom: 20px;
+    padding-bottom: 50px;
     .bg-img {
       position: absolute;
       top: 0;
@@ -334,10 +350,10 @@ function joinRoom(data: { roomId: number }) {
       width: 100%;
       height: 100%;
 
-      object-fit: fill;
+      // object-fit: fill;
     }
     .slider-wrap {
-      padding: 2px 0 4px 0;
+      margin: 0 auto;
     }
     .container {
       display: flex;
@@ -391,8 +407,8 @@ function joinRoom(data: { roomId: number }) {
           position: absolute;
           top: 50%;
           left: 50%;
-          min-width: 100%;
-          min-height: 100%;
+          // min-width: 100%;
+          // min-height: 100%;
           max-width: $w-1100;
           max-height: calc($w-1100 / $video-ratio);
           transform: translate(-50%, -50%);
@@ -403,8 +419,8 @@ function joinRoom(data: { roomId: number }) {
           position: absolute;
           top: 50%;
           left: 50%;
-          min-width: 100%;
-          min-height: 100%;
+          // min-width: 100%;
+          // min-height: 100%;
           max-width: $w-1100;
           max-height: calc($w-1100 / $video-ratio);
           transform: translate(-50%, -50%);
@@ -427,7 +443,7 @@ function joinRoom(data: { roomId: number }) {
           align-items: center;
           justify-content: center;
           box-sizing: border-box;
-          width: 80%;
+          // width: 80%;
           transform: translate(-50%, -50%);
           &.show {
             display: inline-flex !important;

+ 26 - 3
src/views/profile/index.vue

@@ -11,10 +11,27 @@
         :size="30"
       ></Avatar>
     </div>
-    <div class="username">用户昵称:{{ userInfo?.username }}</div>
-    <div class="live-room">
-      直播间:{{ userInfo?.live_rooms?.[0]?.name || '未开通' }}
+    <div>用户昵称:{{ userInfo?.username }}</div>
+    <br />
+    <div>直播间信息:</div>
+    <div v-if="userInfo?.live_rooms?.length">
+      <div>
+        直播间地址:
+        <a
+          :href="getLiveRoomPageUrl(userInfo?.live_rooms?.[0].id!)"
+          class="link"
+          target="_blank"
+        >
+          {{ getLiveRoomPageUrl(userInfo?.live_rooms?.[0].id!) }}
+        </a>
+      </div>
+      <div>直播间名称:{{ userInfo.live_rooms[0].name }}</div>
+      <div>直播间简介:{{ userInfo.live_rooms[0].desc }}</div>
+      <div>
+        直播间分区:{{ userInfo.live_rooms[0].areas?.[0].name || '暂无分区' }}
+      </div>
     </div>
+    <span v-else>未开通</span>
   </div>
 </template>
 
@@ -24,6 +41,7 @@ import { useRoute } from 'vue-router';
 
 import { fetchFindUser } from '@/api/user';
 import { IUser } from '@/interface';
+import { getLiveRoomPageUrl } from '@/utils';
 
 const loading = ref(false);
 const route = useRoute();
@@ -52,6 +70,11 @@ onMounted(() => {
 .profile-wrap {
   position: relative;
   padding: 10px;
+  .link {
+    color: $theme-color-gold;
+    text-decoration: none;
+    cursor: pointer;
+  }
   .avatar {
     display: flex;
     align-items: center;

+ 150 - 52
src/views/pull/index.vue

@@ -1,5 +1,24 @@
 <template>
   <div class="pull-wrap">
+    <div class="bg-img-wrap">
+      <div
+        v-if="configBg !== ''"
+        class="bg-img"
+        :style="{ backgroundImage: `url(${configBg})` }"
+      ></div>
+      <video
+        v-if="configVideo !== ''"
+        class="bg-video"
+        :src="configVideo"
+        muted
+        autoplay
+        loop
+      ></video>
+      <div
+        v-else
+        class="bg-img"
+      ></div>
+    </div>
     <div class="left">
       <div
         ref="topRef"
@@ -11,14 +30,30 @@
             :style="{
               backgroundImage: `url(${anchorInfo?.avatar})`,
             }"
+            @click="
+              router.push({
+                name: routerName.profile,
+                params: { userId: anchorInfo?.id },
+              })
+            "
           ></div>
           <div class="detail">
             <div class="top">{{ anchorInfo?.username }}</div>
             <div class="bottom">
-              <span>{{ appStore.liveRoomInfo?.name }}</span>
+              <span>{{ appStore.liveRoomInfo?.desc }}</span>
               <span v-if="NODE_ENV === 'development'">
                 socketId:{{ mySocketId }}
               </span>
+              <span
+                class="area"
+                @click="
+                  router.push({
+                    name: routerName.area,
+                    query: { id: appStore.liveRoomInfo?.areas?.[0].id },
+                  })
+                "
+                >{{ appStore.liveRoomInfo?.areas?.[0].name }}</span
+              >
             </div>
           </div>
         </div>
@@ -149,9 +184,9 @@
                   item.userInfo.roles?.map((v) => v.role_name).join()
                 }}]
               </span>
-              <span v-else>{{ item.socket_id }}</span>
-              <span>:</span>
+              <span v-else>{{ item.socket_id }}[游客]</span>
             </span>
+            <span>:</span>
             <span
               class="msg"
               v-if="!item.msgIsFile"
@@ -165,6 +200,7 @@
               <img
                 :src="item.msg"
                 alt=""
+                @load="handleScrollTop"
               />
             </div>
           </template>
@@ -201,6 +237,7 @@
               ref="uploadRef"
               type="file"
               class="input-upload"
+              accept=".webp,.png,.jpg,.jpeg,.gif"
               @change="uploadChange"
             />
           </div>
@@ -229,11 +266,12 @@
 import { onMounted, onUnmounted, ref, watch } from 'vue';
 
 import { fetchGoodsList } from '@/api/goods';
-import { QINIU_BLOG } from '@/constant';
+import { QINIU_LIVE } from '@/constant';
 import { loginTip } from '@/hooks/use-login';
 import { usePull } from '@/hooks/use-pull';
 import { useUpload } from '@/hooks/use-upload';
 import { DanmuMsgTypeEnum, GoodsTypeEnum, IGoods } from '@/interface';
+import router, { routerName } from '@/router';
 import { useAppStore } from '@/store/app';
 import { useUserStore } from '@/store/user';
 import { NODE_ENV } from 'script/constant';
@@ -242,6 +280,8 @@ import RechargeCpt from './recharge/index.vue';
 
 const userStore = useUserStore();
 const appStore = useAppStore();
+const configBg = ref();
+const configVideo = ref();
 const giftGoodsList = ref<IGoods[]>([]);
 const height = ref(0);
 const giftLoading = ref(false);
@@ -285,6 +325,7 @@ onMounted(() => {
         topRef.value.getBoundingClientRect().height);
     height.value = res;
   }
+  getBg();
   initPull();
 });
 
@@ -306,6 +347,40 @@ watch(
   }
 );
 
+watch(
+  () => damuList.value.length,
+  () => {
+    setTimeout(() => {
+      handleScrollTop();
+    }, 0);
+  }
+);
+watch(
+  () => appStore.liveRoomInfo,
+  () => {
+    getBg();
+  },
+  {
+    deep: true,
+  }
+);
+
+function getBg() {
+  try {
+    const reg = /.+\.mp4$/g;
+    const url = appStore.liveRoomInfo?.bg_img;
+    if (url) {
+      if (reg.exec(url)) {
+        configVideo.value = url;
+      } else {
+        configBg.value = url;
+      }
+    }
+  } catch (error) {
+    console.log(error);
+  }
+}
+
 function handleWait() {
   window.$message.warning('敬请期待!');
 }
@@ -321,7 +396,7 @@ async function uploadChange() {
       msgLoading.value = true;
       msgIsFile.value = true;
       const res = await useUpload({
-        prefix: QINIU_BLOG.prefix['image/'],
+        prefix: QINIU_LIVE.prefix['billd-live/msg-image/'],
         file: fileList[0],
       });
       if (res?.resultUrl) {
@@ -370,16 +445,11 @@ function handleRecharge() {
   showRecharge.value = true;
 }
 
-watch(
-  () => damuList.value.length,
-  () => {
-    setTimeout(() => {
-      if (danmuListRef.value) {
-        danmuListRef.value.scrollTop = danmuListRef.value.scrollHeight;
-      }
-    }, 0);
+function handleScrollTop() {
+  if (danmuListRef.value) {
+    danmuListRef.value.scrollTop = danmuListRef.value.scrollHeight + 10000;
   }
-);
+}
 </script>
 
 <style lang="scss" scoped>
@@ -388,6 +458,40 @@ watch(
   justify-content: space-around;
   margin: 15px auto 0;
   width: $w-1275;
+  .bg-img-wrap {
+    position: absolute;
+    top: $layout-head-h;
+    left: 50%;
+    max-width: 1920px;
+    max-height: 890px;
+    width: 100%;
+    height: 100%;
+    background-position: center center;
+    background-size: cover;
+    background-repeat: no-repeat;
+    transform: translateX(-50%);
+    .bg-img {
+      position: absolute;
+      top: 0;
+      right: 0;
+      left: 0;
+      z-index: -1;
+      width: 100%;
+      height: 100%;
+      background-position: center;
+      background-size: cover;
+      background-repeat: no-repeat;
+    }
+    .bg-video {
+      position: absolute;
+      top: 0;
+      right: 0;
+      left: 0;
+      z-index: -1;
+      width: 100%;
+      height: 100%;
+    }
+  }
   .left {
     position: relative;
     display: inline-block;
@@ -397,7 +501,7 @@ watch(
     height: 100%;
     border-radius: 6px;
     background-color: papayawhip;
-    color: #9499a0;
+    color: #61666d;
     vertical-align: top;
     .head {
       display: flex;
@@ -414,6 +518,7 @@ watch(
           width: 50px;
           height: 50px;
           border-radius: 50%;
+          cursor: pointer;
 
           @extend %containBg;
         }
@@ -424,6 +529,11 @@ watch(
           }
           .bottom {
             font-size: 14px;
+            .area {
+              margin-left: 10px;
+              color: #9499a0;
+              cursor: pointer;
+            }
           }
         }
       }
@@ -477,8 +587,8 @@ watch(
             left: 50%;
             display: block;
             margin: 0 auto;
-            min-width: 100%;
-            min-height: 100%;
+            // min-width: 100%;
+            // min-height: 100%;
             max-width: $w-1000;
             max-height: 562px;
             transform: translate(-50%, -50%);
@@ -489,8 +599,8 @@ watch(
             left: 50%;
             display: block;
             margin: 0 auto;
-            min-width: 100%;
-            min-height: 100%;
+            // min-width: 100%;
+            // min-height: 100%;
             max-width: $w-1000;
             max-height: 562px;
             transform: translate(-50%, -50%);
@@ -529,24 +639,6 @@ watch(
           }
         }
       }
-      .sidebar {
-        overflow: scroll;
-        width: 120px;
-        height: 100%;
-        background-color: rgba($color: #000000, $alpha: 0.3);
-
-        @extend %hideScrollbar;
-        .join {
-          color: white;
-          cursor: pointer;
-        }
-        video {
-          max-width: 100%;
-        }
-        .name {
-          word-wrap: break-word;
-        }
-      }
     }
 
     .gift-list {
@@ -635,7 +727,7 @@ watch(
       height: 100px;
       background-color: papayawhip;
 
-      @extend %hideScrollbar;
+      @extend %customScrollbar;
       .item {
         display: flex;
         align-items: center;
@@ -645,6 +737,7 @@ watch(
         .info {
           display: flex;
           align-items: center;
+          cursor: pointer;
           .avatar {
             margin-right: 5px;
             width: 25px;
@@ -661,23 +754,30 @@ watch(
     }
     .danmu-list {
       overflow-y: scroll;
-      padding: 0 15px;
+      box-sizing: border-box;
+      padding-top: 4px;
       height: 480px;
+      background-color: #f6f7f8;
       text-align: initial;
 
-      @extend %hideScrollbar;
+      @extend %customScrollbar;
       .item {
-        margin-bottom: 10px;
-        font-size: 13px;
-        word-wrap: break-word;
+        box-sizing: border-box;
+        margin-bottom: 4px;
+        padding: 2px 10px;
         white-space: normal;
+        word-wrap: break-word;
+        font-size: 13px;
+
         .name {
           color: #9499a0;
+          cursor: pointer;
           &.system {
             color: red;
           }
         }
         .msg {
+          margin-top: 4px;
           color: #61666d;
           &.img {
             img {
@@ -688,18 +788,16 @@ watch(
       }
     }
     .send-msg {
-      position: absolute;
-      bottom: 15px;
       box-sizing: border-box;
-      padding: 0 10px;
+      padding: 4px 10px;
       width: 100%;
       .control {
         display: flex;
-        margin-bottom: 4px;
+        margin: 4px 0;
         .ico {
-          margin-right: 4px;
-          width: 20px;
-          height: 20px;
+          margin-right: 6px;
+          width: 24px;
+          height: 24px;
           cursor: pointer;
           .input-upload {
             width: 0;
@@ -707,10 +805,10 @@ watch(
             opacity: 0;
           }
           &.face {
-            @include setBackground('@/assets/img/msg-face.png');
+            @include setBackground('@/assets/img/msg-face.webp');
           }
           &.img {
-            @include setBackground('@/assets/img/msg-img.png');
+            @include setBackground('@/assets/img/msg-img.webp');
           }
         }
       }