|
@@ -17,52 +17,80 @@
|
|
|
<text>3</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
- <view
|
|
|
- class="airCantInfo"
|
|
|
- :style="{
|
|
|
- width: `${length / 150}px`,
|
|
|
- height: `${width / 150}px`,
|
|
|
- }"
|
|
|
- >
|
|
|
+ <view class="radar-box">
|
|
|
<view
|
|
|
- v-for="(item, index) in modules"
|
|
|
- :key="index"
|
|
|
- class="module-content"
|
|
|
+ :style="{
|
|
|
+ width: `${length / 200}px`,
|
|
|
+ height: `${width / 200}px`,
|
|
|
+ position: 'relative',
|
|
|
+ }"
|
|
|
+ :class="[
|
|
|
+ width < 25500 && length < 25000
|
|
|
+ ? 'tranStyle'
|
|
|
+ : 'center',
|
|
|
+ ]"
|
|
|
>
|
|
|
<view
|
|
|
- :class="item.type"
|
|
|
- :style="{
|
|
|
- width: `${item.width / 2}px`,
|
|
|
- height: `${item.length / 2}px`,
|
|
|
- top: `${item.top / 2}px`,
|
|
|
- left: `${item.left / 2}px`,
|
|
|
- transform: `rotate(${item.rotate}deg)`,
|
|
|
- 'transform-origin': 'center center',
|
|
|
- }"
|
|
|
- @touchmove.prevent="onTouchMove(index, $event)"
|
|
|
- @touchstart="onTouchStart(index, $event)"
|
|
|
- @touchend="onTouchEnd(index, $event)"
|
|
|
+ v-for="(item, index) in modules"
|
|
|
+ :key="index"
|
|
|
+ class="moduleContent"
|
|
|
>
|
|
|
- <image
|
|
|
- style="width: 100%; height: 100%; display: block"
|
|
|
- :src="`../../static/furnitures/${item.type}.png`"
|
|
|
- mode=""
|
|
|
- />
|
|
|
+ <view
|
|
|
+ :class="item.type"
|
|
|
+ :style="{
|
|
|
+ width: `${item.width / 2}px`,
|
|
|
+ height: `${item.length / 2}px`,
|
|
|
+ top: `${item.top / 2}px`,
|
|
|
+ left: `${item.left / 2}px`,
|
|
|
+ transform: `rotate(${item.rotate}deg)`,
|
|
|
+ 'transform-origin': 'center center',
|
|
|
+ }"
|
|
|
+ @touchmove.prevent="onTouchMove(index, $event)"
|
|
|
+ @touchstart="onTouchStart(index, $event)"
|
|
|
+ @touchend="onTouchEnd(index, $event)"
|
|
|
+ >
|
|
|
+ <image
|
|
|
+ class="module-img"
|
|
|
+ :src="`../../static/furnitures/${item.type}.png`"
|
|
|
+ mode=""
|
|
|
+ />
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <image
|
|
|
- class="redar-pic"
|
|
|
- src="../../static/rander.png"
|
|
|
- mode=""
|
|
|
- :style="{
|
|
|
- transform:
|
|
|
- 'translate(' +
|
|
|
- -xOffset / 80 +
|
|
|
- 'rpx,' +
|
|
|
- -yOffset / 80 +
|
|
|
- 'rpx)',
|
|
|
- }"
|
|
|
- />
|
|
|
+ <template>
|
|
|
+ <view v-for="item in targetPoints" :key="item.id">
|
|
|
+ <image
|
|
|
+ class="action-icon-M"
|
|
|
+ :style="{
|
|
|
+ position: 'absolute',
|
|
|
+ transform: `translate3d(${
|
|
|
+ item.displayX / 2
|
|
|
+ }px, ${
|
|
|
+ -item.displayY / 2
|
|
|
+ }px, 0) translate(-50%, -50%)`,
|
|
|
+ zIndex: 9999,
|
|
|
+ transition: 'transform 1s linear',
|
|
|
+ willChange: 'transform',
|
|
|
+ }"
|
|
|
+ :src="`../../static/${lnbAction}.png`"
|
|
|
+ mode=""
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
</view>
|
|
|
+
|
|
|
+ <!-- <image
|
|
|
+ class="redar-pic"
|
|
|
+ src="../../static/rander.png"
|
|
|
+ mode=""
|
|
|
+ :style="{
|
|
|
+ transform:
|
|
|
+ 'translate(' +
|
|
|
+ -xOffset / 100 +
|
|
|
+ 'rpx,' +
|
|
|
+ -yOffset / 100 +
|
|
|
+ 'rpx)',
|
|
|
+ }"
|
|
|
+ /> -->
|
|
|
</view>
|
|
|
<view class="airbody">
|
|
|
<view class="header_top">
|
|
@@ -246,6 +274,7 @@
|
|
|
</view>
|
|
|
</template>
|
|
|
<script>
|
|
|
+import MqttService from "../../utils/globalMqtt.js";
|
|
|
export default {
|
|
|
name: "my",
|
|
|
data() {
|
|
@@ -391,6 +420,14 @@ export default {
|
|
|
length: 40,
|
|
|
},
|
|
|
],
|
|
|
+ lnbAction: "action8",
|
|
|
+ // mqtt模块
|
|
|
+ targetPoints: {},
|
|
|
+ inactivityTimer: null,
|
|
|
+ left: 0,
|
|
|
+ top: 0,
|
|
|
+ clientIdProp: null,
|
|
|
+ clientId: null,
|
|
|
};
|
|
|
},
|
|
|
computed: {},
|
|
@@ -711,13 +748,155 @@ export default {
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
+
|
|
|
+ handleMessage(topic, message, clientId) {
|
|
|
+ // 清除不活动定时器
|
|
|
+ clearTimeout(this.inactivityTimer);
|
|
|
+ this.inactivityTimer = setTimeout(() => {
|
|
|
+ this.targetPoints = {};
|
|
|
+ console.log("长时间没有点位消除");
|
|
|
+ }, 1500);
|
|
|
+ // 验证topic格式
|
|
|
+ const match = topic.match(/^\/dev\/(.+)\/tracker_targets$/);
|
|
|
+ if (!match || match[1] !== clientId) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const data = JSON.parse(message.toString());
|
|
|
+ // if (data.health) {
|
|
|
+ // if (
|
|
|
+ // data.health.breath_rpm ||
|
|
|
+ // data.health.breath_rpm === 0
|
|
|
+ // ) {
|
|
|
+ // this.receptHealth(Math.floor(data.health.breath_rpm));
|
|
|
+ // } else {
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // console.log(data.tracker_targets, "MQTT消息解析成功22222");
|
|
|
+ this.processTrackerData(data.tracker_targets);
|
|
|
+ } catch (e) {
|
|
|
+ console.error("MQTT消息解析失败", e);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ processTrackerData(arr) {
|
|
|
+ if (Array.isArray(arr) && arr.length > 0 && Array.isArray(arr[0])) {
|
|
|
+ this.targetPoints = {};
|
|
|
+ const currentIds = new Set();
|
|
|
+ const newTargetPoints = {};
|
|
|
+ // 处理每个追踪目标
|
|
|
+ arr.forEach((item) => {
|
|
|
+ if (!Array.isArray(item) || item.length < 4) return;
|
|
|
+
|
|
|
+ const [x, y, z, id] = item;
|
|
|
+ currentIds.add(id.toString());
|
|
|
+
|
|
|
+ // 处理新点或更新现有点
|
|
|
+ if (!this.targetPoints[id]) {
|
|
|
+ newTargetPoints[id] = this.createNewTargetPoint(
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ z,
|
|
|
+ id
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ newTargetPoints[id] = this.updateExistingTargetPoint(
|
|
|
+ this.targetPoints[id],
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ z,
|
|
|
+ 2
|
|
|
+ );
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 移除不存在的点
|
|
|
+ Object.keys(this.targetPoints).forEach((id) => {
|
|
|
+ if (!currentIds.has(id)) {
|
|
|
+ delete this.targetPoints[id];
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 更新目标点
|
|
|
+ this.targetPoints = {
|
|
|
+ ...this.targetPoints,
|
|
|
+ ...newTargetPoints,
|
|
|
+ };
|
|
|
+ if (Array.isArray(this.targetPoints)) {
|
|
|
+ this.targetPoints = this.targetPoints.filter(
|
|
|
+ (item) => item !== null && item !== undefined
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ createNewTargetPoint(x, y, z, id) {
|
|
|
+ return {
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ z,
|
|
|
+ id,
|
|
|
+ displayX: x - Number(this.xxStart),
|
|
|
+ displayY: y - Number(this.yyEnd),
|
|
|
+ lastX: x,
|
|
|
+ lastY: y,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ updateExistingTargetPoint(existingPoint, x, y, z, THRESHOLD) {
|
|
|
+ const dx = x - existingPoint.lastX;
|
|
|
+ const dy = y - existingPoint.lastY;
|
|
|
+ const distance = Math.sqrt(dx * dx + dy * dy);
|
|
|
+
|
|
|
+ if (distance > THRESHOLD) {
|
|
|
+ return {
|
|
|
+ ...existingPoint,
|
|
|
+ x,
|
|
|
+ y,
|
|
|
+ z,
|
|
|
+ lastX: x,
|
|
|
+ lastY: y,
|
|
|
+ displayX: x - Number(this.xxStart),
|
|
|
+ displayY: y - Number(this.yyEnd),
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ return existingPoint;
|
|
|
+ },
|
|
|
},
|
|
|
onLoad(options) {
|
|
|
this.devId = options.devId;
|
|
|
+ this.clientId = options.clientId;
|
|
|
+
|
|
|
+ console.log(options, "options111111");
|
|
|
this.getdevInfo(this.devId);
|
|
|
this.getRoomInfo(this.devId);
|
|
|
},
|
|
|
- onShow() {},
|
|
|
+ onShow() {
|
|
|
+ const topic = `/dev/${this.clientId}/tracker_targets`;
|
|
|
+ // 使用 MqttService.subscribe 管理订阅
|
|
|
+ this.unsubscribeFn = MqttService.subscribe(
|
|
|
+ "DATA",
|
|
|
+ topic,
|
|
|
+ (message, msgTopic) => {
|
|
|
+ // console.log(`接收到 ${msgTopic} 消息:`, message);
|
|
|
+ // 处理消息
|
|
|
+ const dataMatch = msgTopic.match(
|
|
|
+ /^\/dev\/(.+)\/tracker_targets$/
|
|
|
+ );
|
|
|
+ if (dataMatch && dataMatch[1] === this.clientId) {
|
|
|
+ this.handleMessage(msgTopic, message, this.clientId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ if (this.unsubscribeFn) {
|
|
|
+ console.log(`✅ 已成功订阅主题: ${topic}`);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ onHide() {
|
|
|
+ if (this.unsubscribeFn) {
|
|
|
+ this.unsubscribeFn();
|
|
|
+ this.unsubscribeFn = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
};
|
|
|
</script>
|
|
|
<style lang="less" scoped>
|
|
@@ -763,12 +942,79 @@ export default {
|
|
|
background-color: #e4c5b9;
|
|
|
}
|
|
|
}
|
|
|
- .airCantInfo {
|
|
|
- margin: 30rpx auto 0 auto;
|
|
|
- border: 18rpx solid #1f1f1f;
|
|
|
+ .radar-box {
|
|
|
+ margin: 0 auto;
|
|
|
position: relative;
|
|
|
- .module-content > view {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 710rpx;
|
|
|
+ height: 710rpx;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 37.5rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ .center {
|
|
|
position: absolute;
|
|
|
+ overflow: hidden;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 14rpx solid #333333;
|
|
|
+ background-image: url("https://hflnxx.oss-cn-shanghai.aliyuncs.com/IMAGE/20250919/toilet_bg.png");
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-position: center;
|
|
|
+ transform: scale(1.3);
|
|
|
+
|
|
|
+ .moduleContent {
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ view {
|
|
|
+ position: absolute;
|
|
|
+ }
|
|
|
+
|
|
|
+ .module-img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .tranStyle {
|
|
|
+ position: absolute;
|
|
|
+ overflow: hidden;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 9rpx solid #333333;
|
|
|
+ background-image: url("https://hflnxx.oss-cn-shanghai.aliyuncs.com/IMAGE/20250919/toilet_bg.png");
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-position: center;
|
|
|
+ transform: scale(2.3);
|
|
|
+
|
|
|
+ .moduleContent {
|
|
|
+ // overflow: hidden;
|
|
|
+
|
|
|
+ // position: relative;
|
|
|
+ view {
|
|
|
+ position: absolute;
|
|
|
+ }
|
|
|
+
|
|
|
+ .module-img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-icon-G {
|
|
|
+ position: absolute;
|
|
|
+ width: 100rpx;
|
|
|
+ height: 100rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-icon-M {
|
|
|
+ // position: absolute;
|
|
|
+ width: 50rpx;
|
|
|
+ height: 50rpx;
|
|
|
}
|
|
|
.redar-pic {
|
|
|
position: absolute;
|
|
@@ -779,6 +1025,7 @@ export default {
|
|
|
transform: translate(-50%, -50%); /* 先居中 */
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
.airbody {
|
|
|
margin: 80rpx auto 0 auto;
|
|
|
width: 700rpx;
|