【类 型】:feat

【原  因】:飞行区域安全控制需求,需要前端支持禁飞区与限飞区的可视化设置与展示。
【过  程】:- 新增 RestrictflyControl 控件,支持限飞区绘制并弹窗设置高度;
- 支持将限飞区多边形及高度通过 setRestrictflyData 接口保存;
- 在飞行地图中新增 PolygonToggleControl 控件,可开关显示禁飞区/限飞区图层;
- 限飞区标签支持显示限高信息,如“限飞高度120米”。
【影  响】:

# 类型 包含:
# feat:新功能(feature)
# fix:修补bug
# docs:文档(documentation)
# style: 格式(不影响代码运行的变动)
# refactor:重构(即不是新增功能,也不是修改bug的代码变动)
# test:增加测试
# chore:构建过程或辅助工具的变动
This commit is contained in:
air 2025-06-18 19:58:16 +08:00
parent d731a42bfa
commit 555d480efd
9 changed files with 375 additions and 31477 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.DS_Store
/node_modules
/dist
/package-lock.json

31270
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,16 +9,17 @@
"lint": "eslint --ext .js,.vue src"
},
"dependencies": {
"@turf/turf": "^7.2.0",
"axios": "^1.9.0",
"core-js": "^3.6.5",
"echarts": "^5.6.0",
"element-ui": "^2.15.14",
"geodist": "^0.2.1",
"lodash": "^4.17.21",
"mapbox-gl": "^2.15.0",
"mqtt": "^2.18.9",
"normalize.css": "^8.0.1",
"nprogress": "^0.2.0",
"geodist": "^0.2.1",
"vue": "^2.6.11",
"vue-router": "^3.6.5",
"vue-template-compiler": "^2.7.16",

View File

@ -6,7 +6,7 @@
<script>
import mapboxgl from 'mapbox-gl'
import { MapboxStyleSwitcherControl, FollowControl, CustomFullscreenControl, NoFlyControl, SaveToFileControl, PolygonToggleControl } from '@/utils/mapboxgl_plugs'
import { MapboxStyleSwitcherControl, FollowControl, CustomFullscreenControl, NoFlyControl, RestrictflyControl, SaveToFileControl, PolygonToggleControl } from '@/utils/mapboxgl_plugs'
import planeIcon from '@/assets/svg/plane.svg'
export default {
@ -172,6 +172,10 @@ export default {
type: Boolean,
default: false
},
enableRestrictfly: { //
type: Boolean,
default: false
},
enableShowNofly: { //
type: Boolean,
default: false
@ -345,22 +349,23 @@ export default {
//
if (this.enableNofly) {
const noflyPolygons = this.$store.state.noflyData[0]
const restrictflyPolygons = this.$store.state.noflyData[1]
const shopId = this.$store.state.user.shop_id
this.map.addControl(new NoFlyControl({
noflyPolygons,
restrictflyPolygons,
shopId,
onSave: (nofly, limit) => {
console.log('保存成功:', nofly, limit)
},
onDrawFinish: (nofly) => {
console.log('禁飞区绘制完成:', nofly)
},
onLimitFinish: (limit) => {
console.log('限飞区绘制完成:', limit)
defaultPolygons: this.$store.state.noflyData[0], //
shopId: this.$store.state.user.shop_id,
onSave: (data) => {
console.log('保存成功:', data)
}
}), 'top-left')
}
//
if (this.enableRestrictfly) {
this.map.addControl(new RestrictflyControl({
defaultPolygons: this.$store.state.noflyData[1], //
defaultHeights: this.$store.state.noflyData[2], //
shopId: this.$store.state.user.shop_id,
onSave: (data) => {
console.log('保存成功:', data)
}
}), 'top-left')
}
@ -369,6 +374,7 @@ export default {
if (this.enableShowNofly) {
const noflyPolygons = this.$store.state.noflyData[0] || []
const restrictflyPolygons = this.$store.state.noflyData[1] || []
const restrictflyHeights = this.$store.state.noflyData[2] || []
this.map.addControl(new PolygonToggleControl({
defaultIconClass: 'iconfont icon-jinfeiqu_weidianji f-s-20 seatFontColor',
@ -376,16 +382,18 @@ export default {
onToggle: (isActive) => {
if (isActive) {
//
//
noflyPolygons.forEach((coords, i) => {
this.drawPolygonWithLabel(coords, `nofly-polygon-${i}`, '#F33', '禁飞区')
})
//
//
restrictflyPolygons.forEach((coords, i) => {
this.drawPolygonWithLabel(coords, `restrict-polygon-${i}`, '#F83', '限飞区')
const height = restrictflyHeights[i] || 0
const label = `限飞高度${height}`
this.drawPolygonWithLabel(coords, `restrict-polygon-${i}`, '#F83', label)
})
} else {
//
//
const layerIds = []
const sourceIds = []

View File

@ -53,7 +53,7 @@ const routes = [
component: Layout,
redirect: '/register/index',
meta: {
title: '飞机管理',
title: '管理飞机',
icon: 'el-icon-edit-outline',
roles: ['admin', 'editor'],
tapName: 'plane'
@ -116,23 +116,33 @@ const routes = [
{
path: '/nofly',
component: Layout,
redirect: '/nofly/set',
redirect: '/nofly/setNofly',
meta: {
title: '设置禁飞区',
icon: 'iconfont icon-feihangluxian',
title: '限制飞行',
icon: 'iconfont icon-jinfeiqu',
roles: ['admin', 'editor'],
tapName: 'plane'
},
children: [
{
path: '/nofly/set',
component: () => import('@/views/layout/components/main/nofly/set'),
path: '/nofly/setNofly',
component: () => import('@/views/layout/components/main/nofly/setNofly'),
meta: {
title: '设置禁飞区',
icon: 'iconfont icon-huizhi',
roles: ['admin', 'editor'],
tapName: 'plane'
}
},
{
path: '/nofly/setRestrictfly',
component: () => import('@/views/layout/components/main/nofly/setRestrictfly'),
meta: {
title: '设置限飞区',
icon: 'iconfont icon-huizhi',
roles: ['admin', 'editor'],
tapName: 'plane'
}
}
]
},
@ -141,7 +151,7 @@ const routes = [
component: Layout,
redirect: '/route/index',
meta: {
title: '航线管理',
title: '管理航线',
icon: 'iconfont icon-feihangluxian',
roles: ['admin', 'editor'],
tapName: 'plane'
@ -185,7 +195,7 @@ const routes = [
component: Layout,
redirect: '/site/index',
meta: {
title: '站点管理',
title: '管理站点',
icon: 'iconfont icon-zhandianguanli',
roles: ['admin', 'editor'],
tapName: 'plane'
@ -252,7 +262,7 @@ const routes = [
component: Layout,
redirect: '/shop/edit',
meta: {
title: '商铺管理',
title: '管理商铺',
icon: 'iconfont icon-a-shanghu_choose2x1',
roles: ['admin', 'editor'],
tapName: 'admin'
@ -262,7 +272,7 @@ const routes = [
path: '/shop/edit',
component: () => import('@/views/layout/components/main/shop/add'),
meta: {
title: '商铺设置',
title: '设置商铺',
icon: 'iconfont icon-dianpuguanli',
roles: ['admin', 'editor'],
tapName: 'admin'
@ -340,7 +350,7 @@ const routes = [
component: Layout,
redirect: '/category/index',
meta: {
title: '分类管理',
title: '管理分类',
icon: 'iconfont icon-a-ziliaocaozuoxianshifenleishu',
roles: ['admin', 'editor'],
tapName: 'admin'
@ -350,7 +360,7 @@ const routes = [
path: '/category/index',
component: () => import('@/views/layout/components/main/category/index'),
meta: {
title: '分类管理',
title: '管理分类',
icon: 'iconfont icon-a-ziliaocaozuoxianshifenleishu',
roles: ['admin', 'editor'],
tapName: 'admin'
@ -363,7 +373,7 @@ const routes = [
component: Layout,
redirect: '/spu/index',
meta: {
title: '商品管理',
title: '管理商品',
icon: 'iconfont icon-chanpin',
roles: ['admin', 'editor'],
tapName: 'admin'
@ -438,7 +448,7 @@ const routes = [
component: Layout,
redirect: '/broadcast/banner',
meta: {
title: '广告管理',
title: '管理广告',
icon: 'iconfont icon-guanggao',
roles: ['admin', 'editor'],
tapName: 'admin'
@ -448,7 +458,7 @@ const routes = [
path: '/broadcast/banner',
component: () => import('@/views/layout/components/main/broadcast/banner'),
meta: {
title: 'banner设置',
title: '设置banner',
icon: 'iconfont icon-banner',
roles: ['admin', 'editor'],
tapName: 'admin'
@ -458,7 +468,7 @@ const routes = [
path: '/broadcast/notice',
component: () => import('@/views/layout/components/main/broadcast/notice'),
meta: {
title: '滚动通知设置',
title: '设置滚动通知',
icon: 'iconfont icon-m-gundongwenzi',
roles: ['admin', 'editor'],
tapName: 'admin'
@ -481,7 +491,7 @@ const routes = [
path: '/order/index',
component: () => import('@/views/layout/components/main/order/index'),
meta: {
title: '订单管理',
title: '管理订单',
icon: 'iconfont icon-a-SalesOrderManagement',
roles: ['admin', 'editor'],
tapName: 'admin'

View File

@ -17,7 +17,7 @@ const store = new Vuex.Store({
airList: [], // 所有飞机列表
siteList: [], // 站点列表
routeList: [], // 航线列表
noflyData: [[], []], // [0]禁飞区数据 [1]限制飞区
noflyData: [[], [], []], // [0]禁飞区数据 [1]限制飞区 [2]限飞区高度
categoryList: [], // 分类列表(小程序)
spuList: [], // 商品spu列表
skuList: [], // 商品sku列表
@ -70,13 +70,14 @@ const store = new Vuex.Store({
* @description: 设置禁飞区列表
*/
setNoflyData (state, payload) {
if (payload && payload.nofly_data && payload.restrictfly_data) {
if (payload && payload.nofly_data && payload.restrictfly_data && payload.restrictfly_height) {
state.noflyData = [
JSON.parse(payload.nofly_data || '[]'),
JSON.parse(payload.restrictfly_data || '[]')
JSON.parse(payload.restrictfly_data || '[]'),
JSON.parse(payload.restrictfly_height || '[]')
]
} else {
state.noflyData = [[], []]
state.noflyData = [[], [], []]
}
},
/**
@ -625,7 +626,7 @@ const store = new Vuex.Store({
if (res.data.status === 1) {
commit('setNoflyData', res.data.noflyData)
} else {
commit('setNoflyData', [[], []])
commit('setNoflyData', [[], [], []])
Message.warning(res.data.msg || '暂无禁飞区数据')
}
return res

View File

@ -198,16 +198,15 @@ export async function saveFlyData (data) {
* @param {Array} restrictfly_data 限制飞区数据数组
* @returns {Object|null} 返回接口响应数据 null 表示失败
*/
export async function setNoflyData (shopId, noflyData, restrictflyData) {
export async function setNoflyData (shopId, noflyData) {
try {
const params = new URLSearchParams()
params.append('shop_id', shopId || '')
params.append('nofly_data', JSON.stringify(noflyData || []))
params.append('restrictfly_data', JSON.stringify(restrictflyData || []))
const res = await api.post('setNoflyData', params)
if (res.data.status === 1) {
store.dispatch('fetchNoflyData', shopId)// 更新禁飞区数据
store.dispatch('fetchNoflyData', shopId)// 更新禁飞区数据
Message.success(res.data.msg)
} else {
Message.warning(res.data.msg)
@ -218,3 +217,31 @@ export async function setNoflyData (shopId, noflyData, restrictflyData) {
return null
}
}
/**
* @description: 保存限飞区数据
* @param {string|number} shop_id 商铺ID
* @param {Array} restrictfly_data 限制飞区数据数组
* @param {Array} restrictfly_height 限制飞区数据高度组
* @returns {Object|null} 返回接口响应数据 null 表示失败
*/
export async function setRestrictflyData (shopId, restrictflyData, restrictflyHeight) {
try {
const params = new URLSearchParams()
params.append('shop_id', shopId || '')
params.append('restrictfly_data', JSON.stringify(restrictflyData || []))
params.append('restrictfly_height', JSON.stringify(restrictflyHeight || []))
const res = await api.post('setNoflyData', params)
if (res.data.status === 1) {
store.dispatch('fetchNoflyData', shopId)// 更新禁限飞区数据
Message.success(res.data.msg)
} else {
Message.warning(res.data.msg)
}
return res.data
} catch (error) {
Message.error('保存限飞区数据失败')
return null
}
}

View File

@ -1,8 +1,8 @@
import mapboxgl from 'mapbox-gl'
import MapboxDraw from '@mapbox/mapbox-gl-draw'
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
import { setNoflyData } from '@/utils/api/table'
import { Message } from 'element-ui'
import { setNoflyData, setRestrictflyData } from '@/utils/api/table'
import { Message, MessageBox } from 'element-ui'
/**
* 自定义地图样式切换控件
@ -218,65 +218,45 @@ export class CustomFullscreenControl extends mapboxgl.FullscreenControl {
}
}
// 设置禁飞区 限飞区 保存 删除控件
// 禁飞区控件类
export class NoFlyControl {
constructor (options = {}) {
this._map = null
this._container = null
this._draw = null
this._onDrawFinish = options.onDrawFinish || function () {}
this._noflyPolygons = options.noflyPolygons || []
this._onLimitFinish = options.onLimitFinish || function () {}
this._restrictflyPolygons = options.restrictflyPolygons || []
this._onSave = options.onSave || function () {}
this._shopId = options.shopId
this._activeMode = 'nofly' // 当前绘制类型
this._map = null // 地图实例
this._container = null // 控件容器(用于放按钮)
this._draw = null // MapboxDraw 实例
this._onDrawFinish = options.onDrawFinish || function () {} // 绘制完成时的回调
this._defaultPolygons = options.defaultPolygons || [] // 初始加载的禁飞区多边形坐标
this._onSave = options.onSave || function () {} // 保存时的回调
this._shopId = options.shopId // 商户ID用于提交接口
}
// 当控件添加到地图上时调用
onAdd (map) {
this._map = map
// 创建控件按钮容器
this._container = document.createElement('div')
this._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group'
// --- 绘制禁飞区按钮 ---
// --- 绘制按钮 ---
const drawButton = document.createElement('button')
drawButton.className = 'mapboxgl-ctrl-icon'
drawButton.type = 'button'
drawButton.innerHTML = '✏️'
drawButton.title = '绘制禁飞区'
drawButton.onclick = () => {
this._activeMode = 'nofly'
this._enableDraw()
}
drawButton.innerHTML = '✏️' // 图标:铅笔
drawButton.title = '绘制禁飞区' // 鼠标提示
drawButton.onclick = () => this._enableDraw() // 点击启用绘制模式
this._container.appendChild(drawButton)
// --- 绘制限飞区按钮 ---
const limitButton = document.createElement('button')
limitButton.className = 'mapboxgl-ctrl-icon'
limitButton.type = 'button'
limitButton.innerHTML = '✒️'
limitButton.title = '绘制限飞区'
limitButton.onclick = () => {
this._activeMode = 'limit'
this._enableDraw()
}
this._container.appendChild(limitButton)
// --- 保存按钮 ---
const saveButton = document.createElement('button')
saveButton.className = 'mapboxgl-ctrl-icon'
saveButton.type = 'button'
saveButton.innerHTML = '💾'
saveButton.title = '保存禁飞区及限飞区'
saveButton.innerHTML = '💾' // 图标:磁盘
saveButton.title = '保存禁飞区'
saveButton.onclick = () => this._savePolygons()
this._container.appendChild(saveButton)
// --- 删除按钮 ---
// --- 删除按钮(删除选中图形) ---
const deleteButton = document.createElement('button')
deleteButton.className = 'mapboxgl-ctrl-icon'
deleteButton.type = 'button'
@ -285,43 +265,248 @@ export class NoFlyControl {
deleteButton.onclick = () => this._deleteSelected()
this._container.appendChild(deleteButton)
// 初始化 Draw 控件
// --- 初始化 MapboxDraw 控件 ---
this._draw = new MapboxDraw({
displayControlsDefault: false,
styles: this._getDrawStyles()
displayControlsDefault: false, // 不显示默认工具条
styles: [ // 自定义绘制样式(橙色)
{
id: 'gl-draw-polygon-fill',
type: 'fill',
filter: ['all', ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']],
paint: {
'fill-color': '#f33', // 填充颜色
'fill-opacity': 0.3 // 透明度
}
},
{
id: 'gl-draw-polygon-stroke-active',
type: 'line',
filter: ['all', ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']],
paint: {
'line-color': '#f33', // 边框颜色
'line-width': 2
}
},
// 控制点外圈(白色光晕)
{
id: 'gl-draw-polygon-and-line-vertex-halo-active',
type: 'circle',
filter: ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point']],
paint: {
'circle-radius': 7,
'circle-color': '#fff'
}
},
// 控制点内圈
{
id: 'gl-draw-polygon-and-line-vertex-active',
type: 'circle',
filter: ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point']],
paint: {
'circle-radius': 5,
'circle-color': '#fff'
}
}
]
})
// 将 Draw 控件添加到地图上
map.addControl(this._draw)
// 加载已有禁飞区
if (this._noflyPolygons.length > 0) {
const features = this._noflyPolygons.map(coords => ({
// --- 加载已有禁飞区(回显数据) ---
if (this._defaultPolygons.length > 0) {
const features = this._defaultPolygons.map(coords => ({
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [coords] // 注意GeoJSON Polygon 外层需要再包一层
},
properties: {}
}))
this._draw.set({
type: 'FeatureCollection',
features
})
}
// 监听绘制完成事件
map.on('draw.create', this._handleDraw.bind(this))
return this._container
}
// 当控件被移除时执行
onRemove () {
if (this._map && this._draw) {
this._map.removeControl(this._draw)
}
if (this._container?.parentNode) {
this._container.parentNode.removeChild(this._container)
}
this._map = null
}
// 启用多边形绘制模式
_enableDraw () {
if (this._draw && this._map) {
this._draw.changeMode('draw_polygon')
}
}
// 绘制完成的处理函数
_handleDraw (e) {
const features = this._draw.getAll()
if (features.features.length > 0) {
const coordinates = features.features.map(f => f.geometry.coordinates)
this._onDrawFinish(coordinates) // 通知外部最新绘制结果
}
}
// 删除当前选中的图形
_deleteSelected () {
if (this._draw) {
const selected = this._draw.getSelectedIds()
if (selected.length > 0) {
this._draw.delete(selected)
}
}
}
// 提交所有禁飞区数据到服务器
async _savePolygons () {
if (!this._draw) return
const allFeatures = this._draw.getAll()
// 提取所有 Polygon 类型图形的坐标(只取外环)
const polygons = allFeatures.features
.filter(f => f.geometry.type === 'Polygon')
.map(f => f.geometry.coordinates[0])
try {
const shopId = this._shopId
await setNoflyData(shopId, polygons)
} catch (error) {
Message.error('上传禁飞区数据时发生错误')
console.error(error)
}
// 调用保存成功回调
this._onSave(polygons)
}
}
// 限飞区控件类
export class RestrictflyControl {
constructor (options = {}) {
this._map = null
this._container = null
this._draw = null
this._shopId = options.shopId
this._defaultPolygons = options.defaultPolygons || []
this._defaultHeights = options.defaultHeights || []
this._restrictflyHeights = [] // 保存限高值
this._onSave = options.onSave || function () {}
}
onAdd (map) {
this._map = map
this._container = document.createElement('div')
this._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group'
// 绘制按钮
const drawButton = document.createElement('button')
drawButton.className = 'mapboxgl-ctrl-icon'
drawButton.type = 'button'
drawButton.innerHTML = '✏️'
drawButton.title = '绘制限飞区'
drawButton.onclick = () => this._enableDraw()
this._container.appendChild(drawButton)
// 保存按钮
const saveButton = document.createElement('button')
saveButton.className = 'mapboxgl-ctrl-icon'
saveButton.type = 'button'
saveButton.innerHTML = '💾'
saveButton.title = '保存限飞区'
saveButton.onclick = () => this._savePolygons()
this._container.appendChild(saveButton)
// 删除按钮
const deleteButton = document.createElement('button')
deleteButton.className = 'mapboxgl-ctrl-icon'
deleteButton.type = 'button'
deleteButton.innerHTML = '🗑️'
deleteButton.title = '删除选中图形'
deleteButton.onclick = () => this._deleteSelected()
this._container.appendChild(deleteButton)
// 初始化 MapboxDraw 控件(橙色样式)
this._draw = new MapboxDraw({
displayControlsDefault: false,
styles: [
{
id: 'gl-draw-polygon-fill',
type: 'fill',
filter: ['all', ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']],
paint: {
'fill-color': '#f83',
'fill-opacity': 0.3
}
},
{
id: 'gl-draw-polygon-stroke-active',
type: 'line',
filter: ['all', ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']],
paint: {
'line-color': '#f83',
'line-width': 2
}
},
{
id: 'gl-draw-polygon-and-line-vertex-halo-active',
type: 'circle',
filter: ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point']],
paint: {
'circle-radius': 7,
'circle-color': '#fff'
}
},
{
id: 'gl-draw-polygon-and-line-vertex-active',
type: 'circle',
filter: ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point']],
paint: {
'circle-radius': 5,
'circle-color': '#fff'
}
}
]
})
map.addControl(this._draw)
// 回显已有限飞区
if (this._defaultPolygons.length > 0) {
const features = this._defaultPolygons.map((coords, index) => ({
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [coords]
},
properties: {
type: 'nofly'
height: this._defaultHeights[index] || 0
}
}))
this._draw.add({ type: 'FeatureCollection', features })
}
// 加载已有限飞区
if (this._restrictflyPolygons.length > 0) {
const features = this._restrictflyPolygons.map(coords => ({
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [coords]
},
properties: {
type: 'limit'
}
}))
this._draw.add({ type: 'FeatureCollection', features })
this._draw.set({
type: 'FeatureCollection',
features
})
this._restrictflyHeights = [...this._defaultHeights]
}
// 监听绘制完成
map.on('draw.create', this._handleDraw.bind(this))
return this._container
@ -343,31 +528,21 @@ export class NoFlyControl {
}
}
_handleDraw (e) {
const features = e.features
if (features.length === 0) return
async _handleDraw (e) {
const features = this._draw.getAll()
if (features.features.length > 0) {
const newFeature = features.features[features.features.length - 1]
const type = this._activeMode === 'limit' ? 'limit' : 'nofly'
features.forEach(f => {
f.properties.type = type
})
// 重新添加以确保类型被写入并触发样式
this._draw.delete(features.map(f => f.id))
this._draw.add({
type: 'FeatureCollection',
features
})
const allCoords = this._draw.getAll().features
.filter(f => f.properties.type === type)
.map(f => f.geometry.coordinates)
if (type === 'nofly') {
this._onDrawFinish(allCoords)
} else {
this._onLimitFinish(allCoords)
try {
const height = await this._promptHeightInput()
this._restrictflyHeights.push(parseFloat(height))
// 可选:在 feature 上记录高度
newFeature.properties.height = height
} catch (error) {
// 用户取消输入,移除刚才的图形
this._draw.delete(newFeature.id)
Message.info('已取消限飞区域绘制')
}
}
}
@ -375,94 +550,39 @@ export class NoFlyControl {
if (this._draw) {
const selected = this._draw.getSelectedIds()
if (selected.length > 0) {
// 同时删除对应的限高值(只支持最后一个被删)
this._restrictflyHeights.pop()
this._draw.delete(selected)
}
}
}
async _savePolygons () {
if (!this._draw) return
const allFeatures = this._draw.getAll()
const nofly = allFeatures.features
.filter(f => f.properties.type === 'nofly')
.map(f => f.geometry.coordinates[0])
const limit = allFeatures.features
.filter(f => f.properties.type === 'limit')
const polygons = allFeatures.features
.filter(f => f.geometry.type === 'Polygon')
.map(f => f.geometry.coordinates[0])
try {
const shopId = this._shopId
await setNoflyData(shopId, nofly, limit)
this._onSave(nofly, limit)
await setRestrictflyData(this._shopId, polygons, this._restrictflyHeights)
this._onSave({ polygons, heights: this._restrictflyHeights })
} catch (error) {
Message.error('上传数据失败')
Message.error('保存限飞区失败')
console.error(error)
}
}
_getDrawStyles () {
const noflyColor = '#ff3333'
const limitColor = '#ff8833'
return [
// 区域填充样式
{
id: 'custom-polygon-fill',
type: 'fill',
filter: ['all', ['==', '$type', 'Polygon']],
paint: {
'fill-color': [
'case',
['==', ['get', 'type'], 'nofly'], noflyColor,
['==', ['get', 'type'], 'limit'], limitColor,
limitColor // 默认颜色
],
'fill-opacity': 0.3
}
},
// 区域边框线(不区分 static / active
{
id: 'custom-polygon-stroke',
type: 'line',
filter: ['all', ['==', '$type', 'Polygon']],
paint: {
'line-color': [
'case',
['==', ['get', 'type'], 'nofly'], noflyColor,
['==', ['get', 'type'], 'limit'], limitColor,
limitColor
],
'line-width': 2,
'line-dasharray': [2, 2]
}
},
// 顶点圆点
{
id: 'custom-vertex-point',
type: 'circle',
filter: ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point']],
paint: {
'circle-radius': 5,
'circle-color': [
'case',
['==', ['get', 'type'], 'nofly'], noflyColor,
['==', ['get', 'type'], 'limit'], limitColor,
limitColor
]
}
},
// 顶点外光环
{
id: 'custom-vertex-halo',
type: 'circle',
filter: ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point']],
paint: {
'circle-radius': 7,
'circle-color': '#FFFFFF'
}
}
]
// Element UI 弹窗输入限高
_promptHeightInput () {
return MessageBox.prompt('请输入该区域的限飞高度(单位:米)', '限高设置', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPattern: /^\d+(\.\d+)?$/,
inputErrorMessage: '请输入有效的数字'
}).then(({ value }) => value)
}
}

View File

@ -1,6 +1,6 @@
<template>
<div class="h-100">
<map-box v-if="showMapbox" :key="mapboxKey" ref="mapbox" :enableNofly="true" />
<map-box v-if="showMapbox" :key="mapboxKey" ref="mapbox" :enableRestrictfly="true" />
</div>
</template>
@ -8,7 +8,7 @@
import MapBox from '@/components/MapBox'
export default {
name: 'Nofly',
name: 'Restrictfly',
components: {
MapBox
},