video.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <template>
  2. <div class="tab-content h-full">
  3. <div class="subtitle"><span></span> <el-button type="primary" v-auth="'add'" size="small" @click="addDevice()">添加监控</el-button></div>
  4. <el-table :data="tableData" style="width: 100%" v-loading="loading" max-height="calc(100vh - 280px)">
  5. <el-table-column prop="name" label="设备名称" min-width="130" align="center" show-overflow-tooltip></el-table-column>
  6. <el-table-column prop="deviceId" label="设备ID" min-width="210" align="center" show-overflow-tooltip></el-table-column>
  7. <el-table-column prop="name" label="通道名称" min-width="140" align="center" show-overflow-tooltip></el-table-column>
  8. <el-table-column prop="model" label="型号" width="100" align="center" show-overflow-tooltip></el-table-column>
  9. <el-table-column prop="manufacturer" label="厂商" width="100" align="center" show-overflow-tooltip></el-table-column>
  10. <el-table-column prop="liveStatus" label="状态" width="100" align="center" :formatter="formatLiveStatus" show-overflow-tooltip></el-table-column>
  11. <el-table-column prop="keepAliveTime" label="最后心跳时间" :formatter="formatTime" width="170" align="center" show-overflow-tooltip></el-table-column>
  12. <el-table-column prop="registerTime" label="注册时间" :formatter="formatTime" width="170" align="center" show-overflow-tooltip></el-table-column>
  13. <el-table-column prop="updateAt" label="更新时间" :formatter="formatTime" width="170" align="center" show-overflow-tooltip></el-table-column>
  14. <el-table-column label="操作" width="120" align="center" fixed="right">
  15. <template #default="scope">
  16. <el-button size="small" text type="primary" v-auth="'detail'" @click="view(scope.row)">查看监控</el-button>
  17. <el-button size="small" text type="warning" v-auth="'del'" @click="onDel(scope.row)">解绑</el-button>
  18. </template>
  19. </el-table-column>
  20. </el-table>
  21. <el-dialog title="添加监控" v-model="isShowDialog" width="400">
  22. <el-form v-if="isShowDialog">
  23. <el-form-item label="监控" style="margin-bottom: 0">
  24. <el-select v-model="form.resourcesKey" filterable placeholder="选择监控" :clearable="false" style="width: 100%">
  25. <el-option v-for="item in options" :disabled="item.disabled" :key="item.value" :label="item.label" :value="item.value" />
  26. </el-select>
  27. </el-form-item>
  28. </el-form>
  29. <template #footer>
  30. <span class="dialog-footer">
  31. <el-button @click="onCancel">取 消</el-button>
  32. <el-button type="primary" @click="onSubmit">确 定</el-button>
  33. </span>
  34. </template>
  35. </el-dialog>
  36. <el-dialog title="预览监控" v-model="isShowPreviewDialog" width="90vh">
  37. <template #header>
  38. <span class="dialog-footer">
  39. <el-button type="primary" size="small" @click="openToNewWindow">新窗口预览</el-button>
  40. </span>
  41. </template>
  42. <iframe v-if="isShowPreviewDialog" :src="previewUrl" style="width: 100%; height: 50vh"></iframe>
  43. </el-dialog>
  44. </div>
  45. </template>
  46. <script lang="ts" setup>
  47. import { reactive, ref } from "vue";
  48. import api from "/@/api/projects";
  49. import { useRoute } from "vue-router";
  50. import { dayjs, ElMessage, ElMessageBox } from "element-plus";
  51. import axios from "axios";
  52. import { getMediaOrigin } from "/@/utils/origin";
  53. const route = useRoute();
  54. const props = defineProps({ resourcesTypes: Number });
  55. const isShowDialog = ref(false);
  56. const isShowPreviewDialog = ref(false);
  57. const loading = ref(false);
  58. const previewUrl = ref("");
  59. const options = ref<any[]>([]);
  60. const tableData = ref<any[]>([]);
  61. const channels = ref<any[]>([]);
  62. const resourcesTypes = props.resourcesTypes!;
  63. const projectsCode = route.params.id;
  64. const baseForm = {
  65. resourcesKey: "",
  66. projectsCode,
  67. resourcesTypes,
  68. };
  69. const form = reactive({
  70. ...baseForm,
  71. });
  72. getOptions();
  73. function getSourceList() {
  74. api.getProjectResourcesByCode({ projectsCode }).then((res: any) => {
  75. const ids = (res || []).filter((item: any) => item.resourcesTypes === resourcesTypes).map((item: any) => item.resourcesKey);
  76. const tableDataList: any[] = [];
  77. ids.forEach((id: string) => {
  78. const [deviceID, channelID] = id.split("-");
  79. const channel = channels.value.find((channel: any) => channel.deviceId === deviceID && channel.channelId === channelID);
  80. if (channel) {
  81. options.value.find((item: any) => item.value === id).disabled = true;
  82. tableDataList.push(channel);
  83. }
  84. });
  85. tableData.value = tableDataList;
  86. });
  87. }
  88. function getOptions() {
  89. // 获取流媒体设备列表,拼接成通道列表 设备ID-通道ID
  90. axios.get(getMediaOrigin("/gb28181/api/list?page=1&count=1000&format=json")).then((res: any) => {
  91. const optionsList: any[] = [];
  92. const channelsList: any[] = [];
  93. res.data.data.forEach((item: any) => {
  94. item.channels.forEach((channel: any) => {
  95. optionsList.push({ label: item.name + " - " + channel.name, value: item.deviceId + "-" + channel.channelId });
  96. channelsList.push({
  97. ...channel,
  98. name: item.name,
  99. netAddr: item.netAddr,
  100. registerTime: item.registerTime,
  101. updateAt: item.updateAt,
  102. keepAliveTime: item.keepAliveTime,
  103. deviceId: channel.deviceId,
  104. });
  105. });
  106. });
  107. options.value = optionsList;
  108. channels.value = channelsList;
  109. getSourceList();
  110. });
  111. }
  112. function onCancel() {
  113. Object.assign(form, baseForm);
  114. isShowDialog.value = false;
  115. }
  116. function onSubmit() {
  117. if (!form.resourcesKey) return ElMessage("请先选择监控");
  118. api.bindResources(form).then(() => {
  119. onCancel();
  120. getSourceList();
  121. ElMessage.success("添加成功");
  122. });
  123. }
  124. function addDevice() {
  125. isShowDialog.value = true;
  126. }
  127. function view(row: any) {
  128. previewUrl.value = import.meta.env.VITE_SERVER_ORIGIN + "/plugin/media/index.html?ID=" + row.channelId + "&DeviceID=" + row.deviceId + "#/0/screen-preview";
  129. isShowPreviewDialog.value = true;
  130. }
  131. function openToNewWindow() {
  132. window.open(previewUrl.value);
  133. isShowPreviewDialog.value = false;
  134. }
  135. function onDel(row: any) {
  136. ElMessageBox.confirm(`确定要解绑该监控?`, "提示", {
  137. confirmButtonText: "确认",
  138. cancelButtonText: "取消",
  139. type: "warning",
  140. }).then(() => {
  141. api
  142. .unbindResources({
  143. projectsCode,
  144. resourcesTypes,
  145. resourcesKey: row.ID + "-" + row.deviceId,
  146. })
  147. .then(() => {
  148. getSourceList();
  149. ElMessage.success("解绑成功");
  150. });
  151. });
  152. }
  153. function formatTime(row: any, column: any) {
  154. return dayjs(row[column.property]).format("YYYY-MM-DD HH:mm:ss");
  155. }
  156. function formatLiveStatus(row: any, column: any) {
  157. // 0 代表空闲,1 代表正在调用 invite,2 代表正在拉流
  158. return row[column.property] === 0 ? "空闲" : row[column.property] === 1 ? "调用中" : "拉流中";
  159. }
  160. </script>