index.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. <template>
  2. <div class="video-controls-wrap">
  3. <div class="left">
  4. <div
  5. class="play"
  6. @click="changePlay"
  7. >
  8. <n-icon size="25">
  9. <Pause v-if="appStore.playing"></Pause>
  10. <Play v-else></Play>
  11. </n-icon>
  12. </div>
  13. <div
  14. class="refresh"
  15. @click="debounceRefresh"
  16. >
  17. <n-icon size="25">
  18. <RefreshSharp></RefreshSharp>
  19. </n-icon>
  20. </div>
  21. <div
  22. class="muted"
  23. @click="changeMuted"
  24. >
  25. <n-popover
  26. placement="top"
  27. trigger="hover"
  28. :flip="false"
  29. :style="{ padding: '4px 4px 24px 4px' }"
  30. :show-arrow="false"
  31. >
  32. <template #trigger>
  33. <n-icon size="25">
  34. <VolumeMuteOutline v-if="cacheStore.muted"></VolumeMuteOutline>
  35. <VolumeHighOutline v-else></VolumeHighOutline>
  36. </n-icon>
  37. </template>
  38. <div class="slider">
  39. <div class="txt">{{ cacheStore.volume }}</div>
  40. <n-slider
  41. :value="cacheStore.volume"
  42. :step="1"
  43. vertical
  44. :tooltip="false"
  45. @update-value="changeVolume"
  46. />
  47. </div>
  48. </n-popover>
  49. </div>
  50. </div>
  51. <div class="right">
  52. <div
  53. class="resolution"
  54. v-if="resolution"
  55. >
  56. {{ resolution }}
  57. </div>
  58. <div class="line">
  59. <span
  60. class="txt"
  61. @click="showLine = !showLine"
  62. >
  63. 线路
  64. </span>
  65. <div
  66. class="list"
  67. :class="{ show: showLine }"
  68. >
  69. <div
  70. class="iten"
  71. :class="{ active: appStore.liveLine === item }"
  72. v-for="item in LiveLineEnum"
  73. :key="item"
  74. @click="changeLiveLine(item)"
  75. >
  76. {{ item }}
  77. </div>
  78. </div>
  79. </div>
  80. <div class="speed">
  81. <span
  82. class="txt"
  83. @click="showSpeed = !showSpeed"
  84. >
  85. 倍速
  86. </span>
  87. <div
  88. class="list"
  89. :class="{ show: showSpeed }"
  90. @click="handleTip"
  91. >
  92. <div class="iten">2.0x</div>
  93. <div class="iten">1.5x</div>
  94. <div class="iten active">1.0x</div>
  95. <div class="iten">0.5x</div>
  96. </div>
  97. </div>
  98. <div class="full">
  99. <span
  100. class="txt"
  101. @click="emits('fullScreen')"
  102. >
  103. 全屏
  104. </span>
  105. </div>
  106. </div>
  107. </div>
  108. </template>
  109. <script lang="ts" setup>
  110. import {
  111. Pause,
  112. Play,
  113. RefreshSharp,
  114. VolumeHighOutline,
  115. VolumeMuteOutline,
  116. } from '@vicons/ionicons5';
  117. import { debounce } from 'billd-utils';
  118. import { ref } from 'vue';
  119. import { LiveLineEnum } from '@/interface';
  120. import { useAppStore } from '@/store/app';
  121. import { usePiniaCacheStore } from '@/store/cache';
  122. import { LiveRoomTypeEnum } from '@/types/ILiveRoom';
  123. withDefaults(
  124. defineProps<{
  125. resolution?: string;
  126. }>(),
  127. {}
  128. );
  129. const emits = defineEmits(['refresh', 'fullScreen']);
  130. const debounceRefresh = debounce(() => {
  131. emits('refresh');
  132. }, 500);
  133. const cacheStore = usePiniaCacheStore();
  134. const appStore = useAppStore();
  135. const showLine = ref(false);
  136. const showSpeed = ref(false);
  137. function handleTip() {
  138. window.$message.info('敬请期待!');
  139. }
  140. function changeMuted() {
  141. cacheStore.setMuted(!cacheStore.muted);
  142. }
  143. function changeVolume(v) {
  144. cacheStore.setVolume(v);
  145. }
  146. function changePlay() {
  147. appStore.playing = !appStore.playing;
  148. }
  149. function changeLiveLine(item: LiveLineEnum) {
  150. if (
  151. [
  152. LiveRoomTypeEnum.wertc_live,
  153. LiveRoomTypeEnum.wertc_meeting_one,
  154. LiveRoomTypeEnum.wertc_meeting_two,
  155. ].includes(appStore.liveRoomInfo?.type!) &&
  156. item !== LiveLineEnum.rtc
  157. ) {
  158. window.$message.info('不支持该线路!');
  159. return;
  160. }
  161. appStore.setLiveLine(item);
  162. }
  163. </script>
  164. <style lang="scss" scoped>
  165. .slider {
  166. display: flex;
  167. flex-wrap: wrap;
  168. justify-content: center;
  169. width: 24px;
  170. height: 80px;
  171. text-align: center;
  172. .txt {
  173. font-size: 12px;
  174. }
  175. }
  176. .video-controls-wrap {
  177. position: absolute;
  178. bottom: 0;
  179. left: 0;
  180. z-index: 50;
  181. display: flex;
  182. align-items: center;
  183. justify-content: space-between;
  184. box-sizing: border-box;
  185. padding: 0 20px 0 10px;
  186. width: 100%;
  187. height: 40px;
  188. background-image: linear-gradient(
  189. -180deg,
  190. rgba(0, 0, 0, 0),
  191. rgba(0, 0, 0, 0.7)
  192. );
  193. color: white;
  194. text-align: initial;
  195. user-select: none;
  196. .left {
  197. display: flex;
  198. align-items: center;
  199. .muted,
  200. .refresh,
  201. .play {
  202. display: flex;
  203. align-items: center;
  204. margin-right: 10px;
  205. cursor: pointer;
  206. }
  207. }
  208. .right {
  209. display: flex;
  210. align-items: center;
  211. .resolution {
  212. cursor: no-drop;
  213. }
  214. .resolution,
  215. .line,
  216. .speed,
  217. .full {
  218. position: relative;
  219. margin-right: 15px;
  220. &:hover {
  221. .list {
  222. display: block;
  223. }
  224. }
  225. .txt {
  226. cursor: pointer;
  227. }
  228. .list {
  229. position: absolute;
  230. top: 0;
  231. left: 50%;
  232. display: none;
  233. background-color: rgba($color: #000000, $alpha: 0.5);
  234. text-align: center;
  235. transform: translate(-50%, -100%);
  236. &.show {
  237. display: block;
  238. }
  239. .iten {
  240. padding: 6px 10px;
  241. &.active {
  242. color: $theme-color-gold;
  243. }
  244. &:not(:last-child) {
  245. margin-bottom: 4px;
  246. }
  247. &:hover {
  248. background-color: rgba($color: #ffffff, $alpha: 0.1);
  249. cursor: pointer;
  250. }
  251. }
  252. }
  253. }
  254. .full {
  255. margin-right: 0;
  256. }
  257. }
  258. }
  259. </style>