index.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <template>
  2. <div class="home-wrap">
  3. <div
  4. class="left"
  5. :style="{ backgroundImage: `url(${currentLiveRoom?.coverImg})` }"
  6. >
  7. <video
  8. v-if="currentLiveRoom?.flvurl"
  9. id="localVideo"
  10. ref="localVideoRef"
  11. autoplay
  12. webkit-playsinline="true"
  13. playsinline
  14. x-webkit-airplay="allow"
  15. x5-video-player-type="h5"
  16. x5-video-player-fullscreen="true"
  17. x5-video-orientation="portraint"
  18. muted
  19. controls
  20. ></video>
  21. <div
  22. v-if="currentLiveRoom && currentLiveRoom.system === 2"
  23. class="btn-wrap"
  24. >
  25. <div
  26. class="btn webrtc"
  27. @click="joinRoom()"
  28. >
  29. 进入直播(webrtc)
  30. </div>
  31. <div
  32. v-if="currentLiveRoom?.flvurl"
  33. class="btn flv"
  34. @click="joinFlvRoom()"
  35. >
  36. 进入直播(flv)
  37. </div>
  38. </div>
  39. </div>
  40. <div class="right">
  41. <div
  42. v-if="liveRoomList.length"
  43. class="list"
  44. >
  45. <div
  46. v-for="(item, index) in liveRoomList"
  47. :key="index"
  48. :class="{ item: 1, active: item.roomId === currentLiveRoom?.roomId }"
  49. :style="{ backgroundImage: `url(${item.coverImg})` }"
  50. @click="currentLiveRoom = item"
  51. >
  52. <div
  53. class="border"
  54. :style="{
  55. opacity: item.roomId === currentLiveRoom?.roomId ? 1 : 0,
  56. }"
  57. ></div>
  58. <div
  59. v-if="item.roomId === currentLiveRoom?.roomId"
  60. class="triangle"
  61. ></div>
  62. <div class="txt">{{ item.roomName }}</div>
  63. </div>
  64. </div>
  65. <div
  66. v-else
  67. class="none"
  68. >
  69. 当前没有在线的直播间
  70. </div>
  71. </div>
  72. </div>
  73. </template>
  74. <script lang="ts" setup>
  75. import { nextTick, onMounted, ref } from 'vue';
  76. import { useRouter } from 'vue-router';
  77. import { fetchLiveList } from '@/api/live';
  78. import { useFlvPlay } from '@/hooks/use-play';
  79. import { ILive } from '@/interface';
  80. import { routerName } from '@/router';
  81. const router = useRouter();
  82. const liveRoomList = ref<ILive[]>([]);
  83. const currentLiveRoom = ref<ILive>();
  84. const localVideoRef = ref<HTMLVideoElement>();
  85. async function getLiveRoomList() {
  86. try {
  87. const res = await fetchLiveList({
  88. orderName: 'created_at',
  89. orderBy: 'desc',
  90. });
  91. if (res.code === 200) {
  92. liveRoomList.value = res.data.rows;
  93. if (res.data.total) {
  94. currentLiveRoom.value = res.data.rows[0];
  95. nextTick(() => {
  96. if (currentLiveRoom.value?.flvurl) {
  97. useFlvPlay(currentLiveRoom.value.flvurl, localVideoRef.value!);
  98. }
  99. });
  100. }
  101. }
  102. } catch (error) {
  103. console.log(error);
  104. }
  105. }
  106. onMounted(() => {
  107. getLiveRoomList();
  108. });
  109. function joinRoom() {
  110. if (currentLiveRoom.value?.streamurl) {
  111. router.push({
  112. name: routerName.srsWebRtcPull,
  113. params: { roomId: currentLiveRoom.value.roomId },
  114. });
  115. } else {
  116. router.push({
  117. name: routerName.webrtcPull,
  118. params: { roomId: currentLiveRoom.value?.roomId },
  119. });
  120. }
  121. }
  122. function joinFlvRoom() {
  123. router.push({
  124. name: routerName.srsFlvPull,
  125. params: { roomId: currentLiveRoom.value?.roomId },
  126. });
  127. }
  128. </script>
  129. <style lang="scss" scoped>
  130. .home-wrap {
  131. padding: 20px 0;
  132. min-width: $large-width;
  133. height: 610px;
  134. background-color: skyblue;
  135. text-align: center;
  136. .left {
  137. position: relative;
  138. display: inline-block;
  139. box-sizing: border-box;
  140. width: $large-left-width;
  141. height: 610px;
  142. border-radius: 4px;
  143. background-color: papayawhip;
  144. vertical-align: top;
  145. #localVideo {
  146. width: 100%;
  147. height: 100%;
  148. }
  149. @extend %coverBg;
  150. &:hover {
  151. .btn-wrap {
  152. display: inline-flex;
  153. }
  154. }
  155. .btn-wrap {
  156. position: absolute;
  157. top: 50%;
  158. left: 50%;
  159. display: none;
  160. align-items: center;
  161. transform: translate(-50%, -50%);
  162. .btn {
  163. cursor: pointer;
  164. padding: 14px 26px;
  165. border: 2px solid rgba($color: skyblue, $alpha: 0.5);
  166. border-radius: 6px;
  167. background-color: rgba(0, 0, 0, 0.3);
  168. color: skyblue;
  169. font-size: 16px;
  170. &:hover {
  171. background-color: rgba($color: skyblue, $alpha: 0.5);
  172. }
  173. &.webrtc {
  174. margin-right: 10px;
  175. }
  176. &.flv {
  177. }
  178. }
  179. }
  180. }
  181. .right {
  182. display: inline-block;
  183. overflow: scroll;
  184. box-sizing: border-box;
  185. margin-left: 10px;
  186. padding: 12px;
  187. height: 610px;
  188. border-radius: 4px;
  189. background-color: rgba($color: #000000, $alpha: 0.3);
  190. vertical-align: top;
  191. .list {
  192. .item {
  193. position: relative;
  194. box-sizing: border-box;
  195. margin-bottom: 10px;
  196. width: 200px;
  197. height: 110px;
  198. border-radius: 4px;
  199. background-color: rgba($color: #000000, $alpha: 0.3);
  200. cursor: pointer;
  201. @extend %coverBg;
  202. &:last-child {
  203. margin-bottom: 0;
  204. }
  205. .border {
  206. position: absolute;
  207. top: 0;
  208. right: 0;
  209. bottom: 0;
  210. left: 0;
  211. z-index: 1;
  212. border: 2px solid skyblue;
  213. border-radius: 4px;
  214. }
  215. .triangle {
  216. position: absolute;
  217. top: 50%;
  218. left: 0;
  219. display: inline-block;
  220. border: 5px solid transparent;
  221. border-right-color: skyblue;
  222. transform: translate(-100%, -50%);
  223. }
  224. &.active {
  225. &::before {
  226. background-color: transparent;
  227. }
  228. }
  229. &:hover {
  230. &::before {
  231. background-color: transparent;
  232. }
  233. }
  234. &::before {
  235. position: absolute;
  236. display: block;
  237. width: 100%;
  238. height: 100%;
  239. border-radius: 4px;
  240. background-color: rgba(0, 0, 0, 0.4);
  241. content: '';
  242. transition: all cubic-bezier(0.22, 0.58, 0.12, 0.98) 0.4s;
  243. }
  244. .txt {
  245. position: absolute;
  246. bottom: 0;
  247. left: 0;
  248. box-sizing: border-box;
  249. padding: 4px 8px;
  250. width: 100%;
  251. border-radius: 0 0 4px 4px;
  252. background-image: linear-gradient(
  253. -180deg,
  254. rgba(0, 0, 0, 0),
  255. rgba(0, 0, 0, 0.6)
  256. );
  257. color: white;
  258. text-align: initial;
  259. font-size: 13px;
  260. }
  261. }
  262. }
  263. .none {
  264. color: white;
  265. font-size: 14px;
  266. }
  267. }
  268. }
  269. // 屏幕宽度小于$large-width的时候
  270. @media screen and (max-width: $large-width) {
  271. .home-wrap {
  272. height: 460px;
  273. .left {
  274. width: $medium-left-width;
  275. height: 460px;
  276. }
  277. .right {
  278. height: 460px;
  279. .list {
  280. .item {
  281. width: 150px;
  282. height: 80px;
  283. }
  284. }
  285. }
  286. }
  287. }
  288. </style>