| | |
| | | <template> |
| | | <div class="detail" ref="detailRef"> |
| | | <div class="detail-top">{{ detailTitle }}</div> |
| | | <div class="detail-close" @click="closeMsg"></div> |
| | | <div class="detail-context"> |
| | | <div v-for="(item, key) in detailList" :key="key" class="detail-item"> |
| | | <div class="detail-name">{{ item.name }}</div> |
| | | <div class="detail-value" :title="item.value">{{ item.value || "--" }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="detail" ref="detailRef"> |
| | | <div class="detail-top" :title="name">{{ detailTitle }}</div> |
| | | <div class="detail-close" @click="closeMsg"></div> |
| | | <div class="detail-context"> |
| | | <div v-for="(item, key) in detailList" :key="key" class="detail-item"> |
| | | <div class="detail-name">{{ item.name }}</div> |
| | | <div class="detail-value" :title="item.value"> |
| | | {{ item.value || "--" }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, nextTick, onUnmounted } from "vue"; |
| | | import { showDeviceDetail, deviceDetail, className, dialogPositon } from "@/store" |
| | | import { ref, onMounted, nextTick, onUnmounted } from "vue"; |
| | | import { |
| | | showDeviceDetail, |
| | | deviceDetail, |
| | | className, |
| | | dialogPositon, |
| | | } from "@/store"; |
| | | |
| | | // props: { |
| | | // deviceDetail: { |
| | | // type: Object, |
| | | // default: { |
| | | // deviceCode: "1101161102180100031040", |
| | | // deviceId: "1554360448383913986", |
| | | // deviceName: "怀柔区琉璃庙镇孙胡沟村于家西沟次声仪1040", |
| | | // dictDeviceType: "1437295832", |
| | | // latitude: 40.563822, |
| | | // longitude: 116.592648, |
| | | // type: "次生仪", |
| | | // name: "怀柔区琉璃庙镇孙胡沟村于家西沟次声仪1040", |
| | | // id: "1554360448383913986", |
| | | // }, |
| | | // }, |
| | | // }, |
| | | const detailList = ref([]) |
| | | const detailTitle = ref("设备详情") |
| | | function closeMsg() { |
| | | showDeviceDetail.value = false |
| | | coloseDialog() |
| | | } |
| | | function handlDeviceDetail() { |
| | | const name = deviceDetail.value.name.split("孙胡沟")[1] || deviceDetail.value.deviceName |
| | | detailTitle.value = name |
| | | detailList.value = [ |
| | | { |
| | | name: "设备编号", |
| | | value: deviceDetail.value.deviceCode || Math.floor(Math.random() * 100000), |
| | | }, |
| | | { |
| | | name: "设备类型", |
| | | value: deviceDetail.value.type || "", |
| | | }, |
| | | { |
| | | name: "安装时间", |
| | | value: "2024-01-15 12:55:18", |
| | | }, |
| | | { |
| | | name: "更新时间", |
| | | value: "2025-02-15 8:15:28", |
| | | }, |
| | | { |
| | | name: "设备位置", |
| | | value: deviceDetail.value.name.split("孙胡沟")[0] || cityData.listData[0], |
| | | }, |
| | | ] |
| | | } |
| | | function handleDistrictDetail() { |
| | | const name = deviceDetail.value.name || deviceDetail.value.district |
| | | detailTitle.value = name |
| | | detailList.value = [ |
| | | { |
| | | name: "隐患类型", |
| | | value: deviceDetail.value.type || "泥石流", |
| | | }, |
| | | // { |
| | | // name: "威胁人数", |
| | | // value: deviceDetail.value.type || "", |
| | | // }, |
| | | { |
| | | name: "主管科长", |
| | | value: "张浩", |
| | | }, |
| | | { |
| | | name: "主管镇长", |
| | | value: "刘佳斌", |
| | | }, |
| | | { |
| | | name: "群测群防", |
| | | value: deviceDetail.value.groupMonitor, |
| | | }, |
| | | { |
| | | name: "隐患位置", |
| | | value: deviceDetail.value.district, |
| | | }, |
| | | { |
| | | name: "预防方案", |
| | | value: deviceDetail.value.preventionPlan, |
| | | }, |
| | | ] |
| | | } |
| | | function loadClassNameDetail() { |
| | | if (className.value == "device") { |
| | | handlDeviceDetail() |
| | | } else if (className.value == "district") { |
| | | handleDistrictDetail() |
| | | } |
| | | } |
| | | const detailRef = ref(null) |
| | | //展示属性框 |
| | | function calcDialogPostion() { |
| | | const position = dialogPositon.value; |
| | | if (!position) { |
| | | console.error("dialogPositon is null or invalid"); |
| | | return; |
| | | } |
| | | import { hdByDevice } from "@/api/hpApi"; |
| | | |
| | | const bubble = detailRef.value; |
| | | if (!bubble) { |
| | | console.error("detailRef is null, DOM not ready"); |
| | | return; |
| | | } |
| | | |
| | | let winpos = window.viewer.scene.cartesianToCanvasCoordinates(position); |
| | | if (!winpos || isNaN(winpos.x) || isNaN(winpos.y)) { |
| | | console.error("Invalid canvas coordinates:", winpos); |
| | | return; |
| | | } |
| | | |
| | | let poph = bubble.offsetHeight; |
| | | bubble.style.left = winpos.x - 200 + "px"; |
| | | let top = winpos.y - poph - 50; |
| | | bubble.style.top = top + "px"; |
| | | const detailList = ref([]); |
| | | const detailTitle = ref("设备详情"); |
| | | const name = ref(""); |
| | | function closeMsg() { |
| | | showDeviceDetail.value = false; |
| | | coloseDialog(); |
| | | } |
| | | |
| | | // 监测设备具体信息 |
| | | async function handlDeviceDetail() { |
| | | const hdInfo = ref(); |
| | | |
| | | //关闭属性框 |
| | | const coloseDialog = () => { |
| | | window.viewer.scene.postRender.removeEventListener(calcDialogPostion) |
| | | } |
| | | onMounted(() => { |
| | | loadClassNameDetail(); |
| | | nextTick(() => { |
| | | window.viewer.scene.postRender.addEventListener(calcDialogPostion); |
| | | }); |
| | | try { |
| | | const res = await hdByDevice(deviceDetail.value.hdUnifiedCode); |
| | | hdInfo.value = res.data; |
| | | |
| | | detailList.value = [ |
| | | { |
| | | name: "设备编号", |
| | | value: deviceDetail.value.deviceCode || Math.floor(Math.random() * 100000), |
| | | }, |
| | | { |
| | | name: "设备类型", |
| | | value: deviceDetail.value.type || deviceDetail.value.deviceTypeName, |
| | | }, |
| | | { |
| | | name: "关联隐患点", |
| | | value: deviceDetail.value.hdName, |
| | | }, |
| | | { |
| | | name: "群测群防员", |
| | | value: hdInfo.value?.groupTestGroupDefenseUserName || "暂无信息", |
| | | }, |
| | | { |
| | | name: "群测群防员电话", |
| | | value: hdInfo.value?.groupTestGroupDefenseMobile || "暂无信息", |
| | | }, |
| | | ]; |
| | | |
| | | detailTitle.value = deviceDetail.value.deviceForShort; |
| | | } catch (err) { |
| | | console.error("获取 hdInfo 失败", err); |
| | | detailList.value = [ |
| | | { |
| | | name: "群测群防员", |
| | | value: "接口异常" |
| | | }, |
| | | { |
| | | name: "群测群防员电话", |
| | | value: "接口异常" |
| | | } |
| | | ]; |
| | | } |
| | | } |
| | | |
| | | // 隐患点具体信息 |
| | | function handleDistrictDetail() { |
| | | const name = deviceDetail.value.hdName; |
| | | detailTitle.value = name; |
| | | detailList.value = [ |
| | | // {} |
| | | { |
| | | name: "灾害类型", |
| | | value: deviceDetail.value.disasterType || "泥石流", |
| | | }, |
| | | { |
| | | name: "威胁对象", |
| | | value: deviceDetail.value.threatObj || "居民点", |
| | | }, |
| | | { |
| | | name: "规模等级", |
| | | value: deviceDetail.value.disasterGrade || "小型", |
| | | }, |
| | | { |
| | | name: "险情等级", |
| | | value: deviceDetail.value.riskLevel || "小型", |
| | | }, |
| | | { |
| | | name: "威胁人数", |
| | | value: deviceDetail.value.threatPersonNum || "0", |
| | | }, |
| | | { |
| | | name: "威胁户数", |
| | | value: deviceDetail.value.threatHouseNum || "0", |
| | | }, |
| | | { |
| | | name: "威胁房数", |
| | | value: deviceDetail.value.threatRoomNum || "0", |
| | | }, |
| | | { |
| | | name: "是否治理", |
| | | value: deviceDetail.value.isGovern || "否", |
| | | }, |
| | | { |
| | | name: "群测群防员", |
| | | value: deviceDetail.value.groupTestGroupDefenseUserName, |
| | | }, |
| | | { |
| | | name: "群测群防员电话", |
| | | value: deviceDetail.value.groupTestGroupDefenseMobile, |
| | | }, |
| | | { |
| | | name: "隐患位置", |
| | | value: deviceDetail.value.position, |
| | | }, |
| | | { |
| | | name: "预防方案", |
| | | value: deviceDetail.value.preventionSuggestion, |
| | | }, |
| | | ]; |
| | | } |
| | | function loadClassNameDetail() { |
| | | if (className.value == "device") { |
| | | handlDeviceDetail(); |
| | | name.value = deviceDetail.value.deviceName; |
| | | } else if (className.value == "district") { |
| | | handleDistrictDetail(); |
| | | name.value = deviceDetail.value.hdName; |
| | | } |
| | | } |
| | | const detailRef = ref(null); |
| | | //展示属性框 |
| | | function calcDialogPostion() { |
| | | const position = dialogPositon.value; |
| | | if (!position) { |
| | | console.error("dialogPositon is null or invalid"); |
| | | return; |
| | | } |
| | | |
| | | const bubble = detailRef.value; |
| | | if (!bubble) { |
| | | console.error("detailRef is null, DOM not ready"); |
| | | return; |
| | | } |
| | | |
| | | let winpos = window.viewer.scene.cartesianToCanvasCoordinates(position); |
| | | if (!winpos || isNaN(winpos.x) || isNaN(winpos.y)) { |
| | | console.error("Invalid canvas coordinates:", winpos); |
| | | return; |
| | | } |
| | | |
| | | let poph = bubble.offsetHeight; |
| | | bubble.style.left = winpos.x - 200 + "px"; |
| | | let top = winpos.y - poph - 50; |
| | | bubble.style.top = top + "px"; |
| | | } |
| | | |
| | | //关闭属性框 |
| | | const coloseDialog = () => { |
| | | window.viewer.scene.postRender.removeEventListener(calcDialogPostion); |
| | | }; |
| | | onMounted(() => { |
| | | loadClassNameDetail(); |
| | | nextTick(() => { |
| | | window.viewer.scene.postRender.addEventListener(calcDialogPostion); |
| | | }); |
| | | }); |
| | | |
| | | onUnmounted(() => { |
| | | // 解决dom中offHeight报错 |
| | | window.viewer.scene.postRender.removeEventListener(calcDialogPostion); |
| | | // 解决dom中offHeight报错 |
| | | window.viewer.scene.postRender.removeEventListener(calcDialogPostion); |
| | | }); |
| | | </script> |
| | | <style lang="less" scoped> |
| | | .detail { |
| | | background: url("@/assets/img/tools/messagebg.png"); |
| | | background-size: 100% 100%; |
| | | width: 24.4375rem; |
| | | height: 24.5rem; |
| | | position: absolute; |
| | | top: 30%; |
| | | right: 30%; |
| | | } |
| | | .detail { |
| | | background: url("@/assets/img/tools/messagebg.png"); |
| | | background-size: 100% 100%; |
| | | width: 24.4375rem; |
| | | height: 24.5rem; |
| | | position: absolute; |
| | | top: 30%; |
| | | right: 30%; |
| | | } |
| | | |
| | | .detail-top { |
| | | position: absolute; |
| | | top: 0.3125rem; |
| | | left: 1.25rem; |
| | | font-weight: 700; |
| | | font-size: 1.125rem; |
| | | font-weight: 700; |
| | | color: #fff; |
| | | line-height: 2.5rem; |
| | | width: 16.875rem; |
| | | cursor: pointer; |
| | | } |
| | | .detail-top { |
| | | position: absolute; |
| | | top: 0.3125rem; |
| | | left: 1.25rem; |
| | | font-weight: 700; |
| | | font-size: 1.125rem; |
| | | color: #fff; |
| | | line-height: 2.5rem; |
| | | width: 16.875rem; /* 容器宽度固定或限制 */ |
| | | cursor: pointer; |
| | | |
| | | .detail-close { |
| | | position: absolute; |
| | | right: 0.1875rem; |
| | | top: 0rem; |
| | | width: 1.25rem; |
| | | height: 1.25rem; |
| | | text-align: center; |
| | | line-height: 1.25rem; |
| | | text-align: center; |
| | | /* 超出隐藏 + 省略号 */ |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | |
| | | font-weight: 700; |
| | | font-size: 1.125rem; |
| | | font-weight: 700; |
| | | color: #fff; |
| | | cursor: pointer; |
| | | } |
| | | /* 可选:添加过渡动画 */ |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .detail-context { |
| | | position: absolute; |
| | | top: 3.8rem; |
| | | left: 1.25rem; |
| | | width: 21.875rem; |
| | | } |
| | | .detail-close { |
| | | position: absolute; |
| | | right: 0.1875rem; |
| | | top: 0rem; |
| | | width: 1.25rem; |
| | | height: 1.25rem; |
| | | text-align: center; |
| | | line-height: 1.25rem; |
| | | text-align: center; |
| | | |
| | | .detail-item { |
| | | display: flex; |
| | | height: 1.4375rem; |
| | | margin-top: 0.9375rem; |
| | | margin-left: 0.625rem; |
| | | } |
| | | .detail-name { |
| | | width: 100px; |
| | | font-weight: 700; |
| | | color: #94e0c4; |
| | | &::after { |
| | | content: ":"; |
| | | } |
| | | } |
| | | font-weight: 700; |
| | | font-size: 1.125rem; |
| | | font-weight: 700; |
| | | color: #fff; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .detail-value { |
| | | color: #e1eee9; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | width: 250px; |
| | | } |
| | | .detail-context { |
| | | position: absolute; |
| | | top: 3.8rem; |
| | | left: 1.25rem; |
| | | width: 21.875rem; |
| | | overflow-y: auto; |
| | | height: 63%; |
| | | } |
| | | |
| | | .detail-btn { |
| | | background: url("@/assets/img/tools/messagebtn.png") no-repeat; |
| | | position: absolute; |
| | | bottom: 3.75rem; |
| | | right: 3.75rem; |
| | | width: 6.5625rem; |
| | | height: 1.625rem; |
| | | text-align: center; |
| | | color: #fff; |
| | | cursor: pointer; |
| | | } |
| | | .detail-item { |
| | | display: flex; |
| | | height: 1.4375rem; |
| | | margin-top: 0.9375rem; |
| | | margin-left: 0.625rem; |
| | | } |
| | | .detail-name { |
| | | display: inline-block; /* 关键 */ |
| | | max-width: 100%; /* 防止溢出 */ |
| | | font-weight: 700; |
| | | color: #94e0c4; |
| | | white-space: nowrap; /* 可选:防止文字换行 */ |
| | | &::after { |
| | | content: ":"; |
| | | } |
| | | } |
| | | |
| | | .detail-value { |
| | | color: #e1eee9; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | width: 250px; |
| | | } |
| | | |
| | | .detail-btn { |
| | | background: url("@/assets/img/tools/messagebtn.png") no-repeat; |
| | | position: absolute; |
| | | bottom: 3.75rem; |
| | | right: 3.75rem; |
| | | width: 6.5625rem; |
| | | height: 1.625rem; |
| | | text-align: center; |
| | | color: #fff; |
| | | cursor: pointer; |
| | | } |
| | | </style> |