-
-
+
diff --git a/src/views/alarm/policyConfig/monitorPoint/drawAreaBak.vue b/src/views/alarm/policyConfig/monitorPoint/drawAreaBak.vue
new file mode 100644
index 0000000..919cc3b
--- /dev/null
+++ b/src/views/alarm/policyConfig/monitorPoint/drawAreaBak.vue
@@ -0,0 +1,224 @@
+
+
+
+
+
+
+
diff --git a/public/player/player.html b/public/player/player.html
index dcc534b..93ffb30 100644
--- a/public/player/player.html
+++ b/public/player/player.html
@@ -13,6 +13,7 @@
height: 100vh;
background: rgba(13, 14, 27, 0.7);
overflow: hidden;
+ padding: 0px !important;
}
diff --git a/src/assets/styles/globals.scss b/src/assets/styles/globals.scss
index eff72d0..a49b40f 100644
--- a/src/assets/styles/globals.scss
+++ b/src/assets/styles/globals.scss
@@ -9,7 +9,8 @@
--g-header-height: 60px;
// 侧边栏宽度
--g-main-sidebar-width: 70px;
- --g-sub-sidebar-width: 180px;
+ // --g-sub-sidebar-width: 180px;
+ --g-sub-sidebar-width: 220px;
// 侧边栏Logo高度
--g-sidebar-logo-height: 50px;
// 顶栏高度
diff --git a/src/main.ts b/src/main.ts
index f91e0d9..ef31da6 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -31,6 +31,7 @@
.then((result) => {
console.log('get config')
console.log(result)
+ if (Object.prototype.toString.call(result.data) !== '[object Object]') { return }
window.localStorage.setItem('baseurl-safe', result.data.baseUrl)
request.defaults.baseURL = result.data.baseUrl // 设置默认请求网址
window.localStorage.setItem('baseURL', result.data.baseUrl)
diff --git a/src/router/modules/alarm.ts b/src/router/modules/alarm.ts
index f8109ab..908735c 100644
--- a/src/router/modules/alarm.ts
+++ b/src/router/modules/alarm.ts
@@ -71,7 +71,7 @@
{
path: 'videoPreviewList',
name: 'PolicyConfigVideoPreviewList',
- component: () => import('@/views/alarm/policyConfig/videoPreview/index-media-single.vue'),
+ component: () => import('@/views/alarm/policyConfig/videoPreview/videoPreview.vue'),
meta: {
title: '视频预览',
icon: 'ep:key',
diff --git a/src/utils/useCheckList.ts b/src/utils/useCheckList.ts
index fb5f8ac..608bb98 100644
--- a/src/utils/useCheckList.ts
+++ b/src/utils/useCheckList.ts
@@ -13,7 +13,7 @@
// 检查必填
if (prop.required && !item[prop.value]) {
// ElMessage.warning(`请先完善${tableTitle}第${index + 1}行中${prop.text}`)
- ElMessage.warning(`请先完善${tableTitle}中【${item.typeName}】的${prop.text}`)
+ ElMessage.warning(`请先完善${tableTitle}中【${item.typeName || item.recognitionTypeName}】的${prop.text}`)
return false
}
// 验证正则
diff --git a/src/views/alarm/policyConfig/monitorPoint/drawArea.vue b/src/views/alarm/policyConfig/monitorPoint/drawArea.vue
index 6e72273..9346cbc 100644
--- a/src/views/alarm/policyConfig/monitorPoint/drawArea.vue
+++ b/src/views/alarm/policyConfig/monitorPoint/drawArea.vue
@@ -3,29 +3,48 @@
dialogStatus: {
type: String,
},
+ points: {
+ type: Array,
+ default: () => [],
+ },
})
-const emits = defineEmits(['givePoints'])
-const points = ref([ // 标记点初始
- { x: 50, y: 50 }, // 左上
- { x: 150, y: 50 },
- { x: 150, y: 150 },
- { x: 50, y: 150 },
-])
-onMounted(() => {
- const canvas: any = document.getElementById('myCanvas')
- const container: any = document.getElementById('draw-area')
- const ctx = canvas.getContext('2d')
- ctx.clearRect(0, 0, container.clientWidth, container.clientHeight)
+const emits = defineEmits(['givepointsInfo'])
+const baseurl = ref(window.location.href.split('/#')[0])
+const canvas = ref(null) as any
+const myCtx = ref(null) as any
+const container = ref([]) as any
+const style = ref([]) as any // 点的位置
+const pointsInfo = ref([]) as any // 标记位置信息
+const initDraw = () => {
+ if (!pointsInfo.value.length) {
+ return
+ }
+ const ctx = myCtx.value
// 初始位置
function draw() {
- ctx.clearRect(0, 0, canvas.width, canvas.height)
- ctx.beginPath()
- ctx.moveTo(points.value[0].x, points.value[0].y)
- ctx.lineTo(points.value[1].x, points.value[1].y)
- ctx.lineTo(points.value[2].x, points.value[2].y)
- ctx.lineTo(points.value[3].x, points.value[3].y)
- ctx.closePath()
- ctx.strokeStyle = 'red'
+ ctx.clearRect(0, 0, canvas.value.width, canvas.value.height)
+ if (pointsInfo.value && pointsInfo.value.length) {
+ ctx.beginPath()
+ pointsInfo.value.forEach((e: any) => {
+ if (e.boundary && e.boundary.length) { // 画线
+ ctx.moveTo(e.boundary[0].x, e.boundary[0].y)
+ ctx.lineTo(e.boundary[1].x, e.boundary[1].y)
+ ctx.lineTo(e.boundary[2].x, e.boundary[2].y)
+ ctx.lineTo(e.boundary[3].x, e.boundary[3].y)
+ }
+ // ctx.strokeStyle = e.pointColor
+ ctx.strokeStyle = '#ff0000'
+ ctx.closePath()
+ ctx.font = '13px Arial'
+ // ctx.fillStyle = e.pointColor
+ ctx.fillStyle = '#ff0000'
+ // const minY = Math.min(e.boundary[0].y, e.boundary[1].y, e.boundary[2].y, e.boundary[3].y)
+ // const minX = Math.min(e.boundary[0].x, e.boundary[1].x, e.boundary[2].x, e.boundary[3].x)
+ const textX = e.boundary[0].x === 0 ? 0 : e.boundary[0].x + 3 > 540 ? 540 : e.boundary[0].x + 3
+ const textY = e.boundary[0].y < 12 ? 12 : e.boundary[0].y > 438 ? 438 : e.boundary[0].y - 5
+ ctx.fillText(e.recognitionTypeName, textX, textY)
+ })
+ }
ctx.lineWidth = 1
ctx.stroke()
}
@@ -36,26 +55,36 @@
}
e = e || window.event
e.preventDefault()
- var mousePos = { x: e.clientX - canvas.getBoundingClientRect().left, y: e.clientY - canvas.getBoundingClientRect().top }
- console.log(mousePos, 'mousePos')
+ var mousePos = { x: e.clientX - canvas.value.getBoundingClientRect().left, y: e.clientY - canvas.value.getBoundingClientRect().top }
// 限制在指定区域内
if (mousePos.x < 0) {
mousePos.x = 0
}
- else if (mousePos.x > container.clientWidth) {
- mousePos.x = container.clientWidth
+ else if (mousePos.x > 600) {
+ mousePos.x = 600
}
if (mousePos.y < 0) {
mousePos.y = 0
}
- else if (mousePos.y > container.clientHeight) {
- mousePos.y = container.clientHeight
+ else if (mousePos.y > 450) {
+ mousePos.y = 450
}
- points.value[pointIndex].x = mousePos.x
- points.value[pointIndex].y = mousePos.y
+ const { quotient, remainder } = divideAndModulo(pointIndex, 4)
+ console.log(`移动的是第${quotient + 1}条数据,第${remainder + 1}个点`)
+ pointsInfo.value[quotient].boundary[remainder].x = mousePos.x
+ pointsInfo.value[quotient].boundary[remainder].y = mousePos.y
draw()
}
+ function divideAndModulo(dividend: number, divisor: number) {
+ const quotient = Math.floor(dividend / divisor) // 求商
+ const remainder = dividend % divisor // 求余数
+ return {
+ quotient,
+ remainder,
+ }
+ }
+
function addDragEvents() {
if (props.dialogStatus === 'detail') {
return
@@ -76,10 +105,10 @@
},
}
- var pointsElements = document.getElementsByClassName('point')
- for (var i = 0; i < pointsElements.length; i++) {
- pointsElements[i].addEventListener('mousedown', dragEvents.dragStart)
- pointsElements[i].setAttribute('data-point-index', `${i}`)
+ var pointsInfoElements = document.getElementsByClassName('point')
+ for (var i = 0; i < pointsInfoElements.length; i++) {
+ pointsInfoElements[i].addEventListener('mousedown', dragEvents.dragStart)
+ pointsInfoElements[i].setAttribute('data-point-index', `${i}`)
}
}
@@ -88,56 +117,65 @@
addDragEvents()
}
init()
+}
+
+onMounted(() => {
+ canvas.value = document.getElementById('myCanvas')
+ myCtx.value = canvas.value.getContext('2d')
})
-const style = ref([
- {
- top: `${points.value[0].y - 5}px`,
- left: `${points.value[0].x - 5}px`,
- },
- {
- top: `${points.value[1].y - 5}px`,
- left: `${points.value[1].x - 5}px`,
- },
- {
- top: `${points.value[2].y - 5}px`,
- left: `${points.value[2].x - 5}px`,
- },
- {
- top: `${points.value[3].y - 5}px`,
- left: `${points.value[3].x - 5}px`,
- },
-])
+const removeCanvas = () => {
+ if (myCtx.value) {
+ myCtx.value.clearRect(0, 0, canvas.value.width, canvas.value.height)
+ }
+ pointsInfo.value = []
+}
-watch(() => points.value, () => {
- emits('givePoints', points.value)
- style.value = [
- {
- top: `${points.value[0].y - 5}px`,
- left: `${points.value[0].x - 5}px`,
- },
- {
- top: `${points.value[1].y - 5}px`,
- left: `${points.value[1].x - 5}px`,
- },
- {
- top: `${points.value[2].y - 5}px`,
- left: `${points.value[2].x - 5}px`,
- },
- {
- top: `${points.value[3].y - 5}px`,
- left: `${points.value[3].x - 5}px`,
- },
- ]
+watch(() => props.points, (newValue: any) => {
+ console.log('监听点位信息', newValue)
+ if (newValue && newValue.length) {
+ pointsInfo.value = newValue
+ nextTick(() => {
+ initDraw()
+ })
+ }
+ else {
+ pointsInfo.value = newValue
+ if (myCtx.value) {
+ myCtx.value.clearRect(0, 0, canvas.value.width, canvas.value.height)
+ }
+ }
}, {
deep: true,
+ immediate: true,
})
+
+watch(() => pointsInfo.value, (newValue: any) => {
+ emits('givepointsInfo', newValue)
+}, {
+ deep: true,
+ immediate: true,
+})
+
+defineExpose({ removeCanvas })
-
-
-
+
diff --git a/src/views/alarm/policyConfig/monitorPoint/drawAreaBak.vue b/src/views/alarm/policyConfig/monitorPoint/drawAreaBak.vue
new file mode 100644
index 0000000..919cc3b
--- /dev/null
+++ b/src/views/alarm/policyConfig/monitorPoint/drawAreaBak.vue
@@ -0,0 +1,224 @@
+
+
+
+
+
+
+
diff --git a/src/views/alarm/policyConfig/monitorPoint/editDialog.vue b/src/views/alarm/policyConfig/monitorPoint/editDialog.vue
index 36618a7..d60f330 100644
--- a/src/views/alarm/policyConfig/monitorPoint/editDialog.vue
+++ b/src/views/alarm/policyConfig/monitorPoint/editDialog.vue
@@ -8,18 +8,24 @@
import drawArea from './drawArea.vue'
import type { TableColumn } from '@/components/NormalTable/table_interface'
import { isIp } from '@/utils/validate'
+import { getMediaStream, getMediaToken } from '@/api/monitor/media'
import { useCheckList } from '@/utils/useCheckList'
import { getBoxList, getModelList, getRecognitionList, getSceneList, updateMonitorPoint } from '@/api/alarm/policyConfig/monitorPoint'
const emits = defineEmits(['closeRefresh'])
const dialogStatus = ref('add')
+const baseurl = ref(window.location.href.split('/#')[0])
const dialogVisible = ref(false) // 弹窗显示隐藏
+const mediaToken = ref('') // 流媒体token
+const mediaUrl = ref('') // 流媒体url
+const cameraIndexCode = ref('') // 设备国标号
+const nvrIndexCode = ref('') // nvr国标号
// 显示标题
const textMap: { [key: string]: string } = {
detail: '详情',
edit: '编辑',
add: '新增',
}
-
+const menu = ref([])
// 表单数据对象
const formData: Ref
= ref({
id: '',
@@ -37,6 +43,8 @@
boundary: '', // 识别边界
})
const selectModelList = ref([]) // 选择的算法
+const drawAreaRef = ref()
+const points = ref([]) as any // 标记点位置信息
const algorithmTableRef = ref()
const btnLoading = ref(false) // 保存按钮加载状态
const formDataRef = ref() // 表单对象
@@ -108,36 +116,54 @@
ElMessage.warning('请选择报警对象')
return false
}
- if (!useCheckList(selectModelList.value, columns.value, '报警对象')) {
+ const checkList = [] as any
+ selectModelList.value.forEach((item: { id: string }) => {
+ const index = recognitionList.value.findIndex((i: { id: string }) => i.id === item.id)
+ if (index !== -1) {
+ checkList.push(recognitionList.value[index])
+ }
+ })
+ if (!useCheckList(checkList, columns.value, '报警对象')) {
return false
}
}
if (formDataRef.value) {
formDataRef.value?.validate((valid: boolean) => {
if (valid) {
- selectModelList.value.forEach((item: any) => {
- const index = recognitionList.value.findIndex((i: { id: string }) => i.id === item.id)
- if (index !== -1) {
- recognitionList.value.splice(index, 1, { ...item, isUse: '1' })
- }
- else {
- recognitionList.value.splice(index, 1, { ...item, isUse: '0' })
- }
- })
- const params = {
- ...formData.value,
- sceneRelation: formData.value.type === 1 ? { id: formData.value.id, sceneId: formData.value.sceneId } : null,
- // eslint-disable-next-line multiline-ternary
- deviceModelRelations: formData.value.type === 0 ? recognitionList.value.map((item: any) => {
+ let tempList = [] as any
+ if (formData.value.type === 0) { // 算法
+ // 把是否使用全都置为0
+ recognitionList.value = recognitionList.value.map((e: { isUse: string }) => {
+ return {
+ ...e,
+ isUse: '0',
+ }
+ })
+ // 把画点的是否使用置为1
+ points.value.forEach((itemOut: any) => {
+ const index = recognitionList.value.findIndex((itemIn: any) => itemOut.recognitionTypeId === itemIn.recognitionTypeId)
+ if (index !== -1) {
+ recognitionList.value[index] = { ...itemOut, isUse: '1' }
+ }
+ })
+ tempList = recognitionList.value.map((item: any) => {
return {
...item,
algoModelId: formData.value.algoModelId, // 算法模型id
confidenceLevel: item.confidenceLevel, // 置信度
- isUse: item.isUse,
recognitionTypeId: item.recognitionTypeId, // 模型识别类型
threshold: item.threshold, // 阈值
+ remark: item.recognitionTypeName, // 危险因素描述
+ boundary: item.boundary ? JSON.stringify(item.boundary) : item.boundary,
}
- }) : [],
+ })
+ }
+
+ const params = {
+ ...formData.value,
+ sceneRelation: formData.value.type === 1 ? { id: formData.value.id, sceneId: formData.value.sceneId } : null,
+ // eslint-disable-next-line multiline-ternary
+ deviceModelRelations: tempList,
}
console.log('要传的参数', params)
updateMonitorPoint(params).then(() => {
@@ -172,8 +198,57 @@
recognitionList.value = [] // 报警对象列表
}
+// 取随机颜色
+function getRandomColor() {
+ const r = Math.floor(Math.random() * 256) // 0-255
+ const g = Math.floor(Math.random() * 256) // 0-255
+ const b = Math.floor(Math.random() * 256) // 0-255
+ // const a = Math.random().toFixed(2) // 0-1
+ const a = 1 // 0-1
+ return `rgba(${r}, ${g}, ${b}, ${a})`
+}
+// 多选
const selectModel = (value: any) => {
- selectModelList.value = value
+ // console.log('监听算法报警对象的变化,更新区域绘制', value)
+ selectModelList.value = value.map((item: any) => {
+ return {
+ ...item,
+ pointColor: getRandomColor(),
+ }
+ })
+ if (formData.value.type === 0) { // 算法模式
+ let tempList = []
+ console.log('----------------------', points.value)
+ console.log('[[[[[[[[[[[[[[[]]]]]]]', value)
+ tempList = value.map((i: any, index: number) => {
+ const findIndex = points.value.findIndex((item: { recognitionTypeId: string }) => {
+ console.log(item.recognitionTypeId)
+ console.log(i.recognitionTypeId)
+ console.log(i.recognitionTypeId === item.recognitionTypeId)
+
+ return i.recognitionTypeId === item.recognitionTypeId
+ })
+ if (findIndex === -1) {
+ console.log('没找到', i.recognitionTypeName)
+ return {
+ ...i,
+ remark: i.recognitionTypeName,
+ boundary: [ // 标记点位置
+ { x: 50 + index * 30, y: 50 + index * 30 },
+ { x: 150 + index * 30, y: 50 + index * 30 },
+ { x: 150 + index * 30, y: 150 + index * 30 },
+ { x: 50 + index * 30, y: 150 + index * 30 },
+ ],
+ }
+ }
+ else {
+ console.log('找到了', i.recognitionTypeName)
+ return { ...i, ...points.value[findIndex] }
+ }
+ })
+ points.value = tempList
+ console.log('多选制作的数据', points.value)
+ }
}
// -----------------------------------初始化、关闭对话框相关-----------------------------------------
@@ -191,82 +266,123 @@
formData.value.deviceId = row.deviceId // 设备id
formData.value.recognitionUrl = row.recognitionUrl || 'http://192.168.83.42/recognitionUrl'// 识别流地址
formData.value.rtspUrl = row.rtspUrl || 'http://192.168.83.42/rtsp' // rtsp地址
- // formData.value.boundary = formData.value.boundary ? JSON.parse(formData.value.boundary) : formData.value.boundary // 识别边界
+
if (`${row.type}` === '0') { // 算法关联
formData.value.algoModelId = row.deviceModelRelations && row.deviceModelRelations.length && row.deviceModelRelations[0].algoModelId // 模型id
- recognitionList.value = row.deviceModelRelations.map((item: any) => {
+ // 处理一下返回的数据格式
+ const resultList = row.deviceModelRelations.map((item: any) => {
return {
...item,
confidenceLevel: `${item.confidenceLevel}` ? Number(item.confidenceLevel) : undefined,
threshold: `${item.threshold}` ? Number(item.threshold) : undefined,
+ boundary: item.boundary ? JSON.parse(item.boundary) : item.boundary,
}
})
-
- // 恢复选中状态
- const selectedRows = recognitionList.value.filter((item: any) => `${item.isUse}` === '1')
- if (selectedRows && Array.isArray(selectedRows) && selectedRows.length) {
- nextTick(() => {
- selectedRows.forEach((row: any) => {
- algorithmTableRef.value?.toggleRowSelection(row, true)
- })
+ // 先请求所有的数据,因为场景有可能变化
+ changeAlgoModelId(formData.value.algoModelId).then((res: any) => {
+ // 把其余的没有添加的报警对象给添加上
+ resultList.forEach((itemOut: any) => {
+ const index = recognitionList.value.findIndex((itemIn: any) => itemOut.recognitionTypeId === itemIn.recognitionTypeId)
+ if (index !== -1) {
+ recognitionList.value[index] = { ...itemOut }
+ }
})
- }
+
+ // 原来选中的数据:进行默认选中
+ const selectedRows = recognitionList.value.filter((e: { isUse: string }) => e.isUse === '1') // 把选中的找出来
+ if (selectedRows && Array.isArray(selectedRows) && selectedRows.length) {
+ nextTick(() => {
+ // 默认选中
+ selectedRows.forEach((row: any) => {
+ algorithmTableRef.value?.toggleRowSelection(row, true)
+ })
+ points.value = selectedRows // 画图
+ })
+ }
+ })
}
else if (`${row.type}` === '1') { // 业务场景
formData.value.sceneId = row.sceneRelation.sceneId
}
}
-
if (dialogstatus === 'detail') {
formDataRef.value?.clearValidate()
}
dialogStatus.value = dialogstatus // 类型 新建add 编辑edit 详情detail
+ cameraIndexCode.value = row.cameraIndexCode || '' // 设备国标号
+ nvrIndexCode.value = row.nvrIndexCode || '' // nvr国标号
+ if (cameraIndexCode.value && nvrIndexCode.value) {
+ fetchMediaStream(cameraIndexCode.value, nvrIndexCode.value)
+ }
btnLoading.value = false
}
// 关闭并刷新
function closeRefresh() {
+ drawAreaRef.value.removeCanvas()
dialogVisible.value = false
+ mediaToken.value = '' // 流媒体token
+ mediaToken.value = '' // 流媒体url
+ mediaToken.value = '' // 设备国标号
+ mediaToken.value = '' // nvr国标号
resetForm()
emits('closeRefresh')
}
// 监听算法变化,查询算法报警对象
-const changeAlgoModelId = (newValue: string) => {
- if (newValue) {
+async function changeAlgoModelId(modelId: string) {
+ if (modelId) {
// 获取场景对象
const params = {
- modelId: newValue, // 模型ID
+ modelId, // 模型ID
typeCode: '', // 类型编码
typeName: '', // 类型名称
}
- getRecognitionList(params).then((res) => {
- recognitionList.value = res.data.map((item: { id: string; typeName: string }) => {
- return {
- ...item,
- recognitionTypeName: item.typeName,
- recognitionTypeId: item.id,
- id: '',
- }
- })
+ const res = await getRecognitionList(params)
+ recognitionList.value = res.data.map((item: { id: string; typeName: string }) => {
+ return {
+ ...item,
+ recognitionTypeName: item.typeName,
+ recognitionTypeId: item.id,
+ id: '',
+ }
})
}
}
+// -------------------------------------------区域绘制相关-----------------------------------------------
const givePoints = (value: any) => {
- formData.value.boundary = JSON.stringify(value)
+ console.log('监听到子组件数据变化', value)
+ points.value = value
}
-// ----------------------- 以下是暴露的方法内容 ----------------------------
+
+// ----------------------------------------------取流---------------------------------------------------------
+// 拉取流--普通流
+async function fetchMediaStream(deviceId: string, channelId: string) {
+ // 获取流媒体token
+ const response = await getMediaToken()
+ mediaToken.value = response.data
+ // 取流
+ const res = await getMediaStream(deviceId, channelId, mediaToken.value)
+ if (res && res.data) {
+ mediaUrl.value = res.data.flv
+ }
+ else {
+ ElMessage.warning('设备未注册')
+ }
+}
+
+// ---------------------------------------------- 以下是暴露的方法内容 ---------------------------------------------------------
defineExpose({ initDialog })
-
+
-
- -->
+