<template>
    <!-- 设备详情 -->
    <view class="content">
        <view class="name_box">
            <view class="name_content">{{ devInfo.devName }}</view>
        </view>
        <view class="contentBg"> </view>
        <view
            class="radar-box"
            :style="{
                left: `${offsetLeft}rpx`,
                top: `${offsetTop}rpx`,
            }"
        >
            <view
                :style="{
                    width: `${rotatedRect.width}rpx`,
                    height: `${rotatedRect.height}rpx`,
                    position: 'absolute',
                    top: `${rotatedRect.top - 8}rpx`,
                    left: `${rotatedRect.left - 8}rpx`,
                    border: `${9 / zoomTimes}rpx solid #333333`,
                    overflow: 'hidden',
                    transform: `scale(${zoomTimes})`,
                    transformOrigin: 'center center',
                }"
                class="tranStyle"
            >
                <template v-if="modules.length > 0">
                    <view
                        v-for="(item, index) in modules"
                        :key="index"
                        class="moduleContent"
                    >
                        <view
                            :class="item.type"
                            :style="{
                                width: `${item.width}rpx`,
                                height: `${item.height}rpx`,
                                top: `${item.top - rotatedRect.top}rpx`,
                                left: `${item.left - rotatedRect.left}rpx`,
                                transform: `rotate(${item.rotate}deg)`,
                                'transform-origin': 'center center',
                                zIndex: 44,
                                position: 'absolute',
                            }"
                        >
                            <image
                                style="
                                    width: 100%;
                                    height: 100%;
                                    display: block;
                                "
                                :src="`../../static/furnitures/${item.type}.png`"
                                mode=""
                            />
                        </view>
                    </view>
                </template>

                <template>
                    <image
                        v-for="item in targetPoints"
                        :key="item.id"
                        class="action-icon-M"
                        :src="`../../static/${lnbAction}.png`"
                        :style="{
                            position: 'absolute',
                            transform: `translate(-50%, -50%) translate3d(${
                                item.displayX - rotatedRect.left
                            }rpx, ${item.displayY - rotatedRect.top}rpx, 0)`,
                            transition: 'transform 1s linear',
                            willChange: 'transform',
                            zIndex: 444,
                            top: '0',
                            left: '0',
                            width: `${70 / zoomTimes}rpx`,
                            height: `${70 / zoomTimes}rpx`,
                        }"
                    />
                </template>
            </view>

            <!-- <image class="redar-pic" src="../../static/rander.png" mode="" /> -->
        </view>

        <view class="switchBox">
            <text class="name">呼吸灯</text>
            <switch
                :checked="statusLight == 1"
                @change="handleLightChange"
                :active-value="1"
                :inactive-value="0"
                size="24px"
                active-color="#07c160"
                inactive-color="#eeeff1"
                style="transform: scale(0.8)"
            />
        </view>
        <view class="notice-info">
            <view class="notice_title" @click="discrepancy">
                <text style="color: #95a4b3; font-size: 28rpx">{{
                    todayDate
                }}</text>
                <image src="../../static/rightArrow.png"></image>
            </view>
            <view
                @click="getFrenEcharts()"
                class="title"
                v-if="
                    devInfo.installPosition == 'Bedroom' ||
                    (breathRate !== 0 && breathRate !== '')
                "
            >
                <view
                    class="title-text"
                    style="color: #111111; font-size: 30rpx"
                    >当前呼吸率</view
                >
                <view
                    style="
                        display: flex;
                        justify-content: center;
                        align-items: center;
                    "
                >
                    <view
                        class="title-btn"
                        style="color: #111111; font-size: 30rpx"
                        v-if="breathRate !== ''"
                    >
                        {{ breathRate }}次/分钟</view
                    >
                    <view
                        v-else
                        class="title-btn"
                        style="color: #111111; font-size: 30rpx"
                    >
                        暂无
                    </view>
                    <image
                        src="../../static/rightArrow.png"
                        style="margin-left: auto; width: 30rpx; height: 30rpx"
                    ></image>
                </view>
            </view>

            <view class="title">
                <view class="title-text" style="color: #22dea7"
                    >今日进出频次</view
                >
                <view class="title-btn" style="color: #22dea7">
                    {{ freQuenceList.length || 0 }}次
                </view>
            </view>

            <view class="stayDetail" v-if="freQuenceList.length > 0">
                <!-- 只有一条时直接展示 -->
                <view v-if="freQuenceList.length === 1">
                    <view
                        v-for="item in freQuenceList"
                        :key="item.id"
                        class="stayDetail-item"
                    >
                        <view class="stayDetail-text">
                            {{ formatTime(item.enterTime) }}目标进入
                        </view>
                        <view class="stayDetail-btn">
                            {{ formatTime(item.leaveTime) }}目标离开
                        </view>
                    </view>
                </view>

                <!-- 多条时用 swiper 展示 -->
                <swiper
                    v-else
                    class="auto-scroll-swiper"
                    :indicator-dots="false"
                    :autoplay="false"
                    :interval="3000"
                    :circular="true"
                    :display-multiple-items="1"
                    :vertical="false"
                    :current="currentIndex"
                    @change="onSwiperChange"
                >
                    <swiper-item
                        v-for="item in freQuenceList"
                        :key="item.id"
                        class="stayDetail-item"
                    >
                        <view class="stayDetail-text">
                            {{ formatTime(item.enterTime) }}目标进入
                        </view>
                        <view class="stayDetail-btn">
                            {{ formatTime(item.leaveTime) }}目标离开
                        </view>
                    </swiper-item>
                </swiper>
            </view>
        </view>
        <view class="box" v-if="!breathShow">
            <view class="handle-btn">
                <view class="btn1" @click="shareDevice" v-if="shareJudge"
                    >分享</view
                >
                <view class="noShareFlag" @click="noShareFlag" v-else
                    >分享</view
                >
                <view
                    class="btn1"
                    @click="gotoSetting"
                    v-if="devInfo.online == 1"
                    >设置</view
                >
                <view class="noShareFlag" @click="gotoSetting" v-else
                    >设置</view
                >
                <view class="btn2" @click="healthAlarm">守护计划</view>
            </view>
        </view>

        <view class="box" v-else>
            <view class="handle-btn">
                <view class="closeBreath" @click="breathShow = false"
                    >关闭呼吸率曲线图</view
                >
                <view class="btn2" @click="saveBreath"> 保存呼吸率曲线图 </view>
            </view>
        </view>

        <!-- 遮罩层 -->
        <view class="mask" v-if="shareModel" @click="shareModel = false"></view>
        <!-- 弹窗内容 -->
        <view class="share-modal" v-if="shareModel">
            <view class="modal-header">
                <text class="cancel-btn" @click="shareModel = false">取消</text>
                <text class="modal-title">分享</text>
                <text class="confirm-btn" @click="onShareConfirm()">确认</text>
            </view>
            <view class="modal-body">
                <view class="info-row">
                    <view class="label">设备序列号：</view>
                    <view class="value">{{ devInfo.clientId }}</view>
                </view>
                <view class="info-row">
                    <view class="label">设备名称：</view>
                    <view class="value">{{ devInfo.devName }}</view>
                </view>
                <view class="input-row phoneInfo">
                    <view>被分享人</view>
                    <input
                        class="input"
                        placeholder="请输入手机号"
                        type="number"
                        v-model="sharedPhone"
                    />
                </view>
                <view class="funChoice">
                    <view class="funItem" @click="smChange()">
                        <label class="simple-radio">
                            <radio
                                :value="messageFlag"
                                color="#7c5345"
                                :checked="messageFlag == true"
                                class="hide-original"
                            />
                            <text>短信权限</text>
                        </label>
                    </view>
                    <view class="funItem">
                        <label class="simple-radio" @click="snChange()">
                            <radio
                                :value="serviceNumberFlag"
                                color="#7c5345"
                                :checked="serviceNumberFlag == true"
                                class="hide-original"
                            />
                            <text>服务号通知</text>
                        </label>
                    </view>
                    <view class="funItem">
                        <label class="simple-radio" @click="vfChange()">
                            <radio
                                :value="voipFlag"
                                color="#7c5345"
                                :checked="voipFlag == true"
                                class="hide-original"
                            />
                            <text>语音通话</text>
                        </label>
                    </view>
                </view>
            </view>
        </view>
        <view class="modal-mask" v-if="choiceVisible" @click="closeChoice">
            <view class="modal-container">
                <view class="modal-header">
                    <text class="title">请选择分享方式</text>
                </view>

                <view class="modal-buttons">
                    <!-- 手机号分析按钮 -->
                    <button class="btn phone-btn" @click="handlePhoneAnalysis">
                        <text>手机号分享</text>
                    </button>

                    <!-- 链接分享按钮 -->
                    <button class="btn link-btn" @click="handleLinkShare">
                        <text>链接分享</text>
                    </button>
                </view>
            </view>
        </view>

        <!-- ECharts图标模块 -->
        <view v-if="breathShow" class="echartsClass">
            <image
                src="../../static/closePng.png"
                class="closePng"
                @click="breathShow = false"
            ></image>

            <l-echart
                id="chart-canvas"
                canvas-id="chart-canvas"
                ref="chartRef"
                @finished="initChart"
                v-if="breathShow"
                @click="breathShow = false"
            ></l-echart>
        </view>
        <alarModel v-if="showModle" ref="alarmModel" />
    </view>
</template>
<script>
import * as echarts from "../../uni_modules/lime-echart/static/echarts.min";
import MqttService from "../../utils/globalMqtt.js";
import {
    convert_region_r2c,
    rotateRect_cw,
    convert_furniture_r2c,
    convert_point_r2c,
} from "../../utils/changezb.js";

export default {
    data() {
        return {
            clientId: "",
            width: 0, //检测区域宽度
            length: 0, //检测区域长度
            devInfo: "",
            actionName: "",
            startDate: "",
            endDate: "",
            softWare: "",
            statusLight: 0,
            lnbAction: "",
            stayDetail: "",
            todayDate: "",
            dev_id: "",
            nowTime: "",
            devName: "",
            devType: "",
            localPhone: uni.getStorageSync("phone"),
            freQuenceList: [],
            // mqtt相关
            currentIndex: 0,
            modules: [],
            autoPlayinterval: "",
            choiceVisible: "",
            // 手机号分享授权模块
            shareModel: false,
            alarmModel: false,
            sharedPhone: "",
            messageFlag: false,
            serviceNumberFlag: false,
            voipFlag: false,
            // mqtt模块
            targetPoints: {},
            inactivityTimer: null,
            left: 0,
            top: 0,
            breathRate: "",
            breathShow: false,
            breathRpmList: [],
            option: {
                title: [
                    {
                        text: "呼吸率曲线",
                        left: "center",
                        top: 20,
                        textStyle: { fontSize: 14 },
                    },
                    {
                        text: "BPM: 0 次/分钟",
                        left: "center",
                        top: 50,
                        textStyle: { fontSize: 12, color: "#805246" },
                    },
                    {
                        text: "时间 (秒)",
                        left: "right",
                        top: "bottom",
                        textStyle: { fontSize: 12, color: "#888888" },
                    },
                ],
                grid: { left: 60, right: 20, top: 80, bottom: 50 },
                xAxis: {
                    type: "category",
                    data: Array.from({ length: 60 }, (_, i) => i + 1),
                    boundaryGap: false,
                    splitLine: { show: false },
                },
                yAxis: {
                    type: "value",
                    min: 0,
                    max: 40,
                    name: "呼吸率（次）",
                    nameLocation: "end",
                    nameGap: 20,
                    nameTextStyle: { fontSize: 12, color: "#888888" },
                    splitLine: { show: true },
                },
                series: [
                    {
                        type: "line",
                        smooth: true,
                        symbol: "none",
                        lineStyle: { color: "#805246", width: 2 },
                        data: Array(60).fill(0),
                    },
                ],
                animation: true,
                animationDuration: 100,
            },
            showModle: false,
            zoomTimes: 2,
            // 设备分享权限判断
            shareJudge: false,
            unsubscribeFn: null,
            fallingEventChange: null,
            setIntervalVal: null,

            // 重新计算雷达坐标位置
            x_radar: 250,
            y_radar: 250,
            offsetLeft: 0,
            offsetTop: 0,
            //检测区域计算
            rotatedRect: {},
            // 处理点位
            point: "",
        };
    },
    computed: {
        originX() {
            // 雷达点相对于盒子的内部偏移（横坐标）
            return this.x_radar - (this.rotatedRect.left - 8);
        },
        originY() {
            // 雷达点相对于盒子的内部偏移（纵坐标）
            return this.y_radar - (this.rotatedRect.top - 16);
        },
    },

    methods: {
        // 获取设备信息
        getdevInfo(devId) {
            this.$http
                .get(`wap/device/queryDeviceInfoById`, {
                    devId: devId,
                })
                .then((res) => {
                    if (res.data.data) {
                        this.devInfo = res.data.data;
                        this.devType = this.devInfo.devType;

                        this.width = Math.abs(
                            this.devInfo.yyEnd - this.devInfo.yyStart
                        );
                        this.length = Math.abs(
                            this.devInfo.xxEnd - this.devInfo.xxStart
                        );
                        this.statusLight = this.devInfo.statusLight;
                        this.calculate(this.width, this.length);
                        this.calculateRegion();
                        this.calculateOffset();
                        // 设备分享权限判断
                        this.shareJudge =
                            this.devInfo.userId == uni.getStorageSync("userId")
                                ? true
                                : false;
                    }
                })

                .catch((err) => {});
        },
        getdevRoomInfo(devId) {
            let modules = [];
            this.$http
                .get(`wap/room/readRoom`, {
                    devId: devId,
                })
                .then((res) => {
                    const pRadar = {
                        x: this.x_radar,
                        y: this.y_radar,
                        angle: uni.getStorageSync("northAngle"),
                        mountPlain: this.devInfo.mountPlain,
                    };

                    if (res.data.data) {
                        modules = res.data.data.furnitures;
                    }
                    modules.forEach((item) => {
                        // 1️⃣ 计算家具在参考系中的矩形
                        const rect = convert_furniture_r2c(item, pRadar);
                        const rotatedRect = rotateRect_cw(
                            rect,
                            pRadar,
                            pRadar.angle
                        );
                        item.left = rotatedRect.left;
                        item.top = rotatedRect.top;
                        item.width = rotatedRect.width;
                        item.height = rotatedRect.height;
                        item.name = item.name;
                        item.type = item.type;
                    });
                    this.modules = JSON.parse(JSON.stringify(modules));
                });
        },
        // 处理设备状态灯
        handleLightChange(e) {
            let newValue = e.detail.value == true ? 1 : 0;
            this.$http
                .post(`wap/device/statusLight`, {
                    statusLight: newValue,
                    devId: this.devInfo.devId,
                })
                .then((res) => {
                    if (res.data.code == 200) {
                        uni.showToast({
                            title: "操作成功",
                            icon: "success",
                        });
                        this.statusLight = newValue;
                    } else {
                        wx.showToast({
                            title: res.data.message,
                            icon: "none",
                        });
                    }
                });
        },

        // 分享功能模块
        shareDevice() {
            this.choiceVisible = true;
        },
        noShareFlag() {
            uni.showToast({
                title: "您没有分享权限",
                icon: "none",
            });
        },
        onShareConfirm() {
            if (!this.sharedPhone) {
                uni.showModal({
                    content: "请填写手机号!",
                    showCancel: false,
                });
                return;
            }
            let reg_tel =
                /^(13[0-9]|14[01456879]|15[0-3,5-9]|16[2567]|17[0-8]|18[0-9]|19[0-3,5-9])\d{8}$/;
            if (!reg_tel.test(this.sharedPhone)) {
                uni.showModal({
                    content: "请填写正确手机号!",
                    showCancel: false,
                });
                return;
            }
            let shareParam = {
                sharerUserId: uni.getStorageSync("userId"),
                devId: this.devInfo.devId,
                sharerPhone: uni.getStorageSync("phone"),
                sharedUserId: "",
                sharedPhone: this.sharedPhone,
                messageFlag: this.messageFlag == true ? 0 : 1,
                serviceNumberFlag: this.serviceNumberFlag == true ? 0 : 1,
                voipFlag: this.voipFlag == true ? 0 : 1,
            };

            this.$http
                .post("wap/share/deviceShare", shareParam, {
                    header: {
                        "Content-Type": "application/json;charset=UTF-8",
                    },
                })
                .then((res) => {
                    if (res.data.code == 200) {
                        uni.showToast({
                            title: "分享成功",
                            icon: "success",
                            duration: 1500,
                        });
                    } else {
                        uni.showToast({
                            title: res.data.message,
                            icon: "none",
                            duration: 1500,
                        });
                    }
                });
            this.shareModel = false;
        },
        closeChoice() {
            this.choiceVisible = false;
        },
        handlePhoneAnalysis() {
            this.choiceVisible = false;
            this.shareModel = true;
        },
        handleLinkShare() {
            this.choiceVisible = false;
            uni.navigateTo({
                url:
                    "/pagesA/linkShare/linkShare?devInfo=" +
                    JSON.stringify(this.devInfo),
            });
        },
        smChange() {
            this.messageFlag = !this.messageFlag;
        },
        snChange() {
            this.serviceNumberFlag = !this.serviceNumberFlag;
        },
        vfChange() {
            this.voipFlag = !this.voipFlag;
        },
        gotoSetting() {
            if (this.devInfo.online == 0) {
                uni.showToast({
                    title: "离线设备不支持设置",
                    icon: "none",
                });
                return;
            }
            uni.navigateTo({
                url:
                    "/pagesA/deviceSetting/deviceSetting?devInfo=" +
                    JSON.stringify(this.devInfo),
            });
        },
        getFrequency(devId) {
            let params = {
                devId: devId,
                createTimeStart: this.$time(new Date()),
                createTimeEnd: this.$time(new Date()),
                pageNo: 1,
                pageSize: 999,
            };

            this.$http
                .post(`wap/stats/inOutEventQuery`, params, {
                    header: {
                        "Content-Type": "application/json;charset=UTF-8",
                    },
                })
                .then((res) => {
                    if (res.data.code == 200) {
                        if (res.data.data.rows.length > 0) {
                            this.freQuenceList = res.data.data.rows;
                        } else {
                            this.freQuenceList = [];
                        }
                    } else {
                        uni.showToast({
                            title: res.data.message,
                            icon: "none",
                        });
                    }
                });
        },
        // 健康闹钟方法
        healthAlarm() {
            uni.navigateTo({
                url:
                    "/pagesA/healthAlarm/healthAlarm?devInfo=" +
                    JSON.stringify(this.devInfo),
            });
        },
        onSwiperChange(event) {
            const current = event.detail.current;
            const totalItems = this.freQuenceList.length;
            if (current === totalItems - 1) {
                this.autoplay = false;
            }
            this.currentIndex = current;
        },

        autoSwipe() {
            if (this.freQuenceList && this.freQuenceList.length > 0) {
                this.setIntervalVal = setInterval(() => {
                    let nextIndex = this.currentIndex + 1;
                    if (nextIndex >= this.freQuenceList.length) {
                        nextIndex = 0; // 循环到第一个项目
                    }
                    this.currentIndex = nextIndex;
                }, 3000); // 每3秒自动滚动一次
            }
        },
        discrepancy() {
            uni.navigateTo({
                url:
                    "/pagesA/discrepancy/discrepancy?freQuenceList=" +
                    JSON.stringify(this.freQuenceList),
            });
        },
        receptionChange(val) {
            this.targetPoints = val;
        },
        receptHealth(val) {
            this.breathRate = val;
            this.setEcharts(val);
        },

        // echarts图表模块
        getOption(list) {
            // 固定 X 轴 [0 ~ 60]
            const xData = Array.from({ length: 61 }, (_, i) => i);
            const recent = list.slice(-61);
            const data = new Array(61).fill(null);
            for (let i = 0; i < recent.length; i++) {
                data[i] = recent[i];
            }

            return {
                title: [
                    { text: "呼吸率曲线", left: "center", top: 20 },
                    {
                        text: `BPM: ${recent[recent.length - 1] || 0} 次/分钟`,
                        left: "center",
                        top: 50,
                        textStyle: { fontSize: 12, color: "#805246" },
                    },
                    {
                        text: "时间 (秒)",
                        left: "right",
                        top: "bottom",
                        textStyle: {
                            fontSize: 10,
                            color: "#888888",
                            fontWeight: "normal",
                        },
                    },
                ],
                grid: { left: 60, right: 20, top: 80, bottom: 50 },
                xAxis: {
                    type: "category",
                    data: xData,
                    boundaryGap: false,
                },
                yAxis: {
                    type: "value",
                    min: 0,
                    max: 40,
                    name: "呼吸率（次）",
                    nameLocation: "end",
                    nameGap: 20,
                    nameTextStyle: {
                        fontSize: 10,
                        color: "#888888",
                        fontWeight: "normal",
                    },
                    splitLine: { show: true },
                },
                series: [
                    {
                        type: "line",
                        smooth: true,
                        symbol: "none",
                        data: data,
                        showSymbol: false,
                        lineStyle: { color: "#7a4e42", width: 2 },
                    },
                ],
            };
        },

        getFrenEcharts() {
            if (this.breathRate === "" || this.breathRate === null) {
                uni.showToast({
                    title: "暂无呼吸率",
                    icon: "none",
                    duration: 1500,
                });
                return;
            }
            this.breathShow = true;
            this.$nextTick(() => {
                this.initChart();
            });
        },
        initChart() {
            if (!this.$refs.chartRef) return;
            if (this.chartInstance) {
                this.chartInstance.dispose();
                this.chartInstance = null;
            }
            this.$refs.chartRef.init(echarts, (chart) => {
                this.chartInstance = chart;
                chart.setOption(this.option, true);
            });
        },
        setEcharts(val) {
            if (!Array.isArray(this.breathRpmList)) {
                this.breathRpmList = [];
            }
            this.breathRpmList.push(val);
            if (!this.chartInstance) return;
            const option = this.getOption(this.breathRpmList);
            this.chartInstance.setOption(option, { notMerge: true });
        },
        saveBreath() {
            const chart = this.$refs.chartRef;
            if (!chart) {
                uni.showToast({ title: "图表未渲染", icon: "none" });
                return;
            }
            chart.canvasToTempFilePath({
                success: (res) => {
                    uni.saveImageToPhotosAlbum({
                        filePath: res.tempFilePath,
                        success: () => {
                            uni.showToast({
                                title: "保存成功",
                                icon: "success",
                            });
                        },
                        fail: (err) => {
                            uni.showToast({
                                title: "保存失败",
                                icon: "none",
                            });
                        },
                    });
                },
                fail: (err) => {
                    uni.showToast({
                        title: "导出失败",
                        icon: "none",
                    });
                },
            });
        },

        // 处理点位消息
        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());
                // console.log(data.tracker_targets, "点位消息");
                if (data.health) {
                    if (
                        data.health.breath_rpm ||
                        data.health.breath_rpm === 0
                    ) {
                        this.receptHealth(Math.floor(data.health.breath_rpm));
                    } else {
                    }
                }
                this.processTrackerData(data.tracker_targets);
                // console.log(data.tracker_targets, "MQTT消息解析成功22222");
            } 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());

                    const pRadar = { x: this.x_radar, y: this.y_radar };
                    this.point = convert_point_r2c(
                        { x, y },
                        pRadar,
                        uni.getStorageSync("northAngle")
                    );

                    // 处理新点或更新现有点
                    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,
                };
            }
        },
        createNewTargetPoint(x, y, z, id) {
            return {
                x,
                y,
                z,
                id,
                displayX: this.point.x,
                displayY: this.point.y - 12,
                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: this.point.x,
                    displayY: this.point.y - 12,
                };
            }
            return existingPoint;
        },

        // 计算缩放比例
        calculate(width, length) {
            let zoomTime = width > length ? width : length;
            let practical = zoomTime;
            this.zoomTimes = 680 / practical;
            this.zoomTimes = this.zoomTimes - 0.2;
            this.zoomTimes = Number(this.zoomTimes.toFixed(2));
            this.lnbActionJudean = true;
        },
        calculateRegion() {
            let x_cm_start = this.devInfo.xxStart;
            let y_cm_start = this.devInfo.yyStart;
            let x_cm_stop = this.devInfo.xxEnd;
            let y_cm_stop = this.devInfo.yyEnd;

            const trackingRegion = {
                x_cm_start,
                y_cm_start,
                x_cm_stop,
                y_cm_stop,
            };

            const pRadar = {
                x: this.x_radar,
                y: this.y_radar,
                angle: uni.getStorageSync("northAngle"),
                mountPlain: this.devInfo.mountPlain,
            };
            const rect = convert_region_r2c(trackingRegion, pRadar);
            this.rotatedRect = rotateRect_cw(rect, pRadar, pRadar.angle);
            console.log(this.rotatedRect, "rotatedRect");
        },

        calculateOffset() {
            let x_cm_start = "";
            let x_cm_stop = "";
            let y_cm_start = "";
            let y_cm_stop = "";

            if (this.devInfo.northAngle == 0) {
                x_cm_start = this.devInfo.xxStart;
                x_cm_stop = this.devInfo.xxEnd;
                y_cm_start = this.devInfo.yyStart;
                y_cm_stop = this.devInfo.yyEnd;
                this.offsetLeft = -(x_cm_start + x_cm_stop) / 2;
                this.offsetTop = (y_cm_start + y_cm_stop) / 2 + 80;
            }

            if (this.devInfo.northAngle == 90) {
                x_cm_start = this.devInfo.xxStart;
                x_cm_stop = this.devInfo.xxEnd;
                y_cm_start = -this.devInfo.yyEnd;
                y_cm_stop = -this.devInfo.yyStart;
                this.offsetLeft = -(x_cm_start + x_cm_stop) / 2;
                this.offsetTop = (y_cm_start + y_cm_stop) / 2 + 80;
            }

            if (this.devInfo.northAngle == 180) {
                x_cm_start = -this.devInfo.xxEnd;
                x_cm_stop = -this.devInfo.xxStart;
                y_cm_start = -this.devInfo.yyEnd;
                y_cm_stop = -this.devInfo.yyStart;
                this.offsetLeft = -(x_cm_start + x_cm_stop) / 2;
                this.offsetTop = (y_cm_start + y_cm_stop) / 2 + 80;
            }
            if (this.devInfo.northAngle == 270) {
                x_cm_start = -this.devInfo.xxEnd;
                x_cm_stop = -this.devInfo.xxStart;
                y_cm_start = this.devInfo.yyStart;
                y_cm_stop = this.devInfo.yyEnd;
                this.offsetLeft = -(x_cm_start + x_cm_stop) / 2;
                this.offsetTop = (y_cm_start + y_cm_stop) / 2;
            }
        },

        formatTime(time) {
            return time ? time.slice(11, 19) : "暂无";
        },
        // 订阅消息,处理mqtt消息
        initSubscriptions() {
            const topicList = [
                {
                    topic: `/dev/${this.clientId}/tracker_targets`,
                    key: "unsubscribeFn",
                    callback: (message, msgTopic) => {
                        const dataMatch = msgTopic.match(
                            /^\/dev\/(.+)\/tracker_targets$/
                        );
                        const cmdMatch = msgTopic.match(
                            /^\/mps\/wx_(.+)\/notice$/
                        );
                        if (dataMatch && dataMatch[1] === this.clientId) {
                            this.handleMessage(
                                msgTopic,
                                message,
                                this.clientId
                            );
                        } else if (cmdMatch) {
                            this.$refs.alarmModel.hanOtherMessage(
                                msgTopic,
                                message
                            );
                        }
                    },
                },
                {
                    topic: `/dev/${this.clientId}/falling_event_change`,
                    key: "fallingEventChange",
                    callback: (message, msgTopic) => {
                        const dataMatch = msgTopic.match(
                            /^\/dev\/(.+)\/falling_event_change$/
                        );
                        if (dataMatch && dataMatch[1] === this.clientId) {
                            const dataMessage = JSON.parse(message.toString());

                            console.log(dataMessage, 888888);
                            if (dataMessage.falling == 1) {
                                this.falling = dataMessage.falling;
                                this.lnbAction = "actionWarn";
                            } else if (
                                dataMessage.falling == 2 ||
                                dataMessage.falling == 3
                            ) {
                                this.falling = dataMessage.falling;
                                this.lnbAction = "actionSerious";
                            } else {
                                this.lnbAction = "action8";
                            }
                        }
                    },
                },
            ];

            topicList.forEach((item) => {
                // 避免重复订阅
                if (this[item.key]) return;

                const subscribeFunc = () => {
                    const unsubscribe = MqttService.subscribe(
                        "DATA",
                        item.topic,
                        item.callback
                    );
                    if (unsubscribe) {
                        this[item.key] = unsubscribe;
                        console.log(`✅ 已成功订阅主题: ${item.topic}`);
                    }
                };

                if (MqttService.dataConnected) {
                    subscribeFunc();
                } else {
                    // MQTT 未连接，等待重连成功再订阅
                    const handler = () => {
                        subscribeFunc();
                        uni.$off("mqttData-ready", handler);
                    };
                    uni.$on("mqttData-ready", handler);
                }
            });
        },
    },
    onLoad(options) {
        this.lnbAction = "action8";
        const devItem = JSON.parse(options.devItem);
        const { devId, clientId } = devItem;
        // 缓存到页面实例
        this.clientId = clientId;
        uni.setStorageSync("currentDevItem", devItem);
        this.getFrequency(devId);
        this.dev_id = devId;
        this.todayDate = this.$time(new Date(), 2);
        // 清理旧定时器
        clearTimeout(this.autoPlayinterval);
        this.autoPlayinterval = setTimeout(() => this.autoSwipe(), 3000);

        if (MqttService.dataConnected && MqttService.dataClient) {
            // 已连接，直接订阅
            this.initSubscriptions();
        }
    },

    onShow() {
        this.showModle = true;
        this.lnbAction = "action8";
        // MQTT 初始化
        const userId = uni.getStorageSync("userId");
        if (!userId) return console.error("MQTT 初始化失败：缺少 userId");
        if (!MqttService.dataConnected) {
            // 未连接，先 connect
            MqttService.connectData(userId)
                .then((client) => {
                    // 页面订阅逻辑，等 connect 成功再执行
                    const handler = () => {
                        MqttService.resubscribeAll("DATA");
                        uni.$off("mqttData-ready", handler);
                    };
                    uni.$on("mqttData-ready", handler);
                })
                .catch((err) => console.error("DATA MQTT 初始化失败", err));
        }
        this.getdevInfo(this.dev_id);
        this.getdevRoomInfo(this.dev_id);
    },

    onUnload() {
        // 清理定时器
        clearTimeout(this.autoPlayinterval);
        // 清理自动滑动定时器
        clearInterval(this.setIntervalVal);
        this.setIntervalVal = null;
        this.autoPlayinterval = null;
        // 取消订阅
        ["unsubscribeFn", "fallingEventChange"].forEach((key) => {
            if (this[key]) {
                this[key]();
                this[key] = null;
            }
        });
    },
    onHide() {
        // MqttService.dataConnected = false;
        this.showModle = false;
    },
};
</script>
<style lang="less" scoped>
.content {
    height: 100vh;
    background: linear-gradient(180deg, #faede2 0%, #f4f4f4 100%);
    box-sizing: border-box;
    padding-top: 20rpx;
    position: relative;

    .name_box {
        display: flex;
        justify-content: center;
        align-items: center;
        margin: 0 auto 40rpx 0;

        .name_content {
            display: inline-flex;
            background: rgba(255, 255, 255, 0.65);
            border-radius: 37rpx;
            padding: 6rpx 18rpx;
        }
    }
    .contentBg {
        position: absolute;
        border-radius: 37.5rpx;
        top: 30%;
        left: 50%;
        width: 710rpx;
        height: 680rpx;
        background-color: #ffffff;
        -webkit-transform: translate(-50%, -50%);
        transform: translate(-50%, -50%);
        z-index: 0;
    }

    .radar-box {
        margin: 0 auto;
        position: relative;
        // display: flex;
        // align-items: center;
        // justify-content: center;
        width: 500rpx;
        height: 500rpx;
        // background: #ffffff;
        border-radius: 37.5rpx;
        box-sizing: border-box;

        .tranStyle {
            background-repeat: no-repeat;
            background-position: center;
            z-index: 1; // 父元素层级要高于伪元素容器
            &::after {
                content: "";
                position: absolute;
                inset: 0;
                background: url("https://hflnxx.oss-cn-shanghai.aliyuncs.com/IMAGE/20250919/toilet_bg.png")
                    no-repeat center;
                background-size: 150% 150%;
                z-index: -1;
            }
        }

        .moduleContent {
            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;
            // transform: translate(-50%, -50%);
            // transition: transform 1s linear;
            // will-change: transform;
            // z-index: 9999;
        }
        .redar-pic {
            position: absolute;
            top: 50%;
            left: 50%;
            width: 40rpx;
            height: 40rpx;
            transform: translate(-50%, -50%);
            z-index: 20;
        }
    }

    .switchBox {
        width: 710rpx;
        height: 94rpx;
        margin: 190rpx auto 20rpx auto;
        padding: 0 37rpx;
        display: flex;
        align-items: center;
        background: #ffffff;
        border-radius: 37rpx;
        box-sizing: border-box;

        .name {
            color: #111111;
            font-size: 32rpx;
        }
    }

    .notice-info {
        width: 710rpx;
        max-height: 300rpx;
        // overflow: hidden;
        padding: 30rpx 37rpx 10rpx 37rpx;
        background: #ffffff;
        border-radius: 37rpx;
        box-sizing: border-box;
        margin: 0 auto;

        .notice_title {
            display: flex;
            align-items: space-between;

            image {
                margin-left: auto;
                width: 30rpx;
                height: 30rpx;
            }
        }

        .title {
            margin-top: 10rpx;
            margin-bottom: 10rpx;
            font-family: PingFang SC, PingFang SC;
            font-weight: 500;
            font-size: 34rpx;
            color: #1757dd;
            display: flex;
            align-items: center;
            justify-content: space-between;

            .title-text {
                font-size: 28rpx;
                font-weight: 500;
                color: #1757dd;
            }

            .title-btn {
                font-size: 28rpx;
                font-weight: 500;
                color: #5a5a5a;
            }
        }

        .stayDetail {
            height: 80rpx;
            // overflow: hidden;
            margin-top: 10rpx;
            margin-bottom: 10rpx;
            padding-left: 20rpx;
            font-family: PingFang SC, PingFang SC;
            font-weight: 500;
            font-size: 34rpx;

            .stayDetail-item {
                display: flex;
                padding-bottom: 5rpx !important;
                padding-top: 10rpx !important;
                box-sizing: border-box;
                line-height: 60rpx;

                .stayDetail-text {
                    width: 40%;
                    font-size: 28rpx;
                    height: 30rpx !important;
                }

                .stayDetail-btn {
                    padding-left: 30rpx;
                    font-size: 28rpx;
                    height: 30rpx !important;
                }
            }
        }
    }

    .box {
        position: fixed;
        bottom: 0;
        left: 0;
        width: 100vw;
        height: 168rpx;
        padding: 0 37rpx;
        background: #ffffff;
        box-sizing: border-box;

        .handle-btn {
            margin-top: 40rpx;
            display: flex;
            align-items: center;
            justify-content: space-between;

            .btn1 {
                display: flex;
                align-items: center;
                justify-content: center;
                width: 155rpx;
                height: 94rpx;
                background: #ffebe4;
                border-radius: 28rpx;
                font-weight: 500;
                color: #111111;
                font-size: 32rpx;
                text-align: center;
            }
            .noShareFlag {
                display: flex;
                align-items: center;
                justify-content: center;
                width: 155rpx;
                height: 94rpx;
                border-radius: 28rpx;
                font-weight: 500;
                font-size: 32rpx;
                text-align: center;
                background: #f0f0f0;
                color: #999999;
                opacity: 0.6;
            }

            .btn2 {
                display: flex;
                align-items: center;
                justify-content: center;
                width: 328rpx;
                height: 94rpx;
                background: linear-gradient(
                    105.95deg,
                    #a27867 0%,
                    #74483d 100%
                );
                border-radius: 28rpx;
                box-shadow: 0rpx 4.69rpx 18.75rpx rgba(72, 41, 29, 0.15),
                    0rpx 9.38rpx 9.38rpx rgba(154, 132, 89, 0.2),
                    0rpx -4.69rpx 28.13rpx 4.69rpx #a16647 inset;
                font-family: MiSans;
                font-weight: 500;
                color: #ffffff;
                font-size: 32rpx;
            }
            .closeBreath {
                display: flex;
                align-items: center;
                justify-content: center;
                width: 328rpx;
                height: 94rpx;
                background: #ffebe4;
                border-radius: 28rpx;
                font-weight: 500;
                color: #111111;
                font-size: 32rpx;
                text-align: center;
            }
        }
    }

    /* 弹窗部分样式 */
    .mask {
        position: fixed;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        background: rgba(0, 0, 0, 0.3);
        z-index: 100;
    }

    .share-modal {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        background: #fff;
        border-radius: 24rpx 24rpx 0 0;
        z-index: 101;
        height: 750rpx;

        .modal-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 32rpx 32rpx 0 32rpx;
            font-size: 30rpx;

            .cancel-btn {
                color: #888;
                font-size: 32rpx;
            }

            .modal-title {
                color: #111111;
                font-size: 36rpx;
            }

            .confirm-btn {
                color: #996e5f;
                font-size: 32rpx;
            }
        }

        .modal-body {
            padding: 50rpx;

            .info-row {
                display: flex;
                margin-bottom: 24rpx;
                font-size: 28rpx;
                padding: 0 20rpx;

                .label {
                    color: #111111;
                    width: 200rpx;
                    font-size: 32rpx;
                    text-align-last: justify;
                }

                .value {
                    text-align: right;
                    width: 65%;
                    color: #111111;
                    font-size: 32rpx;
                }
            }

            .input-row {
                display: flex;
                align-items: center;
                margin-top: 32rpx;
                border-radius: 40rpx;
                background: #f7f7f7;
                padding: 0 24rpx;
                height: 80rpx;

                .input {
                    text-align: right;
                    flex: 1;
                    border: none;
                    background: transparent;
                    font-size: 28rpx;
                    color: #333;
                }
            }

            .funChoice {
                .funItem {
                    .simple-radio {
                        display: flex;
                        align-items: center;
                        padding: 20rpx 0;
                    }
                }
            }
        }
    }

    // 分享弹窗样式

    .modal-mask {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: rgba(0, 0, 0, 0.5);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 555;

        .modal-container {
            width: 80%;
            background: #fff;
            border-radius: 16rpx;
            // overflow: hidden;
            animation: fadeIn 0.3s;

            .modal-header {
                padding: 30rpx;
                text-align: center;
                border-bottom: 1rpx solid #f5f5f5;

                .title {
                    font-size: 36rpx;
                    display: block;
                    margin-bottom: 10rpx;
                }
            }

            .modal-buttons {
                display: flex;
                flex-direction: column;
                padding: 20rpx;

                .btn {
                    flex: 1;
                    height: 90rpx;
                    margin: 15rpx 0;
                    border-radius: 45rpx;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    font-size: 32rpx;
                    border: none;
                    background: none;
                    position: relative;
                }

                .btn-icon {
                    width: 40rpx;
                    height: 40rpx;
                    margin-right: 15rpx;
                }

                .phone-btn {
                    background: linear-gradient(
                        105.95deg,
                        #ba978a 0%,
                        #a27867 100%
                    );
                    color: white;
                }

                .link-btn {
                    background: linear-gradient(
                        105.95deg,
                        #a27867 0%,
                        #74483d 100%
                    );
                    color: white;
                }
            }
        }
    }

    .echartsClass {
        position: absolute;
        width: 650rpx;
        height: 600rpx;
        top: -8%;
        left: -37%;
        transform: translate(50%, 50%);
        background: #ffffff;
        z-index: 99;
        .closePng {
            width: 40rpx;
            height: 40rpx;
            position: fixed;
            top: 10rpx;
            right: 10rpx;
            z-index: 555;
        }
    }
}
</style>
