打卡添加电子围栏
src同级的index.html引入高德地图插件
<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=c57a0390d2e37350f319d6d170fac8f4&plugin=AMap.GeoJSON,AMap.Autocomplete,AMap.PlaceSearch,AMap.MouseTool,AMap.CircleEditor,AMap.ToolBar,AMap.Scale" ></script>
页面
页面内容
css地图内样式
初始化加载地图
位置搜索框
1 startDraw(type) { 2 let that = this; 3 this.clearDraw(); 4 if(type == 'marker'){//绘制点 5 this.mapInitialization.clearMap(); 6 if(entityMarker) this.mapInitialization.remove(entityMarker); 7 mouseToolMarker = new AMap.MouseTool(this.mapInitialization); 8 mouseToolMarker.marker({ 9 zoom: 16, 10 icon: 'https://files.xatasoft.com/Uploads/zhonghuan/icon/point12.png', 11 offset: new AMap.Pixel(-17, -56) 12 }); 13 mouseToolMarker.on('draw',function(e){ 14 entityMarker = e.obj; 15 if(mouseToolMarker) mouseToolMarker.close(false); 16 }) 17 this.drawCircleDisabled = true//绘制圆时显示(项目中的逻辑,不用管) 18 this.circleShow = false//编辑时半径不显示(项目中的逻辑,不用管) 19 } 20 if(type == 'polygon'){//绘制多边形 21 if(mouseToolMarker) mouseToolMarker.close(false); 22 if(mouseTool) mouseTool.close(true); 23 mouseTool = new AMap.MouseTool(this.mapInitialization); 24 mouseTool.polygon({ 25 strokeColor: "#FF33FF", 26 strokeOpacity: 1, 27 strokeWeight: 6, 28 strokeOpacity: 0.2, 29 fillColor: '#1791fc', 30 fillOpacity: 0.4, 31 strokeStyle: "dashed", 32 }); 33 mouseTool.on('draw',function(e){ 34 entity = e.obj; 35 if(mouseTool) mouseTool.close(false); 36 }) 37 } 38 }, 39 40 //判断是否存在, 如果存在就关闭和清除 41 clearDraw(){ 42 if(mouseTool) mouseTool.close(true); 43 if(entity) this.mapInitialization.remove(entity); 44 },
绘制圆形
1 clearDraw(){ 2 if(mouseTool) mouseTool.close(true); 3 if(entity) this.mapInitialization.remove(entity); 4 }, 5 clearMarker(){ 6 if(entityMarker) this.mapInitialization.remove(entityMarker); 7 if(mouseToolMarker) mouseToolMarker.close(true); 8 entityMarker = undefined 9 mouseToolMarker = undefined 10 this.drawCircleDisabled = true//绘制圆显示 11 this.circleShow = false//编辑半径不显示 12 },
1 let myLngLat = new AMap.LngLat(this.location.lng,this.location.lat) 2 let result = this.currentFenceInfo.some(item =>{ 3 let polygonOrCircle; 4 if(item.radius){//圆形 5 polygonOrCircle = new AMap.Circle({ 6 center: new AMap.LngLat(item.setting[0].lng,item.setting[0].lat), 7 radius: item.radius 8 }); 9 }else{//多边形 10 polygonOrCircle = new AMap.Polygon({ 11 path:item.setting 12 }); 13 } 14 console.log("判断点是否在多边形和圆范围内",polygonOrCircle.contains(myLngLat))
整体页面代码内容
1 <template lang='pug'> 2 .boxCommon 3 .header 4 xt-search(:searchList="searchList" @submit="searchHandle" ref="formName" :hasResetBtn="true") 5 .btn-group 6 el-button(type="primary" size="small" @click="handleAddFun" icon="iconfont icon-icon_xinzeng") 新增 7 .boxTable.boxTableStriped 8 el-table(:data="tableData" stripe border v-loading="tableLoading" height="calc(100vh - 240px)") 9 el-table-column(prop="serial_number" label="序号" align="center" width="80") 10 el-table-column(prop="title" label="标题" align="center") 11 el-table-column(prop="type" label="类型" align="center") 12 template(slot-scope="scope") 13 span {{ scope.row.type == '1'?'多边形':'圆形'}} 14 el-table-column(prop="remark" label="备注" align="center") 15 el-table-column(prop="user_name" label="创建人" align="center") 16 el-table-column(prop="create_time" label="创建时间" align="center") 17 el-table-column(label="操作" align="center" width="180") 18 template(slot-scope="scope") 19 .operateBtn 20 i.iconfont.icon-bianji(@click="handleFun(1, scope.row)" title="编辑") 21 i.iconfont.icon-shanchu(@click="handleFun(2,scope.row)" title="删除") 22 i.iconfont.icon-chakan(@click="handleFun(3, scope.row)" title="查看") 23 xt-pagination(:total="total" @change="changePage" :page="pageForm.page" :page-size="pageForm.page_size") 24 xt-dialog.patrolDialog( 25 ref="mapFenceDialog" 26 :title="title" 27 top="5vh" 28 width="65%" 29 :showfooter="title != '详情' ? true : false" 30 @confirm="$refs.xtFormRef.submit()" 31 :autoclose="false" 32 @close="mapFenceClose" 33 ) 34 xt-form(:formList="formList" ref="xtFormRef" :type="title" :label-width="120" @submit="handleSubmit") 35 .mapBox 36 #mapContainer(style="width: 100%;height: 100%;") 37 .mapSearchWrap(v-show="title != '详情'") 38 .searchBox 39 .searchInput 40 el-input(v-model="keyword" placeholder="请输入关键字:" size="mini" @keyup.enter.native="searchMap" style="width:80px") 41 .searchList(v-show="showSearch") 42 ul(v-show="searchMapList.length") 43 li(v-for="item in searchMapList" :key="item.id" @click="checkPoint(item)") {{ item.name}} 44 .emptyBox(v-show="!searchMapList.length") 暂无数据 45 el-button(type="primary" plain @click="searchMap" size="mini") 搜索 46 .drawBtn(v-if='polygonShow') 47 el-tooltip(effect="dark" content="定位" placement="top") 48 el-button.iconfont.icon-techreport-(type="primary" plain @click="startDraw('marker')" size="mini") 49 el-tooltip(effect="dark" content="开始绘制多边形" placement="top") 50 el-button.iconfont.icon-duobianxing(type="primary" plain @click="startDraw('polygon')" size="mini") 51 .drawBtn(v-else) 52 el-tooltip(effect="dark" content="定位" placement="top") 53 el-button.iconfont.icon-techreport-(type="primary" @click="startDraw('marker')" plain size="mini") 54 el-tooltip(effect="dark" content="开始绘制圆形" placement="top") 55 el-button.iconfont.icon-yuanquan(type="primary" plain @click="startDrawCircle('add')" size="mini" v-if="drawCircleDisabled") 56 span(v-if="circleShow" style="margin-left:10px") 57 el-tooltip(effect="dark" content="设置半径" placement="top") 58 el-button.iconfont.icon-lujing759(type="primary" plain @click="circleEditorOpen" size="mini") 59 el-tooltip(effect="dark" content="完成设置" placement="top") 60 el-button.iconfont.icon-wanchenggouxuanxuanzhong(type="primary" plain @click="circleEditorClose" size="mini") 61 .helpDescription(v-show="title != '详情'") 62 .tip 63 span(style="color:#000;font-weight:bold;width:80px;") 帮助说明: 64 span(style="color:#666;margin-left:8px;") 1.类型为多边形时,点击绘图按钮, 单击地图开始绘制, 右键结束绘制。 65 div(style="color:#666;margin-left:80px;") 2.类型为圆形时,点击定位按钮在地图上单击定位后, 点击绘制圆形按钮,默认半径300米的圆形绘制完成。 66 div(style="color:#666;margin-left:90px;") 点击设置半径按钮, 鼠标在地图圆形边缘半径圆点处拖动可进行圆形大小设置。 67 </template> 68 69 <script> 70 import { mapGetters } from 'vuex' 71 let circleEditor, mouseTool, entity ,mouseToolMarker, entityMarker; 72 export default { 73 name: '', 74 data() { 75 let vm = this 76 return { 77 title: '新增', 78 tableData: [], 79 tableLoading: false, 80 total: 0, //页码变量 81 pageForm: { //页码 82 page: 1, 83 page_size: 20 84 }, 85 searchForm: {}, 86 searchList: [ 87 { 88 type: 'xt-form', 89 children: [ 90 { 91 title: '标题:', 92 type: 'input', 93 key: 'title', 94 props: { 95 placeholder: '请输入标题' 96 } 97 }, 98 ] 99 } 100 ], 101 enclosureDetails:{}, 102 rowObj:{}, 103 formList:[ 104 { 105 renderContent (h, item, form) { 106 return (<div style="font-size: 18px;color: #000;font-weight: bold;margin-left: -120px;">基本信息</div>) 107 } 108 }, 109 { 110 title: '标题:', 111 type: 'input', 112 key: 'title', 113 defaultValue:"电子围栏设置", 114 rule: {required: true, message: '请输入标题', trigger: 'change'}, 115 props: { 116 'placeholder': '请输入标题' 117 } 118 }, 119 { 120 title: '类型:', 121 type: 'radio-group', 122 key: 'type', 123 defaultValue: 1, 124 options: [{ 125 value: 1, 126 text:'多边形' 127 },{ 128 value: 2, 129 text:'圆形' 130 }], 131 onInput(value, item, form) { 132 if (value == 1) { 133 vm.drawPolygon() 134 }else { 135 vm.drawCircle() 136 } 137 } 138 }, 139 { 140 title: '半径:', 141 type: 'input', 142 key: 'radius', 143 isShow:false 144 }, 145 { 146 title: '备注:', 147 type: 'input', 148 key: 'remark', 149 disabled: false, 150 props: { 151 placeholder: '请输入备注', 152 type: 'textarea', 153 rows: 3 154 } 155 }, 156 { 157 renderContent (h, item, form) { 158 return (<div class="lastItem">围栏设置</div>) 159 } 160 }, 161 ], 162 setting:null,//围栏设置 163 radius:"",//半径默认300 164 polygonShow:true,//多边形工具 165 mapInitialization:'',//地图 166 keyword: '', // 地图搜索关键字 167 searchMapList: [], 168 showSearch: false, 169 drawCircleDisabled:true,//绘制圆形 170 circleShow:false,//圆形编辑工具 171 } 172 }, 173 computed: {}, 174 watch: {}, 175 methods: { 176 initMap(lon_lat){ 177 this.mapInitialization = new AMap.Map("mapContainer", { 178 zoom: lon_lat ? 16 : 11, 179 resizeEnable: true, 180 }); 181 var scale = new AMap.Scale() 182 this.mapInitialization.addControl(scale); 183 if(lon_lat){ 184 let location = JSON.parse(lon_lat) 185 this.mapInitialization.setCenter([location.lng, location.lat]) 186 } 187 this.searchMap(false)//搜索 188 }, 189 async getDetails(data){ 190 let res = await this.$api.electricFence_detail(data) 191 this.enclosureDetails = res.result 192 this.enclosureDetails.radius = res.result.radius + '(m)' 193 this.handleReset(this.enclosureDetails) 194 if(this.enclosureDetails.type == 2){ 195 this.formList[3].radius = this.enclosureDetails.radius 196 this.formList[3].isShow = true 197 }else{ 198 this.formList[3].isShow = false 199 } 200 }, 201 checkPoint(item){ // 选中搜索项 202 this.showSearch = false 203 let map = this.mapInitialization 204 map.setCenter([item.location.lng, item.location.lat]); // 定位中心点 205 map.setZoom(16); // 设置缩放 206 //搜索完成后清空关键字 207 this.keyword = '' 208 this.searchMapList = [] 209 }, 210 handleAddFun(){ 211 this.title = '新增' 212 this.$refs.mapFenceDialog.open() 213 this.formList[3].isShow = false 214 this.$nextTick(() => { 215 this.initMap() 216 this.drawPolygon()//默认绘制多边形 217 if(entity) entity = undefined 218 }) 219 }, 220 handleFun(index,row){ 221 if(index == 1){ 222 this.title = '编辑' 223 this.$refs.mapFenceDialog.open() 224 this.formList[3].isShow = false 225 this.rowObj = row 226 this.handleReset(this.rowObj) 227 }else if(index == 2){ 228 this.handleDelete(row) 229 }else{ 230 this.title = '详情' 231 this.$refs.mapFenceDialog.open() 232 this.getDetails({id:row.id}) 233 } 234 }, 235 handleReset(rowData){ 236 if(rowData.type == 1){//多边形 237 this.polygonShow = true; 238 this.$nextTick(() => { 239 this.$refs.xtFormRef.setForm(rowData) 240 this.initMap() 241 if(rowData.setting && rowData.setting.length>0){ 242 let path = []; 243 rowData.setting.forEach(element => { 244 let a = new AMap.LngLat(element.lng,element.lat); 245 path.push(a); 246 }); 247 entity = new AMap.Polygon({ 248 path: path, 249 strokeColor: "#FF33FF", 250 strokeOpacity: 1, 251 strokeWeight: 6, 252 strokeOpacity: 0.2, 253 fillColor: '#1791fc', 254 fillOpacity: 0.4, 255 strokeStyle: "dashed", 256 zIndex: 50, 257 }); 258 259 this.mapInitialization.add(entity); 260 this.mapInitialization.setFitView([ entity ]) 261 } 262 }) 263 }else{//圆形 264 if(rowData.setting && rowData.setting.length > 0){ 265 let lng_lat = [rowData.setting[0].lng,rowData.setting[0].lat] 266 this.polygonShow = false; 267 this.$nextTick(() => { 268 this.$refs.xtFormRef.setForm(rowData) 269 this.initMap() 270 this.mapInitialization.clearMap(); 271 var marker = new AMap.Marker({ 272 position: lng_lat, 273 icon: 'https://files.xatasoft.com/Uploads/zhonghuan/icon/point12.png', 274 offset: new AMap.Pixel(-17, -56) 275 }); 276 entityMarker = marker 277 this.mapInitialization.add(marker); 278 this.startDrawCircle('edit',rowData.radius,lng_lat) 279 }) 280 } 281 } 282 }, 283 searchHandle(row) { 284 this.searchForm = { ...row } 285 this.getData() 286 }, 287 changePage (row) { 288 this.pageForm = { ...row } 289 this.getData() 290 }, 291 async getData() { 292 this.tableLoading = true 293 let data = { 294 ...this.searchForm, 295 ...this.pageForm 296 } 297 let res = await this.$api.electricFence_index(data) 298 this.tableData = res.result.data 299 this.total = res.result.total 300 this.tableLoading = false 301 }, 302 handleDelete(row) { 303 this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', { 304 confirmButtonText: '确定', 305 cancelButtonText: '取消', 306 type: 'warning' 307 }).then(async () => { 308 await this.$api.electricFence_remove({id: row.id}) 309 this.$success('删除成功') 310 this.pageForm.page = 1 311 this.getData() 312 }) 313 }, 314 //切换至多边形 315 drawPolygon(){ 316 this.clearDraw(); 317 this.clearMarker() 318 this.polygonShow = true; 319 this.mapInitialization.clearMap(); 320 }, 321 //绘制多边形和定位 322 startDraw(type) { 323 let that = this; 324 this.clearDraw(); 325 if(type == 'marker'){ 326 this.mapInitialization.clearMap(); 327 if(entityMarker) this.mapInitialization.remove(entityMarker); 328 mouseToolMarker = new AMap.MouseTool(this.mapInitialization); 329 mouseToolMarker.marker({ 330 zoom: 16, 331 icon: 'https://files.xatasoft.com/Uploads/zhonghuan/icon/point12.png', 332 offset: new AMap.Pixel(-17, -56) 333 }); 334 mouseToolMarker.on('draw',function(e){ 335 entityMarker = e.obj; 336 if(mouseToolMarker) mouseToolMarker.close(false); 337 }) 338 this.drawCircleDisabled = true//绘制圆显示 339 this.circleShow = false//编辑半径不显示 340 } 341 if(type == 'polygon'){ 342 if(mouseToolMarker) mouseToolMarker.close(false); 343 if(mouseTool) mouseTool.close(true); 344 mouseTool = new AMap.MouseTool(this.mapInitialization); 345 mouseTool.polygon({ 346 strokeColor: "#FF33FF", 347 strokeOpacity: 1, 348 strokeWeight: 6, 349 strokeOpacity: 0.2, 350 fillColor: '#1791fc', 351 fillOpacity: 0.4, 352 strokeStyle: "dashed", 353 }); 354 mouseTool.on('draw',function(e){ 355 entity = e.obj; 356 if(mouseTool) mouseTool.close(false); 357 }) 358 } 359 }, 360 //切换至圆形 361 drawCircle(){ 362 this.clearDraw() 363 this.clearMarker() 364 this.polygonShow = false; 365 }, 366 //绘制圆形 367 startDrawCircle(type,radius,lng_lat){ 368 let that = this; 369 this.clearDraw(); 370 if(type == 'add'){//新增 371 if(!entityMarker){ 372 this.circleShow = false; 373 that.$message({message: '请先选择位置进行定位',type: 'warning'}); 374 }else{ 375 this.circleShow = true; 376 entity = new AMap.Circle({ 377 center:[entityMarker.w.position.lng,entityMarker.w.position.lat], 378 radius:300, //半径 379 borderWeight: 3, 380 strokeColor: "#FF33FF", 381 strokeOpacity: 1, 382 strokeWeight: 6, 383 strokeOpacity: 0.2, 384 fillOpacity: 0.4, 385 strokeStyle: 'dashed', 386 strokeDasharray: [10, 10], 387 fillColor: '#1791fc', 388 zIndex: 50, 389 }) 390 this.mapInitialization.add(entity); 391 this.mapInitialization.setFitView([ entity ]) 392 393 circleEditor = new AMap.CircleEditor(this.mapInitialization, entity) 394 circleEditor.on('move', function(event) { 395 entity = event.target; 396 }) 397 } 398 }else{//编辑回显 399 this.circleShow = true;//编辑半径显示 400 this.drawCircleDisabled = false//绘制圆不显示 401 entity = new AMap.Circle({ 402 center:lng_lat, 403 radius:radius, //半径 404 borderWeight: 3, 405 strokeColor: "#FF33FF", 406 strokeOpacity: 1, 407 strokeWeight: 6, 408 strokeOpacity: 0.2, 409 fillOpacity: 0.4, 410 strokeStyle: 'dashed', 411 strokeDasharray: [10, 10], 412 fillColor: '#1791fc', 413 zIndex: 50, 414 }) 415 this.mapInitialization.add(entity); 416 this.mapInitialization.setFitView([ entity ]) 417 418 circleEditor = new AMap.CircleEditor(this.mapInitialization, entity) 419 circleEditor.on('move', function(event) { 420 entity = event.target; 421 }) 422 } 423 424 }, 425 clearDraw(){ 426 if(mouseTool) mouseTool.close(true); 427 if(entity) this.mapInitialization.remove(entity); 428 }, 429 clearMarker(){ 430 if(entityMarker) this.mapInitialization.remove(entityMarker); 431 if(mouseToolMarker) mouseToolMarker.close(true); 432 entityMarker = undefined 433 mouseToolMarker = undefined 434 this.drawCircleDisabled = true//绘制圆显示 435 this.circleShow = false//编辑半径不显示 436 }, 437 circleEditorOpen(){ 438 circleEditor.open() 439 this.drawCircleDisabled = false 440 }, 441 circleEditorClose(){ 442 circleEditor.close() 443 this.circleShow = false; 444 this.drawCircleDisabled = true 445 }, 446 searchMap(bool=true){ // 地图搜索关键字 447 if(!this.keyword && bool) { 448 this.$message.warning('请先输入关键字!') 449 return 450 } 451 let _this = this 452 let keyword = this.keyword 453 AMap.plugin('AMap.PlaceSearch', function(){ 454 var autoOptions = { 455 city: '浙江省', 456 citylimit: true, //是否强制限制在设置的城市内搜索 457 pageSize: 20, 458 } 459 var placeSearch = new AMap.PlaceSearch(autoOptions); 460 placeSearch.search(keyword, function(status, result) { // 搜索成功时,result即是对应的匹配数据 461 if(status == 'complete'){ // 搜索成功时 462 let list = result.poiList.pois 463 _this.searchMapList = list 464 _this.showSearch = true // 显示搜索列表 465 } 466 }) 467 }) 468 }, 469 async handleSubmit(form, valid) { 470 if (valid) { 471 if(!entity){ 472 this.$message({message: '电子围栏未设置',type: 'warning'}); 473 }else{ 474 let result; 475 if(form.type === 1) { 476 this.radius = "" 477 this.setting = entity.getPath() 478 } else { 479 result = entity.getCenter() 480 this.radius = entity.getRadius() 481 this.setting = [{lat:result.lat,lng:result.lng}] 482 } 483 let data = { 484 title:form.title, //标题 485 type:form.type, //类型 1-多边形 2-圆 486 radius:this.radius, //半径 (m) 487 remark:form.remark, //备注 488 setting:this.setting, //围栏设置 489 } 490 if (this.title == '编辑') { 491 data.id = this.rowObj.id 492 } 493 await this.$api.electricFence_createOrEdit(data) 494 this.$success(`${this.title == '新增' ? '新增' : '编辑'}成功!`) 495 this.$refs.mapFenceDialog.handleClose() 496 this.getData() 497 498 } 499 } 500 }, 501 mapFenceClose(){ 502 this.$refs.xtFormRef.reset() 503 this.drawPolygon() 504 } 505 }, 506 created() {}, 507 mounted() { 508 this.getData() 509 }, 510 } 511 </script> 512 <style scoped lang="scss"> 513 .boxCommon { 514 .header { 515 display: flex; 516 justify-content: space-between; 517 width: 100%; 518 } 519 } 520 .patrolDialog { 521 /deep/ .el-form-item__content { 522 color: #666 !important; 523 margin-left: 120px !important; 524 } 525 /deep/ .el-input { 526 width: 100% !important; 527 } 528 /deep/ .el-textarea { 529 width: 100% !important; 530 } 531 /deep/ .el-select { 532 width: 100% !important; 533 } 534 /deep/ .el-form-item .lastItem { 535 margin-bottom: 0px; 536 font-size: 18px;color: #000;font-weight: bold;margin-left: -120px; 537 } 538 /deep/ .el-form-item--small.el-form-item{ 539 margin-bottom: 8px; 540 } 541 } 542 .mapBox{ 543 width: calc(100% - 120px); 544 height: 420px; 545 margin-left:120px; 546 position: relative; 547 .mapSearchWrap{ 548 position: absolute; left: 0px; top:0px; z-index: 99; 549 padding: 8px; 550 background-color: rgba(206, 240, 248, 0.6); 551 display: flex; 552 justify-content: space-between; 553 align-items: flex-end; 554 .searchBox{ 555 width: 240px; display: flex; 556 /deep/ .el-button{ 557 margin: auto 10px; 558 } 559 .searchInput{ 560 position: relative; 561 flex: 1; min-width: 0; 562 .searchList{ 563 position: absolute; max-height: 200px; width: 100%; overflow-y: auto; 564 background-color: #fff; 565 .emptyBox{ 566 line-height: 200px; text-align: center; color: #ccc; 567 } 568 ul{ 569 padding: 10px 0; 570 li{ 571 line-height: 20px; padding: 5px 15px; 572 cursor: pointer; 573 &:hover{ 574 background-color: #A0C5E8; 575 } 576 } 577 } 578 } 579 } 580 } 581 } 582 /deep/.amap-logo{ 583 display: none !important; 584 } 585 /deep/ .amap-copyright{ 586 display: none !important; 587 } 588 /deep/.amap-scalecontrol{ 589 bottom: 0 !important; 590 } 591 } 592 .helpDescription{ 593 width: calc(100% - 120px); 594 height: 80px; 595 margin-top: 10px; 596 line-height: 20px; 597 margin-left:120px; 598 } 599 600 </style>