feat: 地图

This commit is contained in:
Tony 2024-03-25 16:08:44 +08:00
parent 4b486a2166
commit 13d3f9d41c
10 changed files with 647 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -0,0 +1,114 @@
export const dataList = [
{
id: '1',
type: 'monitor',
name: '视频监控点',
online: true,
position: [106.51685063838954, 29.549996433530573],
},
{
id: '2',
type: 'monitor',
name: '视频监控点',
online: true,
position: [106.5020019292831, 29.56104644463005],
},
{
id: '3',
type: 'monitor',
name: '视频监控点',
online: true,
position: [106.42818753719325, 29.53058132616194],
},
{
id: '4',
type: 'monitor',
name: '视频监控点',
online: true,
position: [106.502345252037, 29.53207492831776],
},
{
id: '5',
type: 'monitor',
name: '视频监控点',
online: true,
position: [106.52054135799403, 29.604935898075833],
},
// ----------------危险运输车辆---------------------
{
id: '6',
type: 'car',
name: '危险运输车辆',
online: true,
position: [106.46732633113857, 29.530880048357652],
},
{
id: '7',
type: 'car',
name: '危险运输车辆',
online: true,
position: [106.4748794317245, 29.648806258349282],
},
{
id: '8',
type: 'car',
name: '危险运输车辆',
online: true,
position: [106.425440955162, 29.624933602158773],
},
// ----------------应急人员手机---------------------
{
id: '9',
type: 'phone',
name: '应急人员手机',
phone: '15832469588',
online: true,
position: [106.61083524227138, 29.572991044188402],
},
{
id: '10',
type: 'phone',
name: '应急人员手机',
phone: '15022564484',
online: true,
position: [106.51539151668544, 29.630902296713813],
},
{
id: '11',
type: 'phone',
name: '应急人员手机',
phone: '15845441514',
online: true,
position: [106.41857450008388, 29.669093565747513],
},
{
id: '12',
type: 'phone',
name: '应急人员手机',
phone: '17845448475',
online: false,
position: [106.42956082820888, 29.522216747672],
},
// --------------应急指挥车-----------------------
{
id: '13',
type: 'track',
name: '应急指挥车',
online: true,
position: [106.49410550594325, 29.526697856167267],
},
{
id: '14',
type: 'track',
name: '应急指挥车',
online: true,
position: [106.45565335750575, 29.46244964301153],
},
{
id: '16',
type: 'track',
name: '应急指挥车',
online: false,
position: [106.41102139949794, 29.4633464099924],
},
]

View File

@ -0,0 +1,227 @@
<template>
<div class="sudden-map-wrapper">
<div id="imageMap"></div>
<div class="top-tool-wrapper" v-show="false">
<div class="top-tool-item">
<el-input
style="width: 80%"
size="mini"
id="tipinput"
class="form-control input-style"
type="text"
placeholder="请输入搜索地址"
prefix-icon="el-icon-search"
v-model="mapAddress"
>
</el-input>
<el-button style="margin-left: .4rem;" type="primary" size="mini" @click="startPlaceSearch.search(mapAddress);">搜索</el-button>
</div>
<div class="top-tool-item extra-tool-item" style="padding-top: .4rem;">
<div style="font-size: .9rem;padding-bottom: .2rem;font-family: 'BiaoTiFont';color: #252525 ;">历史突发事件总览</div>
<el-radio-group v-model="radio" @change="handleRadioChange" size="small">
<el-radio-button label="全部"></el-radio-button>
<el-radio-button label="过去24h"></el-radio-button>
</el-radio-group>
</div>
</div>
<div class="legend-wrapper">
<div class="legend-item">
<img src="/images/mapIcon/monitor.png" alt="" style="width: 2rem;">
<span style="padding-left: .2rem;">视频监控点</span>
</div>
<div class="legend-item">
<img src="/images/mapIcon/car.png" alt="" style="width: 2rem;">
<span style="padding-left: .2rem;">危险运输车辆</span>
</div>
<div class="legend-item">
<img src="/images/mapIcon/phone.png" alt="" style="width: 2rem;">
<span style="padding-left: .2rem;">应急人员手机</span>
</div>
<div class="legend-item">
<img src="/images/mapIcon/track.png" alt="" style="width: 2rem;">
<span style="padding-left: .2rem;">应急指挥车</span>
</div>
</div>
</div>
</template>
<script>
import AMapLoader from "@amap/amap-jsapi-loader";
window._AMapSecurityConfig = {
securityJsCode: "b6314ade5a42c3f3ac2284b6d4d89b1f",
};
import { dataList } from "./data";
export default {
data() {
return {
map: null,
mapAddress: '',
startAutoComplete: null,
startPlaceSearch: null, //
radio: '全部',
}
},
mounted() {
this.initMap()
},
methods: {
handleRadioChange(e) {
console.log('err', e);
},
initMap() {
const that = this;
AMapLoader.load({
key: "e49669059fa36494531a82ed982f395c", // WebKey load
version: "1.4.15", // JSAPI 1.4.15
plugins: ["AMap.AutoComplete", "AMap.PlaceSearch"], // 使'AMap.Scale'
}).then((AMap) => {
that.map = new AMap.Map("imageMap", {
zoom: 12, //
center: [106.45916663154958, 29.55508114847212], //
mapStyle: "amap://styles/blue",
});
that.map.on("click", (e) => {
navigator.clipboard.writeText(
`[${e.lnglat.R.toString()}, ${e.lnglat.Q.toString()}],`
);
});
//
AMap.plugin(
["AMap.PlaceSearch", "AMap.Autocomplete"],
(status, result) => {
let autoOptions1 = {
input: "tipinput",
city: "重庆",
};
that.startAutoComplete = new AMap.Autocomplete(autoOptions1);
that.startPlaceSearch = new AMap.PlaceSearch({
map: that.map,
})
that.startAutoComplete.on("select", that.handleStartSelect); //
}
);
dataList.forEach(item => {
that.addMarker(item.position, item.type, item)
})
})
},
handleStartSelect(event) {
console.log(event, "起点经纬度 [lng,lat]");
},
addMarker(sourceData = [], type = "", info = {}) {
if (!type) return
const marker = new AMap.Marker({
position: new AMap.LngLat(sourceData[0], sourceData[1]),
offset: new AMap.Pixel(-30, -52),
icon: new AMap.Icon({
size: new AMap.Size(40, 40), //
image: `/images/mapIcon/${type}.png`, // Icon
// imageOffset: new AMap.Pixel(0, -60), //
imageSize: new AMap.Size(40, 40) //
}),
title: "",
});
this.map.add(marker);
marker.on("click", (e) => {
this.showInfoWindow(sourceData[0], sourceData[1], {
type, ...info,
});
});
},
//
showInfoWindow(lng, lat, sourceInfo) {
let content = `
<div style="padding: .4rem;background-color: white;border-radius: .3rem;min-width: 10rem;">
<div style="font-family: 'BiaoTiFont';text-align:center;">
${sourceInfo.name || '监控点'}
</div>
<div style="padding: .4rem;">
<div style="font-size: .9rem;display: flex;align-items:center;padding: .1rem;">
<div style="width: 3rem;">经度:</div>
<div>${lng}</div>
</div>
<div style="font-size: .9rem;display: flex;align-items:center;padding: .1rem;">
<div style="width: 3rem;">纬度:</div>
<div>${lat}</div>
</div>
${
sourceInfo.phone ?
`<div style="font-size: .9rem;display: flex;align-items:center;padding: .1rem;">
<div style="width: 3rem;">手机:</div>
<div>${sourceInfo.phone}</div>
</div>`
: ''
}
<div style="font-size: .9rem;display: flex;align-items:center;padding: .1rem;">
<div style="width: 3rem;">状态:</div>
<div>${sourceInfo.online ? '在线' : '离线'}</div>
</div>
</div>
</div>
`;
const infoWindow = new AMap.InfoWindow({
content,
anchor: "middle-left",
isCustom: true,
});
infoWindow.open(this.map, [lng, lat]);
},
}
}
</script>
<style scoped>
.sudden-map-wrapper {
width: 100%;
position: relative;
height: calc(100vh - 84px);
}
#imageMap {
width: 100%;
height: 100%;
background-color: #00ffff45;
position: relative;
z-index: 10;
}
.top-tool-wrapper {
position: absolute;
left: 1rem;
top: 1rem;
z-index: 99;
}
.top-tool-item {
display: flex;
}
.extra-tool-item {
display: block !important;
background-color: white;
padding: .6rem;
box-shadow: 2px 2px 2px #25252525, -2px -2px 2px #13131313;
border-radius: .3rem;
}
.legend-wrapper {
display: flex;
align-items: center;
position: absolute;
right: 1rem;
bottom: 1rem;
z-index: 99;
background-color: #ffffffc4;
backdrop-filter: blur(2px);
padding: .8rem .6rem;
box-shadow: 2px 2px 2px #25252525, -2px -2px 2px #13131313;
border-radius: .3rem;
}
.legend-item {
display: flex;
align-items: center;
padding: 0 .6rem;
}
</style>

View File

@ -0,0 +1,60 @@
import { formatDate } from '@/utils/index'
export const dataList = [
{
id: '1',
timeStamp: new Date().valueOf() - 100,
time: formatDate(new Date().valueOf() - 100),
position: [106.41385381221767, 29.56672030501069],
location: '未知地点',
info: '出现突发事件,请及时处理'
},
{
id: '2',
timeStamp: new Date().valueOf() - 60 * 1000 * 60 * 7,
time: formatDate(new Date().valueOf() - 60 * 1000 * 60 * 7),
position: [106.45711247920985, 29.527892786699596],
location: '未知地点',
info: '出现突发事件,请及时处理'
},
{
id: '3',
timeStamp: new Date().valueOf() - 60 * 1000 * 60 * 25,
time: formatDate(new Date().valueOf() - 60 * 1000 * 60 * 25),
position: [106.42621343001724, 29.50668069012108],
location: '未知地点',
info: '出现突发事件,请及时处理'
},
{
id: '4',
timeStamp: new Date().valueOf() - 60 * 1000 * 60 * 49,
time: formatDate(new Date().valueOf() - 60 * 1000 * 60 * 49),
position: [106.46843913808465, 29.5644299141877],
location: '重庆大学',
info: '出现突发事件,请及时处理'
},
{
id: '5',
timeStamp: new Date().valueOf() - 60 * 1000 * 60 * 79,
time: formatDate(new Date().valueOf() - 60 * 1000 * 60 * 79),
position: [106.41634001210332, 29.52937152958798],
location: '重庆中医院',
info: '出现突发事件,请及时处理'
},
{
id: '6',
timeStamp: new Date().valueOf() - 60 * 1000 * 60 * 71,
time: formatDate(new Date().valueOf() - 60 * 1000 * 60 * 71),
position: [106.47633566334844, 29.470897658110307],
location: '新山村',
info: '出现突发事件,请及时处理'
},
{
id: '7',
timeStamp: new Date().valueOf() - 60 * 1000 * 60 * 70,
time: formatDate(new Date().valueOf() - 60 * 1000 * 60 * 70),
position: [106.53264059364795, 29.54790951985214],
location: '佛图关',
info: '出现突发事件,请及时处理'
},
]

View File

@ -0,0 +1,246 @@
<template>
<div class="sudden-map-wrapper">
<div id="suddenMap"></div>
<div class="top-tool-wrapper">
<div class="top-tool-item" v-show="false">
<el-input
style="width: 80%"
size="mini"
id="tipinput"
class="form-control input-style"
type="text"
placeholder="请输入搜索地址"
prefix-icon="el-icon-search"
v-model="mapAddress"
>
</el-input>
<el-button style="margin-left: .4rem;" type="primary" size="mini" @click="startPlaceSearch.search(mapAddress);">搜索</el-button>
</div>
<div class="top-tool-item extra-tool-item" style="padding-top: .4rem;">
<div style="font-size: .9rem;padding-bottom: .2rem;font-family: 'BiaoTiFont';color: #252525 ;">历史突发事件总览</div>
<el-radio-group v-model="radio" @change="handleRadioChange" size="small">
<el-radio-button label="全部"></el-radio-button>
<el-radio-button label="过去24h"></el-radio-button>
<el-radio-button label="过去48h"></el-radio-button>
<el-radio-button label="过去72h"></el-radio-button>
</el-radio-group>
</div>
</div>
<div class="legend-wrapper">
<div class="legend-item">
<img src="/images/mapIcon/error.png" alt="" style="width: 2rem;">
<span style="padding-left: .2rem;">突发事件</span>
</div>
</div>
</div>
</template>
<script>
import AMapLoader from "@amap/amap-jsapi-loader";
import { dataList } from "./data";
window._AMapSecurityConfig = {
securityJsCode: "b6314ade5a42c3f3ac2284b6d4d89b1f",
};
export default {
data() {
return {
map: null,
mapAddress: '',
startAutoComplete: null,
startPlaceSearch: null, //
radio: '全部',
mouseTool: null,
overlays: []
}
},
mounted() {
this.initMap()
},
methods: {
handleRadioChange(e) {
console.log('err', e);
this.map.clearMap();
dataList.filter(item => {
console.log('time', item.timeStamp);
if (e === '过去24h') return item.timeStamp < (new Date().valueOf() - 1000 * 60 * 60 * 24);
if (e === '过去48h') return item.timeStamp < (new Date().valueOf() - 1000 * 60 * 60 * 48);
if (e === '过去72h') return item.timeStamp < (new Date().valueOf() - 1000 * 60 * 60 * 72);
return true
}).forEach(item => {
this.addMarker(item.position, 'error', item)
})
},
initMap() {
const that = this;
AMapLoader.load({
key: "e49669059fa36494531a82ed982f395c", // WebKey load
version: "1.4.15", // JSAPI 1.4.15
plugins: ["AMap.AutoComplete", "AMap.PlaceSearch"], // 使'AMap.Scale'
}).then((AMap) => {
that.map = new AMap.Map("suddenMap", {
zoom: 12, //
center: [106.45916663154958, 29.55508114847212], //
mapStyle: "amap://styles/blue",
});
that.map.on("click", (e) => {
navigator.clipboard.writeText(
`[${e.lnglat.R.toString()}, ${e.lnglat.Q.toString()}],`
);
});
//
AMap.plugin(
["AMap.PlaceSearch", "AMap.Autocomplete", "AMap.MouseTool"],
(status, result) => {
let autoOptions1 = {
input: "tipinput",
city: "重庆",
};
that.startAutoComplete = new AMap.Autocomplete(autoOptions1);
that.startPlaceSearch = new AMap.PlaceSearch({
map: that.map,
})
that.startAutoComplete.on("select", that.handleStartSelect); //
that.mouseTool = new AMap.MouseTool(that.map);
that.mouseTool.on('draw',function(e){
that.overlays.push(e.obj);
setTimeout(() => {
that.map.remove(that.overlays)
}, 200)
})
that.mouseTool.rectangle({
fillColor: '#00b0ff',
strokeColor: '#80d8ff'
// PolygonOption
});
}
);
dataList.forEach(item => {
console.log('item', item);
that.addMarker(item.position, 'error', item)
})
})
},
handleStartSelect(event) {
console.log(event, "起点经纬度 [lng,lat]");
},
addMarker(sourceData = [], type = "error", info = {}) {
if (!type) return
const marker = new AMap.Marker({
position: new AMap.LngLat(sourceData[0], sourceData[1]),
offset: new AMap.Pixel(-30, -52),
icon: new AMap.Icon({
size: new AMap.Size(40, 40), //
image: `/images/mapIcon/${type}.png`, // Icon
// imageOffset: new AMap.Pixel(0, -60), //
imageSize: new AMap.Size(40, 40) //
}),
title: "",
});
this.map.add(marker);
marker.on("click", (e) => {
this.showInfoWindow(sourceData[0], sourceData[1], {
type, ...info,
});
});
},
//
showInfoWindow(lng, lat, sourceInfo) {
let content = `
<div style="padding: .4rem;background-color: white;border-radius: .3rem;min-width: 10rem;">
<div style="font-family: 'BiaoTiFont';text-align:center;">
${'突发事件'}
</div>
<div style="padding: .4rem;">
<div style="font-size: .9rem;display: flex;align-items:center;padding: .1rem;">
<div style="width: 5rem;">经度:</div>
<div>${lng}</div>
</div>
<div style="font-size: .9rem;display: flex;align-items:center;padding: .1rem;">
<div style="width: 5rem;">纬度:</div>
<div>${lat}</div>
</div>
<div style="font-size: .9rem;display: flex;align-items:center;padding: .1rem;">
<div style="width: 5rem;">时间:</div>
<div>${sourceInfo.time}</div>
</div>
<div style="font-size: .9rem;display: flex;align-items:center;padding: .1rem;">
<div style="width: 5rem;">地点:</div>
<div>${sourceInfo.location}</div>
</div>
<div style="font-size: .9rem;display: flex;align-items:center;padding: .1rem;">
<div style="width: 5rem;">事件内容:</div>
<div>${sourceInfo.info}</div>
</div>
</div>
</div>
`;
const infoWindow = new AMap.InfoWindow({
content,
anchor: "middle-left",
isCustom: true,
});
infoWindow.open(this.map, [lng, lat]);
},
}
}
</script>
<style scoped>
.sudden-map-wrapper {
width: 100%;
position: relative;
height: calc(100vh - 84px);
}
#suddenMap {
width: 100%;
height: 100%;
background-color: #00ffff45;
position: relative;
z-index: 10;
}
.top-tool-wrapper {
position: absolute;
left: 1rem;
top: 1rem;
z-index: 99;
}
.top-tool-item {
display: flex;
}
.extra-tool-item {
display: block !important;
background-color: white;
padding: .6rem;
box-shadow: 2px 2px 2px #25252525, -2px -2px 2px #13131313;
border-radius: .3rem;
}
.legend-wrapper {
display: flex;
align-items: center;
position: absolute;
right: 1rem;
bottom: 1rem;
z-index: 99;
background-color: #ffffffc4;
backdrop-filter: blur(2px);
padding: .8rem .6rem;
box-shadow: 2px 2px 2px #25252525, -2px -2px 2px #13131313;
border-radius: .3rem;
}
.legend-item {
display: flex;
align-items: center;
padding: 0 .6rem;
}
</style>