2025-06-09 18:40:38 +08:00

838 lines
24 KiB
Vue

<template>
<div class="map-content">
<div class="map-box" id="mapContainer"></div>
<div class="wei-lan">
<div class="icon-off" v-if="!fenceShow" @click="openFence">
<img src="@/assets/images/carPosition/iconOff.png" alt="" />
<div>围栏</div>
</div>
<div class="icon-on" v-if="fenceShow" @click="fenceShow = false">
<img src="@/assets/images/carPosition/iconOn.png" alt="" />
<div>围栏</div>
</div>
<!-- **********************围栏弹窗******************************** -->
<div class="fenceDialog" v-if="fenceShow">
<div class="fence-dialog-modal" v-if="fenceCreateShow"></div>
<div class="fence-box">
<div class="close-icon" @click="closeFence">
<i class="el-icon-close" style="font-size: 22px; color: #919398"></i>
</div>
<div class="fence-title">围栏</div>
<div class="fence-tool">
<div class="tool" @click="openFenceCreate">创建围栏</div>
<div class="tool" @click="deleteFence">删除围栏</div>
</div>
<div class="fence-select">
<el-input v-model="fenceSearch" placeholder="请输入" size="small" clearable @change="fenceNameChange"></el-input>
</div>
<div class="fence-radio" v-if="fenceList.length > 0">
<el-checkbox :indeterminate="isIndeterminateFence" v-model="checkAllFence" @change="fenceAllChange">全选</el-checkbox>
<vue-scroll :ops="{ scrollPanel: { overflowX: false } }">
<div style="margin: 5px 0"></div>
<div class="fence-checkbox">
<el-checkbox-group v-model="checkedFence" @change="fenceCitiesChange">
<!-- <div v-for="item in fenceList" :key="item.id">
<el-checkbox :label="item.id" :key="item.id">{{ item.fenceName }} </el-checkbox>
</div> -->
<div class="fence-checkbox-item" v-for="item in fenceList" :key="item.id">
<el-checkbox class="fence-checkbox-item-checkbox" @change="fenceCitiesChange($event, item)" :label="item.id" :value="item.id" :key="item.id"
>{{ item.fenceName }}
</el-checkbox>
<div class="fence-checkbox-item-btn">
<i class="el-icon-link icon" @click="openWorkerDialog(item)"></i>
<i class="el-icon-edit icon" @click="openEditDialog(item)"></i>
<i class="el-icon-delete icon icon-delete" @click="deleteFenceInfo(item.id)"></i>
</div>
</div>
</el-checkbox-group>
</div>
</vue-scroll>
</div>
<div v-else style="text-align: center; margin-top: 100px">暂无围栏</div>
</div>
<!-- 创建围栏弹窗 -->
<div class="fenceCreate" v-if="fenceCreateShow">
<!-- <div class="fence-modal"></div> -->
<div class="fenceCrete-box">
<div class="close-icon" @click="closeFenceCreate">
<i class="el-icon-close" style="font-size: 22px; color: #919398"></i>
</div>
<div class="fence-title">{{ addForm.id ? '编辑围栏' : '创建围栏' }}</div>
<el-form size="medium" :model="addForm" ref="addForm" label-width="80px" :rules="formFenceRules">
<el-form-item label="围栏名称" prop="fenceName">
<el-input v-model="addForm.fenceName" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="范围类型" prop="rangeType">
<el-radio-group
v-model="addForm.rangeType"
style="display: flex; justify-content: space-between; padding-top: 10px; padding-right: 10px"
@change="changeAreaType"
>
<el-radio :label="1">标准区域</el-radio>
<el-radio :label="2">自定义</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="区域半径" prop="areaRadius" v-if="addForm.rangeType === 1">
<el-input
type="number"
v-model="addForm.areaRadius"
placeholder="请输入"
:maxlength="5"
@input="areaRadiusChange"
></el-input>
</el-form-item>
<el-form-item label="围栏形状" prop="fenceShape" v-if="addForm.rangeType === 2">
<div class="fence-shape">多边形</div>
</el-form-item>
<div class="create-footer">
<el-button class="cancleBtn" @click="handleCancel" icon="el-icon-circle-close" size="medium"
>{{ $t('message.alarmValueSet.cancel') }}
</el-button>
<el-button type="primary" icon="el-icon-circle-check" @click="submitFence" size="medium"
>{{ $t('message.alarmValueSet.save') }}
</el-button>
</div>
</el-form>
</div>
</div>
</div>
</div>
<settingDialog :visible.sync="settingDialogVisible" :id="dialogId" />
</div>
</template>
<script>
import settingDialog from './components/settingDialog.vue'
import { getHatFenceListApi, deleteHatFenceBatchApi, addHatFenceApi, editHatFenceApi } from '@/assets/js/api/smartSafeHat/smartSafeHat.js'
var mouseTool
var map
export default {
components: {
settingDialog
},
data() {
return {
settingDialogVisible: false,
dialogId: '',
fenceShow: false,
fenceCreateShow: false,
addForm: {
areaRadius: 100, //区域半径
fenceName: '', //围栏名称
addr: '',
rangeType: 1,
locationList: [
{
fenceId: 0,
id: 0,
latitude: '',
longitude: '',
sortNum: 0
}
],
projectSn: '',
enterpriseId: ''
},
formFenceRules: {
fenceName: [
{
required: true,
message: this.$t('message.personnelPosition.required'),
trigger: 'blur'
},
{ min: 1, max: 20, message: this.$t('message.alarmValueSet.message1'), trigger: 'blur' }
], // 长度在 1 到 20 个字符
areaRadius: [
{
required: true,
message: this.$t('message.personnelPosition.required'),
trigger: 'change'
}
]
},
fenceList: [],
checkedFence: [],
isIndeterminateFence: false,
checkAllFence: false,
fenceSearch: '',
locationList: [],
map: null,
geocoder: null,
auto: null,
placeSearch: null,
polygonPath: []
}
},
mounted() {
this.initMap()
this.getFenceList()
},
methods: {
openEditDialog(item) {
this.fenceCreateShow = true
this.addForm = item
this.locationList = JSON.parse(item.fenceShapeArr)
},
handleCancel() {
this.fenceCreateShow = false
this.closeFenceCreate()
},
// 围栏定位地图
initMap() {
var that = this
//地图加载
map = new AMap.Map('mapContainer', {
resizeEnable: true
})
var geocoder = new AMap.Geocoder({})
//输入提示
var autoOptions = {
input: 'tipinput'
}
this.auto = new AMap.Autocomplete(autoOptions)
this.placeSearch = new AMap.PlaceSearch({
map: map
}) //构造地点查询类
AMap.event.addListener(this.auto, 'select', this.select) //注册监听,当选中某条记录时会触发
mouseTool = new AMap.MouseTool(map)
mouseTool.on('draw', function (event) {
// event.obj 为绘制出来的覆盖物对象
console.log('覆盖物对象绘制完成', event.obj.getPath())
let overlaysList = map.getAllOverlays('polygon')
if (overlaysList.length > 1) {
map.remove(overlaysList[0])
}
that.locationList = []
var pathArr = event.obj.getPath()
pathArr.forEach(element => {
that.locationList.push({
longitude: element.lng,
latitude: element.lat
})
})
})
geocoder.getLocation(this.addForm.addr, function (status, result) {
if (status === 'complete' && result.geocodes.length) {
var lnglat = result.geocodes[0].location
console.log(result.geocodes[0])
// var arr = lnglat.split(',')
that.locationList = [
{
longitude: lnglat.lng,
latitude: lnglat.lat
}
]
that.drawCircle()
} else {
console.log('获取绘制', status, result)
}
})
map.on('click', e => {
if (!this.fenceCreateShow) {
console.log('还未到创建围栏弹窗')
return
}
console.log('您在 [ ' + e.lnglat.getLng() + ',' + e.lnglat.getLat() + ' ] 的位置单击了地图!')
if (this.addForm.rangeType == 1) {
this.locationList = []
this.locationList.push({
longitude: e.lnglat.getLng(),
latitude: e.lnglat.getLat()
})
var lnglatXY = new AMap.LngLat(e.lnglat.getLng(), e.lnglat.getLat())
geocoder.getAddress(lnglatXY, function (status, result) {
console.log(status, result)
that.addForm.addr = result.regeocode.formattedAddress
})
this.drawCircle()
} else {
this.locationList.push({
longitude: e.lnglat.getLng(),
latitude: e.lnglat.getLat()
})
}
console.log('当前位置列表', this.locationList)
})
},
getFenceList() {
let data = {
fenceName: this.fenceSearch,
projectSn: this.$store.state.projectSn
}
getHatFenceListApi(data).then(res => {
if (res.success) {
this.fenceList = res.result
this.circleMapData = res.result.filter(item => item.rangeType === 1)
this.shapeMapData = res.result.filter(item => item.rangeType === 2)
console.log('围栏', this.circleMapData, this.shapeMapData)
}
})
// this.fenceList = this.fenceList.filter(item => item.fenceName.includes(this.fenceSearch))
},
fenceNameChange(e) {
console.log('围栏名称', e)
this.fenceSearch = e
this.getFenceList()
},
fenceAllChange(val) {
this.clearFn()
let nameArr = this.fenceList.map(item => item.id)
this.checkedFence = val ? nameArr : []
this.isIndeterminateFence = false
console.log('全选', val, this.checkedFence)
if (val) {
this.drawAllFencePoint()
}
this.pointSelectChange()
map.setFitView()
},
fenceCitiesChange(value) {
this.clearFn()
let checkedCount = value.length
this.checkAllFence = checkedCount === this.fenceList.length
this.isIndeterminateFence = checkedCount > 0 && checkedCount < this.fenceList.length
this.drawFencePoint()
this.pointSelectChange()
// this.circleMapData =
console.log('选中', value)
},
pointSelectChange() {},
drawAllFencePoint() {
for (let index = 0; index < this.fenceList.length; index++) {
const element = this.fenceList[index]
// console.log('选中某条', currentRecord)
if (element.rangeType === 1) {
this.echoCircle(element)
}
if (element.rangeType === 2) {
this.echoDrawPolygon(element)
}
}
},
select(e) {
console.log('select', e)
this.placeSearch.setCity(e.poi.adcode)
this.placeSearch.search(e.poi.name) //关键字查询查询
},
//清空地图
clearFn() {
map.clearMap()
},
changeAreaType(e) {
// console.log("切换选项",e);
if (e === 1) {
this.drawCircle()
} else {
this.drawPolygon()
}
this.locationList = []
},
//添加点标记
addMarker() {
// 创建一个 Icon
var startIcon = new AMap.Icon({
// 图标尺寸
size: new AMap.Size(25, 34),
// 图标的取图地址
image: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
// 图标所用图片大小
imageSize: new AMap.Size(25, 34)
// 图标取图偏移量
// imageOffset: new AMap.Pixel(-9, -3)
})
var marker = new AMap.Marker({
icon: startIcon,
position: [this.locationList[0].longitude, this.locationList[0].latitude],
size: new AMap.Size(25, 34)
// offset: new AMap.Pixel(-13, -30)
})
marker.setMap(map)
},
exitEditFn() {
mouseTool.close()
},
//画圆
drawCircle() {
if (this.locationList.length == 0) {
return
}
this.clearFn()
this.addMarker()
var circle = new AMap.Circle({
center: [this.locationList[0].longitude, this.locationList[0].latitude],
radius: this.addForm.areaRadius, //半径
borderWeight: 2,
strokeColor: '#6caffc',
strokeOpacity: 1,
strokeWeight: 2,
fillOpacity: 0.6,
strokeStyle: 'solid',
// strokeDasharray: [10, 10],
// 线样式还支持 'dashed'
fillColor: '#6caffc',
zIndex: 50
})
circle.setMap(map)
// 缩放地图到合适的视野级别
map.setFitView([circle])
},
//绘制多边形
drawPolygon() {
this.clearFn()
console.log('自定义绘制')
mouseTool.polygon({
strokeColor: '#6caffc',
strokeOpacity: 1,
strokeWeight: 2,
// strokeOpacity: 0.2,
fillColor: '#6caffc',
fillOpacity: 0.6,
// 线样式还支持 'dashed'
strokeStyle: 'solid'
// strokeStyle是dashed时有效
// strokeDasharray: [30,10],
})
},
// 圆
echoCircle(item) {
// console.log("画圆",item)
// 创建纯文本标记
let text = new AMap.Text({
text: item.fenceName,
anchor: 'center', // 设置文本标记锚点
// draggable: true, // 是否拖拽
cursor: 'pointer',
angle: 10,
style: {
padding: '10px',
'border-radius': '10px',
'background-color': 'white',
'border-width': 0,
'box-shadow': '0 2px 6px 0 rgba(114, 124, 245, .5)',
'text-align': 'center',
'font-size': '20px',
color: 'blue'
},
position: [item.longitude, item.latitude]
})
let circle = new AMap.Circle({
center: [item.longitude, item.latitude],
radius: item.areaRadius, //半径
borderWeight: 2,
strokeColor: '#6caffc',
strokeOpacity: 1,
strokeWeight: 2,
fillOpacity: 0.6,
strokeStyle: 'solid',
// strokeDasharray: [10, 10],
// 线样式还支持 'dashed'
fillColor: '#6caffc',
zIndex: 50
})
text.setMap(map)
circle.setMap(map)
// 缩放地图到合适的视野级别
map.setFitView([circle])
},
echoDrawPolygon(item) {
// console.log("画多边形",item)
let polygonPath = []
let polygonArr = JSON.parse(item.fenceShapeArr)
for (let index = 0; index < polygonArr.length; index++) {
const element = polygonArr[index]
polygonPath.push([element.longitude, element.latitude])
}
// console.log("多边形位置",polygonPath)
// let path = [
// [116.403322, 39.920255],
// [116.410703, 39.897555],
// [116.402292, 39.892353],
// [116.389846, 39.891365]
// ]
let path = polygonPath
// 创建纯文本标记
let text = new AMap.Text({
text: item.fenceName,
anchor: 'center', // 设置文本标记锚点
// draggable: true, // 是否拖拽
cursor: 'pointer',
angle: 10,
style: {
padding: '10px',
'border-radius': '10px',
'background-color': 'white',
'border-width': 0,
'box-shadow': '0 2px 6px 0 rgba(114, 124, 245, .5)',
'text-align': 'center',
'font-size': '20px',
color: 'blue'
},
position: path[0]
})
let polygon = new AMap.Polygon({
path: path,
strokeColor: '#FF33FF',
strokeWeight: 6,
strokeOpacity: 0.2,
fillOpacity: 0.4,
fillColor: '#1791fc',
zIndex: 50
})
text.setMap(map)
map.add(polygon)
// 缩放地图到合适的视野级别
map.setFitView([polygon])
},
drawFencePoint() {
for (let index = 0; index < this.checkedFence.length; index++) {
const element = this.checkedFence[index]
let currentRecord = this.fenceList.filter(item => item.id === element)[0]
// console.log('选中某条', currentRecord)
if (currentRecord.rangeType === 1) {
this.echoCircle(currentRecord)
}
if (currentRecord.rangeType === 2) {
this.echoDrawPolygon(currentRecord)
}
}
},
areaRadiusChange() {
if (this.addForm.locationList?.length === 1) {
this.drawCircle()
}
},
submitFence() {
if (this.locationList.length == 0) {
this.$message.error('未设置围栏区域!')
return
}
this.addForm.locationList = this.locationList
console.log('新增围栏', this.addForm)
let latitude = ''
let longitude = ''
let fenceShape = ''
if (this.addForm.locationList.length === 1) {
latitude = this.addForm.locationList[0].latitude
longitude = this.addForm.locationList[0].longitude
}
if (this.addForm.locationList.length > 1) {
for (let index = 0; index < this.addForm.locationList.length; index++) {
const element = this.addForm.locationList[index]
let currentStr = element.latitude + '|' + element.longitude
if (this.addForm.locationList.length - 1 > index) {
currentStr = currentStr + ','
}
fenceShape = fenceShape + currentStr
}
}
console.log('多边形', fenceShape)
this.$refs['addForm'].validate(valid => {
if (valid) {
let params = {
fenceName: this.addForm.fenceName,
areaRadius: this.addForm.areaRadius,
fenceShapeArr: JSON.stringify(this.addForm.locationList),
fenceShape: fenceShape,
latitude: latitude,
longitude: longitude,
rangeType: this.addForm.rangeType,
projectSn: this.$store.state.projectSn,
id: this.addForm.id
}
// params.alarmPushWorkerId = this.addForm.alarmPushWorkerId.join(',');
const api = this.addForm.id ? editHatFenceApi : addHatFenceApi
console.log('新增信息', params)
api(params).then(res => {
if (res.success) {
this.$message.success(res.message)
this.getFenceList()
}
})
this.closeFenceCreate()
} else {
console.log('error submit!!')
return false
}
})
},
// 打开创建围栏弹窗
openFenceCreate() {
this.fenceCreateShow = true
},
deleteFence() {
if (this.checkedFence.length === 0) {
this.$message({
type: 'info',
message: '请选择删除围栏'
})
return
}
console.log('删除围栏', this.checkedFence)
let idString = ''
for (let index = 0; index < this.checkedFence.length; index++) {
const element = this.checkedFence[index]
if (this.checkedFence.length - 1 > index) {
idString = idString + element + ','
} else {
idString = idString + element
}
}
this.deleteFenceInfo(idString)
},
// 删除围栏
deleteFenceInfo(idGroups) {
console.log('删除id', idGroups)
let data = {
ids: idGroups
}
this.$confirm('此操作将永久删除该围栏, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
deleteHatFenceBatchApi(data).then(res => {
if (res.success) {
this.getFenceList()
this.checkedFence = ''
this.fenceCitiesChange(this.checkedFence)
this.$message.success('删除成功')
}
})
})
.catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
},
openWorkerDialog(item) {
console.log('打开绑定人员弹窗', item)
this.dialogId = item.id
this.settingDialogVisible = true
},
// 关闭创建围栏弹窗
closeFenceCreate() {
this.fenceCreateShow = false
this.addForm = {
areaRadius: 100, //区域半径
fenceName: '', //围栏名称
addr: '',
rangeType: 1,
locationList: [
{
fenceId: 0,
id: 0,
latitude: '',
longitude: '',
sortNum: 0
}
],
projectSn: '',
enterpriseId: ''
}
this.exitEditFn()
this.clearFn()
},
// 打开围栏弹窗
openFence() {
this.fenceShow = true
},
// 关闭围栏弹窗
closeFence() {
this.fenceShow = false
}
}
}
</script>
<style lang="scss" scoped>
.map-content {
width: 100%;
height: 100%;
position: relative;
}
#mapContainer {
width: 100%;
height: 100%;
}
.wei-lan {
// position: absolute;
// left: 1%;
// top: 8%;
// width: 100%;
// height: 0;
.icon-off {
position: absolute;
padding-top: 5px;
top: 8%;
left: 1%;
width: 48px;
height: 48px;
cursor: pointer;
font-size: 14px;
background: #ffffff;
text-align: center;
border-radius: 2px 2px 2px 2px;
img {
width: 20px;
height: 20px;
margin: 0 auto;
}
}
.icon-on {
position: absolute;
padding-top: 5px;
top: 8%;
left: 1%;
text-align: center;
width: 48px;
height: 48px;
cursor: pointer;
font-size: 14px;
background: #ffffff;
color: #5181f6;
border-radius: 2px 2px 2px 2px;
img {
width: 20px;
height: 20px;
margin: 0 auto;
}
}
}
// 围栏弹窗
.fenceDialog {
position: absolute;
background: #fff;
box-sizing: border-box;
padding: 25px;
left: 5%;
top: 20px;
width: 330px;
height: 380px;
z-index: 1;
.fence-dialog-modal {
position: absolute;
width: 100%;
height: 100%;
top: 0%;
left: 0%;
z-index: 3;
background: rgba(39, 45, 69, 0.5);
}
.close-icon {
position: absolute;
top: 0px;
right: 0px;
cursor: pointer;
}
.fence-title {
border-left: 4px solid #5c81ee;
font-size: 15px;
color: #272d45;
padding-left: 10px;
margin-bottom: 20px;
font-weight: 600;
font-family: Source Han Sans CN, Source Han Sans CN;
}
}
.fenceCreate {
position: absolute;
background: #fff;
box-sizing: border-box;
padding: 25px;
width: 330px;
height: 380px;
left: 40px;
top: 40px;
z-index: 5;
// .fence-modal {
// position: absolute;
// width: 330px;
// height: 90px;
// top: -90px;
// left: 0%;
// background: rgba(39, 45, 69, 0.5);
// }
.fenceCrete-box {
position: relative;
.create-footer {
margin: 100px 0 0 50px;
}
}
}
.fence-box {
position: relative;
.fence-tool {
display: flex;
justify-content: space-around;
padding: 0 25px;
.tool {
display: flex;
align-items: center;
justify-content: center;
width: 80px;
height: 33px;
font-size: 14px;
cursor: pointer;
background: #ffffff;
color: #5181f6;
border-radius: 2px 2px 2px 2px;
border: 1px solid #5181f6;
}
}
.fence-select {
margin: 15px 0;
}
.fence-radio {
height: 160px;
}
}
.fence-checkbox {
width: 100%;
.fence-checkbox-item {
display: flex;
justify-content: space-between;
align-items: center;
}
.fence-checkbox-item-checkbox {
max-width: 200px;
overflow: hidden;
}
.fence-checkbox-item-btn {
flex: 1;
// min-width: 80px;
flex-shrink: 0;
text-align: right;
margin-left: 10px;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 4px;
.icon {
cursor: pointer;
font-size: 14px;
color: #5181f6;
}
.icon-delete {
color: #f56c6c;
}
}
}
</style>