|
|
@@ -1,44 +1,39 @@ |
|
|
|
<!-- |
|
|
|
* @Description: 告警管理 |
|
|
|
* @Author: huguodong |
|
|
|
* @Date: 2023-12-15 15:44:05 |
|
|
|
* @Description: 监控管理 |
|
|
|
* @Author: wangwenpei |
|
|
|
* @Date: 2024-07-18 15:44:05 |
|
|
|
!--> |
|
|
|
<template> |
|
|
|
<div class="main-box"> |
|
|
|
<div class="card treeBox"> |
|
|
|
<p class="title">摄像头分组管理</p> |
|
|
|
<div class="btn"> |
|
|
|
<el-button @click="append('add', {})" type="primary">添加分组</el-button> |
|
|
|
<el-button icon="CirclePlus" @click="append('add', {})" type="primary">添加分组</el-button> |
|
|
|
</div> |
|
|
|
<!-- <div class="treeContent"> |
|
|
|
<ul class="treeList" v-for="(item, i) in treeData" :key="i"> |
|
|
|
<li class="treeItem"> |
|
|
|
<div class="treeLabel">{{ item.label }}</div> |
|
|
|
<div class="treeBtn"> |
|
|
|
<el-icon><Edit /></el-icon> |
|
|
|
<el-icon><Delete /></el-icon> |
|
|
|
</div> |
|
|
|
</li> |
|
|
|
</ul> |
|
|
|
</div> --> |
|
|
|
<div class="treeContent"> |
|
|
|
<el-input v-model="filterText" style="width: 240px" placeholder="请输入关键字" /> |
|
|
|
<el-tree |
|
|
|
style="max-width: 600px" |
|
|
|
ref="treeRef" |
|
|
|
:data="treeData" |
|
|
|
node-key="id" |
|
|
|
default-expand-all |
|
|
|
:props="defaultProps" |
|
|
|
:expand-on-click-node="false" |
|
|
|
:check-on-click-node="true" |
|
|
|
:highlight-current="true" |
|
|
|
:filter-node-method="filterNode" |
|
|
|
:current-node-key="defaultHighlightKey" |
|
|
|
@node-click="handleNodeClick" |
|
|
|
> |
|
|
|
<template #default="{ node, data }"> |
|
|
|
<span class="custom-tree-node"> |
|
|
|
<span class="node-label" :title="node.label">{{ node.label }}</span> |
|
|
|
<span v-if="data.id && data.id != '-1'"> |
|
|
|
<el-icon size="16" @click.stop="append('edit', data)"><Edit /></el-icon> |
|
|
|
<el-icon size="16" @click.stop="pushPerson('push', data)" style="margin-left: 8px"><UserFilled /></el-icon> |
|
|
|
<el-icon size="16" @click.stop="remove(node, data)" style="margin-left: 8px"><Delete /></el-icon> |
|
|
|
<el-icon size="16" title="添加" @click.stop="append('add', data)"><CirclePlus /></el-icon> |
|
|
|
<el-icon size="16" title="编辑" @click.stop="append('edit', data)" style="margin-left: 8px"><Edit /></el-icon> |
|
|
|
<el-icon size="16" title="设置推送人" @click.stop="pushPerson('push', data)" style="margin-left: 8px"><UserFilled /></el-icon> |
|
|
|
<el-icon size="16" title="删除" @click.stop="remove(data.id, '删除该分组')" style="margin-left: 8px"><Delete /></el-icon> |
|
|
|
</span> |
|
|
|
</span> |
|
|
|
</template> |
|
|
@@ -46,7 +41,7 @@ |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="table-box"> |
|
|
|
<ProTable ref="proTable" title="视频列表" :columns="columns" :request-api="monitorLIVEApi.page"> |
|
|
|
<ProTable ref="proTable" title="视频列表" :columns="columns" :request-api="monitorLIVEApi.list"> |
|
|
|
<!-- 表格 header 按钮 --> |
|
|
|
<template #tableHeader="scope"> |
|
|
|
<s-button v-auth="monitorLiveButtonCode.add" suffix="摄像头" @click="onOpen(FormOptEnum.ADD)" /> |
|
|
@@ -58,21 +53,9 @@ |
|
|
|
:disabled="!scope.isSelected" |
|
|
|
@click="onDelete(scope.selectedListIds, '删除所选数据')" |
|
|
|
/> |
|
|
|
<el-button plain @click="omMove(FormOptEnum.ADD)" type="success">移动至分组</el-button> |
|
|
|
<el-button :disabled="!scope.isSelected" plain @click="omMove(FormOptEnum.ADD, scope.selectedListIds)" type="success">移动至分组</el-button> |
|
|
|
</template> |
|
|
|
<!-- 表格 菜单类型 按钮 --> |
|
|
|
<!-- <template #menuType="scope"> |
|
|
|
<el-space wrap> |
|
|
|
<el-tag v-if="scope.row.menuType === MenuTypeDictEnum.MENU" type="success">{{ |
|
|
|
dictStore.dictTranslation(SysDictEnum.MENU_TYPE, MenuTypeDictEnum.MENU) |
|
|
|
}}</el-tag> |
|
|
|
<el-tag v-else-if="scope.row.menuType === MenuTypeDictEnum.LINK" type="warning">{{ |
|
|
|
dictStore.dictTranslation(SysDictEnum.MENU_TYPE, MenuTypeDictEnum.LINK) |
|
|
|
}}</el-tag> |
|
|
|
<el-tag v-else type="info">{{ dictStore.dictTranslation(SysDictEnum.MENU_TYPE, scope.row.menuType) }}</el-tag> |
|
|
|
<el-tag v-if="scope.row.isHome === true" type="danger">首页</el-tag> |
|
|
|
</el-space> |
|
|
|
</template> --> |
|
|
|
<!-- 操作 --> |
|
|
|
<template #operation="scope"> |
|
|
|
<s-button link :opt="FormOptEnum.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)">编辑</s-button> |
|
|
@@ -103,7 +86,7 @@ |
|
|
|
<!-- 移动至分组 --> |
|
|
|
<moveForm ref="moveFormRef" /> |
|
|
|
<!-- 视频详情 --> |
|
|
|
<el-dialog v-model="visible" :title="detailData.title" width="830px" :before-close="closeGroup"> |
|
|
|
<el-dialog v-model="visible" :title="detailData.title" width="830px" :before-close="handleClose"> |
|
|
|
<div> |
|
|
|
<div class="dialogHeader"> |
|
|
|
<div></div> |
|
|
@@ -128,187 +111,195 @@ |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
<script setup lang="tsx" name="sysSpa"> |
|
|
|
|
|
|
|
import VideoPlay from "@/components/VideoPlay/videoplay.vue"; |
|
|
|
import { ElMessage,ElMessageBox } from "element-plus"; |
|
|
|
import type Node from 'element-plus/es/components/tree/src/model/node' |
|
|
|
import { monitorLIVEApi, monitorLiveButtonCode } from "@/api"; |
|
|
|
import { ZJRQ } from "@/api/interface"; |
|
|
|
import { useHandleData } from "@/hooks/useHandleData"; |
|
|
|
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; |
|
|
|
import { useDictStore } from "@/stores/modules"; |
|
|
|
import Form from "./components/form.vue"; |
|
|
|
import userForm from "./components/userForm.vue"; |
|
|
|
import moveForm from "./components/moveForm.vue"; |
|
|
|
import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums"; |
|
|
|
// import './aliyun-rts-sdk.js' |
|
|
|
import './ali.js' |
|
|
|
const groupVisible = ref(false); //是否显示表单 |
|
|
|
const groupTitle = ref('新增分组'); |
|
|
|
const groupForm = reactive({ |
|
|
|
name: '' |
|
|
|
}); |
|
|
|
const groupRules = ref({ |
|
|
|
name: [{ required: true, message: '请输入分组名称', trigger: 'blur' }] |
|
|
|
<script setup lang="tsx" name="sysSpa"> |
|
|
|
import VideoPlay from "@/components/VideoPlay/videoplay.vue"; |
|
|
|
import { ElMessage, ElMessageBox, ElTree } from "element-plus"; |
|
|
|
import type Node from "element-plus/es/components/tree/src/model/node"; |
|
|
|
import { monitorLIVEApi, monitorLiveButtonCode } from "@/api"; |
|
|
|
import { ZJRQ } from "@/api/interface"; |
|
|
|
import { useHandleData } from "@/hooks/useHandleData"; |
|
|
|
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; |
|
|
|
import { useDictStore } from "@/stores/modules"; |
|
|
|
import Form from "./components/form.vue"; |
|
|
|
import userForm from "./components/userForm.vue"; |
|
|
|
import moveForm from "./components/moveForm.vue"; |
|
|
|
import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums"; |
|
|
|
// import './aliyun-rts-sdk.js' |
|
|
|
import "./ali.js"; |
|
|
|
// 分组字段配置 |
|
|
|
const defaultProps = { |
|
|
|
children: "children", |
|
|
|
label: "name" |
|
|
|
}; |
|
|
|
// 默认高亮 |
|
|
|
const defaultHighlightKey = ref(""); |
|
|
|
|
|
|
|
let treeDada1 = ref([ |
|
|
|
{ |
|
|
|
id: "", |
|
|
|
name: "全部" |
|
|
|
} |
|
|
|
]); |
|
|
|
const treeData = ref<any>([]); |
|
|
|
var treeRef = ref<InstanceType<typeof ElTree>>(); |
|
|
|
// 获取摄像头分组 |
|
|
|
function getGroupList() { |
|
|
|
monitorLIVEApi.groupList({}).then((res:any) => { |
|
|
|
if (res.code == 200) { |
|
|
|
treeData.value = [...treeDada1.value, ...res.data]; |
|
|
|
} |
|
|
|
}); |
|
|
|
const groupFormRef = ref(null); |
|
|
|
const closeGroup = () => { |
|
|
|
groupVisible.value = false; |
|
|
|
groupFormRef.value.resetFields(); |
|
|
|
groupForm.name = '' |
|
|
|
} |
|
|
|
|
|
|
|
const groupVisible = ref(false); //是否显示表单 |
|
|
|
const groupTitle = ref("新增分组"); |
|
|
|
const groupForm = reactive({ |
|
|
|
name: "", |
|
|
|
id: "" |
|
|
|
}); |
|
|
|
const groupRules = ref({ |
|
|
|
name: [{ required: true, message: "请输入分组名称", trigger: "blur" }] |
|
|
|
}); |
|
|
|
const groupFormRef = ref<any>(null); |
|
|
|
const closeGroup = () => { |
|
|
|
groupVisible.value = false; |
|
|
|
groupFormRef.value.resetFields(); |
|
|
|
groupForm.name = ""; |
|
|
|
}; |
|
|
|
// 新增编辑分组 |
|
|
|
const append = (type: string, data: Tree) => { |
|
|
|
groupVisible.value = true; |
|
|
|
if (type == "edit") { |
|
|
|
groupForm.name = data.name; |
|
|
|
groupForm.id = data.id; |
|
|
|
} |
|
|
|
const onSubmit = () => { |
|
|
|
groupFormRef.value.validate((valid:any) => { |
|
|
|
if (valid) { |
|
|
|
closeGroup() |
|
|
|
ElMessage.success('提交成功'); |
|
|
|
}; |
|
|
|
// 删除分组 |
|
|
|
async function remove(id: string[], msg: string) { |
|
|
|
await useHandleData(monitorLIVEApi.deleteGroup, { id }, msg); |
|
|
|
getGroupList(); |
|
|
|
} |
|
|
|
// 提交分组 |
|
|
|
const onSubmit = () => { |
|
|
|
groupFormRef.value.validate((valid: any) => { |
|
|
|
if (valid) { |
|
|
|
let params: any = reactive({ |
|
|
|
id: "", |
|
|
|
name: groupForm.name |
|
|
|
}); |
|
|
|
if (!groupForm.id) { |
|
|
|
monitorLIVEApi.addGroup(params).then(res => { |
|
|
|
if (res.code == 200) { |
|
|
|
getGroupList(); |
|
|
|
closeGroup(); |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
return false; |
|
|
|
params.id = groupForm.id; |
|
|
|
monitorLIVEApi.updateGroup(params).then(res => { |
|
|
|
if (res.code == 200) { |
|
|
|
getGroupList(); |
|
|
|
closeGroup(); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
}); |
|
|
|
}; |
|
|
|
// 摄像头分组 |
|
|
|
closeGroup(); |
|
|
|
} else { |
|
|
|
return false; |
|
|
|
} |
|
|
|
}); |
|
|
|
}; |
|
|
|
// 摄像头分组过滤 |
|
|
|
interface Tree { |
|
|
|
id: any |
|
|
|
label: string |
|
|
|
children?: Tree[] |
|
|
|
[key: string]: any; |
|
|
|
id: any; |
|
|
|
label: string; |
|
|
|
children?: Tree[]; |
|
|
|
} |
|
|
|
let id = 1000 |
|
|
|
const filterText = ref(""); |
|
|
|
|
|
|
|
watch(filterText, val => { |
|
|
|
treeRef.value!.filter(val); |
|
|
|
}); |
|
|
|
|
|
|
|
const filterNode = (value: string, data: Tree) => { |
|
|
|
if (!value) return true; |
|
|
|
return data.name.includes(value); |
|
|
|
}; |
|
|
|
|
|
|
|
const handleNodeClick = (data: Tree) => { |
|
|
|
console.log(data) |
|
|
|
} |
|
|
|
console.log(data); |
|
|
|
// personSetId.value = val |
|
|
|
proTable.value!.pageable.pageNum = 1; |
|
|
|
proTable.value!.searchParam.groupId = data.id; |
|
|
|
proTable.value!.search(); |
|
|
|
}; |
|
|
|
|
|
|
|
// 设置分组推送人 |
|
|
|
// async function pushPerson(type:string,data: Tree) { |
|
|
|
|
|
|
|
// } |
|
|
|
const visible = ref(false); //是否显示表单 |
|
|
|
|
|
|
|
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) |
|
|
|
const proTable = ref<ProTableInstance>(); |
|
|
|
const dictStore = useDictStore(); |
|
|
|
|
|
|
|
const treeData = ref<Tree[]>([ |
|
|
|
// 表格配置项 |
|
|
|
const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ |
|
|
|
{ type: "selection", fixed: "left", width: 80 }, |
|
|
|
{ |
|
|
|
id: '', |
|
|
|
label: '全部', |
|
|
|
|
|
|
|
prop: "sensorId", |
|
|
|
label: "摄像头ID" |
|
|
|
}, |
|
|
|
{ |
|
|
|
id: '-1', |
|
|
|
label: '无分组', |
|
|
|
|
|
|
|
prop: "sensorName", |
|
|
|
label: "摄像头名称" |
|
|
|
}, |
|
|
|
{ |
|
|
|
id: 1, |
|
|
|
label: '走廊', |
|
|
|
|
|
|
|
prop: "fieldName", |
|
|
|
label: "所属学校" |
|
|
|
}, |
|
|
|
{ |
|
|
|
id: 2, |
|
|
|
label: '大厅', |
|
|
|
|
|
|
|
prop: "directUrlIp", |
|
|
|
label: "设备ip" |
|
|
|
}, |
|
|
|
{ |
|
|
|
id: 3, |
|
|
|
label: '厨房', |
|
|
|
|
|
|
|
prop: "resWidth", |
|
|
|
label: "分辨率", |
|
|
|
render: row => { |
|
|
|
return row.row.resWidth + "*" + row.row.resHeight; |
|
|
|
} |
|
|
|
}, |
|
|
|
]) |
|
|
|
// 新增分组 |
|
|
|
const append = (type:string,data: Tree) => { |
|
|
|
console.log(type,data) |
|
|
|
groupVisible.value = true; |
|
|
|
if(type == 'edit') { |
|
|
|
groupForm.name = treeData.value.find(item => item.id ==data.id).label; |
|
|
|
} |
|
|
|
{ prop: "operation", label: "操作", width: 250, fixed: "right" } |
|
|
|
]; |
|
|
|
// 移动分组禁用 |
|
|
|
const moveFormRef = ref<InstanceType<typeof Form> | null>(null); |
|
|
|
function omMove(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) { |
|
|
|
console.log(record,"record") |
|
|
|
|
|
|
|
|
|
|
|
// const newChild = { id: id++, label: 'testtest', children: [] } |
|
|
|
// if (!data.children) { |
|
|
|
// data.children = [] |
|
|
|
// } |
|
|
|
// data.children.push(newChild) |
|
|
|
// treeData.value = [...treeData.value] |
|
|
|
moveFormRef.value?.omMove({ opt: opt, records: record, successful: RefreshTable }); |
|
|
|
} |
|
|
|
// 删除分组 |
|
|
|
const remove = (node: Node, data: Tree) => { |
|
|
|
const parent = node.parent |
|
|
|
const children: Tree[] = parent.data.children || parent.data |
|
|
|
const index = children.findIndex((d) => d.id === data.id) |
|
|
|
children.splice(index, 1) |
|
|
|
treeData.value = [...treeData.value] |
|
|
|
/** |
|
|
|
* 删除 |
|
|
|
* @param ids id数组 |
|
|
|
*/ |
|
|
|
async function onDelete(ids: string[], msg: string) { |
|
|
|
return; |
|
|
|
// 二次确认 => 请求api => 刷新表格 |
|
|
|
await useHandleData(monitorLIVEApi.delete, { ids }, msg); |
|
|
|
RefreshTable(); |
|
|
|
} |
|
|
|
// 设置分组推送人 |
|
|
|
// async function pushPerson(type:string,data: Tree) { |
|
|
|
|
|
|
|
// } |
|
|
|
const visible = ref(false); //是否显示表单 |
|
|
|
|
|
|
|
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) |
|
|
|
const proTable = ref<ProTableInstance>(); |
|
|
|
const dictStore = useDictStore(); |
|
|
|
|
|
|
|
// 表格配置项 |
|
|
|
const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ |
|
|
|
{ type: "selection", fixed: "left", width: 80 }, |
|
|
|
// { prop: "searchKey", label: "关键字", search: { el: "input" }, isShow: false }, |
|
|
|
// { |
|
|
|
// prop: "poiId", |
|
|
|
// label: "所属学校", |
|
|
|
// render: () => { |
|
|
|
// return "演示学校"; |
|
|
|
// } |
|
|
|
// }, |
|
|
|
{ |
|
|
|
prop: "sensorId", |
|
|
|
label: "摄像头ID", |
|
|
|
// render: () => { |
|
|
|
// return "楼道"; |
|
|
|
// } |
|
|
|
}, |
|
|
|
{ |
|
|
|
prop: "sensorName", |
|
|
|
label: "摄像头名称", |
|
|
|
// render: () => { |
|
|
|
// return "楼道"; |
|
|
|
// } |
|
|
|
}, |
|
|
|
{ |
|
|
|
prop: "fieldName", |
|
|
|
label: "所属学校", |
|
|
|
}, |
|
|
|
{ |
|
|
|
prop: "directUrlIp", |
|
|
|
label: "设备ip", |
|
|
|
}, |
|
|
|
{ |
|
|
|
prop: "resWidth", |
|
|
|
label: "分辨率", |
|
|
|
render: (row) => { |
|
|
|
return row.row.resWidth + '*' + row.row.resHeight; |
|
|
|
} |
|
|
|
}, |
|
|
|
{ prop: "operation", label: "操作", width: 250, fixed: "right" } |
|
|
|
]; |
|
|
|
|
|
|
|
/** |
|
|
|
* 删除 |
|
|
|
* @param ids id数组 |
|
|
|
*/ |
|
|
|
async function onDelete(ids: string[], msg: string) { |
|
|
|
return |
|
|
|
// 二次确认 => 请求api => 刷新表格 |
|
|
|
await useHandleData(monitorLIVEApi.delete, { ids }, msg); |
|
|
|
RefreshTable(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const moveFormRef = ref<InstanceType<typeof Form> | null>(null); |
|
|
|
function omMove(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) { |
|
|
|
moveFormRef.value?.omMove({ opt: opt, record: record, successful: RefreshTable }); |
|
|
|
/** |
|
|
|
* 刷新表格 |
|
|
|
*/ |
|
|
|
function RefreshTable() { |
|
|
|
proTable.value?.refresh(); |
|
|
|
} |
|
|
|
/** |
|
|
|
* 刷新表格 |
|
|
|
*/ |
|
|
|
function RefreshTable() { |
|
|
|
proTable.value?.refresh(); |
|
|
|
} |
|
|
|
// 表单引用 |
|
|
|
// 表单引用 |
|
|
|
const formRef = ref<InstanceType<typeof Form> | null>(null); |
|
|
|
/** |
|
|
|
/** |
|
|
|
* 打开表单 |
|
|
|
* @param opt 操作类型 |
|
|
|
* @param record 记录 |
|
|
@@ -318,9 +309,9 @@ function onOpen(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) { |
|
|
|
} |
|
|
|
|
|
|
|
// 人员选择 |
|
|
|
// 表单引用 |
|
|
|
const userFormRef = ref<InstanceType<typeof Form> | null>(null); |
|
|
|
/** |
|
|
|
// 表单引用 |
|
|
|
const userFormRef = ref<InstanceType<typeof Form> | null>(null); |
|
|
|
/** |
|
|
|
* 打开表单 |
|
|
|
* @param opt 操作类型 |
|
|
|
* @param record 记录 |
|
|
@@ -328,183 +319,179 @@ function onOpen(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) { |
|
|
|
function pushPerson(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) { |
|
|
|
userFormRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); |
|
|
|
} |
|
|
|
// 详情数据 |
|
|
|
// let detailData: globalThis.Ref<{}> |
|
|
|
let detailData = reactive({ |
|
|
|
title: '', |
|
|
|
videoUrl: '', |
|
|
|
sensorId: '', |
|
|
|
streamId: '', |
|
|
|
videoToken:'', |
|
|
|
videoType: '' |
|
|
|
}); |
|
|
|
function onDetail(row: any) { |
|
|
|
|
|
|
|
visible.value = true; |
|
|
|
detailData.sensorId = row.sensorId; |
|
|
|
detailData.title = row.sensorName + '('+ row.sensorId + ')'; |
|
|
|
getUrl() |
|
|
|
|
|
|
|
} |
|
|
|
// 刷新 |
|
|
|
// var showVideo = false |
|
|
|
const showVideo = ref(false) |
|
|
|
function refreshUrl() { |
|
|
|
stopUrl(); |
|
|
|
showVideo.value = false; |
|
|
|
setTimeout(()=> { |
|
|
|
showVideo.value = true; |
|
|
|
getUrl() |
|
|
|
},1000) |
|
|
|
|
|
|
|
} |
|
|
|
let num = 1; |
|
|
|
function getUrl() { |
|
|
|
detailData.videoType = 'm3u8' |
|
|
|
setTimeout(async ()=> { |
|
|
|
await monitorLIVEApi.detail({ sensorId: detailData.sensorId}).then(res => { |
|
|
|
let { code, data } = res; |
|
|
|
|
|
|
|
if (code == 200) { |
|
|
|
// window.location.origin+ |
|
|
|
detailData.videoUrl = ''; |
|
|
|
detailData.videoUrl= data.rtsPullStreamUrls[0].url; |
|
|
|
// detailData.videoUrl = data.pullStreamUrls[2].url; |
|
|
|
detailData.streamId = data.streamId; |
|
|
|
detailData.videoToken = data.videoToken; |
|
|
|
// getvideo1() |
|
|
|
getvideo2() |
|
|
|
} |
|
|
|
}); |
|
|
|
}) |
|
|
|
} |
|
|
|
function getvideo1() { |
|
|
|
let aliRts = new AliRTS() |
|
|
|
// let url = detailData.videoUrl.replace('http://rts-pull-live.deepeleph.com', '/Files') |
|
|
|
// console.log(url,888) |
|
|
|
let pullStreamUrl = detailData.videoUrl; |
|
|
|
const mediaEle = document.querySelector('video'); |
|
|
|
aliRts.on("onError", (err) => { |
|
|
|
console.log(`errorCode: ${err.errorCode}`); |
|
|
|
console.log(`message: ${err.message}`); |
|
|
|
}) |
|
|
|
// 详情数据 |
|
|
|
// let detailData: globalThis.Ref<{}> |
|
|
|
let detailData = reactive({ |
|
|
|
title: "", |
|
|
|
videoUrl: "", |
|
|
|
sensorId: "", |
|
|
|
streamId: "", |
|
|
|
videoToken: "", |
|
|
|
videoType: "" |
|
|
|
}); |
|
|
|
function onDetail(row: any) { |
|
|
|
visible.value = true; |
|
|
|
detailData.sensorId = row.sensorId; |
|
|
|
detailData.title = row.sensorName + "(" + row.sensorId + ")"; |
|
|
|
getUrl(); |
|
|
|
} |
|
|
|
// 刷新 |
|
|
|
const showVideo = ref(false); |
|
|
|
function refreshUrl() { |
|
|
|
stopUrl(); |
|
|
|
showVideo.value = false; |
|
|
|
setTimeout(() => { |
|
|
|
showVideo.value = true; |
|
|
|
getUrl(); |
|
|
|
}, 1000); |
|
|
|
} |
|
|
|
let num = 1; |
|
|
|
function getUrl() { |
|
|
|
detailData.videoType = "m3u8"; |
|
|
|
setTimeout(async () => { |
|
|
|
await monitorLIVEApi.detail({ sensorId: detailData.sensorId }).then((res:any) => { |
|
|
|
let { code, data } = res; |
|
|
|
|
|
|
|
const PLAY_EVENT = { |
|
|
|
CANPLAY: "canplay", |
|
|
|
WAITING: "waiting", |
|
|
|
PLAYING: "playing" |
|
|
|
} |
|
|
|
if (code == '200') { |
|
|
|
// window.location.origin+ |
|
|
|
detailData.videoUrl = ""; |
|
|
|
detailData.videoUrl = data.rtsPullStreamUrls[0].url; |
|
|
|
// detailData.videoUrl = data.pullStreamUrls[2].url; |
|
|
|
detailData.streamId = data.streamId; |
|
|
|
detailData.videoToken = data.videoToken; |
|
|
|
// getvideo1() |
|
|
|
getvideo2(); |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
function getvideo1() { |
|
|
|
let aliRts = new AliRTS(); |
|
|
|
let pullStreamUrl = detailData.videoUrl; |
|
|
|
const mediaEle = document.querySelector("video"); |
|
|
|
aliRts.on("onError", err => { |
|
|
|
console.log(`errorCode: ${err.errorCode}`); |
|
|
|
console.log(`message: ${err.message}`); |
|
|
|
}); |
|
|
|
|
|
|
|
aliRts.on('onPlayEvent', (play) => { |
|
|
|
console.log(">>play.event:" + play.event); |
|
|
|
if (play.event === PLAY_EVENT.CANPLAY) { |
|
|
|
// 拉流可以播放 |
|
|
|
console.log('可以播放') |
|
|
|
} else if (play.event === PLAY_EVENT.WAITING) { |
|
|
|
// 拉流卡顿等待缓冲中 (仅Chrome) |
|
|
|
console.log('拉流卡顿等待缓冲中') |
|
|
|
const PLAY_EVENT = { |
|
|
|
CANPLAY: "canplay", |
|
|
|
WAITING: "waiting", |
|
|
|
PLAYING: "playing" |
|
|
|
}; |
|
|
|
|
|
|
|
} else if (play.event === PLAY_EVENT.PLAYING) { |
|
|
|
// 拉流卡顿结束恢复播放 (仅Chrome) |
|
|
|
console.log('拉流卡顿结束恢复播放') |
|
|
|
} |
|
|
|
}); |
|
|
|
aliRts.startLiveStream(pullStreamUrl, mediaEle); |
|
|
|
// aliRts.startLiveStream(pullStreamUrl, mediaEle); |
|
|
|
} |
|
|
|
let player = ref(null); |
|
|
|
function getvideo2() { |
|
|
|
var options = { |
|
|
|
"id": "player-con", |
|
|
|
"source": detailData.videoUrl + '&subaudio=no&jitterbuffer=6000', |
|
|
|
// "rtsFallbackSource": "降级地址,如HLS", |
|
|
|
"width": "100%", |
|
|
|
"height": "600px", |
|
|
|
"autoplay": true, |
|
|
|
"isLive": true, |
|
|
|
"playsinline": true, |
|
|
|
"skipRtsSupportCheck": false, // 对于不在 https://help.aliyun.com/document_detail/397569.html 中的浏览器,可以传 true 跳过检查,强制使用 RTS(有风险,需要自测保证) |
|
|
|
aliRts.on("onPlayEvent", play => { |
|
|
|
console.log(">>play.event:" + play.event); |
|
|
|
if (play.event === PLAY_EVENT.CANPLAY) { |
|
|
|
// 拉流可以播放 |
|
|
|
console.log("可以播放"); |
|
|
|
} else if (play.event === PLAY_EVENT.WAITING) { |
|
|
|
// 拉流卡顿等待缓冲中 (仅Chrome) |
|
|
|
console.log("拉流卡顿等待缓冲中"); |
|
|
|
} else if (play.event === PLAY_EVENT.PLAYING) { |
|
|
|
// 拉流卡顿结束恢复播放 (仅Chrome) |
|
|
|
console.log("拉流卡顿结束恢复播放"); |
|
|
|
} |
|
|
|
}); |
|
|
|
aliRts.startLiveStream(pullStreamUrl, mediaEle); |
|
|
|
// aliRts.startLiveStream(pullStreamUrl, mediaEle); |
|
|
|
} |
|
|
|
let player = ref<any>(null); |
|
|
|
function getvideo2() { |
|
|
|
var options = { |
|
|
|
id: "player-con", |
|
|
|
source: detailData.videoUrl + "&subaudio=no&jitterbuffer=6000", |
|
|
|
// "rtsFallbackSource": "降级地址,如HLS", |
|
|
|
width: "100%", |
|
|
|
height: "600px", |
|
|
|
autoplay: true, |
|
|
|
isLive: true, |
|
|
|
playsinline: true, |
|
|
|
skipRtsSupportCheck: false, // 对于不在 https://help.aliyun.com/document_detail/397569.html 中的浏览器,可以传 true 跳过检查,强制使用 RTS(有风险,需要自测保证) |
|
|
|
|
|
|
|
/** |
|
|
|
* RTS 拉流超时会默认重试 |
|
|
|
* 以下两个参数用来控制降级之前的重试策略,比如 3000 毫秒超时,重试一次,如果再拉不到流就降级,那么总共等待 6000 毫秒降级 |
|
|
|
**/ |
|
|
|
// RTS 多久拉不到流会重试,默认 3000 ms |
|
|
|
rtsLoadDataTimeout: 1500, |
|
|
|
/** |
|
|
|
* RTS 拉流超时会默认重试 |
|
|
|
* 以下两个参数用来控制降级之前的重试策略,比如 3000 毫秒超时,重试一次,如果再拉不到流就降级,那么总共等待 6000 毫秒降级 |
|
|
|
**/ |
|
|
|
// RTS 多久拉不到流会重试,默认 3000 ms |
|
|
|
rtsLoadDataTimeout: 1500, |
|
|
|
|
|
|
|
// RTS 拉不到流重试的次数,默认 5,此参数建议设为 1,即重试 1 次后降级,可以减少降级等待时间 |
|
|
|
liveRetry: 1, |
|
|
|
}; |
|
|
|
// RTS 拉不到流重试的次数,默认 5,此参数建议设为 1,即重试 1 次后降级,可以减少降级等待时间 |
|
|
|
liveRetry: 1 |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
player.value = new Aliplayer(options, function () {/* player ready */ }) |
|
|
|
player.value = new Aliplayer(options, function () { |
|
|
|
/* player ready */ |
|
|
|
}); |
|
|
|
|
|
|
|
// 降级时会触发此事件 |
|
|
|
player.value.on('rtsFallback', function (event) { |
|
|
|
console.log('[EVENT]rtsFallback', event.paramData); |
|
|
|
// event.paramData.reason 降级的原因 |
|
|
|
// event.paramData.fallbackUrl 降级到的地址 |
|
|
|
}) |
|
|
|
// 降级时会触发此事件 |
|
|
|
player.value.on("rtsFallback", function (event:any) { |
|
|
|
console.log("[EVENT]rtsFallback", event.paramData); |
|
|
|
// event.paramData.reason 降级的原因 |
|
|
|
// event.paramData.fallbackUrl 降级到的地址 |
|
|
|
}); |
|
|
|
|
|
|
|
player.value.on('error', function (event) { |
|
|
|
console.log('[EVENT]error', event.paramData); |
|
|
|
}) |
|
|
|
player.value.on("error", function (event:any) { |
|
|
|
console.log("[EVENT]error", event.paramData); |
|
|
|
}); |
|
|
|
|
|
|
|
// 当RTS拉流成功时触发,通过订阅该事件,可以获取到RTS TraceId |
|
|
|
player.value.on('rtsTraceId', function (data) { |
|
|
|
console.log('[EVENT]rtsTraceId', data.paramData); |
|
|
|
// event.paramData.traceId 拉流的TraceId |
|
|
|
// event.paramData.source 当前RTS流的播放地址 |
|
|
|
}) |
|
|
|
// 当RTS拉流成功时触发,通过订阅该事件,可以获取到RTS TraceId |
|
|
|
player.value.on("rtsTraceId", function (data:any) { |
|
|
|
console.log("[EVENT]rtsTraceId", data.paramData); |
|
|
|
// event.paramData.traceId 拉流的TraceId |
|
|
|
// event.paramData.source 当前RTS流的播放地址 |
|
|
|
}); |
|
|
|
} |
|
|
|
const handleClose = () => { |
|
|
|
visible.value = false; |
|
|
|
detailData.videoUrl = ""; |
|
|
|
detailData.videoType = ""; |
|
|
|
stopUrl(); |
|
|
|
if (player.value) { |
|
|
|
player.value.dispose(); |
|
|
|
} |
|
|
|
const handleClose = () => { |
|
|
|
visible.value = false; |
|
|
|
detailData.videoUrl = '' |
|
|
|
detailData.videoType = '' |
|
|
|
stopUrl(); |
|
|
|
if(player.value) { |
|
|
|
player.value.dispose(); |
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
function stopUrl() { |
|
|
|
detailData.videoUrl = '' |
|
|
|
if(player.value) { |
|
|
|
player.value.dispose(); |
|
|
|
} |
|
|
|
let params = { |
|
|
|
sensorId: detailData.sensorId, |
|
|
|
streamId: detailData.streamId, |
|
|
|
videoToken: detailData.videoToken |
|
|
|
} |
|
|
|
setTimeout(async ()=> { |
|
|
|
await monitorLIVEApi.stopUrl(params).then(res => { |
|
|
|
let { code, data, msg } = res; |
|
|
|
|
|
|
|
if (code == 200) { |
|
|
|
// ElMessage.success(msg); |
|
|
|
} |
|
|
|
}); |
|
|
|
}) |
|
|
|
}; |
|
|
|
function stopUrl() { |
|
|
|
detailData.videoUrl = ""; |
|
|
|
if (player.value) { |
|
|
|
player.value.dispose(); |
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<style lang="scss" scoped> |
|
|
|
@import url("https://g.alicdn.com/apsara-media-box/imp-web-player/2.16.3/skins/default/aliplayer-min.css"); |
|
|
|
let params = { |
|
|
|
sensorId: detailData.sensorId, |
|
|
|
streamId: detailData.streamId, |
|
|
|
videoToken: detailData.videoToken |
|
|
|
}; |
|
|
|
setTimeout(async () => { |
|
|
|
await monitorLIVEApi.stopUrl(params).then((res:any) => { |
|
|
|
let { code, data, msg } = res; |
|
|
|
|
|
|
|
if (code == 200) { |
|
|
|
// ElMessage.success(msg); |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
onMounted(() => { |
|
|
|
getGroupList(); |
|
|
|
}); |
|
|
|
</script> |
|
|
|
|
|
|
|
<style lang="scss" scoped> |
|
|
|
@import "https://g.alicdn.com/apsara-media-box/imp-web-player/2.16.3/skins/default/aliplayer-min.css"; |
|
|
|
@import "./index.scss"; |
|
|
|
.dialogHeader { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
margin: 20px; |
|
|
|
color: #409efc; |
|
|
|
font-size: 18px; |
|
|
|
color: #409efc; |
|
|
|
cursor: pointer; |
|
|
|
.dialogBtn { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |
|
|
|
|