shuisheng пре 2 година
родитељ
комит
535990260d

+ 1 - 0
src/assets/constant.scss

@@ -31,3 +31,4 @@ $w-250: 250px;
 $w-200: 200px;
 
 $theme-color-gold: #ffd700;
+$header-height: 60px;

+ 13 - 22
src/hooks/use-pull.ts

@@ -3,20 +3,24 @@ import { useRoute } from 'vue-router';
 
 import { useFlvPlay, useHlsPlay } from '@/hooks/use-play';
 import { useSrsWs } from '@/hooks/use-srs-ws';
-import { DanmuMsgTypeEnum, IDanmu, IMessage, LiveTypeEnum } from '@/interface';
+import {
+  DanmuMsgTypeEnum,
+  IDanmu,
+  IMessage,
+  LiveRoomTypeEnum,
+} from '@/interface';
 import { WsMsgTypeEnum } from '@/network/webSocket';
 import { useAppStore } from '@/store/app';
 import { useNetworkStore } from '@/store/network';
 import { useUserStore } from '@/store/user';
 import { createVideo, videoToCanvas } from '@/utils';
 
-export function usePull({ liveType }: { liveType: LiveTypeEnum }) {
+export function usePull() {
   const route = useRoute();
   const userStore = useUserStore();
   const networkStore = useNetworkStore();
   const appStore = useAppStore();
   const roomId = ref(route.params.roomId as string);
-  const roomLiveType = ref<LiveTypeEnum>(liveType);
   const localStream = ref<MediaStream>();
   const danmuStr = ref('');
   const autoplayVal = ref(false);
@@ -100,30 +104,18 @@ export function usePull({ liveType }: { liveType: LiveTypeEnum }) {
 
   async function handlePlay() {
     console.warn('handlePlay');
-    if (roomLiveType.value === LiveTypeEnum.srsFlvPull) {
-      if (!autoplayVal.value) return;
-      await handleFlvPlay();
-    } else if (roomLiveType.value === LiveTypeEnum.srsHlsPull) {
+    if (liveRoomInfo.value?.type !== LiveRoomTypeEnum.user_wertc) {
       if (!autoplayVal.value) return;
+      // await handleFlvPlay();
       await handleHlsPlay();
     }
   }
 
-  watch(
-    () => autoplayVal.value,
-    (val) => {
-      console.log('autoplayVal变了', val);
-      if (val && roomLiveType.value === LiveTypeEnum.webrtcPull) {
-        handlePlay();
-      }
-    }
-  );
-
   watch(
     () => roomLiving.value,
     (val) => {
       if (val) {
-        if (roomLiveType.value !== LiveTypeEnum.webrtcPull) {
+        if (liveRoomInfo.value?.type !== LiveRoomTypeEnum.user_wertc) {
           flvurl.value = liveRoomInfo.value?.flv_url!;
           hlsurl.value = liveRoomInfo.value?.hls_url!;
           handlePlay();
@@ -148,7 +140,7 @@ export function usePull({ liveType }: { liveType: LiveTypeEnum }) {
   watch(
     () => networkStore.rtcMap,
     (newVal) => {
-      if (roomLiveType.value === LiveTypeEnum.webrtcPull) {
+      if (liveRoomInfo.value?.type === LiveRoomTypeEnum.user_wertc) {
         newVal.forEach((item) => {
           videoLoading.value = false;
           const { canvas } = videoToCanvas({
@@ -172,7 +164,7 @@ export function usePull({ liveType }: { liveType: LiveTypeEnum }) {
         console.log('localStream变了');
         console.log('音频轨:', val?.getAudioTracks());
         console.log('视频轨:', val?.getVideoTracks());
-        if (roomLiveType.value === LiveTypeEnum.webrtcPull) {
+        if (liveRoomInfo.value?.type === LiveRoomTypeEnum.user_wertc) {
           videoElArr.value.forEach((dom) => {
             dom.remove();
           });
@@ -193,7 +185,7 @@ export function usePull({ liveType }: { liveType: LiveTypeEnum }) {
             videoElArr.value.push(video);
           });
           videoLoading.value = false;
-        } else if (roomLiveType.value === LiveTypeEnum.srsWebrtcPull) {
+        } else {
           videoElArr.value.forEach((dom) => {
             dom.remove();
           });
@@ -318,7 +310,6 @@ export function usePull({ liveType }: { liveType: LiveTypeEnum }) {
     handleHlsPlay,
     handleFlvPlay,
     remoteVideo,
-    roomLiveType,
     roomLiving,
     autoplayVal,
     videoLoading,

+ 1 - 3
src/interface.ts

@@ -178,13 +178,11 @@ export interface IUserLiveRoom {
 }
 
 export enum LiveTypeEnum {
-  webrtcPull = 'webrtcPull',
-  srsWebrtcPull = 'srsWebrtcPull',
   srsFlvPull = 'srsFlvPull',
   srsHlsPull = 'srsHlsPull',
+
   srsPush = 'srsPush',
   webrtcPush = 'webrtcPush',
-  canvasPush = 'canvasPush',
 }
 
 /** 直播间类型 */

+ 421 - 411
src/layout/pc/head/index.vue

@@ -1,250 +1,265 @@
 <template>
-  <div class="head-wrap">
-    <div class="left">
-      <div
-        class="logo-wrap"
-        @click="router.push('/')"
-      >
-        <div class="logo"></div>
-      </div>
+  <header class="head-wrap">
+    <div class="head">
+      <div class="left">
+        <div
+          class="logo-wrap"
+          @click="router.push('/')"
+        >
+          <div class="logo"></div>
+        </div>
 
-      <div class="nav">
-        <a
+        <div class="nav">
+          <a
+            class="item"
+            :class="{
+              active: router.currentRoute.value.path === '/',
+            }"
+            href="/"
+            @click.prevent="router.push('/')"
+          >
+            首页
+          </a>
+          <a
+            class="item"
+            :class="{
+              active: router.currentRoute.value.name === routerName.area,
+            }"
+            @click.prevent="router.push({ name: routerName.area })"
+          >
+            分区
+          </a>
+          <a
+            class="item"
+            :class="{
+              active: router.currentRoute.value.name === routerName.shop,
+            }"
+            @click.prevent="router.push({ name: routerName.shop })"
+          >
+            商店
+          </a>
+          <a
+            class="item"
+            href="https://live-admin.hsslive.cn"
+            @click.prevent="openToTarget('https://live-admin.hsslive.cn')"
+          >
+            后台
+          </a>
+          <!-- <a
           class="item"
           :class="{
-            active: router.currentRoute.value.path === '/',
+            active: router.currentRoute.value.name === routerName.ad,
           }"
-          href="/"
-          @click.prevent="router.push('/')"
+          href="/ad"
+          @click.prevent="router.push({ name: routerName.ad })"
         >
-          首页
-        </a>
+          广告
+        </a> -->
+        </div>
+      </div>
+      <div class="right">
+        <Dropdown
+          v-model="dropdownDoc"
+          class="doc"
+        >
+          <template #btn>
+            <div class="btn">
+              文档<VPIconChevronDown class="icon"></VPIconChevronDown>
+            </div>
+          </template>
+          <template #list>
+            <div class="list">
+              <a
+                class="item"
+                @click="quickStart"
+              >
+                <div class="txt">快速上手</div>
+              </a>
+              <a
+                class="item"
+                @click="openToTarget(APIFOX_URL)"
+              >
+                <div class="txt">接口文档</div>
+                <VPIconExternalLink class="icon"></VPIconExternalLink>
+              </a>
+            </div>
+          </template>
+        </Dropdown>
+
+        <Dropdown
+          v-model="dropdownSys"
+          class="ecosystem"
+        >
+          <template #btn>
+            <div class="btn">
+              生态系统<VPIconChevronDown class="icon"></VPIconChevronDown>
+            </div>
+          </template>
+          <template #list>
+            <div class="list">
+              <div class="title">资源</div>
+              <a
+                v-for="(item, index) in resource"
+                :key="index"
+                :href="item.url"
+                class="item"
+                @click.prevent="handleJump(item)"
+              >
+                <div class="txt">{{ item.label }}</div>
+                <VPIconExternalLink
+                  v-if="item.url"
+                  class="icon"
+                ></VPIconExternalLink>
+              </a>
+              <div class="hr"></div>
+              <div class="title">官方库</div>
+              <a
+                v-for="(item, index) in plugins"
+                :key="index"
+                class="item"
+                :href="item.url"
+                @click.prevent="handleJump(item)"
+              >
+                <div class="txt">{{ item.label }}</div>
+                <VPIconExternalLink
+                  v-if="item.url"
+                  class="icon"
+                ></VPIconExternalLink>
+              </a>
+            </div>
+          </template>
+        </Dropdown>
+
+        <Dropdown
+          v-model="dropdownAbout"
+          class="about"
+        >
+          <template #btn>
+            <div class="btn">
+              关于<VPIconChevronDown class="icon"></VPIconChevronDown>
+            </div>
+          </template>
+          <template #list>
+            <div class="list">
+              <a
+                v-for="(item, index) in about"
+                :key="index"
+                class="item"
+                :href="item.url"
+                @click.prevent="
+                  item.routerName
+                    ? router.push({ name: item.routerName })
+                    : openToTarget(item.url)
+                "
+              >
+                <div class="txt">{{ item.label }}</div>
+                <VPIconExternalLink
+                  v-if="item.url"
+                  class="icon"
+                ></VPIconExternalLink>
+              </a>
+            </div>
+          </template>
+        </Dropdown>
+
         <a
-          v-for="(item, index) in areaList"
-          :key="index"
-          class="item"
+          class="sponsors"
           :class="{
-            active: router.currentRoute.value.name === routerName.ad,
+            active: router.currentRoute.value.name === routerName.sponsors,
           }"
-          href="/ad"
-          @click.prevent="changeArea(item)"
+          href="/sponsors"
+          @click.prevent="router.push({ name: routerName.sponsors })"
         >
-          {{ item.name }}
+          赞助
         </a>
-        <!-- <a
-          class="item"
+        <a
+          class="privatizationDeployment"
           :class="{
-            active: router.currentRoute.value.name === routerName.ad,
+            active:
+              router.currentRoute.value.name ===
+              routerName.privatizationDeployment,
           }"
-          href="/ad"
-          @click.prevent="router.push({ name: routerName.ad })"
+          href="/privatizationDeployment"
+          @click.prevent="
+            router.push({ name: routerName.privatizationDeployment })
+          "
         >
-          广告
-        </a> -->
-      </div>
-    </div>
-    <div class="right">
-      <Dropdown
-        v-model="dropdownDoc"
-        class="doc"
-      >
-        <template #btn>
-          <div class="btn">
-            文档<VPIconChevronDown class="icon"></VPIconChevronDown>
-          </div>
-        </template>
-        <template #list>
-          <div class="list">
-            <a
-              class="item"
-              @click="quickStart"
-            >
-              <div class="txt">快速上手</div>
-            </a>
-            <a
-              class="item"
-              @click="openToTarget(APIFOX_URL)"
-            >
-              <div class="txt">接口文档</div>
-              <VPIconExternalLink class="icon"></VPIconExternalLink>
-            </a>
-          </div>
-        </template>
-      </Dropdown>
-
-      <Dropdown
-        v-model="dropdownSys"
-        class="ecosystem"
-      >
-        <template #btn>
-          <div class="btn">
-            生态系统<VPIconChevronDown class="icon"></VPIconChevronDown>
-          </div>
-        </template>
-        <template #list>
-          <div class="list">
-            <div class="title">资源</div>
-            <a
-              v-for="(item, index) in resource"
-              :key="index"
-              :href="item.url"
-              class="item"
-              @click.prevent="handleJump(item)"
-            >
-              <div class="txt">{{ item.label }}</div>
-              <VPIconExternalLink
-                v-if="item.url"
-                class="icon"
-              ></VPIconExternalLink>
-            </a>
-            <div class="hr"></div>
-            <div class="title">官方库</div>
-            <a
-              v-for="(item, index) in plugins"
-              :key="index"
-              class="item"
-              :href="item.url"
-              @click.prevent="handleJump(item)"
-            >
-              <div class="txt">{{ item.label }}</div>
-              <VPIconExternalLink
-                v-if="item.url"
-                class="icon"
-              ></VPIconExternalLink>
-            </a>
+          私有化部署
+          <div class="badge">
+            <div class="txt">new</div>
           </div>
-        </template>
-      </Dropdown>
-
-      <Dropdown
-        v-model="dropdownAbout"
-        class="about"
-      >
-        <template #btn>
-          <div class="btn">
-            关于<VPIconChevronDown class="icon"></VPIconChevronDown>
-          </div>
-        </template>
-        <template #list>
-          <div class="list">
-            <a
-              v-for="(item, index) in about"
-              :key="index"
-              class="item"
-              :href="item.url"
-              @click.prevent="
-                item.routerName
-                  ? router.push({ name: item.routerName })
-                  : openToTarget(item.url)
-              "
-            >
-              <div class="txt">{{ item.label }}</div>
-              <VPIconExternalLink
-                v-if="item.url"
-                class="icon"
-              ></VPIconExternalLink>
-            </a>
-          </div>
-        </template>
-      </Dropdown>
-
-      <a
-        class="sponsors"
-        :class="{
-          active: router.currentRoute.value.name === routerName.sponsors,
-        }"
-        href="/sponsors"
-        @click.prevent="router.push({ name: routerName.sponsors })"
-      >
-        赞助
-      </a>
-      <a
-        class="privatizationDeployment"
-        :class="{
-          active:
-            router.currentRoute.value.name ===
-            routerName.privatizationDeployment,
-        }"
-        href="/privatizationDeployment"
-        @click.prevent="
-          router.push({ name: routerName.privatizationDeployment })
-        "
-      >
-        私有化部署
-        <div class="badge">
-          <div class="txt">new</div>
+        </a>
+
+        <a
+          class="github"
+          target="_blank"
+          href="https://github.com/galaxy-s10/billd-live"
+        >
+          <img
+            :src="githubStar"
+            alt=""
+          />
+        </a>
+
+        <Dropdown class="start-live">
+          <template #btn>
+            <div class="btn">我要开播</div>
+          </template>
+          <template #list>
+            <div class="list">
+              <a
+                class="item"
+                @click.prevent="handleStartLive(LiveRoomTypeEnum.user_srs)"
+              >
+                <div class="txt">srs开播</div>
+              </a>
+              <a
+                class="item"
+                @click.prevent="handleStartLive(LiveRoomTypeEnum.user_wertc)"
+              >
+                <div class="txt">webrtc开播</div>
+              </a>
+            </div>
+          </template>
+        </Dropdown>
+
+        <div
+          v-if="!userStore.userInfo"
+          class="qqlogin"
+          @click="useQQLogin()"
+        >
+          <div class="btn">登录</div>
         </div>
-      </a>
-
-      <a
-        class="github"
-        target="_blank"
-        href="https://github.com/galaxy-s10/billd-live"
-      >
-        <img
-          :src="githubStar"
-          alt=""
-        />
-      </a>
-
-      <Dropdown class="start-live">
-        <template #btn>
-          <div class="btn">我要开播</div>
-        </template>
-        <template #list>
-          <div class="list">
-            <a
-              class="item"
-              @click.prevent="handleStartLive(LiveTypeEnum.srsPush)"
-            >
-              <div class="txt">srs开播</div>
-            </a>
-            <a
-              class="item"
-              @click.prevent="handleStartLive(LiveTypeEnum.webrtcPush)"
-            >
-              <div class="txt">webrtc开播</div>
-            </a>
-          </div>
-        </template>
-      </Dropdown>
-
-      <div
-        v-if="!userStore.userInfo"
-        class="qqlogin"
-        @click="useQQLogin()"
-      >
-        <div class="btn">登录</div>
+        <Dropdown
+          v-else
+          class="qqlogin"
+        >
+          <template #btn>
+            <div
+              class="btn"
+              :style="{ backgroundImage: `url(${userStore.userInfo.avatar})` }"
+            ></div>
+          </template>
+          <template #list>
+            <div class="list">
+              <a
+                class="item"
+                @click.prevent="router.push({ name: routerName.account })"
+              >
+                <div class="txt">个人信息</div>
+              </a>
+              <a
+                class="item"
+                @click.prevent="handleLogout"
+              >
+                <div class="txt">退出</div>
+              </a>
+            </div>
+          </template>
+        </Dropdown>
       </div>
-      <Dropdown
-        v-else
-        class="qqlogin"
-      >
-        <template #btn>
-          <div
-            class="btn"
-            :style="{ backgroundImage: `url(${userStore.userInfo.avatar})` }"
-          ></div>
-        </template>
-        <template #list>
-          <div class="list">
-            <a
-              class="item"
-              @click.prevent="router.push({ name: routerName.account })"
-            >
-              <div class="txt">个人信息</div>
-            </a>
-            <a
-              class="item"
-              @click.prevent="handleLogout"
-            >
-              <div class="txt">退出</div>
-            </a>
-          </div>
-        </template>
-      </Dropdown>
     </div>
-  </div>
+  </header>
 </template>
 
 <script lang="ts" setup>
@@ -258,7 +273,7 @@ import VPIconChevronDown from '@/components/icons/VPIconChevronDown.vue';
 import VPIconExternalLink from '@/components/icons/VPIconExternalLink.vue';
 import { APIFOX_URL, bilibiliCollectiondetail } from '@/constant';
 import { loginTip, useQQLogin } from '@/hooks/use-login';
-import { IArea, LiveTypeEnum } from '@/interface';
+import { IArea, LiveRoomTypeEnum } from '@/interface';
 import { routerName } from '@/router';
 import { useUserStore } from '@/store/user';
 
@@ -361,23 +376,14 @@ function quickStart() {
   window.$message.info('敬请期待!');
 }
 
-function handleStartLive(key: LiveTypeEnum) {
+function handleStartLive(key: LiveRoomTypeEnum) {
   if (!loginTip()) {
     return;
   }
-  // if (key === LiveTypeEnum.canvasPush) {
   const url = router.resolve({
     name: routerName.push,
     query: { liveType: key },
   });
-  // } else {
-  //   window.$message.info('请体验canvas混流开播~');
-  //   return;
-  //   url = router.resolve({
-  //     name: routerName.push,
-  //     query: { liveType: key },
-  //   });
-  // }
   openToTarget(url.href);
 }
 </script>
@@ -388,227 +394,231 @@ function handleStartLive(key: LiveTypeEnum) {
   top: 0;
   left: 0;
   z-index: 50;
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
   box-sizing: border-box;
-  padding: 0 30px;
   min-width: $w-1100;
-  height: 64px;
-  background-color: #fff;
-  box-shadow: inset 0 -1px #f1f2f3 !important;
-  font-size: 15px;
   width: 100%;
-  .hr {
-    width: 100%;
-    height: 1px;
-    background-color: #e7e7e7;
-  }
-  .left {
+  background-color: #fff;
+
+  .head {
     display: flex;
     align-items: center;
-    height: 100%;
-    .logo-wrap {
-      display: flex;
-      align-items: center;
-      margin-right: 20px;
-      cursor: pointer;
-
-      .logo {
-        width: 90px;
-        height: 56px;
-
-        @include setBackground('@/assets/img/logo-txt.png');
-      }
+    justify-content: space-between;
+    padding: 0 30px;
+    height: 60px;
+    box-shadow: inset 0 -1px #f1f2f3 !important;
+    font-size: 15px;
+    .hr {
+      width: 100%;
+      height: 1px;
+      background-color: #e7e7e7;
     }
-
-    .nav {
+    .left {
       display: flex;
       align-items: center;
       height: 100%;
-      .item {
-        position: relative;
+      .logo-wrap {
         display: flex;
         align-items: center;
         margin-right: 20px;
-        height: 100%;
-        color: black;
-        text-decoration: none;
         cursor: pointer;
 
-        &.active {
-          &::after {
-            position: absolute;
-            top: calc(50% - 8px);
-            right: -5px;
-            width: 5px;
-            height: 5px;
-            border-radius: 50%;
-            background-color: $theme-color-gold;
-            content: '';
-            transition: all 0.1s ease;
-            transform: translateY(-100%);
-          }
-        }
-        &:hover {
-          color: $theme-color-gold;
+        .logo {
+          width: 90px;
+          height: 56px;
+
+          @include setBackground('@/assets/img/logo-txt.png');
         }
       }
-    }
-  }
 
-  .right {
-    display: flex;
-    align-items: center;
-    height: 100%;
-
-    .doc,
-    .about,
-    .ecosystem {
-      margin-right: 20px;
-      &:hover {
-        color: $theme-color-gold;
-      }
-      .btn {
+      .nav {
         display: flex;
         align-items: center;
-        .icon {
-          margin-left: 5px;
-          width: 13px;
-
-          fill: currentColor;
-        }
-        &:hover {
-          color: $theme-color-gold;
-        }
-      }
-
-      .list {
-        width: 120px;
+        height: 100%;
         .item {
+          position: relative;
           display: flex;
           align-items: center;
-          margin-bottom: 5px;
-          padding: 0 15px;
+          margin-right: 20px;
+          height: 100%;
           color: black;
           text-decoration: none;
           cursor: pointer;
-          &:hover {
-            color: $theme-color-gold;
-          }
-          .icon {
-            margin-left: 5px;
-            width: 14px;
-            color: #3c3c4354;
 
-            fill: currentColor;
+          &.active {
+            &::after {
+              position: absolute;
+              top: calc(50% - 8px);
+              right: -5px;
+              width: 5px;
+              height: 5px;
+              border-radius: 50%;
+              background-color: $theme-color-gold;
+              content: '';
+              transition: all 0.1s ease;
+              transform: translateY(-100%);
+            }
           }
-        }
-      }
-    }
-    .ecosystem {
-      .list {
-        width: 225px;
-        .title {
-          margin: 10px 0 5px;
-          padding: 0 15px;
-          color: rgba(60, 60, 60, 0.33);
-
-          &:first-child {
-            margin-top: 0;
+          &:hover {
+            color: $theme-color-gold;
           }
         }
       }
     }
 
-    .github,
-    .sponsors,
-    .privatizationDeployment {
+    .right {
       display: flex;
       align-items: center;
-      margin-right: 20px;
-      color: black;
-      text-decoration: none;
-      &:hover {
-        color: $theme-color-gold;
-      }
-      .txt {
-        margin-right: 5px;
-      }
-    }
-    .privatizationDeployment {
-      position: relative;
-      .badge {
-        position: absolute;
-        right: -10px;
-        top: -10px;
-        background-color: red;
-        color: white;
-        line-height: 1;
-        border-radius: 4px;
-        padding: 0 2px;
-        .txt {
-          margin-right: 0;
-          @include minFont(10);
-          transform-origin: top !important;
-        }
-      }
-    }
-
-    .start-live {
-      margin-right: 20px;
+      height: 100%;
 
-      .btn {
-        padding: 5px 15px;
-        border-radius: 6px;
-        background-color: $theme-color-gold;
-        color: white;
-        font-size: 13px;
-        cursor: pointer;
-      }
-      .list {
-        width: 150px;
-        .item {
+      .doc,
+      .about,
+      .ecosystem {
+        margin-right: 20px;
+        &:hover {
+          color: $theme-color-gold;
+        }
+        .btn {
           display: flex;
           align-items: center;
-          margin-bottom: 5px;
-          padding: 0 15px;
-          cursor: pointer;
+          .icon {
+            margin-left: 5px;
+            width: 13px;
 
+            fill: currentColor;
+          }
           &:hover {
             color: $theme-color-gold;
           }
-          &.disabled {
-            color: initial !important;
-            opacity: 0.5;
-            cursor: not-allowed;
+        }
+
+        .list {
+          width: 120px;
+          .item {
+            display: flex;
+            align-items: center;
+            margin-bottom: 5px;
+            padding: 0 15px;
+            color: black;
+            text-decoration: none;
+            cursor: pointer;
+            &:hover {
+              color: $theme-color-gold;
+            }
+            .icon {
+              margin-left: 5px;
+              width: 14px;
+              color: #3c3c4354;
+
+              fill: currentColor;
+            }
           }
         }
       }
-    }
-    .qqlogin {
-      .btn {
+      .ecosystem {
+        .list {
+          width: 225px;
+          .title {
+            margin: 10px 0 5px;
+            padding: 0 15px;
+            color: rgba(60, 60, 60, 0.33);
+
+            &:first-child {
+              margin-top: 0;
+            }
+          }
+        }
+      }
+
+      .github,
+      .sponsors,
+      .privatizationDeployment {
         display: flex;
         align-items: center;
-        justify-content: center;
-        box-sizing: border-box;
-        width: 35px;
-        height: 35px;
-        border-radius: 50%;
-        background-color: papayawhip;
-        font-size: 13px;
-        cursor: pointer;
+        margin-right: 20px;
+        color: black;
+        text-decoration: none;
+        &:hover {
+          color: $theme-color-gold;
+        }
+        .txt {
+          margin-right: 5px;
+        }
+      }
+      .privatizationDeployment {
+        position: relative;
+        .badge {
+          position: absolute;
+          top: -10px;
+          right: -10px;
+          padding: 0 2px;
+          border-radius: 4px;
+          background-color: red;
+          color: white;
+          line-height: 1;
+          .txt {
+            margin-right: 0;
+            transform-origin: top !important;
+
+            @include minFont(10);
+          }
+        }
+      }
 
-        @extend %containBg;
+      .start-live {
+        margin-right: 20px;
+
+        .btn {
+          padding: 5px 15px;
+          border-radius: 6px;
+          background-color: $theme-color-gold;
+          color: white;
+          font-size: 13px;
+          cursor: pointer;
+        }
+        .list {
+          width: 150px;
+          .item {
+            display: flex;
+            align-items: center;
+            margin-bottom: 5px;
+            padding: 0 15px;
+            cursor: pointer;
+
+            &:hover {
+              color: $theme-color-gold;
+            }
+            &.disabled {
+              color: initial !important;
+              opacity: 0.5;
+              cursor: not-allowed;
+            }
+          }
+        }
       }
-      .list {
-        width: 90px;
-        .item {
+      .qqlogin {
+        .btn {
           display: flex;
-          padding: 0 15px;
+          align-items: center;
+          justify-content: center;
+          box-sizing: border-box;
+          width: 35px;
+          height: 35px;
+          border-radius: 50%;
+          background-color: papayawhip;
+          font-size: 13px;
           cursor: pointer;
-          &:hover {
-            color: $theme-color-gold;
+
+          @extend %containBg;
+        }
+        .list {
+          width: 90px;
+          .item {
+            display: flex;
+            padding: 0 15px;
+            cursor: pointer;
+            &:hover {
+              color: $theme-color-gold;
+            }
           }
         }
       }

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

@@ -21,7 +21,7 @@ document.body.style.minWidth = '1200px';
 <style lang="scss" scoped>
 .layout {
   box-sizing: border-box;
-  padding-top: 64px;
+  padding-top: $header-height;
   min-height: 100vh;
   .fixed-mask {
     position: fixed;

+ 9 - 1
src/router/index.ts

@@ -18,6 +18,7 @@ export const routerName = {
   home: 'home',
   about: 'about',
   area: 'area',
+  areaDetail: 'areaDetail',
   account: 'account',
   rank: 'rank',
   sponsors: 'sponsors',
@@ -85,8 +86,15 @@ export const defaultRoutes: RouteRecordRaw[] = [
       },
       {
         name: routerName.area,
-        path: '/area/:id',
+        path: '/area',
         component: () => import('@/views/area/index.vue'),
+        children: [
+          {
+            name: routerName.areaDetail,
+            path: '/area/:id',
+            component: () => import('@/views/area/id/index.vue'),
+          },
+        ],
       },
       {
         name: routerName.rank,

+ 7 - 16
src/views/account/index.vue

@@ -9,8 +9,9 @@
       ></Avatar>
     </div>
     <div class="username">用户昵称:{{ userInfo?.username }}</div>
+    <br />
     <div class="pull-url">
-      <span>直播间:</span>
+      <span>直播间信息:</span>
       <span
         v-if="!userInfo?.live_rooms?.length"
         class="link"
@@ -21,19 +22,9 @@
       <div v-else>
         <div>直播间名字:{{ userInfo?.live_rooms?.[0].name }}</div>
         <div>
-          直播间地址1(webrtc开播时):https://live.hsslive.cn/pull/<span>
-            {{ userInfo?.live_rooms?.[0].id }}?liveType=webrtcPull
-          </span>
-        </div>
-        <div>
-          直播间地址2(srs-webrtc开播时):https://live.hsslive.cn/pull/<span>
-            {{ userInfo?.live_rooms?.[0].id }}?liveType=srsWebrtcPull
-          </span>
-        </div>
-        <div>
-          直播间地址3(srs-webrtc开播或obs推流时):https://live.hsslive.cn/pull/<span>
-            {{ userInfo?.live_rooms?.[0].id }}?liveType=srsFlvPull
-          </span>
+          直播间地址:https://live.hsslive.cn/pull/{{
+            userInfo?.live_rooms?.[0].id
+          }}
         </div>
         <div
           v-loading="keyLoading"
@@ -75,7 +66,7 @@ import { useRouter } from 'vue-router';
 import { fetchUpdateLiveRoomKey } from '@/api/liveRoom';
 import { fetchUserInfo } from '@/api/user';
 import { loginTip } from '@/hooks/use-login';
-import { IUser, LiveRoomTypeEnum, LiveTypeEnum } from '@/interface';
+import { IUser, LiveRoomTypeEnum } from '@/interface';
 import { routerName } from '@/router';
 
 const newRtmpUrl = ref();
@@ -108,7 +99,7 @@ function openLiveRoom() {
   }
   const url = router.resolve({
     name: routerName.push,
-    query: { liveType: LiveTypeEnum.srsWebrtcPull },
+    query: { liveType: LiveRoomTypeEnum.user_srs },
   });
   openToTarget(url.href);
 }

+ 168 - 0
src/views/area/id/index.vue

@@ -0,0 +1,168 @@
+<template>
+  <div class="area-wrap">
+    <div class="wrap">
+      <div
+        v-loading="loading"
+        class="live-room-list"
+      >
+        <div
+          v-for="(iten, indey) in liveRoomList"
+          :key="indey"
+          class="live-room"
+          @click="goRoom(iten)"
+        >
+          <div
+            class="cover"
+            :style="{
+              backgroundImage: `url('${
+                iten?.cover_img || iten?.users?.[0].avatar
+              }')`,
+            }"
+          >
+            <div
+              v-if="iten?.cdn === 1"
+              class="cdn-ico"
+            >
+              <div class="txt">CDN</div>
+            </div>
+            <div class="txt">{{ iten?.users?.[0].username }}</div>
+          </div>
+          <div class="desc">{{ iten?.name }}</div>
+        </div>
+        <div
+          v-if="!liveRoomList.length"
+          class="null"
+        >
+          暂无数据
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { onMounted, ref, watch } from 'vue';
+import { useRoute } from 'vue-router';
+
+import { fetchLiveRoomList } from '@/api/area';
+import { ILiveRoom } from '@/interface';
+import router, { routerName } from '@/router';
+
+const liveRoomList = ref<ILiveRoom[]>([]);
+
+const route = useRoute();
+
+const loading = ref(false);
+
+watch(
+  () => route.params.id,
+  (newVal) => {
+    if (!newVal) return;
+    getData();
+  }
+);
+
+function goRoom(item: ILiveRoom) {
+  if (!item.live) {
+    window.$message.info('该直播间没在直播~');
+    return;
+  }
+  router.push({
+    name: routerName.pull,
+    params: { roomId: item.id },
+  });
+}
+
+onMounted(() => {
+  getData();
+});
+
+async function getData() {
+  try {
+    loading.value = true;
+    const res = await fetchLiveRoomList({
+      id: Number(route.params.id),
+    });
+    if (res.code === 200) {
+      liveRoomList.value = res.data.rows;
+    }
+  } catch (error) {
+    console.log(error);
+  } finally {
+    loading.value = false;
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.area-wrap {
+  .wrap {
+    margin-top: 10px;
+    padding: 0 20px;
+    .live-room-list {
+      display: flex;
+      align-items: center;
+      flex-wrap: wrap;
+      .live-room {
+        display: inline-block;
+        margin-right: 25px;
+        margin-bottom: 12px;
+        width: 300px;
+        cursor: pointer;
+        .cover {
+          position: relative;
+          overflow: hidden;
+          width: 100%;
+          height: 150px;
+          border-radius: 8px;
+          background-position: center center;
+          background-size: cover;
+          .cdn-ico {
+            position: absolute;
+            top: -10px;
+            right: -10px;
+            z-index: 2;
+            width: 70px;
+            height: 28px;
+            background-color: #f87c48;
+            color: white;
+            transform: rotate(45deg);
+            transform-origin: bottom;
+            .txt {
+              margin-left: 18px;
+              background-image: initial !important;
+              font-size: 13px;
+            }
+          }
+
+          .txt {
+            position: absolute;
+            bottom: 0;
+            left: 0;
+            box-sizing: border-box;
+            padding: 4px 8px;
+            width: 100%;
+            border-radius: 0 0 4px 4px;
+            background-image: linear-gradient(
+              -180deg,
+              rgba(0, 0, 0, 0),
+              rgba(0, 0, 0, 0.6)
+            );
+            color: white;
+            text-align: initial;
+            font-size: 13px;
+
+            @extend %singleEllipsis;
+          }
+        }
+        .desc {
+          margin-top: 4px;
+          font-size: 14px;
+
+          @extend %singleEllipsis;
+        }
+      }
+    }
+  }
+}
+</style>

+ 56 - 142
src/views/area/index.vue

@@ -1,169 +1,83 @@
 <template>
-  <div class="area-wrap">
-    <div
-      v-loading="loading"
-      class="live-room-list"
+  <div class="area-list">
+    <a
+      v-for="(item, index) in areaList"
+      :key="index"
+      class="item"
+      :class="{
+        active: router.currentRoute.value.name === routerName.ad,
+      }"
+      @click.prevent="changeArea(item)"
     >
-      <div
-        v-for="(iten, indey) in liveRoomList"
-        :key="indey"
-        class="live-room"
-        @click="goRoom(iten)"
-      >
-        <div
-          class="cover"
-          :style="{
-            backgroundImage: `url('${
-              iten?.cover_img || iten?.users?.[0].avatar
-            }')`,
-          }"
-        >
-          <div
-            v-if="iten?.cdn === 1"
-            class="cdn-ico"
-          >
-            <div class="txt">CDN</div>
-          </div>
-          <div class="txt">{{ iten?.users?.[0].username }}</div>
-        </div>
-        <div class="desc">{{ iten?.name }}</div>
-      </div>
-      <div
-        v-if="!liveRoomList.length"
-        class="null"
-      >
-        暂无数据
-      </div>
-    </div>
+      {{ item.name }}
+    </a>
   </div>
+  <router-view></router-view>
 </template>
 
 <script lang="ts" setup>
-import { onMounted, ref, watch } from 'vue';
-import { useRoute } from 'vue-router';
+import { onMounted, ref } from 'vue';
 
-import { fetchLiveRoomList } from '@/api/area';
-import { ILiveRoom, LiveTypeEnum } from '@/interface';
+import { fetchAreaList } from '@/api/area';
+import { IArea } from '@/interface';
 import router, { routerName } from '@/router';
 
-const liveRoomList = ref<ILiveRoom[]>([]);
+const areaList = ref<IArea[]>([]);
 
-const route = useRoute();
-
-const loading = ref(false);
-
-watch(
-  () => route.params.id,
-  (newVal) => {
-    if (!newVal) return;
-    getData();
-  }
-);
+function changeArea(item: IArea) {
+  router.push({ name: routerName.areaDetail, params: { id: item.id } });
+}
 
-function goRoom(item: ILiveRoom) {
-  if (!item.live) {
-    window.$message.info('该直播间没在直播~');
-    return;
+async function getAreaList() {
+  const res = await fetchAreaList();
+  if (res.code === 200) {
+    areaList.value = res.data.rows;
+    router.push({
+      name: routerName.areaDetail,
+      params: { id: areaList.value[0].id },
+    });
   }
-  router.push({
-    name: routerName.pull,
-    params: { roomId: item.id },
-    query: {
-      liveType: LiveTypeEnum.srsHlsPull,
-    },
-  });
 }
 
 onMounted(() => {
-  getData();
+  getAreaList();
 });
-
-async function getData() {
-  try {
-    loading.value = true;
-    const res = await fetchLiveRoomList({
-      id: Number(route.params.id),
-    });
-    if (res.code === 200) {
-      liveRoomList.value = res.data.rows;
-    }
-  } catch (error) {
-    console.log(error);
-  } finally {
-    loading.value = false;
-  }
-}
 </script>
 
 <style lang="scss" scoped>
-.area-wrap {
-  padding: 15px 20px;
-  .title {
-    margin-bottom: 10px;
-  }
-  .live-room-list {
+.area-list {
+  display: flex;
+  align-items: center;
+  padding: 10px 30px;
+  height: 30px;
+  .item {
+    position: relative;
     display: flex;
     align-items: center;
-    flex-wrap: wrap;
-    .live-room {
-      display: inline-block;
-      margin-right: 25px;
-      margin-bottom: 12px;
-      width: 300px;
-      cursor: pointer;
-      .cover {
-        position: relative;
-        overflow: hidden;
-        width: 100%;
-        height: 150px;
-        border-radius: 8px;
-        background-position: center center;
-        background-size: cover;
-        .cdn-ico {
-          position: absolute;
-          right: -10px;
-          top: -10px;
-          background-color: #f87c48;
-          color: white;
-          z-index: 2;
-          height: 28px;
-          width: 70px;
-          transform-origin: bottom;
-          transform: rotate(45deg);
-          .txt {
-            margin-left: 18px;
-            font-size: 13px;
-            background-image: initial !important;
-          }
-        }
-
-        .txt {
-          position: absolute;
-          bottom: 0;
-          left: 0;
-          box-sizing: border-box;
-          padding: 4px 8px;
-          width: 100%;
-          border-radius: 0 0 4px 4px;
-          background-image: linear-gradient(
-            -180deg,
-            rgba(0, 0, 0, 0),
-            rgba(0, 0, 0, 0.6)
-          );
-          color: white;
-          text-align: initial;
-          font-size: 13px;
+    margin-right: 20px;
+    height: 100%;
+    color: black;
+    text-decoration: none;
+    font-size: 14px;
+    cursor: pointer;
 
-          @extend %singleEllipsis;
-        }
-      }
-      .desc {
-        margin-top: 4px;
-        font-size: 14px;
-
-        @extend %singleEllipsis;
+    &.active {
+      &::after {
+        position: absolute;
+        top: calc(50% - 8px);
+        right: -5px;
+        width: 5px;
+        height: 5px;
+        border-radius: 50%;
+        background-color: $theme-color-gold;
+        content: '';
+        transition: all 0.1s ease;
+        transform: translateY(-100%);
       }
     }
+    &:hover {
+      color: $theme-color-gold;
+    }
   }
 }
 </style>

+ 3 - 6
src/views/h5/room/index.vue

@@ -112,7 +112,7 @@ import { useRoute } from 'vue-router';
 
 import { fetchFindLiveRoom } from '@/api/liveRoom';
 import { usePull } from '@/hooks/use-pull';
-import { DanmuMsgTypeEnum, LiveRoomTypeEnum, LiveTypeEnum } from '@/interface';
+import { DanmuMsgTypeEnum, LiveRoomTypeEnum } from '@/interface';
 import router, { mobileRouterName } from '@/router';
 import { useAppStore } from '@/store/app';
 
@@ -131,7 +131,6 @@ const {
   keydownDanmu,
   sendDanmu,
   handleHlsPlay,
-  roomLiveType,
   autoplayVal,
   videoLoading,
   damuList,
@@ -142,9 +141,7 @@ const {
   remoteVideo,
   closeRtc,
   closeWs,
-} = usePull({
-  liveType: LiveTypeEnum.srsHlsPull,
-});
+} = usePull();
 
 watch(
   () => remoteVideo.value,
@@ -177,7 +174,7 @@ async function getLiveRoomInfo() {
     if (res.code === 200) {
       if (res.data.type === LiveRoomTypeEnum.user_wertc) {
         autoplayVal.value = true;
-        roomLiveType.value = LiveTypeEnum.webrtcPull;
+        roomLiveType.value = LiveRoomTypeEnum.user_wertc;
         showPlayBtn.value = false;
       } else {
         showPlayBtn.value = true;

+ 40 - 51
src/views/home/index.vue

@@ -103,11 +103,13 @@
               }"
               @click="changeLiveRoom(item)"
             >
-              <div
-                class="cdn-ico"
-                v-if="item?.live_room?.cdn === 1"
-              >
-                <div class="txt">CDN</div>
+              <div class="hidden">
+                <div
+                  class="cdn-ico"
+                  v-if="item?.live_room?.cdn === 1"
+                >
+                  <div class="txt">CDN</div>
+                </div>
               </div>
               <div
                 class="border"
@@ -182,7 +184,7 @@
 <script lang="ts" setup>
 import { isMobile } from 'billd-utils';
 import { onMounted, ref, watch } from 'vue';
-import { useRoute, useRouter } from 'vue-router';
+import { useRouter } from 'vue-router';
 
 import { fetchLiveList } from '@/api/live';
 import { sliderList } from '@/constant';
@@ -190,7 +192,6 @@ import { usePull } from '@/hooks/use-pull';
 import { ILive, LiveRoomTypeEnum, LiveTypeEnum } from '@/interface';
 import { routerName } from '@/router';
 
-const route = useRoute();
 const router = useRouter();
 const canvasRef = ref<Element>();
 const showControls = ref(false);
@@ -201,11 +202,8 @@ const currentLiveRoom = ref<ILive>();
 const interactionList = ref(sliderList);
 const remoteVideoRef = ref<HTMLDivElement>();
 
-const { handleHlsPlay, videoLoading, remoteVideo, handleStopDrawing } = usePull(
-  {
-    liveType: route.query.liveType as LiveTypeEnum,
-  }
-);
+const { handleHlsPlay, videoLoading, remoteVideo, handleStopDrawing } =
+  usePull();
 
 watch(
   () => remoteVideo.value,
@@ -270,27 +268,12 @@ onMounted(() => {
 });
 
 function joinRtcRoom() {
-  if (currentLiveRoom.value?.live_room?.type === LiveRoomTypeEnum.user_srs) {
-    router.push({
-      name: routerName.pull,
-      params: {
-        roomId: currentLiveRoom.value.live_room_id,
-      },
-      query: {
-        liveType: LiveTypeEnum.srsWebrtcPull,
-      },
-    });
-  } else {
-    router.push({
-      name: routerName.pull,
-      params: {
-        roomId: currentLiveRoom.value?.live_room_id,
-      },
-      query: {
-        liveType: LiveTypeEnum.webrtcPull,
-      },
-    });
-  }
+  router.push({
+    name: routerName.pull,
+    params: {
+      roomId: currentLiveRoom.value?.live_room_id,
+    },
+  });
 }
 
 function joinRoom(data: { roomId: number; isFlv: boolean }) {
@@ -451,7 +434,6 @@ function joinRoom(data: { roomId: number; isFlv: boolean }) {
         .list {
           .item {
             position: relative;
-            overflow: hidden;
             box-sizing: border-box;
             margin-bottom: 10px;
             width: 200px;
@@ -465,25 +447,32 @@ function joinRoom(data: { roomId: number; isFlv: boolean }) {
             &:last-child {
               margin-bottom: 0;
             }
-            .cdn-ico {
-              position: absolute;
-              top: -9px;
-              right: -9px;
-              z-index: 2;
-              width: 60px;
-              height: 28px;
-              background-color: #f87c48;
-              color: white;
-              transform: rotate(45deg);
-              transform-origin: bottom;
-
-              .txt {
-                margin-left: 10px;
-                background-image: initial !important;
-                font-size: 12px;
-                line-height: 0.8;
+            .hidden {
+              position: relative;
+              overflow: hidden;
+              width: 200px;
+              height: 110px;
+              .cdn-ico {
+                position: absolute;
+                top: -9px;
+                right: -9px;
+                z-index: 2;
+                width: 60px;
+                height: 28px;
+                background-color: #f87c48;
+                color: white;
+                transform: rotate(45deg);
+                transform-origin: bottom;
+
+                .txt {
+                  margin-left: 10px;
+                  background-image: initial !important;
+                  font-size: 12px;
+                  line-height: 0.8;
+                }
               }
             }
+
             .border {
               position: absolute;
               top: 0;

+ 2 - 20
src/views/pull/index.vue

@@ -187,12 +187,7 @@ import { useRoute } from 'vue-router';
 import { fetchGoodsList } from '@/api/goods';
 import { loginTip } from '@/hooks/use-login';
 import { usePull } from '@/hooks/use-pull';
-import {
-  DanmuMsgTypeEnum,
-  GoodsTypeEnum,
-  IGoods,
-  LiveTypeEnum,
-} from '@/interface';
+import { DanmuMsgTypeEnum, GoodsTypeEnum, IGoods } from '@/interface';
 import { useAppStore } from '@/store/app';
 import { useUserStore } from '@/store/user';
 import { NODE_ENV } from 'script/constant';
@@ -206,13 +201,11 @@ const giftGoodsList = ref<IGoods[]>([]);
 const height = ref(0);
 const giftLoading = ref(false);
 const showRecharge = ref(false);
-const showSidebar = ref(true);
 const topRef = ref<HTMLDivElement>();
 const bottomRef = ref<HTMLDivElement>();
 const danmuListRef = ref<HTMLDivElement>();
 const remoteVideoRef = ref<HTMLDivElement>();
 const containerRef = ref<HTMLDivElement>();
-const queryLiveType = ref(route.query.liveType as LiveTypeEnum);
 const {
   initPull,
   closeWs,
@@ -228,9 +221,7 @@ const {
   danmuStr,
   liveRoomInfo,
   anchorInfo,
-} = usePull({
-  liveType: queryLiveType.value,
-});
+} = usePull();
 
 onUnmounted(() => {
   closeWs();
@@ -255,15 +246,6 @@ onMounted(() => {
     scrollTo(0, 0);
   }, 100);
   getGoodsList();
-  if (
-    [
-      LiveTypeEnum.srsHlsPull,
-      LiveTypeEnum.srsFlvPull,
-      LiveTypeEnum.srsWebrtcPull,
-    ].includes(route.query.liveType as LiveTypeEnum)
-  ) {
-    showSidebar.value = false;
-  }
   if (topRef.value && bottomRef.value && containerRef.value) {
     const res =
       bottomRef.value.getBoundingClientRect().top -

+ 2 - 18
src/views/rank/index.vue

@@ -96,13 +96,7 @@ import { fetchLiveRoomList } from '@/api/liveRoom';
 import { fetchBlogUserList, fetchUserList } from '@/api/user';
 import { fetchWalletList } from '@/api/wallet';
 import { fullLoading } from '@/components/FullLoading';
-import {
-  ILiveRoom,
-  IUser,
-  LiveRoomTypeEnum,
-  LiveTypeEnum,
-  RankTypeEnum,
-} from '@/interface';
+import { ILiveRoom, IUser, RankTypeEnum } from '@/interface';
 import router, { routerName } from '@/router';
 
 export interface IRankType {
@@ -193,19 +187,9 @@ const mockRank: {
 const rankList = ref(mockRank);
 
 function handleJoin(item) {
-  let liveType: LiveTypeEnum = LiveTypeEnum.webrtcPull;
-  if (
-    item?.type === LiveRoomTypeEnum.system ||
-    item?.type === LiveRoomTypeEnum.user_obs
-  ) {
-    liveType = LiveTypeEnum.srsFlvPull;
-  } else if (item?.type === LiveRoomTypeEnum.user_srs) {
-    liveType = LiveTypeEnum.srsWebrtcPull;
-  }
   router.push({
     name: routerName.pull,
     params: { roomId: item.live.live_room_id },
-    query: { liveType },
   });
 }
 
@@ -362,7 +346,7 @@ onMounted(() => {
 .rank-wrap {
   box-sizing: border-box;
   padding-top: 10px;
-  height: calc(100vh - 64px);
+  height: calc(100vh - $header-height);
   background-color: #f4f4f4;
   .type-list {
     display: flex;

+ 1 - 1
src/views/shop/index.vue

@@ -135,7 +135,7 @@ function startPay(item: IGoods) {
 
 <style lang="scss" scoped>
 .shop-wrap {
-  padding: 20px 30px;
+  padding: 10px 30px;
   .tab-list {
     display: flex;
     align-items: center;