' +
- '
' + (sz.description || '安全区域') + '
' +
- '
(' + Number(sz.lat).toFixed(4) + ', ' + Number(sz.lng).toFixed(4) + ') R' + (sz.radius || 50) + 'm
' +
+ var zid = sz.id || '';
+ return '
' +
+ '
' +
+ '
✔' +
+ '
' +
+ '
' + (sz.description || '安全区域') + '
' +
+ '
(' + Number(sz.lat).toFixed(4) + ', ' + Number(sz.lng).toFixed(4) + ') R' + (sz.radius || 50) + 'm
' +
+ '
' +
'
' +
+ (zid ? '
🗑' : '') +
'
';
}).join('');
}
+ // =============== 区域标注管理 ===============
+
+ function openZoneModal(keepValues) {
+ if (!keepValues) {
+ document.getElementById('zone-name').value = '';
+ document.getElementById('zone-coords').value = '';
+ document.getElementById('zone-lat').value = '';
+ document.getElementById('zone-lng').value = '';
+ document.getElementById('zone-radius').value = '100';
+ }
+ MapModule.stopZonePick();
+ var radios = document.querySelectorAll('#modal-zone input[name="ztype"]');
+ if (radios.length > 0) radios[0].checked = true;
+ document.getElementById('modal-zone').style.display = 'flex';
+ }
+
+ function closeZoneModal() {
+ MapModule.stopZonePick();
+ document.getElementById('modal-zone').style.display = 'none';
+ }
+
+ function pickZoneFromMap() {
+ if (!mapInited) {
+ addLog('warning', '请先进入无人机监控页面加载地图');
+ return;
+ }
+ closeZoneModal();
+ addLog('info', '请在地图上点击选择区域位置');
+ MapModule.startZonePick(function(lat, lng) {
+ document.getElementById('zone-coords').value = lat.toFixed(6) + ', ' + lng.toFixed(6);
+ document.getElementById('zone-lat').value = lat.toFixed(6);
+ document.getElementById('zone-lng').value = lng.toFixed(6);
+ openZoneModal(true); // 传入 true 保留已填入的坐标
+ });
+ }
+
+ async function addZone() {
+ var name = document.getElementById('zone-name').value.trim();
+ var lat = parseFloat(document.getElementById('zone-lat').value);
+ var lng = parseFloat(document.getElementById('zone-lng').value);
+ var radius = parseInt(document.getElementById('zone-radius').value) || 100;
+ var typeEl = document.querySelector('#modal-zone input[name="ztype"]:checked');
+ var type = typeEl ? typeEl.value : 'danger';
+
+ if (!name) { addLog('warning', '请输入区域名称'); return; }
+ if (isNaN(lat) || isNaN(lng)) { addLog('warning', '请输入有效的经纬度'); return; }
+
+ try {
+ var resp = await fetch('/api/zones', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ description: name,
+ lat: lat, lng: lng,
+ radius: radius,
+ zone_type: type
+ })
+ });
+ if (resp.ok) {
+ addLog('success', '已添加' + (type === 'danger' ? '危险区域' : '安全区域') + ': ' + name);
+ closeZoneModal();
+ fetchZones();
+ if (mapInited) {
+ if (type === 'danger') MapModule.addDangerZone(lat, lng, radius, name);
+ else MapModule.addSafeZone(lat, lng, radius, name);
+ }
+ }
+ } catch (e) {
+ addLog('error', '添加区域失败: 网络错误');
+ }
+ }
+
+ async function deleteZone(id) {
+ try {
+ var resp = await fetch('/api/zones/' + id, { method: 'DELETE' });
+ if (resp.ok) {
+ addLog('info', '已删除区域 #' + id);
+ fetchZones();
+ }
+ } catch (e) {
+ addLog('error', '删除失败: 网络错误');
+ }
+ }
+
// =============== 闪光检测功能 ===============
function onEnableFlashDetection() {
@@ -861,6 +962,8 @@ const UIModule = (() => {
onTelemetry,
onStatus,
onDroneDisconnected,
+ deleteZone,
+ pickZoneFromMap,
updateWaypointList,
updateButtons,
addLog
diff --git a/software/src/软件电脑端/server/app.py b/software/src/软件电脑端/server/app.py
index 76d0900d..8eae6075 100644
--- a/software/src/软件电脑端/server/app.py
+++ b/software/src/软件电脑端/server/app.py
@@ -306,8 +306,8 @@ def get_zones():
@app.route("/api/zones", methods=["POST"])
-@require_auth
def add_zone():
+ """添加区域标注(电脑端管理,不需要 auth)"""
data = request.get_json(force=True)
zone_type = data.get("zone_type", "danger")
if zone_type not in ("danger", "safe"):
@@ -363,6 +363,16 @@ def add_danger_zone_legacy():
return jsonify({"ok": True, "id": zone_id})
+@app.route("/api/zones/
", methods=["DELETE"])
+def delete_zone(zone_id):
+ """删除区域标注"""
+ conn = get_db()
+ conn.execute("DELETE FROM zones WHERE id=?", (zone_id,))
+ conn.commit()
+ conn.close()
+ return jsonify({"ok": True})
+
+
# ===== REST API: 物资需求(单兵APP) =====
def _next_demand_id():