Files
dyf-vue-ui/src/views/controlCenter/controlPanel/components/map.vue
2025-08-26 16:20:35 +08:00

267 lines
6.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="amap_page">
<div ref="mapRef" class="amap-container"></div>
<div class="content_top">
<div class="content_layout">
<!-- 左侧设备列表带复选框 -->
<div class="device_list">
<!-- 全选复选框 -->
<div class="list_header">
<el-checkbox v-model="checkAll" @change="handleCheckAllChange" label="全选"></el-checkbox>
</div>
<!-- 设备项带复选框 -->
<div class="device_item" v-for="(device, index) in props.deviceList" :key="index">
<!-- 复选框 -->
<el-checkbox :value="device.id" v-model="checkedDeviceIds" class="device_checkbox"></el-checkbox>
<!-- 设备信息 -->
<div class="device_page">
<div class="device_info">
<div class="device_name">{{ device.deviceName }}</div>
<div class="device_model">{{ device.typeName }}</div>
<div class="device_status"
:class="{ online: device.onlineStatus === 1, offline: device.onlineStatus === 0 }">
{{ device.onlineStatus === 1 ? '在线' : '离线' }}
</div>
</div>
<!-- 控制按钮 -->
<el-button class="control_btn" @click="handleControl(device)">控制</el-button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const props = defineProps({
deviceList: {
type: Array,
required: false,
default: () => [] // 数组/对象类型的默认值必须用函数返回,避免引用共享
}
});
console.log(props.deviceList);
const router = useRouter();
// 声明高德地图全局类型
declare var AMap: any;
// 高德Key与安全密钥
const AMAP_KEY = '90bc158992feb8ccd0145e168cab1307';
const AMAP_SECURITY_CODE = '5ed9004cb461cd463580b02a775c8d91';
// 地图实例
const mapRef = ref<HTMLDivElement | null>(null);
let mapInstance: any = null;
// 复选框状态管理
const checkedDeviceIds = ref(); // 存储选中的设备ID
const checkAll = ref(false); // 全选状态
// 全选/取消全选
const handleCheckAllChange = (val: boolean) => {
checkedDeviceIds.value = val
? props.deviceList.map(device => device.id) // 全选选中所有设备ID
: []; // 取消全选:清空
};
// 监听单个复选框变化,更新全选状态
watch(checkedDeviceIds, (newVal) => {
checkAll.value = newVal.length === props.deviceList.length && props.deviceList.length > 0;
});
// 设备控制事件
const handleControl = (device: any) => {
console.log('控制设备:', device);
const deviceId = device.id;
router.push('/controlCenter/6170/' + deviceId);
};
// 新增:获取地图中心坐标(优先用设备数据,无则用默认)
const getCenterCoord = () => {
// 1. 遍历设备列表,找第一个有有效经纬度的设备
const validDevice = props.deviceList.find(
(device:any) =>
device.longitude !== undefined &&
device.longitude !== null &&
device.latitude !== undefined &&
device.latitude !== null &&
!isNaN(Number(device.longitude)) && // 确保是数字(避免字符串空值/非数字)
!isNaN(Number(device.latitude))
);
// 2. 有有效设备则用它的坐标,否则用默认值
if (validDevice) {
return [Number(validDevice.longitude), Number(validDevice.latitude)]; // 转数字防字符串坐标
} else {
return [114.4074, 30.5928]; // 默认中心坐标
}
};
// 地图初始化修改center配置
const initMap = () => {
if (!window.AMap || !mapRef.value) return;
// 2. 调用函数获取中心坐标(不再用固定值)
const centerCoord = getCenterCoord();
mapInstance = new AMap.Map(mapRef.value, {
center: centerCoord, // 改用动态获取的坐标
zoom: 15,
resizeEnable: true
});
// 后续的设备打点逻辑不变...
if (Array.isArray(props.deviceList)) {
props.deviceList.forEach(device => {
console.log(device, 'devicedevice');
if (device.longitude && device.latitude) {
new AMap.Marker({
position: [device.longitude, device.latitude],
title: device.deviceName,
map: mapInstance
});
}
});
}
};
watch(
() => props.deviceList, // 监听props中的deviceList
(newDeviceList) => {
if (!mapInstance || !Array.isArray(newDeviceList)) return;
// 1. 清除地图上已有的所有标记(避免重复打点)
mapInstance.clearMap();
// 2. 重新添加新的设备标记
newDeviceList.forEach((device) => {
console.log(device, 'device');
// 确保设备有经纬度lng和lat避免无效打点
if (device.longitude && device.latitude) {
new AMap.Marker({
position: [device.longitude, device.latitude],
title: device.deviceName, // 用设备名当标题(匹配父组件字段)
map: mapInstance,
});
}
});
},
{ deep: true } // 深度监听(如果设备列表里的子对象变化也能触发)
);
onMounted(() => {
window._AMapSecurityConfig = { securityJsCode: AMAP_SECURITY_CODE };
if (window.AMap) {
initMap();
} else {
const script = document.createElement('script');
script.src = `https://webapi.amap.com/maps?v=2.0&key=${AMAP_KEY}`;
script.onload = initMap;
document.head.appendChild(script);
}
});
onUnmounted(() => {
if (mapInstance) mapInstance.destroy();
});
</script>
<style scoped>
/* 地图容器 */
.amap_page {
position: relative;
}
.amap-container {
height: 640px;
border-radius: 4px;
overflow: hidden;
width: 100%;
}
.content_top {
width: 210px;
border-radius: 4px;
box-shadow: 0px 0px 6px 0px rgba(0, 34, 96, 0.1);
background: rgba(255, 255, 255, 1);
height: 620px;
position: absolute;
z-index: 1;
top: 10px;
left: 10px
}
/* 全选行样式 */
.list_header {
padding: 12px;
border-bottom: 1px solid #eee;
font-weight: 600;
}
/* 设备项样式 */
.device_item {
padding: 0px 12px;
display: flex;
align-items: center;
/* 复选框与内容间距 */
cursor: default;
transition: background 0.2s;
}
/* 复选框样式 */
.device_checkbox {
flex-shrink: 0;
/* 复选框不压缩 */
}
/* 设备信息区域 */
.device_page {
background-color: rgba(247, 248, 252, 1);
margin-bottom: 5px;
width: 84%;
padding: 5px;
border-radius: 4px;
position: relative;
}
.device_name {
font-weight: 500;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.device_model {
font-size: 12px;
color: #666;
margin: 4px 0;
}
.device_status {
font-size: 12px;
}
.online {
color: #00b42a;
}
.offline {
color: #f53f3f;
}
/* 控制按钮 */
.control_btn {
font-size: 12px;
padding: 0px 15px;
flex-shrink: 0;
position: absolute;
right: 16px;
bottom: 10px;
background: rgba(2, 124, 251, 0.06);
color: rgba(2, 124, 251, 1);
border: none;
}
</style>