Files
ibs-fullstack/ruoyi-ui/src/map/BMapPolygonEditor.vue

1497 lines
41 KiB
Vue
Raw Normal View History

2026-02-26 14:51:13 +08:00
<template>
<div v-loading="mapLoading" class="map-wrap">
<div ref="mapContainer" class="map-container" />
<div
class="control-panel-out"
v-if="$store.state.featuredAreas.level === 1 && is931"
>
<el-button
key="0"
size="middle"
round
type="primary"
icon="el-icon-open"
@click="showHotmap"
>
{{ `${showHotMapFlag ? '关闭' : '显示'}企业客户热力图` }}
</el-button>
</div>
<div
v-if="
$store.state.featuredAreas.level !== 1 &&
layerInfo.id &&
!isDrawing &&
!isEditing &&
!visible &&
infoType !== 'EDITSHAPE'
"
class="control-panel"
>
<el-button
key="1"
:disabled="!currentPolygon && isDrawing"
size="middle"
round
type="primary"
icon="el-icon-share"
@click="startDrawing"
>
开始绘制
</el-button>
<el-button
key="2"
:disabled="editEnable"
size="middle"
round
type="primary"
icon="el-icon-edit"
@click="editPolygon"
>
编辑图形
</el-button>
<el-button
key="3"
:disabled="editEnable"
size="middle"
round
type="primary"
icon="el-icon-delete"
@click="deletePolygon"
>
删除图形
</el-button>
<!-- <el-button
@click="getWKT"
:disabled="editEnable"
size="small"
round
type="primary"
icon="el-icon-finished"
>
获取WKT
</el-button> -->
</div>
<div
v-if="(isEditing && !visible) || infoType === 'EDITSHAPE'"
class="control-panel"
>
<el-button
size="middle"
round
type="primary"
icon="el-icon-refresh"
@click="refreshEdit"
>
恢复
</el-button>
<el-button
size="middle"
round
type="primary"
icon="el-icon-close"
@click="cancelEdit"
>
取消
</el-button>
<el-button
size="middle"
round
type="primary"
icon="el-icon-check"
@click="saveEdit"
>
保存
</el-button>
</div>
<div v-if="isDrawing" class="drawing-tip"> ESC 键取消绘制</div>
<div v-if="isEditing" class="drawing-tip"> 键可撤销操作</div>
<transition name="fade-transform">
<div v-show="visible" class="area-info-modal">
<h4>
{{ infoTitle
}}<i class="el-icon-close" @click="cancelSaveArea('justcancel')" />
</h4>
<el-form
ref="form"
:model="areaForm"
:rules="areaRules"
label-width="90px"
size="small"
class="form-box"
>
<el-form-item
v-if="infoType !== 'ADD'"
label="创建者"
prop="createBy"
class="area-form-item area-form-item1"
>
<span>{{ areaForm.createBy }}</span>
</el-form-item>
<el-form-item
label="区域名称"
prop="shapeName"
class="area-form-item area-form-item1"
>
<span v-if="!show">{{ areaForm.shapeName }}</span>
<el-input v-else v-model="areaForm.shapeName" clearable />
</el-form-item>
<el-form-item label="区域类型" prop="areaType" class="area-form-item">
<span>{{ layerName }}</span>
</el-form-item>
<el-form-item
v-if="infoType === 'ADD'"
label="业务部门归属"
prop="opsDept"
label-width="120px"
class="area-radio"
>
<el-radio-group
v-model="areaForm.opsDept"
size="small"
:disabled="opsDeptDisable"
>
<el-radio
v-for="item in businessBelongList"
:key="item.key"
:label="item.key"
>
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<template v-if="infoType !== 'ADD'">
<el-form-item
label="业务部门归属"
prop="businessbelongName"
class="area-form-item"
label-width="120px"
>
<span>{{ getBusinesslongName }}</span>
</el-form-item>
<el-form-item
label="区域规模"
prop="areades"
class="area-form-item"
>
<span v-if="areaForm.areades">{{ areaForm.areades }}</span>
<span v-else class="module-tips">次日跑批之后自动更新</span>
</el-form-item>
<el-form-item
label="审批状态"
prop="auditStatus"
class="area-form-item area-form-item1"
>
<span>{{
areaForm.auditStatus == "0"
? "审批中"
: areaForm.auditStatus == "1"
? "通过"
: areaForm.auditStatus == "2"
? "拒绝"
: ""
}}</span>
</el-form-item>
<el-form-item
label="区域备注"
prop="remark"
class="area-form-item area-form-item1"
>
<span v-if="!show">{{ areaForm.remark }}</span>
<el-input
v-else
v-model="areaForm.remark"
type="textarea"
maxlength="200"
clearable
:disabled="!show"
:autosize="{ minRows: 2, maxRows: 4 }"
/>
</el-form-item>
</template>
</el-form>
<div class="edit-operate">
<template v-if="show">
<el-button size="small" @click.stop="cancelSaveArea('justcancel')">
取消
</el-button>
<el-button type="primary" size="small" @click.stop="saveArea">
保存
</el-button>
</template>
<template v-if="infoType === 'SHOW'">
<el-tooltip placement="top" effect="light" content="重新申请">
<i
v-if="areaForm.deptId == deptId && areaForm.auditStatus == '2'"
class="el-icon-coordinate icon-area"
@click.stop="approveAgain"
/>
</el-tooltip>
<el-tooltip placement="top" effect="light" content="修改信息">
<i
class="el-icon-edit icon-area"
:class="
areaForm.deptId != deptId || areaForm.batchFlag
? 'disabled'
: ''
"
@click.stop="updateAreaInfo"
/>
</el-tooltip>
<!-- 查看客户 -->
<el-tooltip placement="top" effect="light" content="查看客户">
<i
class="el-icon-user icon-area"
@click.stop="previewCustomer"
/>
</el-tooltip>
<!-- 删除区域 -->
2026-02-26 14:51:13 +08:00
<el-tooltip placement="top" effect="light" content="删除区域">
<el-popconfirm
title="确定删除吗?"
icon="el-icon-info"
icon-color="red"
:disabled="areaForm.deptId != deptId || areaForm.batchFlag"
@confirm="delAreaInfo"
>
<i
slot="reference"
class="el-icon-delete icon-area"
:class="
areaForm.deptId != deptId || areaForm.batchFlag
? 'disabled'
: ''
"
/>
</el-popconfirm>
</el-tooltip>
<el-tooltip placement="top" effect="light" content="调整边界">
<i
class="el-icon-house icon-area"
:class="
areaForm.deptId != deptId || areaForm.batchFlag
? 'disabled'
: ''
"
@click.stop="updateAreaShape"
/>
</el-tooltip>
</template>
</div>
</div>
</transition>
<!-- 查看客户模态框 -->
<customer-modal
ref="customerModal"
cardType="featured"
:detailInfo="areaForm"
:btnType="'2'"
/>
2026-02-26 14:51:13 +08:00
<div class="search-box">
<el-form size="small" class="myForm">
<el-form-item style="width: 130px">
<el-select v-model="region" placeholder="请选择" @change="toggleCity">
<el-option v-for="item in cityList" :key="item" :value="item">{{
item
}}</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-autocomplete
v-model="address"
clearable
placeholder="请输入详细地址"
suffix-icon="el-icon-search"
:fetch-suggestions="querySearch"
:trigger-on-focus="false"
:debounce="800"
@clear="handleSearch"
@select="handleSelect"
@focus="handleFocus"
/>
</el-form-item>
<el-form-item
class="tree-select"
prop="addressTree"
v-show="$store.state.featuredAreas.level === 1"
>
<el-tree
ref="addressTree"
class="tree-border"
:data="menuOptions"
show-checkbox
node-key="value"
empty-text="加载中,请稍候"
:default-checked-keys="areaChecked"
:default-expanded-keys="areaChecked"
:props="defaultGridProps"
@check="onChecked"
/>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import {
addAreasInfo,
updateAreasInfo,
removeAreasInfo,
drawAreaShape,
checkEdit,
approveAgainApi,
queryAddressList,
getCustCount,
getRegionCoordQuery
} from '@/api/grid/draw-area'
// import { getAddressTree } from '@/api/grid/address/tree.js'
import { getAddressTree } from '@/api/grid/list/gridlist.js'
import { getUserDefaultLoc } from '@/api/customRadar/customRadar.js'
import WKT from 'terraformer-wkt-parser'
import { businessBelongList } from '@/views/grid/create/utils'
import { mapGetters } from 'vuex'
import { Message } from 'element-ui'
import { isEmpty } from 'lodash'
import CustomerModal from '@/views/grid/map/draw-area/customer-modal.vue'
2026-02-26 14:51:13 +08:00
const polygonOptions = {
strokeColor: '#5E87DB',
strokeWeight: 3,
strokeOpacity: 1,
fillColor: '#5E87DB',
fillOpacity: 0.2
}
const labelOptions = {
backgroundColor: 'rgba(0, 0, 0, 0.7)',
borderRadius: '4px',
color: '#fff',
padding: '8px 16px',
fontSize: '12px',
fontWeight: 'normal',
border: 'none'
}
export default {
name: 'BMapPolygonEditor',
components: {
CustomerModal
},
2026-02-26 14:51:13 +08:00
props: ['layerInfo'],
data() {
return {
businessBelongList: businessBelongList,
mapLoading: false,
map: null, // 地图
drawingManager: null, // 绘制管理器
currentPolygon: null,
currentPolygonType: '',
originalPlygon: null, // 开始编辑前的覆盖物
polygonEditor: null,
isDrawing: false, // 是否开始绘制
isEditing: false, // 是否编辑
isDeleting: false, // 是否删除
keydownHandler: null, // 键盘Escape事件
visible: false,
infoType: null, // 区域详情弹窗类型
areaForm: {
shapeName: '',
remark: '',
opsDept: ''
},
locationAddress: '',
areaRules: {
shapeName: [
{
required: true,
message: '请输入区域名称',
trigger: 'blur'
},
{
max: 20,
message: '长度在20个字符以内',
trigger: 'blur'
}
],
opsDept: [
{
required: true,
message: '请选择业务部门归属',
trigger: 'change'
}
]
},
clickCount: 0,
singleClickTimer: null,
opsDeptDisable: false,
cityList: [
'杭州',
'宁波',
'温州',
'嘉兴',
'湖州',
'绍兴',
'金华',
'衢州',
'舟山',
'台州',
'丽水',
'上海'
],
region: '',
address: '',
options: [],
addressList: [],
func: () => {},
showHotMapFlag: false,
hotMapData: [],
max: 100,
heatmapOverlay: '',
menuOptions: [],
areaChecked: [],
defaultGridProps: {
children: 'children',
label: 'label'
},
}
},
computed: {
...mapGetters(['roles', 'userName', 'deptId']),
// 莲都
is931() {
return this.userName.slice(0, 3) === '931'
},
editEnable() {
if (!this.currentPolygon || this.isDrawing) {
return true
} else if (this.currentPolygon && this.currentPolygonType === 'noAdd') {
return true
}
},
// 区域类型
layerName() {
const { layerData } = this.$store.state.featuredAreas
const layer = layerData.find(
(layer) => layer.layerId === this.layerInfo.layerId
)
return layer ? layer.label : ''
},
// 区域标题
infoTitle() {
return this.infoType === 'ADD' ? '区域新建' : '区域详情'
},
show() {
return this.infoType === 'ADD' || this.infoType === 'EDIT'
},
getBusinesslongName() {
const index = this.businessBelongList.findIndex(
(v) => v.key === this.areaForm.opsDept
)
if (index >= 0) {
return this.businessBelongList[index].label
} else {
return ''
}
}
},
watch: {
'$store.state.featuredAreas.level'(newval) {
if (newval === 1) {
// this.heatmapOverlay && this.removeHotMap()
this.cancelSaveArea()
}
},
showHotMapFlag(newVal) {
if (newVal) {
this.getHotMapPoint()
} else {
this.removeHotMap()
}
}
},
mounted() {
console.log('init')
this.initMap()
// 添加键盘事件监听
this.keydownHandler = this.handleKeydown.bind(this)
document.addEventListener('keydown', this.keydownHandler)
this.getMenuTreeselect()
},
beforeDestroy() {
// 组件销毁时移除事件监听
if (this.keydownHandler) {
document.removeEventListener('keydown', this.keydownHandler)
}
},
methods: {
// 防抖
// debounce(fn,delay){
// let timer = null;
// clearTimeout(timer);
// timer = setTimeout(()=>{
// fn();
// clearTimeout(timer);
// },delay)
// },
handleFocus() {
if (this.address && this.addressList.length > 0) {
this.func(this.addressList)
}
},
querySearch(queryString, cb) {
this.func = cb
console.log(queryString, 1111)
if (!queryString) {
cb([])
return
}
// this.debounce(()=>{
queryAddressList({
region: this.region,
address: this.address
}).then((res) => {
if (res.code == 200) {
const addressList = res?.data?.map((item) => {
return {
value: item.name,
location: item.location
}
})
this.addressList = addressList
cb(addressList || [])
}
})
// },1000)
},
handleSelect(v) {
console.log(v, this.address)
this.map.centerAndZoom(v.location, 14)
this.addMarker(v.location.lng, v.location.lat)
},
toggleCity() {
this.address = ''
this.addressList = []
this.map.centerAndZoom(this.region, 14)
},
handleSearch() {
this.map.centerAndZoom(this.region, 14)
},
// 重新申请
approveAgain() {
approveAgainApi({ ...this.areaForm }).then((res) => {
if (res.code == 200) {
Message.success('重新申请成功')
this.$emit('refreshApprove')
this.$store.dispatch('lookAreas', this.layerInfo).then((res) => {
this.deletePolygon()
this.showWKT(res.data)
})
}
})
},
setSomeData() {
if (this.roles.includes('headPrivate')) {
// 零售部
this.areaForm.opsDept = '0'
this.opsDeptDisable = true
} else if (this.roles.includes('headPublic')) {
// 公司部
this.areaForm.opsDept = '1'
this.opsDeptDisable = true
} else if (this.roles.includes('headOps')) {
// 运管部
this.areaForm.opsDept = '2'
this.opsDeptDisable = true
} else {
// 总行管理员或者支行管理员
this.areaForm.opsDept = undefined
this.opsDeptDisable = false
}
},
initMap() {
const { layerInfo } = this.$store.state.featuredAreas
console.log(layerInfo)
// 初始化地图
this.mapLoading = true
this.map = new BMapGL.Map(this.$refs.mapContainer)
getUserDefaultLoc().then((res) => {
if (res.code === 200) {
this.locationAddress = res?.data?.address || '临海市'
this.map.centerAndZoom(this.locationAddress, 14)
}
})
this.map.enableScrollWheelZoom()
this.map.addEventListener('zoomend', () => {
this.updateHotMap()
})
this.map.addEventListener('dragend', () => {
this.updateHotMap()
})
// 初始化绘制管理器
this.drawingManager = new BMapGLLib.DrawingManager(this.map, {
isOpen: false, // 是都开启绘制模式
enableDrawingTool: false, // 是否添加绘制工具
confirmVisable: true,
enableSorption: true, // 是否开启吸附功能
drawingToolOptions: {
anchor: BMAP_ANCHOR_TOP_RIGHT,
offset: new BMapGL.Size(5, 5)
},
polygonOptions: polygonOptions, // 多边形样式
labelOptions: labelOptions // 提示语样式
})
this.mapLoading = false
// 监听绘制完成事件
this.drawingManager.addEventListener('overlaycomplete', (e) => {
console.log('完成绘制')
this.isDrawing = false
this.areaForm = {
shapeName: '',
remark: '',
opsDept: ''
}
this.$store.dispatch('setIsDrawing', false)
if (this.currentPolygon) {
this.map.removeOverlay(this.currentPolygon)
this.originalPlygon = null
}
this.currentPolygon = e.overlay
this.originalPlygon = e.overlay.getPath()
this.currentPolygonType = 'add'
this.drawingManager.close()
this.setSomeData()
this.visible = true
this.infoType = 'ADD'
this.currentPolygon.addEventListener('click', () => {
if (this.isDrawing || this.isEditing) return
this.currentPolygon = e.overlay
this.originalPlygon = e.overlay.getPath()
this.currentPolygonType = 'add'
this.setSomeData()
this.visible = true
this.infoType = 'ADD'
})
// 监听编辑结束事件
// this.currentPolygon.addEventListener("end", () => {
// console.log('编辑结束');
// });
})
// 监听绘制取消事件
this.drawingManager.addEventListener('overlaycancel', (e) => {
console.log('取消绘制')
this.isDrawing = false
this.areaForm = {
shapeName: '',
remark: '',
opsDept: ''
}
this.$store.dispatch('setIsDrawing', false)
if (this.currentPolygon) {
this.map.removeOverlay(this.currentPolygon)
}
this.currentPolygon = null
this.originalPlygon = null
this.currentPolygonType = ''
})
},
handleKeydown(event) {
// 处理 ESC 键
if (event.key === 'Escape' && this.isDrawing) {
this.cancelDrawing()
const { shapeList } = this.$store.state.featuredAreas
this.showWKT(shapeList[0].children)
}
},
// 取消绘制
cancelDrawing() {
if (this.isDrawing) {
this.drawingManager.close()
this.isDrawing = false
this.$store.dispatch('setIsDrawing', false)
// 清除正在绘制的临时覆盖物
const overlays = this.map.getOverlays()
overlays.map((overlay) => {
// 行政区标志true的时候不删除
if (overlay._config.isRegion) return;
this.map.removeOverlay(overlay)
})
}
},
// 开始绘制
startDrawing() {
if (this.currentPolygon && this.currentPolygonType === 'add') {
// 移除监听和已经绘制完成的覆盖物,一次只能绘制一个覆盖物
// this.cancelDeleting();
this.map.removeOverlay(this.currentPolygon)
this.currentPolygon = null
}
this.isDrawing = true
this.$store.dispatch('setIsDrawing', true)
if (this.polygonEditor) {
this.polygonEditor.close()
}
this.drawingManager.setDrawingMode(BMAP_DRAWING_POLYGON) // 默认多边形绘制模式
this.drawingManager.open()
},
// 显示热力图
showHotmap() {
this.showHotMapFlag = !this.showHotMapFlag
},
getHotMapPoint() {
getCustCount().then(res => {
if (res.code == 200) {
this.hotMapData = res.data
if (this.hotMapData.length) {
this.hotMapMax = this.hotMapData.reduce((prev, current) =>
Number(prev.count) > Number(current.count) ? prev : current
).count
this.drawHeatMap()
}
}
})
},
drawHeatMap() {
this.heatmapOverlay = new BMapLib.HeatmapOverlay({
radius: 30,
visible: true,
opacity: 70
})
this.map.addOverlay(this.heatmapOverlay)
// this.heatmapOverlay.setOptions({
// gradient:{
// 0:'blue',
// 0.1:'rgb(0,255,255)',
// 0.2:'rgb(0,255,0)',
// 0.4:'yellow',
// 0.6:'red',
// 1:'maroon',
// }
// })
const data = {
max: this.hotMapMax,
data: this.hotMapData
}
// console.log(this.heatmapOverlay)
this.heatmapOverlay.setDataSet(data)
// this.map.setViewport();
// this.mapLoading = false
},
// 更新热力图
updateHotMap() {
if (this.heatmapOverlay) {
const data = {
max: this.hotMapMax,
data: this.hotMapData
}
this.heatmapOverlay.setDataSet(data)
}
},
// 清除热力图
removeHotMap() {
this.map.removeOverlay(this.heatmapOverlay)
this.hotMapMax = 100
this.hotMapData = []
this.heatmapOverlay = ''
this.showHotMapFlag = false
},
deleteEvent(e) {
this.map.removeOverlay(e.target)
this.currentPolygon = null
this.originalPlygon = null
this.currentPolygonType = ''
},
startDeleting() {
if (!this.currentPolygon) return
this.currentPolygon.setFillOpacity(0.2)
this.currentPolygon.setFillColor('red')
this.currentPolygon.addEventListener('click', this.deleteEvent)
},
cancelDeleting() {
this.currentPolygon.removeEventListener('click')
this.currentPolygon.setFillColor(polygonOptions.fillColor)
},
editPolygon() {
if (!this.currentPolygon) return
// this.cancelDeleting();
this.isEditing = true
this.$store.dispatch('setIsDrawing', true)
this.currentPolygon.enableEditing()
},
deletePolygon() {
if (!this.currentPolygon) return
if (this.polygonEditor) {
this.polygonEditor.close()
}
this.map.removeOverlay(this.currentPolygon)
this.currentPolygon = null
this.originalPlygon = null
this.currentPolygonType = ''
},
getWKT(polygon) {
if (this.currentPolygon || polygon) {
const currentPolygon = polygon || this.currentPolygon
// this.cancelDeleting();
const path = currentPolygon.getPath()
const coordinates = path
.map((point) => `${point.lng} ${point.lat}`)
.join(',')
const wkt = `POLYGON((${coordinates}))`
return wkt
}
},
/**
* 恢复编辑前的图形
*/
resetPolygon() {
if (this.originalPlygon) {
this.currentPolygon.setPath(this.originalPlygon)
}
},
/**
* 恢复编辑前的图片
*/
refreshEdit() {
this.resetPolygon()
},
/**
* 取消编辑
*/
cancelEdit() {
this.currentPolygon.disableEditing()
this.isEditing = false
this.$store.dispatch('setIsDrawing', false)
this.resetPolygon()
this.cancelSaveArea()
},
/**
* 保存编辑
*/
async saveEdit() {
this.currentPolygon.disableEditing()
this.isEditing = false
this.$store.dispatch('setIsDrawing', false)
if (this.infoType === 'EDITSHAPE') {
// 调整边界
console.log('当前区域', this.areaForm)
const shapeWkt = this.getWKT()
const res = await drawAreaShape({
layerId: this.areaForm.layerId,
shapeId: this.areaForm.shapeId,
opsDept: this.areaForm.opsDept,
shapeWkt
})
if (res.code === 200) {
this.$message({
type: 'success',
message: '边界调整成功'
})
this.areaForm = {
shapeName: '',
remark: '',
opsDept: ''
}
this.currentPolygon = null
this.originalPlygon = null
this.currentPolygonType = ''
this.cancelSaveArea()
this.$store.dispatch('goBack', 2)
this.$emit('refreshApprove')
this.$store.dispatch('lookAreas', this.layerInfo).then((res) => {
this.deletePolygon()
this.showWKT(res.data)
})
}
return
}
this.setSomeData()
this.visible = true
this.infoType = 'ADD'
},
/**
* 区域详情弹窗取消事件
*/
cancelSaveArea(justcancel) {
this.visible = false
this.infoType = null
if (!justcancel) {
this.currentPolygon = null
this.originalPlygon = null
this.currentPolygonType = ''
}
this.$refs.form.clearValidate()
this.setAllFillColor()
setTimeout(() => {
this.areaForm = {
shapeName: '',
remark: '',
opsDept: ''
}
}, 500)
},
/**
* 区域详情弹窗保存事件
*/
saveArea() {
this.$refs.form.validate(async(valid) => {
if (valid) {
const shapeWkt = this.getWKT()
const API =
this.infoType === 'ADD'
? addAreasInfo
: this.infoType === 'EDIT'
? updateAreasInfo
: ''
const res = await API(
this.infoType === 'ADD'
? {
layerId: this.layerInfo.layerId,
shapeName: this.areaForm.shapeName,
opsDept: this.areaForm.opsDept,
shapeWkt
}
: this.infoType === 'EDIT'
? {
shapeName: this.areaForm.shapeName,
shapeId: this.areaForm.shapeId,
layerId: this.areaForm.layerId,
opsDept: this.areaForm.opsDept,
remark: this.areaForm.remark
}
: {}
)
if (res.code === 200) {
this.$message({
type: 'success',
message: this.infoType === 'ADD' ? '保存成功' : '修改成功'
})
this.cancelSaveArea()
this.$store.dispatch('goBack', 2)
this.$store.dispatch('lookAreas', this.layerInfo).then((res) => {
if (this.infoType === 'EDIT') return
this.deletePolygon()
this.showWKT(res.data)
})
}
} else {
return false
}
})
},
removeALLOverlays() {
const overlays = this.map.getOverlays()
overlays.map((overlay) => {
// 行政区标志true的时候不删除
if (overlay._config.isRegion) return;
this.map.removeOverlay(overlay)
})
},
showWKT(data, showModal = false) {
console.log(data, '绘图')
this.visible = false
this.infoType = null
this.removeALLOverlays()
if (!data.length) {
this.map.centerAndZoom(this.locationAddress, 14)
}
let allPoints = []
data.map((item) => {
const wkt = item.shapeWkt
const geojson = WKT.parse(wkt)
allPoints = allPoints.concat(
this.renderPolygon(geojson.coordinates, item.shapeId, showModal)
)
})
console.log(allPoints, 'allPoints')
this.map.setViewport(allPoints)
if (this.showHotMapFlag) {
this.drawHeatMap()
}
},
/**
* 绘制多边形覆盖物
*/
renderPolygon(coordinates, id, showModal) {
console.log(this.layerInfo, 'this.layerInfo')
const than = this
const pointArr = []
coordinates.map((ring) => {
const points = ring.map((coord) => {
const point = new BMapGL.Point(coord[0], coord[1])
pointArr.push(point)
return point
// return new BMapGL.Point(coord[0], coord[1]);
})
const polygon = new BMapGL.Polygon(points, {
strokeColor: this.layerInfo.color,
strokeWeight: 3,
strokeOpacity: 0.8,
strokeStyle: 'solid',
fillColor: this.layerInfo.color,
fillOpacity: 0.4,
shapeId: id // 添加额外的属性
})
if (showModal) {
// 点击单个区域 显示详情弹窗
const { shapeList } = this.$store.state.featuredAreas
const shapeItem = shapeList[0].children.find(
(shape) => shape.shapeId === id
)
if (shapeItem) {
console.log(shapeItem)
this.areaForm = shapeItem
this.infoType = 'SHOW'
this.visible = true
this.currentPolygon = polygon
this.originalPlygon = polygon.getPath()
this.currentPolygonType = 'noAdd'
} else {
this.$message({
type: 'info',
message: '未找到图形信息'
})
}
}
polygon.addEventListener('click', function(e) {
if (than.isEditing) return
than.clickCount = Number(than.clickCount) + 1
clearTimeout(than.singleClickTimer)
if (than.clickCount === 1) {
than.singleClickTimer = setTimeout(() => {
if (than.clickCount === 1) {
// 单击
console.log('单击')
than.handlerPolygon(e)
than.currentPolygon = polygon
than.originalPlygon = polygon.getPath()
than.currentPolygonType = 'noAdd'
}
than.clickCount = 0
}, 300)
} else if (than.clickCount === 2) {
// 双击
console.log('双击')
clearTimeout(than.singleClickTimer)
than.clickCount = 0
}
})
this.map.addOverlay(polygon)
polygon.show()
// const view = this.map.getViewport(points);
// this.map.centerAndZoom(points[0], view.zoom-1);
})
// console.log(pointArr)
return pointArr
},
/**
* 多边形点击事件
*/
handlerPolygon(e) {
// 行政区标志true的时候不显示弹窗
if (e.target._config.isRegion) return
if (!e.target.getFillColor) return
const currentColor = e.target.getFillColor()
const { shapeList } = this.$store.state.featuredAreas
const shapeId = e.target._config.shapeId
const shapeItem = shapeList[0].children.find(
(shape) => shape.shapeId === shapeId
)
if (shapeItem) {
this.areaForm = shapeItem
this.infoType = 'SHOW'
console.log(shapeItem)
} else {
this.$message({
type: 'info',
message: '未找到图形信息'
})
}
if (currentColor === this.layerInfo.color) {
this.setAllFillColor()
e.target.setFillOpacity(0.1)
e.target.setFillColor('red')
e.target.setStrokeColor('red')
e.target.setStrokeWeight(5)
if (shapeItem) this.visible = true
} else {
e.target.setFillOpacity(0.4)
e.target.setFillColor(this.layerInfo.color)
e.target.setStrokeColor(this.layerInfo.color)
e.target.setStrokeWeight(3)
this.cancelSaveArea()
}
},
setAllFillColor() {
const overlays = this.map.getOverlays()
overlays.map((overlay) => {
// 行政区标志true的时候不用变颜色
if (overlay._config.isRegion) return
if (!overlay.getFillColor) return
const currentColor = overlay.getFillColor()
if (currentColor === this.layerInfo.color) return
overlay.setFillOpacity(0.4)
overlay.setFillColor(this.layerInfo.color)
overlay.setStrokeColor(this.layerInfo.color)
overlay.setStrokeWeight(3)
})
},
/**
* 判断是否有编辑权限
*/
async toCheckEdit() {
const res = await checkEdit({ shapeId: this.areaForm.shapeId })
if (res.code === 200) return false
else return true
},
/**
* 修改信息
*/
async updateAreaInfo() {
if (this.areaForm.deptId != this.deptId || this.areaForm.batchFlag) {
return
}
if (this.areaForm.batchFlag) {
this.$message({
type: 'info',
message: '暂不能编辑,请稍后再试'
})
return
}
// const flag = await this.toCheckEdit();
// if (flag) return;
this.infoType = 'EDIT'
},
/**
* 删除区域
*/
async delAreaInfo() {
if (this.areaForm.batchFlag) {
this.$message({
type: 'info',
message: '暂不能删除,请稍后再试'
})
return
}
// const flag = await this.toCheckEdit();
// if (flag) return;
const res = await removeAreasInfo({ idList: [this.areaForm.shapeId] })
if (res.code === 200) {
this.$message({
type: 'success',
message: '删除成功'
})
this.cancelSaveArea()
this.$store.dispatch('goBack', 2)
this.$emit('refreshApprove')
this.$store.dispatch('lookAreas', this.layerInfo).then((res) => {
this.deletePolygon()
this.showWKT(res.data)
})
}
},
/**
* 调整边界
*/
async updateAreaShape() {
if (this.areaForm.deptId != this.deptId || this.areaForm.batchFlag) {
return
}
if (this.areaForm.batchFlag) {
this.$message({
type: 'info',
message: '暂不能调整,请稍后再试'
})
return
}
// const flag = await this.toCheckEdit();
// if (flag) return;
this.visible = false
this.infoType = 'EDITSHAPE'
this.isEditing = true
this.$store.dispatch('setIsDrawing', true)
this.currentPolygon.enableEditing()
},
setForm(data) {
this.areaForm = data
this.visible = true
this.infoType = 'SHOW'
const overlays = this.map.getOverlays()
this.currentPolygon = overlays[0]
this.originalPlygon = overlays[0].getPath()
},
async getMenuTreeselect() {
getAddressTree()
.then((response) => {
if (response.code !== 200) return
this.menuOptions = response.data.children
this.menuOptions.forEach((item) => {
if (item.level === 2) {
item.disabled = true
}
})
})
.catch((error) => {
console.log('error', error)
})
},
// 删除行政区
clearRegionOverlays() {
const overlays = this.map.getOverlays()
overlays.map((overlay) => {
// 行政区标志true的时候不删除
if (!overlay._config.isRegion) return;
this.map.removeOverlay(overlay)
})
},
// 行政区选择事件
async onChecked(data, checkedObj) {
const collectedArr = this.regionCodeFilter(checkedObj.checkedKeys)
if (isEmpty(collectedArr)) {
this.clearRegionOverlays();
return
}
const regionKeys = this.regionCodeFilter(collectedArr)
const output = await getRegionCoordQuery(regionKeys)
const polygonData = output['data'].map((item) => item['polygonList'])
if (!isEmpty(polygonData)) {
this.addPolygon(polygonData)
}
},
// 绘制行政区块
addPolygon(regionMapVOList) {
this.clearRegionOverlays();
var allPoints = []
var regionPoints = []
regionMapVOList.forEach(polygonList => {
polygonList.forEach(polygon => {
polygon.forEach(points => {
var areaPoints = []
points.forEach(point => {
var point = new BMapGL.Point(parseFloat(point['x']), parseFloat(point['y']));
areaPoints.push(point);
allPoints.push(point)
})
regionPoints.push(areaPoints)
});
})
});
var geom = new BMapGL.Polygon(regionPoints,
{
strokeColor: "#9200cf",
strokeWeight: 3,
strokeOpacity: 0.5,
isRegion: true, // 行政区标志
});
this.map.addOverlay(geom);
this.map.setViewport(allPoints);
},
regionCodeFilter(regionArr) {
const sorted = regionArr?.sort((a, b) => a.length - b.length)
const keyLen = sorted?.[0]?.length
if (keyLen === 12) {
return regionArr
}
const keys = regionArr?.filter((code) => code.length === keyLen)
keys?.forEach((key) => {
regionArr = regionArr?.filter((code) => !code?.startsWith(key))
})
return [...keys, ...regionArr]
},
addMarker(x, y) {
const overlays = this.map.getOverlays()
overlays.map((overlay) => {
// 只删除标志点
if (!overlay._config.isMarker) return;
this.map.removeOverlay(overlay)
})
var point = new BMapGL.Point(x, y);
var marker = new BMapGL.Marker(point, {
isMarker: true
});
this.map.centerAndZoom(point, 18);
this.map.addOverlay(marker);
}
}
}
</script>
<style lang="scss" scoped>
.map-wrap {
flex: 1;
position: relative;
}
.search-box {
position: absolute;
top: 5px;
left: 10px;
z-index: 1000;
.myForm {
display: flex;
width: 340px;
flex-wrap: wrap;
}
}
.map-container {
width: 100%;
height: calc(100vh - 225px);
margin-bottom: 10px;
}
.control-panel {
padding: 10px;
position: absolute;
right: 0;
top: 0;
z-index: 1000;
background-color: rgba(0, 0, 0, 0.65);
}
.control-panel button, .control-panel-out button {
margin-right: 10px;
padding: 5px 10px;
cursor: pointer;
}
.control-panel button:disabled, .control-panel-out button:disabled {
cursor: not-allowed;
opacity: 0.6;
}
.control-panel-out {
padding: 10px;
position: absolute;
right: 0;
top: 0;
z-index: 1000;
background-color: rgba(0, 0, 0, 0.65);
display: flex;
flex-direction: row;
}
.control-panel-in {
background-color: rgba(0, 0, 0, 0.65);
}
.drawing-tip {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 8px 16px;
border-radius: 4px;
z-index: 1000;
}
.area-info-modal {
width: 390px;
color: #fff;
position: absolute;
top: 40px;
right: 40px;
background-color: rgba(0, 0, 0, 0.7);
border-radius: 8px;
z-index: 1000;
.form-box {
padding-right: 20px;
}
.area-form-item {
margin-bottom: 0px;
span {
color: #ccc;
line-height: 24px;
display: inline-block;
}
.module-tips {
color: #ffa0a0;
}
}
.area-radio {
::v-deep .el-radio {
margin-right: 15px;
}
::v-deep .el-radio__label {
padding-left: 0;
color: #ccc;
}
::v-deep .el-radio__input.is-disabled .el-radio__inner {
background-color: #c6c6c6;
border-color: #6d6d6d;
}
::v-deep .el-radio__input.is-disabled.is-checked .el-radio__inner::after {
background-color: #5c5c5c;
}
}
.area-form-item1 {
margin-bottom: 6px;
}
h4 {
font-size: 18px;
color: #ffffff;
line-height: 25px;
font-weight: 600;
text-align: center;
margin: 24px 0;
position: relative;
}
.el-icon-close {
position: absolute;
right: 24px;
top: 0;
font-size: 18px;
cursor: pointer;
}
::v-deep .el-form-item__label {
color: #fff;
font-weight: normal;
}
}
.edit-operate {
display: flex;
align-items: center;
justify-content: flex-end;
padding: 12px 30px;
border-top: 1px solid #646363;
margin-top: 20px;
.icon-area {
font-size: 20px;
margin-left: 20px;
font-weight: bold;
}
}
.disabled {
cursor: not-allowed;
color: #ccc;
}
.tree-select {
width: 100%;
margin-top: -15px;
::v-deep .is-disabled {
display: none;
}
}
.tree-border {
height: 240px;
overflow-y: scroll;
}
</style>