index.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. <template>
  2. <div class="deviceLive">
  3. <div class="deviceLive-frames">
  4. <LivePlayer :text="state.playerText" :url="state.playerUrl" />
  5. </div>
  6. <div class="deviceLive-operation">
  7. <a-select style="width:150px;margin-right: 13px;" placeholder="摄像头" v-model:value="state.cameraValue">
  8. <a-select-option v-for="item in state.cameraList" :key="item.value" :value="item.value"
  9. @click="onCameraSelect(item)">
  10. {{ item.label }}
  11. </a-select-option>
  12. </a-select>
  13. <a-select style="width:150px;margin-right: 13px;" placeholder="清晰度" v-model:value="state.clarityValue"
  14. @select="onClaritySelect">
  15. <a-select-option v-for="item in clarityList" :key="item.value" :value="item.value">
  16. {{ item.label }}
  17. </a-select-option>
  18. </a-select>
  19. <a-button style="margin-right: 13px;" type="primary" large @click="onStart">播放</a-button>
  20. <a-button type="primary" large @click="onStop">停止</a-button>
  21. </div>
  22. </div>
  23. </template>
  24. <script lang="ts" setup>
  25. import { reactive, onMounted } from 'vue';
  26. import { message } from 'ant-design-vue';
  27. import LivePlayer from '/@/components/livePlayer/index.vue';
  28. import { CURRENT_CONFIG as config } from '/@/api/http/config';
  29. import { getLiveCapacity, startLivestream, stopLivestream } from '/@/api/manage';
  30. interface Props {
  31. sn: string,
  32. };
  33. const props = withDefaults(defineProps<Props>(), {
  34. });
  35. interface SelectOption {
  36. value: any,
  37. label: string,
  38. more?: any
  39. }
  40. const clarityList: SelectOption[] = [
  41. {
  42. value: 0,
  43. label: '自适应'
  44. },
  45. {
  46. value: 1,
  47. label: '流畅'
  48. },
  49. {
  50. value: 2,
  51. label: '标清'
  52. },
  53. {
  54. value: 3,
  55. label: '高清'
  56. },
  57. {
  58. value: 4,
  59. label: '超清'
  60. }
  61. ]
  62. interface State {
  63. cameraList: SelectOption[],
  64. cameraValue?: string,
  65. videoList: SelectOption[],
  66. videoValue?: string,
  67. clarityValue: number,
  68. videoId: string,
  69. playerText: string,
  70. playerUrl: string,
  71. }
  72. const state: State = reactive({
  73. cameraList: [],
  74. cameraValue: undefined,
  75. videoList: [],
  76. videoValue: undefined,
  77. clarityValue: 0,
  78. videoId: '',
  79. playerText: '',
  80. playerUrl: '',
  81. })
  82. const fetchLiveCapacity = async () => {
  83. try {
  84. const res = await getLiveCapacity({});
  85. if (res.code === 0) {
  86. const deviceInfo = res.data.filter((item: any) => item.sn === props.sn)[0];
  87. const cameras_list = deviceInfo.cameras_list || [];
  88. const cameraList = cameras_list.map((item: any) => {
  89. return {
  90. label: item.name,
  91. value: item.index,
  92. more: item.videos_list
  93. }
  94. })
  95. state.cameraList = cameraList;
  96. }
  97. } catch (e: any) {
  98. console.error(e);
  99. }
  100. }
  101. onMounted(async () => {
  102. await fetchLiveCapacity()
  103. })
  104. const onCameraSelect = (record: SelectOption) => {
  105. state.cameraValue = record.value;
  106. if (!record.more) {
  107. return
  108. }
  109. const videoList = record.more.map((ele: any) => {
  110. return {
  111. label: ele.type,
  112. value: ele.index,
  113. more: ele.switch_video_types
  114. }
  115. })
  116. state.videoList = videoList;
  117. if (videoList.length === 0) {
  118. return;
  119. }
  120. const firstVideo: SelectOption = videoList[0];
  121. state.videoValue = firstVideo.value;
  122. }
  123. const onClaritySelect = (value: any) => {
  124. state.clarityValue = value;
  125. }
  126. const onStart = async () => {
  127. const { cameraValue, videoValue } = state;
  128. if (!cameraValue) {
  129. return message.warn('请选择摄像头');
  130. }
  131. const videoId = `${props.sn}/${cameraValue}/${videoValue || 'normal-0'}`;
  132. state.videoId = videoId;
  133. const liveURL = config.rtmpURL;
  134. try {
  135. const res = await startLivestream({
  136. url: liveURL,
  137. video_id: videoId,
  138. url_type: 1,// RTMP
  139. video_quality: state.clarityValue
  140. });
  141. if (res.code !== 0) {
  142. state.playerText = res.message;
  143. } else {
  144. const playerUrl = res.data.url;
  145. state.playerText = '';
  146. state.playerUrl = playerUrl;
  147. message.success('已开启直播');
  148. }
  149. } catch (e: any) {
  150. console.error(e);
  151. }
  152. }
  153. const onStop = async () => {
  154. const { cameraValue, videoValue } = state;
  155. if (!cameraValue) {
  156. return message.warn('请选择摄像头');
  157. }
  158. const videoId = `${props.sn}/${cameraValue}/${videoValue || 'normal-0'}`;
  159. const res = await stopLivestream({
  160. video_id: videoId,
  161. });
  162. if (res.code === 0) {
  163. state.videoId = '';
  164. state.playerUrl = '';
  165. message.success('已停止直播');
  166. }
  167. }
  168. </script>
  169. <style lang="scss" scoped>
  170. .deviceLive {
  171. width: 100%;
  172. &-frames {
  173. width: 100%;
  174. height: 270px;
  175. }
  176. &-operation {
  177. margin-top: 20px;
  178. }
  179. }
  180. </style>