index.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. <template>
  2. <a-spin :spinning="spinning">
  3. <a-alert
  4. v-if="areaAvailable"
  5. message="检测区域范围未配置或数值较小,请在设备配置调整参数!"
  6. banner
  7. />
  8. <div class="viewer">
  9. <div class="viewer-header">
  10. <div class="viewer-header-title">家具与子区域配置</div>
  11. <div class="viewer-header-extra">
  12. <a-space>
  13. <span v-if="props.online === 0" style="color: red">⚠️设备离线,不允许编辑保存</span>
  14. <a-switch
  15. :checked="isEditDraggable"
  16. checked-children="启用"
  17. un-checked-children="禁用"
  18. :disabled="props.online === 0"
  19. @change="isEditDraggable = !isEditDraggable"
  20. />
  21. <a-button
  22. type="primary"
  23. size="small"
  24. :disabled="!isEditDraggable"
  25. @click="saveAllConfig"
  26. >保存配置</a-button
  27. >
  28. </a-space>
  29. </div>
  30. </div>
  31. <RadarEditor
  32. v-if="!areaAvailable"
  33. ref="radarEditorRef"
  34. :coordinates="props.ranges"
  35. :angle="props.angle"
  36. :disabled="!isEditDraggable"
  37. />
  38. </div>
  39. </a-spin>
  40. </template>
  41. <script setup lang="ts">
  42. import { ref, computed } from 'vue'
  43. import * as roomApi from '@/api/room'
  44. import { message } from 'ant-design-vue'
  45. import RadarEditor from '@/components/RadarEditor/index.vue'
  46. import { useRoomStore } from '@/stores/room'
  47. import {
  48. convert_furniture_r2c,
  49. convert_region_c2r,
  50. convert_region_r2c,
  51. rotateRect_ccw,
  52. rotateRect_cw,
  53. } from '@/utils/coordTransform'
  54. defineOptions({
  55. name: 'deviceAreaConfig',
  56. })
  57. type Props = {
  58. devId: string // 设备id,用于获取房间布局
  59. // x,y的范围,用于初始化画布的大小
  60. length: number
  61. width: number
  62. ranges: [number, number, number, number] // 区域范围
  63. angle: number // 设备角度,用于初始化画布的旋转角度
  64. online?: SwitchType | 9 // 设备在线状态,用于判断是否可以保存配置
  65. }
  66. const emit = defineEmits<{
  67. (e: 'success', value: void): void
  68. }>()
  69. const props = withDefaults(defineProps<Props>(), {
  70. devId: '',
  71. length: 0, // 区域宽度
  72. width: 0, // 区域高度
  73. ranges: () => [Infinity, Infinity, Infinity, Infinity], // 区域范围
  74. online: 0,
  75. })
  76. const deviceRoomId = ref('')
  77. const roomStore = useRoomStore()
  78. // 检测区域宽度 length
  79. const areaWidth = computed(() => {
  80. return Math.abs(props.length)
  81. })
  82. // 检测区域高度 width
  83. const areaHeight = computed(() => {
  84. return Math.abs(props.width)
  85. })
  86. // 检测区域是否可用,小于50cm的区域,不可用
  87. const areaAvailable = computed(() => {
  88. return areaWidth.value < 50 || areaHeight.value < 50
  89. })
  90. const spinning = ref(false)
  91. // 获取房间布局
  92. const fetchRoomLayout = async () => {
  93. console.log('fetchRoomLayout', props, props.devId)
  94. if (!props.devId) {
  95. message.error('设备ID不能为空')
  96. return
  97. }
  98. try {
  99. spinning.value = true
  100. const res = await roomApi.queryRoomInfo({
  101. devId: props.devId,
  102. })
  103. console.log('✅获取到房间布局信息', res)
  104. if (!res) {
  105. spinning.value = false
  106. return
  107. }
  108. const { furnitures, roomId, subRegions } = res.data
  109. deviceRoomId.value = roomId || ''
  110. roomStore.cacheFurniture(furnitures ?? [])
  111. roomStore.cacheSubRegion(subRegions ?? [])
  112. spinning.value = false
  113. roomStore.localFurnitureItems = roomStore.localFurnitureItems.map((item) => {
  114. const itemConvert = convert_furniture_r2c(
  115. {
  116. x: item.x,
  117. y: item.y,
  118. width: item.width,
  119. height: item.length,
  120. },
  121. {
  122. x_radar: 250,
  123. y_radar: 250,
  124. }
  125. )
  126. const rotatedRect = rotateRect_cw(
  127. {
  128. left: itemConvert.left,
  129. top: itemConvert.top,
  130. width: item.width,
  131. height: item.length,
  132. },
  133. {
  134. x: 250,
  135. y: 250,
  136. },
  137. props.angle
  138. )
  139. return {
  140. ...item,
  141. left: rotatedRect.left,
  142. top: rotatedRect.top,
  143. width: rotatedRect.width,
  144. length: rotatedRect.height,
  145. }
  146. })
  147. } catch (error) {
  148. console.error('❌获取房间布局信息失败', error)
  149. spinning.value = false
  150. roomStore.cacheFurniture([])
  151. roomStore.cacheSubRegion([])
  152. }
  153. }
  154. fetchRoomLayout()
  155. const radarEditorRef = ref<InstanceType<typeof RadarEditor>>()
  156. // 画布上的家具列表
  157. const isEditDraggable = ref(false)
  158. // 保存所有配置
  159. const saveAllConfig = () => {
  160. console.log('保存所有配置', {
  161. furnitureItems: roomStore.localFurnitureItems,
  162. subRegions: roomStore.localSubRegions,
  163. })
  164. const furnitureItems = roomStore.localFurnitureItems.map((item) => {
  165. return {
  166. name: item.name,
  167. type: item.type,
  168. width: item.width,
  169. length: item.length,
  170. rotate: item.rotate,
  171. x: item?.x || 0,
  172. y: item?.y || 0,
  173. }
  174. })
  175. console.log('保存的家具数据📚📚📚📚📚📚furnitureItems', furnitureItems)
  176. const subRegions = roomStore.localSubRegions.map((item) => {
  177. const pRadar = {
  178. x: 250,
  179. y: 250,
  180. }
  181. const rectRotatedBefore = convert_region_r2c(
  182. {
  183. x_cm_start: Number(item.startXx),
  184. x_cm_stop: Number(item.stopXx),
  185. y_cm_start: Number(item.startYy),
  186. y_cm_stop: Number(item.stopYy),
  187. },
  188. {
  189. x_radar: 250,
  190. y_radar: 250,
  191. }
  192. )
  193. const rectRotatedBack = rotateRect_ccw(rectRotatedBefore, pRadar, props.angle)
  194. const newRegion = convert_region_c2r(rectRotatedBack, {
  195. x_radar: 250,
  196. y_radar: 250,
  197. })
  198. return {
  199. startXx: newRegion.x_cm_start,
  200. stopXx: newRegion.x_cm_stop,
  201. startYy: newRegion.y_cm_start,
  202. stopYy: newRegion.y_cm_stop,
  203. startZz: item.startZz,
  204. stopZz: item.stopZz,
  205. isLowSnr: Number(item.isBed),
  206. isDoor: item.isDoor,
  207. presenceEnterDuration: item.presenceEnterDuration,
  208. presenceExitDuration: item.presenceExitDuration,
  209. trackPresence: Number(item.isTracking),
  210. excludeFalling: Number(item.isFalling),
  211. }
  212. })
  213. try {
  214. const res = roomApi.saveRoomInfo({
  215. roomId: deviceRoomId.value,
  216. devId: props.devId,
  217. furnitures: furnitureItems,
  218. subRegions,
  219. })
  220. console.log('保存所有配置 ✅', res)
  221. message.success('保存成功')
  222. emit('success')
  223. } catch (error) {
  224. console.error('保存所有配置 ❌', error)
  225. }
  226. }
  227. </script>
  228. <style scoped lang="less">
  229. .viewer {
  230. flex-shrink: 0;
  231. &-header {
  232. display: flex;
  233. justify-content: space-between;
  234. padding-bottom: 20px;
  235. &-title {
  236. font-size: 16px;
  237. font-weight: 600;
  238. line-height: 24px;
  239. }
  240. }
  241. &-content {
  242. display: flex;
  243. gap: 20px;
  244. }
  245. }
  246. </style>