|
@@ -1,5 +1,12 @@
|
|
|
<template>
|
|
|
<a-spin :spinning="spinning">
|
|
|
+ <furnitureCard
|
|
|
+ v-if="isEditDraggable"
|
|
|
+ v-model:is-edit="isEditDraggable"
|
|
|
+ :style="{ marginTop: '30px' }"
|
|
|
+ @add="addHnadler"
|
|
|
+ ></furnitureCard>
|
|
|
+
|
|
|
<div class="viewer">
|
|
|
<div class="viewer-header">
|
|
|
<div>
|
|
@@ -18,8 +25,8 @@
|
|
|
type="primary"
|
|
|
size="small"
|
|
|
:disabled="!isEditDraggable"
|
|
|
- @click="saveFurnitureMapConfig"
|
|
|
- >保存家具</a-button
|
|
|
+ @click="saveAllConfig"
|
|
|
+ >保存配置</a-button
|
|
|
>
|
|
|
</a-space>
|
|
|
</div>
|
|
@@ -31,6 +38,7 @@
|
|
|
:style="{
|
|
|
width: `${areaWidth}px`,
|
|
|
height: `${areaHeight}px`,
|
|
|
+ cursor: !isEditDraggable ? 'no-drop' : 'default',
|
|
|
}"
|
|
|
@mousedown="handleMouseDownMapCanvas"
|
|
|
>
|
|
@@ -130,18 +138,23 @@
|
|
|
<div class="mapConfig-item">
|
|
|
<div class="mapConfig-item-label">删除家具:</div>
|
|
|
<div class="mapConfig-item-content">
|
|
|
- <DeleteOutlined @click="deleteFurnitureIcon(clickedDragItem?.nanoid || '')" />
|
|
|
+ <a-popconfirm
|
|
|
+ v-if="clickedDragItem.type === 'bed'"
|
|
|
+ placement="bottom"
|
|
|
+ @confirm="deleteFurnitureBed(clickedDragItem?.nanoid || '')"
|
|
|
+ >
|
|
|
+ <template #icon><question-circle-outlined style="color: red" /></template>
|
|
|
+ <template #title>
|
|
|
+ <div>删除 “床”也会删除子区域,</div>
|
|
|
+ <div>是否继续删除?</div>
|
|
|
+ </template>
|
|
|
+ <DeleteOutlined />
|
|
|
+ </a-popconfirm>
|
|
|
+ <DeleteOutlined v-else @click="deleteFurnitureIcon(clickedDragItem?.nanoid || '')" />
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
- <furnitureCard
|
|
|
- v-if="isEditDraggable"
|
|
|
- v-model:is-edit="isEditDraggable"
|
|
|
- :style="{ marginTop: '30px' }"
|
|
|
- @add="addHnadler"
|
|
|
- ></furnitureCard>
|
|
|
</div>
|
|
|
|
|
|
<div class="viewer">
|
|
@@ -152,10 +165,9 @@
|
|
|
</div>
|
|
|
<div class="viewer-header-extra">
|
|
|
<a-space>
|
|
|
- <a-button size="small" @click="createNewBlock">{{
|
|
|
+ <a-button size="small" :disabled="!isEditDraggable" @click="createNewBlock">{{
|
|
|
isCreating ? '创建中...' : '新建区域'
|
|
|
}}</a-button>
|
|
|
- <a-button type="primary" size="small" @click="saveBlockConfig">保存子区域</a-button>
|
|
|
</a-space>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -166,7 +178,7 @@
|
|
|
:style="{
|
|
|
width: `${areaWidth}px`,
|
|
|
height: `${areaHeight}px`,
|
|
|
- cursor: isCreating ? 'crosshair' : 'default',
|
|
|
+ cursor: !isEditDraggable ? 'no-drop' : isCreating ? 'crosshair' : 'default',
|
|
|
}"
|
|
|
@mousedown="handleMouseDown"
|
|
|
>
|
|
@@ -208,14 +220,21 @@
|
|
|
top: `${block.y}px`,
|
|
|
width: `${block.width}px`,
|
|
|
height: `${block.height}px`,
|
|
|
- border: `2px solid ${block.isActice ? 'yellow' : '#1890ff'}`,
|
|
|
+ border: `2px solid ${block?.isBed ? '#1abc1a' : block.isActice ? 'yellow' : '#1890ff'}`,
|
|
|
position: 'absolute',
|
|
|
- cursor: 'move',
|
|
|
+ cursor: !isEditDraggable ? 'no-drop' : 'move',
|
|
|
+ backgroundColor: block.isBed ? 'rgba(26, 188, 26, 0.1)' : 'rgba(24, 144, 255, 0.1)',
|
|
|
}"
|
|
|
@mousedown="startDrag(block, $event)"
|
|
|
@click="selectBlock(block)"
|
|
|
>
|
|
|
- <div class="resize-handle" @mousedown.stop="startResize(block, $event)">
|
|
|
+ <div
|
|
|
+ class="resize-handle"
|
|
|
+ :style="{
|
|
|
+ backgroundColor: block.isBed ? '#1abc1a' : '#1890ff',
|
|
|
+ }"
|
|
|
+ @mousedown.stop="startResize(block, $event)"
|
|
|
+ >
|
|
|
{{ blockIndex + 1 }}
|
|
|
</div>
|
|
|
</div>
|
|
@@ -303,6 +322,11 @@
|
|
|
</div>
|
|
|
|
|
|
<div class="mapConfig-item">
|
|
|
+ <div class="mapConfig-item-label">呼吸检测:</div>
|
|
|
+ <div class="mapConfig-item-content"> 默认开启 </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="mapConfig-item">
|
|
|
<div class="mapConfig-item-label">删除区域:</div>
|
|
|
<div class="mapConfig-item-content">
|
|
|
<DeleteOutlined @click="deleteBlockArea(selectedBlock.id || '')" />
|
|
@@ -332,6 +356,7 @@ import {
|
|
|
ArrowLeftOutlined,
|
|
|
ArrowRightOutlined,
|
|
|
DeleteOutlined,
|
|
|
+ QuestionCircleOutlined,
|
|
|
} from '@ant-design/icons-vue'
|
|
|
|
|
|
defineOptions({
|
|
@@ -416,7 +441,7 @@ const fetchRoomLayout = async () => {
|
|
|
|
|
|
if (subRegions) {
|
|
|
// 将接口的子区域,添加在子区域画布上
|
|
|
- subRegions.forEach((item) => {
|
|
|
+ subRegions.forEach((item, index) => {
|
|
|
blocks.value.push({
|
|
|
// 本地需要使用的数据
|
|
|
id: nanoid(),
|
|
@@ -431,21 +456,24 @@ const fetchRoomLayout = async () => {
|
|
|
isActice: false,
|
|
|
isTracking: Boolean(item.trackPresence),
|
|
|
isFalling: Boolean(item.excludeFalling),
|
|
|
+ isBed: index === 0 && mapCanvasList.value.some((item) => item.type === 'bed'),
|
|
|
// 来自接口回显的数据
|
|
|
startXx: item.startXx,
|
|
|
stopXx: item.stopXx,
|
|
|
startYy: item.startYy,
|
|
|
stopYy: item.stopYy,
|
|
|
- startZz: 0,
|
|
|
- stopZz: 0,
|
|
|
- isLowSnr: 0,
|
|
|
- isDoor: 0,
|
|
|
- presenceEnterDuration: 3,
|
|
|
- presenceExitDuration: 3,
|
|
|
+ startZz: item.startZz,
|
|
|
+ stopZz: item.stopZz,
|
|
|
+ isLowSnr: item.isLowSnr,
|
|
|
+ isDoor: item.isDoor,
|
|
|
+ presenceEnterDuration: item.presenceEnterDuration,
|
|
|
+ presenceExitDuration: item.presenceExitDuration,
|
|
|
trackPresence: item.trackPresence,
|
|
|
excludeFalling: item.excludeFalling,
|
|
|
})
|
|
|
})
|
|
|
+
|
|
|
+ console.log('🚀', blocks.value)
|
|
|
}
|
|
|
spinning.value = false
|
|
|
} catch (error) {
|
|
@@ -479,6 +507,15 @@ const isEditDraggable = ref(false)
|
|
|
// 家具列表添加
|
|
|
const addHnadler = (icon: FurnitureIconType) => {
|
|
|
console.log('addHnadler', icon)
|
|
|
+ // 检查画布上是否已经添加过了 icon 为 bed 的家具
|
|
|
+ if (icon === 'bed') {
|
|
|
+ const isExist = mapCanvasList.value.some((item) => item.type === icon)
|
|
|
+ if (isExist) {
|
|
|
+ message.error('床已经添加过了,不可重复添加')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
const { originOffsetX, originOffsetY } = getOriginPosition()
|
|
|
// 家具原始宽高
|
|
|
const originWidth = furnitureIconSizeMap[icon].width || 30
|
|
@@ -496,7 +533,41 @@ const addHnadler = (icon: FurnitureIconType) => {
|
|
|
nanoid: nanoid(),
|
|
|
isActice: false,
|
|
|
})
|
|
|
- message.success('已添加')
|
|
|
+ message.success('已添加家具')
|
|
|
+ if (icon === 'bed') {
|
|
|
+ // 同步添加一个子区域
|
|
|
+ blocks.value.unshift({
|
|
|
+ // 本地用
|
|
|
+ id: nanoid(),
|
|
|
+ x: 20,
|
|
|
+ y: 15,
|
|
|
+ ox: -150,
|
|
|
+ oy: 180,
|
|
|
+ width: originWidth,
|
|
|
+ height: originHeight,
|
|
|
+ isDragging: false,
|
|
|
+ isResizing: false,
|
|
|
+ isActice: false,
|
|
|
+ isTracking: false,
|
|
|
+ isFalling: false,
|
|
|
+ isBed: true,
|
|
|
+ // 接口用
|
|
|
+ startXx: -150,
|
|
|
+ stopXx: -100,
|
|
|
+ startYy: 180,
|
|
|
+ stopYy: 120,
|
|
|
+ startZz: 0,
|
|
|
+ stopZz: 0,
|
|
|
+ isLowSnr: 1,
|
|
|
+ isDoor: 0,
|
|
|
+ presenceEnterDuration: 3,
|
|
|
+ presenceExitDuration: 3,
|
|
|
+ trackPresence: 0,
|
|
|
+ excludeFalling: 0,
|
|
|
+ })
|
|
|
+ console.log('blocks', blocks.value)
|
|
|
+ message.success('已添加子区域')
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
const contentEl = ref<HTMLElement>()
|
|
@@ -654,6 +725,15 @@ const deleteFurnitureIcon = (nanoid: string) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 删除家具床
|
|
|
+const deleteFurnitureBed = (nanoid: string) => {
|
|
|
+ console.log('deleteFurnitureBed', nanoid)
|
|
|
+ // 先从家具画布移除床
|
|
|
+ deleteFurnitureIcon(nanoid)
|
|
|
+ // 再从子区域画布删除对应的子区域
|
|
|
+ blocks.value.shift()
|
|
|
+}
|
|
|
+
|
|
|
// 新增区块类型
|
|
|
interface BlockItem {
|
|
|
// 本地用
|
|
@@ -667,8 +747,9 @@ interface BlockItem {
|
|
|
isDragging: boolean // 是否正在拖动
|
|
|
isResizing: boolean // 是否正在调整大小
|
|
|
isActice: boolean // 是否选中
|
|
|
- isTracking: boolean // 是否开启区域跟踪 0-否,1-是
|
|
|
- isFalling: boolean // 是否屏蔽区域跌倒检测 0-否,1-是
|
|
|
+ isTracking: boolean // 是否开启区域跟踪 0-否,1-是 对应 trackPresence 字段
|
|
|
+ isFalling: boolean // 是否屏蔽区域跌倒检测 0-否,1-是 对应 excludeFalling 字段
|
|
|
+ isBed?: boolean // 是否是床 本地判断使用
|
|
|
// 接口用
|
|
|
startXx: number // 屏蔽子区域X开始
|
|
|
stopXx: number // 屏蔽子区域X结束
|
|
@@ -676,7 +757,7 @@ interface BlockItem {
|
|
|
stopYy: number // 屏蔽子区域Y结束
|
|
|
startZz: number // 屏蔽子区域Z开始
|
|
|
stopZz: number // 屏蔽子区域Z结束
|
|
|
- isLowSnr: number // 默认0
|
|
|
+ isLowSnr: number // 是否为床 0-不是,1-是
|
|
|
isDoor: number // 是否是门 0-否,1-是 默认0
|
|
|
presenceEnterDuration: number // 人员进入时间 默认3
|
|
|
presenceExitDuration: number // 人员离开时间 默认3
|
|
@@ -711,6 +792,7 @@ const getContainerRect = () => {
|
|
|
|
|
|
// 鼠标事件处理
|
|
|
const handleMouseDown = (e: MouseEvent) => {
|
|
|
+ if (!isEditDraggable.value) return
|
|
|
console.log('handleMouseDown', e)
|
|
|
blocks.value.forEach((item) => {
|
|
|
item.isActice = false
|
|
@@ -789,6 +871,7 @@ const handleMouseUp = () => {
|
|
|
|
|
|
// 区块拖动
|
|
|
const startDrag = (block: BlockItem, e: MouseEvent) => {
|
|
|
+ if (!isEditDraggable.value) return
|
|
|
console.log('startDrag', block)
|
|
|
e.stopPropagation()
|
|
|
block.isDragging = true
|
|
@@ -826,6 +909,7 @@ const startDrag = (block: BlockItem, e: MouseEvent) => {
|
|
|
}
|
|
|
|
|
|
const selectBlock = (block: BlockItem) => {
|
|
|
+ if (!isEditDraggable.value) return
|
|
|
console.log('selectBlock', block)
|
|
|
selectedBlock.value = block
|
|
|
blocks.value.forEach((item) => {
|
|
@@ -834,37 +918,37 @@ const selectBlock = (block: BlockItem) => {
|
|
|
}
|
|
|
|
|
|
// 保存子区域配置
|
|
|
-const saveBlockConfig = () => {
|
|
|
- const blockData = blocks.value.map((item) => {
|
|
|
- return {
|
|
|
- startXx: item.startXx,
|
|
|
- stopXx: item.stopXx,
|
|
|
- startYy: item.startYy,
|
|
|
- stopYy: item.stopYy,
|
|
|
- startZz: Number(item.startZz) || 0,
|
|
|
- stopZz: Number(item.stopZz) || 0,
|
|
|
- isLowSnr: item.isLowSnr,
|
|
|
- isDoor: item.isDoor,
|
|
|
- presenceEnterDuration: item.presenceEnterDuration,
|
|
|
- presenceExitDuration: item.presenceExitDuration,
|
|
|
- trackPresence: Number(item.isTracking),
|
|
|
- excludeFalling: Number(item.isFalling),
|
|
|
- }
|
|
|
- })
|
|
|
- console.log('当前所有区块配置:', blockData)
|
|
|
- try {
|
|
|
- const res = roomApi.saveRoomInfo({
|
|
|
- roomId: deviceRoomId.value,
|
|
|
- devId: props.devId,
|
|
|
- subRegions: blockData,
|
|
|
- })
|
|
|
- console.log('saveBlockConfig 保存成功', res)
|
|
|
- message.success('保存成功')
|
|
|
- emit('success')
|
|
|
- } catch (error) {
|
|
|
- console.error('saveBlockConfig 保存失败', error)
|
|
|
- }
|
|
|
-}
|
|
|
+// const saveBlockConfig = () => {
|
|
|
+// const blockData = blocks.value.map((item) => {
|
|
|
+// return {
|
|
|
+// startXx: item.startXx,
|
|
|
+// stopXx: item.stopXx,
|
|
|
+// startYy: item.startYy,
|
|
|
+// stopYy: item.stopYy,
|
|
|
+// startZz: Number(item.startZz) || 0,
|
|
|
+// stopZz: Number(item.stopZz) || 0,
|
|
|
+// isLowSnr: item.isLowSnr,
|
|
|
+// isDoor: item.isDoor,
|
|
|
+// presenceEnterDuration: item.presenceEnterDuration,
|
|
|
+// presenceExitDuration: item.presenceExitDuration,
|
|
|
+// trackPresence: Number(item.isTracking),
|
|
|
+// excludeFalling: Number(item.isFalling),
|
|
|
+// }
|
|
|
+// })
|
|
|
+// console.log('当前所有区块配置:', blockData)
|
|
|
+// try {
|
|
|
+// const res = roomApi.saveRoomInfo({
|
|
|
+// roomId: deviceRoomId.value,
|
|
|
+// devId: props.devId,
|
|
|
+// subRegions: blockData,
|
|
|
+// })
|
|
|
+// console.log('saveBlockConfig 保存成功', res)
|
|
|
+// message.success('保存成功')
|
|
|
+// emit('success')
|
|
|
+// } catch (error) {
|
|
|
+// console.error('saveBlockConfig 保存失败', error)
|
|
|
+// }
|
|
|
+// }
|
|
|
|
|
|
/**
|
|
|
* 获取坐标位置
|
|
@@ -956,8 +1040,56 @@ const initRadarIcon = () => {
|
|
|
}
|
|
|
|
|
|
// 保存家具配置
|
|
|
-const saveFurnitureMapConfig = () => {
|
|
|
- console.log('saveFurnitureMapConfig', mapCanvasList.value)
|
|
|
+// const saveFurnitureMapConfig = () => {
|
|
|
+// console.log('saveFurnitureMapConfig', mapCanvasList.value)
|
|
|
+// try {
|
|
|
+// const res = roomApi.saveRoomInfo({
|
|
|
+// roomId: deviceRoomId.value,
|
|
|
+// devId: props.devId,
|
|
|
+// furnitures: mapCanvasList.value
|
|
|
+// .filter((item) => item.type !== 'radar')
|
|
|
+// .map((item) => {
|
|
|
+// return {
|
|
|
+// name: item.name,
|
|
|
+// type: item.type as FurnitureType,
|
|
|
+// width: item.width,
|
|
|
+// length: item.height,
|
|
|
+// top: item.top,
|
|
|
+// left: item.left,
|
|
|
+// rotate: item.rotate as 0 | 90 | 180 | 270,
|
|
|
+// x: item?.x || 0,
|
|
|
+// y: item?.y || 0,
|
|
|
+// }
|
|
|
+// }),
|
|
|
+// })
|
|
|
+// console.log('保存家具配置 成功', res)
|
|
|
+// message.success('保存成功')
|
|
|
+// emit('success')
|
|
|
+// } catch (error) {
|
|
|
+// console.error('保存家具配置 失败', error)
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// 保存所有配置
|
|
|
+const saveAllConfig = () => {
|
|
|
+ console.log('保存所有配置')
|
|
|
+ const blockData = blocks.value.map((item) => {
|
|
|
+ return {
|
|
|
+ startXx: item.startXx,
|
|
|
+ stopXx: item.stopXx,
|
|
|
+ startYy: item.startYy,
|
|
|
+ stopYy: item.stopYy,
|
|
|
+ startZz: Number(item.startZz) || 0,
|
|
|
+ stopZz: Number(item.stopZz) || 0,
|
|
|
+ isLowSnr: item.isLowSnr,
|
|
|
+ isDoor: item.isDoor,
|
|
|
+ presenceEnterDuration: item.presenceEnterDuration,
|
|
|
+ presenceExitDuration: item.presenceExitDuration,
|
|
|
+ trackPresence: Number(item.isTracking),
|
|
|
+ excludeFalling: Number(item.isFalling),
|
|
|
+ }
|
|
|
+ })
|
|
|
+ console.log('当前所有区块配置:', blockData)
|
|
|
try {
|
|
|
const res = roomApi.saveRoomInfo({
|
|
|
roomId: deviceRoomId.value,
|
|
@@ -977,12 +1109,13 @@ const saveFurnitureMapConfig = () => {
|
|
|
y: item?.y || 0,
|
|
|
}
|
|
|
}),
|
|
|
+ subRegions: blockData,
|
|
|
})
|
|
|
- console.log('保存家具配置 成功', res)
|
|
|
+ console.log('保存所有配置 成功', res)
|
|
|
message.success('保存成功')
|
|
|
emit('success')
|
|
|
} catch (error) {
|
|
|
- console.error('保存家具配置 失败', error)
|
|
|
+ console.error('保存所有配置 失败', error)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1072,7 +1205,7 @@ const deleteBlockArea = (id: string) => {
|
|
|
padding: 10px;
|
|
|
min-width: 500px;
|
|
|
flex-shrink: 0;
|
|
|
- margin-top: 10px;
|
|
|
+ // margin-top: 10px;
|
|
|
|
|
|
&-header {
|
|
|
display: flex;
|