499 lines
17 KiB
HTML
499 lines
17 KiB
HTML
|
|
<!DOCTYPE html>
|
|||
|
|
<html>
|
|||
|
|
<head>
|
|||
|
|
<meta charset="utf-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|||
|
|
<title>配置资产边界</title>
|
|||
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|||
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.css" />
|
|||
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|||
|
|
<script src="https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.js"></script>
|
|||
|
|
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
|
|||
|
|
<style>
|
|||
|
|
* { margin:0; padding:0; box-sizing:border-box; }
|
|||
|
|
html, body { height:100%; overflow:hidden; font-family:"Microsoft YaHei",Arial,sans-serif; }
|
|||
|
|
#app { display:flex; height:100%; }
|
|||
|
|
|
|||
|
|
/* 左侧地图 */
|
|||
|
|
#mapWrap { flex:1; position:relative; min-width:0; }
|
|||
|
|
#map { height:100%; width:100%; }
|
|||
|
|
|
|||
|
|
/* 右侧配置面板 */
|
|||
|
|
#configPanel {
|
|||
|
|
width:360px; height:100%; background:#fff;
|
|||
|
|
border-left:1px solid #e0e0e0; display:flex; flex-direction:column;
|
|||
|
|
flex-shrink:0; z-index:10000;
|
|||
|
|
}
|
|||
|
|
.panel-header {
|
|||
|
|
padding:12px 16px; background:#f7f8fa; border-bottom:1px solid #eee;
|
|||
|
|
font-size:14px; font-weight:bold; color:#333; flex-shrink:0;
|
|||
|
|
}
|
|||
|
|
.panel-body {
|
|||
|
|
flex:1; overflow-y:auto; padding:12px 16px;
|
|||
|
|
}
|
|||
|
|
.panel-footer {
|
|||
|
|
padding:10px 16px; border-top:1px solid #eee; display:flex; gap:8px; flex-shrink:0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 基本设置 */
|
|||
|
|
.setting-row {
|
|||
|
|
display:flex; align-items:center; gap:8px; margin-bottom:10px;
|
|||
|
|
}
|
|||
|
|
.setting-row label { font-size:12px; color:#888; white-space:nowrap; }
|
|||
|
|
.setting-row input[type="color"] { width:36px; height:30px; border:1px solid #ddd; border-radius:4px; cursor:pointer; }
|
|||
|
|
.setting-row span { font-size:12px; color:#888; }
|
|||
|
|
|
|||
|
|
/* 区域卡片 */
|
|||
|
|
.region-card {
|
|||
|
|
border:1px solid #e0e0e0; border-radius:6px; padding:10px 12px;
|
|||
|
|
margin-bottom:8px; background:#fafafa; cursor:pointer;
|
|||
|
|
}
|
|||
|
|
.region-card:hover { border-color:#27ae60; }
|
|||
|
|
.region-card.selected { border-color:#27ae60; background:#e8f5e9; }
|
|||
|
|
.region-header {
|
|||
|
|
display:flex; justify-content:space-between; align-items:center; margin-bottom:6px;
|
|||
|
|
}
|
|||
|
|
.region-header span { font-size:13px; font-weight:bold; color:#333; }
|
|||
|
|
.region-header .del-btn { color:#e74c3c; cursor:pointer; font-size:16px; padding:0 4px; }
|
|||
|
|
.region-info { font-size:12px; color:#888; }
|
|||
|
|
.hole-info { font-size:11px; color:#e74c3c; margin-top:4px; padding-left:10px; border-left:2px solid #e74c3c; }
|
|||
|
|
|
|||
|
|
/* 按钮 */
|
|||
|
|
.btn {
|
|||
|
|
flex:1; padding:9px 0; border:none; border-radius:6px;
|
|||
|
|
cursor:pointer; font-size:13px; font-weight:bold; transition:all 0.2s;
|
|||
|
|
}
|
|||
|
|
.btn-primary { background:#27ae60; color:#fff; }
|
|||
|
|
.btn-primary:hover { background:#219653; }
|
|||
|
|
.btn-success { background:#3498db; color:#fff; }
|
|||
|
|
.btn-reset { background:#f0f0f0; color:#666; border:1px solid #ddd; }
|
|||
|
|
.btn-danger { background:#e74c3c; color:#fff; }
|
|||
|
|
|
|||
|
|
.tip { font-size:11px; color:#999; margin-top:4px; }
|
|||
|
|
|
|||
|
|
/* 移动端 */
|
|||
|
|
@media (max-width:768px) {
|
|||
|
|
#app { flex-direction:column; }
|
|||
|
|
#mapWrap { height:50%; flex:none; }
|
|||
|
|
#configPanel { width:100%; height:50%; flex:none; border-left:none; border-top:1px solid #e0e0e0; }
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<div id="app">
|
|||
|
|
<div id="mapWrap"><div id="map"></div></div>
|
|||
|
|
<div id="configPanel">
|
|||
|
|
<div class="panel-header">配置资产区域边界</div>
|
|||
|
|
<div class="panel-body">
|
|||
|
|
<!-- 颜色 -->
|
|||
|
|
<div class="setting-row">
|
|||
|
|
<label>边界颜色:</label>
|
|||
|
|
<input type="color" v-model="color" @change="onColorChange">
|
|||
|
|
<span>{{color}}</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 区域列表 -->
|
|||
|
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">
|
|||
|
|
<span style="font-size:13px;font-weight:bold;">区域列表 ({{regions.length}})</span>
|
|||
|
|
<button class="btn btn-primary" style="flex:none;padding:5px 12px;" @click="addRegion">+ 新增区域</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div v-if="regions.length === 0" style="text-align:center;padding:20px;color:#ccc;">
|
|||
|
|
暂无区域,点击"新增区域"开始
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div v-for="(r, ri) in regions" :key="r.id"
|
|||
|
|
class="region-card" :class="{selected: selectedRegionIndex === ri}"
|
|||
|
|
@click="selectRegionCard(ri)">
|
|||
|
|
<div class="region-header">
|
|||
|
|
<span>区域 {{ri + 1}} <span style="font-size:11px;color:#aaa;">ID:{{r.id}}</span></span>
|
|||
|
|
<span class="del-btn" @click.stop="removeRegion(ri)">×</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="region-info">
|
|||
|
|
外圈:{{r.outer ? r.outer.length : 0}} 个点
|
|||
|
|
<span v-if="r.holes && r.holesCount > 0"> | 孔洞:{{r.holesCount}} 个</span>
|
|||
|
|
</div>
|
|||
|
|
<div v-if="r.holes && r.holesCount > 0" class="hole-info">
|
|||
|
|
孔洞共 {{r.holesCount}} 个
|
|||
|
|
</div>
|
|||
|
|
<div style="display:flex;gap:4px;margin-top:6px;">
|
|||
|
|
<button class="btn" style="flex:none;padding:3px 8px;font-size:11px;background:#9b59b6;color:#fff;border:none;border-radius:4px;cursor:pointer;" @click.stop="startDrawHole(ri)">挖洞</button>
|
|||
|
|
<button v-if="r.holes && r.holesCount > 0" class="btn" style="flex:none;padding:3px 8px;font-size:11px;background:#e67e22;color:#fff;border:none;border-radius:4px;cursor:pointer;" @click.stop="clearHoles(ri)">清除孔洞</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="tip">提示:点击区域卡片选中后,可在地图上看到高亮显示</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="panel-footer">
|
|||
|
|
<button class="btn btn-primary" @click="confirmSave">确认保存</button>
|
|||
|
|
<button class="btn btn-reset" @click="cancelClose">取消</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
// 从父页面获取已有边界数据
|
|||
|
|
var oldBoundConfig = '';
|
|||
|
|
var assetsId = '';
|
|||
|
|
var _host = '';
|
|||
|
|
try {
|
|||
|
|
var params = window.parentDialogObj['boundConfigDialog'].getTransParams();
|
|||
|
|
console.log(window.parentDialogObj['boundConfigDialog'])
|
|||
|
|
console.log('[boundConfig] 父页面传入的参数:', JSON.stringify(params));
|
|||
|
|
oldBoundConfig = params.oldBoundConfig || '';
|
|||
|
|
assetsId = params.assetsId || params.assetId || params.assetsNo || '';
|
|||
|
|
} catch(e) {
|
|||
|
|
console.warn('获取父页面参数异常:', e);
|
|||
|
|
}
|
|||
|
|
// 尝试从父页面URL推断host
|
|||
|
|
try {
|
|||
|
|
_host = window.parent.location.origin || '';
|
|||
|
|
} catch(e) {}
|
|||
|
|
|
|||
|
|
console.log('[boundConfig] oldBoundConfig:', oldBoundConfig ? (oldBoundConfig.substring(0, 100) + '...') : '(空)');
|
|||
|
|
console.log('[boundConfig] assetsId:', assetsId);
|
|||
|
|
new Vue({
|
|||
|
|
el: '#app',
|
|||
|
|
data: {
|
|||
|
|
map: null,
|
|||
|
|
drawnItems: null,
|
|||
|
|
color: '#ff0000',
|
|||
|
|
regions: [],
|
|||
|
|
assetsId: assetsId,
|
|||
|
|
selectedRegionIndex: -1,
|
|||
|
|
_drawingMode: null // 'new' | 'hole'
|
|||
|
|
},
|
|||
|
|
mounted() {
|
|||
|
|
this.initMap();
|
|||
|
|
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
initMap() {
|
|||
|
|
console.log('[boundConfig] initMap, assetsId:', assetsId);
|
|||
|
|
this.map = L.map('map').setView([30.2856, 109.4783], 13);
|
|||
|
|
L.tileLayer('http://localhost:3080/seeyon/seeyonExtend/assetsMap/map/{z}/{x}/{y}/tile.png', { maxZoom: 18, minZoom: 8 }).addTo(this.map);
|
|||
|
|
this.drawnItems = L.featureGroup().addTo(this.map);
|
|||
|
|
this.markerGroup = L.layerGroup().addTo(this.map);
|
|||
|
|
this.markerIcon = L.divIcon({
|
|||
|
|
html: '<img src="./markicon.png" style="width:48px;height:48px;" onerror="this.style.display=\'none\';this.parentNode.innerHTML=\'<div style=width:24px;height:24px;background:#e74c3c;border-radius:50%;border:3px solid #fff;box-shadow:0 0 4px rgba(0,0,0,0.4);></div>\';">',
|
|||
|
|
className: 'custom-marker-icon',
|
|||
|
|
iconSize: [48, 48],
|
|||
|
|
iconAnchor: [24, 24]
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 绘制控件
|
|||
|
|
var self = this;
|
|||
|
|
this.drawControl = new L.Control.Draw({
|
|||
|
|
draw: {
|
|||
|
|
polygon: {
|
|||
|
|
allowIntersection: false,
|
|||
|
|
shapeOptions: { color: self.color, weight: 2, fillOpacity: 0.3 }
|
|||
|
|
},
|
|||
|
|
polyline: false, rectangle: false, circle: false, circlemarker: false, marker: false
|
|||
|
|
},
|
|||
|
|
edit: { featureGroup: self.drawnItems, remove: true }
|
|||
|
|
});
|
|||
|
|
this.map.addControl(this.drawControl);
|
|||
|
|
// 同步颜色到绘制控件
|
|||
|
|
this.syncDrawColor();
|
|||
|
|
|
|||
|
|
// 绘制完成事件
|
|||
|
|
this.map.on(L.Draw.Event.CREATED, function(e) {
|
|||
|
|
var layer = e.layer;
|
|||
|
|
var latlngs = layer.getLatLngs()[0].map(function(ll) { return [ll.lat, ll.lng]; });
|
|||
|
|
|
|||
|
|
if (self._drawingMode === 'hole' && self.selectedRegionIndex >= 0 && self.selectedRegionIndex < self.regions.length) {
|
|||
|
|
// 挖洞:将绘制的多边形作为孔洞添加到选中的区域
|
|||
|
|
var region = self.regions[self.selectedRegionIndex];
|
|||
|
|
if (!region.holes) region.holes = [];
|
|||
|
|
region.holes.push(latlngs);
|
|||
|
|
region.holesCount = region.holes.length;
|
|||
|
|
} else if (self._pendingRegionIndex >= 0 && self._pendingRegionIndex < self.regions.length) {
|
|||
|
|
self.regions[self._pendingRegionIndex].outer = latlngs;
|
|||
|
|
} else {
|
|||
|
|
self.regions.push({ id: self.generateId(), outer: latlngs, holes: [], holesCount: 0 });
|
|||
|
|
self.selectedRegionIndex = self.regions.length - 1;
|
|||
|
|
}
|
|||
|
|
self._drawingMode = null;
|
|||
|
|
self._pendingRegionIndex = -1;
|
|||
|
|
self.refreshMap();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 编辑完成事件
|
|||
|
|
this.map.on(L.Draw.Event.EDITED, function(e) {
|
|||
|
|
var layers = e.layers;
|
|||
|
|
layers.eachLayer(function(layer) {
|
|||
|
|
var latlngs = layer.getLatLngs();
|
|||
|
|
var idx = self.findRegionByLayer(layer);
|
|||
|
|
if (idx >= 0) {
|
|||
|
|
self.regions[idx].outer = latlngs[0].map(function(ll) { return [ll.lat, ll.lng]; });
|
|||
|
|
// 保留孔洞
|
|||
|
|
var holes = [];
|
|||
|
|
for (var i = 1; i < latlngs.length; i++) {
|
|||
|
|
holes.push(latlngs[i].map(function(ll) { return [ll.lat, ll.lng]; }));
|
|||
|
|
}
|
|||
|
|
self.regions[idx].holes = holes;
|
|||
|
|
self.regions[idx].holesCount = holes.length;
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
self.refreshMap();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 删除事件
|
|||
|
|
this.map.on(L.Draw.Event.DELETED, function(e) {
|
|||
|
|
// 删除对应 region
|
|||
|
|
e.layers.eachLayer(function(layer) {
|
|||
|
|
var idx = self.findRegionByLayer(layer);
|
|||
|
|
if (idx >= 0) {
|
|||
|
|
self.regions.splice(idx, 1);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
if (self.selectedRegionIndex >= self.regions.length) {
|
|||
|
|
self.selectedRegionIndex = self.regions.length - 1;
|
|||
|
|
}
|
|||
|
|
self.refreshMap();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
this._pendingRegionIndex = -1;
|
|||
|
|
|
|||
|
|
setTimeout(function() {
|
|||
|
|
self.map.invalidateSize();
|
|||
|
|
self.loadAssetLocation();
|
|||
|
|
self.loadBoundData();
|
|||
|
|
}, 200);
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
findRegionByLayer(layer) {
|
|||
|
|
if (layer._regionIndex !== undefined && layer._regionIndex >= 0) {
|
|||
|
|
return layer._regionIndex;
|
|||
|
|
}
|
|||
|
|
var latlngs = layer.getLatLngs()[0];
|
|||
|
|
if (!latlngs || latlngs.length === 0) return -1;
|
|||
|
|
var firstPt = [latlngs[0].lat, latlngs[0].lng];
|
|||
|
|
for (var i = 0; i < this.regions.length; i++) {
|
|||
|
|
var r = this.regions[i];
|
|||
|
|
if (r.outer && r.outer.length > 0 &&
|
|||
|
|
Math.abs(r.outer[0][0] - firstPt[0]) < 0.0001 &&
|
|||
|
|
Math.abs(r.outer[0][1] - firstPt[1]) < 0.0001) {
|
|||
|
|
return i;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return -1;
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
loadBoundData() {
|
|||
|
|
console.log('[boundConfig] loadBoundData, oldBoundConfig:', oldBoundConfig);
|
|||
|
|
if (!oldBoundConfig) {
|
|||
|
|
console.log('[boundConfig] oldBoundConfig为空,跳过');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
try {
|
|||
|
|
var bound = typeof oldBoundConfig === 'string' ? JSON.parse(oldBoundConfig) : oldBoundConfig;
|
|||
|
|
console.log('[boundConfig] 解析后的边界数据:', bound);
|
|||
|
|
this.color = bound.color || '#ff0000';
|
|||
|
|
this.syncDrawColor();
|
|||
|
|
this.regions = this.normalizeBoundary(bound);
|
|||
|
|
console.log('[boundConfig] regions数量:', this.regions.length);
|
|||
|
|
this.refreshMap();
|
|||
|
|
} catch(e) {
|
|||
|
|
console.error('[boundConfig] 解析边界数据失败:', e, '原始数据:', oldBoundConfig);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 根据 assetsId(资产编号)调接口获取经纬度,在地图上标点
|
|||
|
|
loadAssetLocation() {
|
|||
|
|
if (!assetsId) {
|
|||
|
|
console.log('[boundConfig] assetsId为空,跳过标点');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
var self = this;
|
|||
|
|
var url = _host + '/seeyon/rest/assetsRegion/getByBounds';
|
|||
|
|
console.log('[boundConfig] 请求资产位置, url:', url, 'assetId:', assetsId);
|
|||
|
|
fetch(url, {
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: { 'Content-Type': 'application/json' },
|
|||
|
|
body: JSON.stringify({ assetId: assetsId })
|
|||
|
|
}).then(function(r) {
|
|||
|
|
console.log('[boundConfig] 响应状态:', r.status);
|
|||
|
|
return r.json();
|
|||
|
|
}).then(function(d) {
|
|||
|
|
console.log('[boundConfig] 资产位置返回:', d);
|
|||
|
|
if (d.code === 0 && d.data && d.data.length > 0) {
|
|||
|
|
var region = d.data[0];
|
|||
|
|
var lat = parseFloat(region.lat);
|
|||
|
|
var lng = parseFloat(region.lng);
|
|||
|
|
console.log('[boundConfig] 经纬度:', lat, lng);
|
|||
|
|
if (!isNaN(lat) && !isNaN(lng)) {
|
|||
|
|
var m = L.marker([lat, lng], { icon: self.markerIcon });
|
|||
|
|
m.bindPopup(
|
|||
|
|
'<b>' + (region.assets && region.assets[0] ? region.assets[0].assetName : assetsId) + '</b><br>' +
|
|||
|
|
'坐标:' + lat + ', ' + lng,
|
|||
|
|
{ offset: [0, -24] }
|
|||
|
|
);
|
|||
|
|
m.addTo(self.markerGroup);
|
|||
|
|
self.map.setView([lat, lng], 16);
|
|||
|
|
setTimeout(function() { m.openPopup(); }, 300);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
console.warn('[boundConfig] 未查到资产位置数据, code:', d.code, 'data:', d.data);
|
|||
|
|
}
|
|||
|
|
}).catch(function(err) {
|
|||
|
|
console.error('[boundConfig] 请求资产位置失败:', err);
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
normalizeBoundary(bound) {
|
|||
|
|
if (!bound) return [];
|
|||
|
|
var self = this;
|
|||
|
|
if (bound.regions && Array.isArray(bound.regions)) {
|
|||
|
|
return bound.regions.map(function(r) {
|
|||
|
|
var holes = r.holes || [];
|
|||
|
|
return {
|
|||
|
|
id: r.id || self.generateId(),
|
|||
|
|
outer: r.outer || [],
|
|||
|
|
holes: holes,
|
|||
|
|
holesCount: holes.length
|
|||
|
|
};
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
if (!bound.polygon || bound.polygon.length === 0) return [];
|
|||
|
|
var polygon = bound.polygon;
|
|||
|
|
if (typeof polygon[0][0] === 'number') {
|
|||
|
|
return [{ id: self.generateId(), outer: polygon, holes: [], holesCount: 0 }];
|
|||
|
|
}
|
|||
|
|
if (typeof polygon[0][0][0] === 'number') {
|
|||
|
|
return [{ id: self.generateId(), outer: polygon[0], holes: polygon.slice(1), holesCount: polygon.length - 1 }];
|
|||
|
|
}
|
|||
|
|
return polygon.map(function(r) {
|
|||
|
|
if (typeof r[0][0] === 'number') {
|
|||
|
|
return { id: self.generateId(), outer: r, holes: [], holesCount: 0 };
|
|||
|
|
}
|
|||
|
|
var h = r.slice(1);
|
|||
|
|
return { id: self.generateId(), outer: r[0], holes: h, holesCount: h.length };
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
generateId() {
|
|||
|
|
return Date.now() * 1000 + Math.floor(Math.random() * 1000);
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
onColorChange() {
|
|||
|
|
this.syncDrawColor();
|
|||
|
|
this.refreshMap();
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
syncDrawColor() {
|
|||
|
|
// 重建绘制控件以同步颜色
|
|||
|
|
if (this.drawControl) {
|
|||
|
|
this.map.removeControl(this.drawControl);
|
|||
|
|
}
|
|||
|
|
var self = this;
|
|||
|
|
this.drawControl = new L.Control.Draw({
|
|||
|
|
draw: {
|
|||
|
|
polygon: {
|
|||
|
|
allowIntersection: false,
|
|||
|
|
shapeOptions: { color: self.color, fillColor: self.color, weight: 2, fillOpacity: 0.3 }
|
|||
|
|
},
|
|||
|
|
polyline: false, rectangle: false, circle: false, circlemarker: false, marker: false
|
|||
|
|
},
|
|||
|
|
edit: { featureGroup: self.drawnItems, remove: true }
|
|||
|
|
});
|
|||
|
|
this.map.addControl(this.drawControl);
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
refreshMap() {
|
|||
|
|
this.drawnItems.clearLayers();
|
|||
|
|
var self = this;
|
|||
|
|
this.regions.forEach(function(region, idx) {
|
|||
|
|
if (!region.outer || region.outer.length < 3) return;
|
|||
|
|
var rings = [region.outer].concat(region.holes || []);
|
|||
|
|
var isSelected = (idx === self.selectedRegionIndex);
|
|||
|
|
var polygon = L.polygon(rings, {
|
|||
|
|
color: isSelected ? '#27ae60' : self.color,
|
|||
|
|
fillColor: isSelected ? '#27ae60' : self.color,
|
|||
|
|
weight: isSelected ? 4 : 2,
|
|||
|
|
fillOpacity: isSelected ? 0.5 : 0.3
|
|||
|
|
});
|
|||
|
|
polygon._regionIndex = idx;
|
|||
|
|
self.drawnItems.addLayer(polygon);
|
|||
|
|
});
|
|||
|
|
if (this.drawnItems.getLayers().length > 0) {
|
|||
|
|
this.map.fitBounds(this.drawnItems.getBounds(), { padding: [30, 30] });
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
selectRegionCard(index) {
|
|||
|
|
this.selectedRegionIndex = index;
|
|||
|
|
this.refreshMap();
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
addRegion() {
|
|||
|
|
// 直接触发多边形绘制,绘制完成后再添加到 regions
|
|||
|
|
this._pendingRegionIndex = -1;
|
|||
|
|
this._drawingMode = 'new';
|
|||
|
|
new L.Draw.Polygon(this.map, {
|
|||
|
|
shapeOptions: { color: this.color, weight: 2, fillOpacity: 0.3 },
|
|||
|
|
allowIntersection: false
|
|||
|
|
}).enable();
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
startDrawHole(index) {
|
|||
|
|
if (!this.regions[index] || !this.regions[index].outer || this.regions[index].outer.length < 3) {
|
|||
|
|
alert('请先绘制外圈边界!');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
this.selectedRegionIndex = index;
|
|||
|
|
this._drawingMode = 'hole';
|
|||
|
|
new L.Draw.Polygon(this.map, {
|
|||
|
|
shapeOptions: { color: '#9b59b6', weight: 2, fillOpacity: 0.3 },
|
|||
|
|
allowIntersection: false
|
|||
|
|
}).enable();
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
clearHoles(index) {
|
|||
|
|
if (this.regions[index]) {
|
|||
|
|
this.regions[index].holes = [];
|
|||
|
|
this.regions[index].holesCount = 0;
|
|||
|
|
this.refreshMap();
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
removeRegion(index) {
|
|||
|
|
this.regions.splice(index, 1);
|
|||
|
|
if (this.selectedRegionIndex >= this.regions.length) {
|
|||
|
|
this.selectedRegionIndex = this.regions.length - 1;
|
|||
|
|
}
|
|||
|
|
this.refreshMap();
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
confirmSave() {
|
|||
|
|
var cleanRegions = this.regions
|
|||
|
|
.filter(function(r) { return r.outer && r.outer.length >= 3; })
|
|||
|
|
.map(function(r) {
|
|||
|
|
return {
|
|||
|
|
id: r.id,
|
|||
|
|
outer: r.outer,
|
|||
|
|
holes: (r.holes || []).filter(function(h) { return h && h.length >= 3; })
|
|||
|
|
};
|
|||
|
|
});
|
|||
|
|
var result = JSON.stringify({ regions: cleanRegions, color: this.color });
|
|||
|
|
// 设置返回值供父页面获取
|
|||
|
|
window._boundConfigResult = result;
|
|||
|
|
alert('数据已生成,请点击"确认保存"按钮完成保存');
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
cancelClose() {
|
|||
|
|
window._boundConfigResult = '';
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
function OK() {
|
|||
|
|
// 弹框框架调用此函数获取返回值
|
|||
|
|
return window._boundConfigResult || '';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|