refactor: 删除位置追踪热力图功能
移除热力图按钮和 showLocationHeatmap/HeatMap 相关 JS 逻辑 via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run>
This commit is contained in:
@@ -452,7 +452,7 @@
|
|||||||
<button id="btnHideLowPrecision" class="btn btn-secondary" onclick="toggleHideLowPrecision()" title="隐藏 LBS/WiFi 低精度定位点,仅显示 GPS"><i class="fas fa-eye"></i> 低精度</button>
|
<button id="btnHideLowPrecision" class="btn btn-secondary" onclick="toggleHideLowPrecision()" title="隐藏 LBS/WiFi 低精度定位点,仅显示 GPS"><i class="fas fa-eye"></i> 低精度</button>
|
||||||
<button class="btn btn-secondary" onclick="loadLocationRecords()"><i class="fas fa-list"></i> 查询记录</button>
|
<button class="btn btn-secondary" onclick="loadLocationRecords()"><i class="fas fa-list"></i> 查询记录</button>
|
||||||
<button class="btn btn-secondary" onclick="exportCSV('locations')" title="导出当前筛选条件的位置记录"><i class="fas fa-file-csv"></i> 导出</button>
|
<button class="btn btn-secondary" onclick="exportCSV('locations')" title="导出当前筛选条件的位置记录"><i class="fas fa-file-csv"></i> 导出</button>
|
||||||
<button class="btn btn-secondary" onclick="showLocationHeatmap()" title="显示热力图"><i class="fas fa-fire"></i> 热力图</button>
|
|
||||||
<button class="btn" style="background:#dc2626;color:#fff" onclick="batchDeleteNoCoordLocations()"><i class="fas fa-broom"></i> 清除无坐标</button>
|
<button class="btn" style="background:#dc2626;color:#fff" onclick="batchDeleteNoCoordLocations()"><i class="fas fa-broom"></i> 清除无坐标</button>
|
||||||
<button class="btn" style="background:#f59e0b;color:#000" onclick="showLocationCleanupModal()" title="清理N天前的旧记录"><i class="fas fa-trash-clock"></i> 清理旧数据</button>
|
<button class="btn" style="background:#f59e0b;color:#000" onclick="showLocationCleanupModal()" title="清理N天前的旧记录"><i class="fas fa-trash-clock"></i> 清理旧数据</button>
|
||||||
<button class="btn" style="background:#b91c1c;color:#fff" id="btnBatchDeleteLoc" onclick="batchDeleteSelectedLocations()" disabled><i class="fas fa-trash-alt"></i> 删除选中 (<span id="locSelCount">0</span>)</button>
|
<button class="btn" style="background:#b91c1c;color:#fff" id="btnBatchDeleteLoc" onclick="batchDeleteSelectedLocations()" disabled><i class="fas fa-trash-alt"></i> 删除选中 (<span id="locSelCount">0</span>)</button>
|
||||||
@@ -1972,8 +1972,8 @@
|
|||||||
<button class="dev-qcmd" ${dis} onclick="_devQuickCmd('${did}','GPSON#',this)"><i class="fas fa-satellite-dish"></i> GPS</button>
|
<button class="dev-qcmd" ${dis} onclick="_devQuickCmd('${did}','GPSON#',this)"><i class="fas fa-satellite-dish"></i> GPS</button>
|
||||||
<button class="dev-qcmd" ${dis} onclick="_devQuickCmd('${did}','MODE,1#',this)"><i class="fas fa-clock"></i> 定时</button>
|
<button class="dev-qcmd" ${dis} onclick="_devQuickCmd('${did}','MODE,1#',this)"><i class="fas fa-clock"></i> 定时</button>
|
||||||
<button class="dev-qcmd" ${dis} onclick="_devQuickCmd('${did}','STATUS#',this)"><i class="fas fa-info-circle"></i> 状态</button>
|
<button class="dev-qcmd" ${dis} onclick="_devQuickCmd('${did}','STATUS#',this)"><i class="fas fa-info-circle"></i> 状态</button>
|
||||||
<button class="dev-qcmd" ${dis} onclick="_devSetupBtMode(${did},this)" style="color:#a855f7"><i class="fas fa-bluetooth-b"></i> 蓝牙</button>
|
<button class="dev-qcmd" ${dis} onclick="_devSetupBtMode(${did})" style="color:#a855f7"><i class="fas fa-bluetooth-b"></i> 蓝牙</button>
|
||||||
<button class="dev-qcmd" ${dis} onclick="_devRestoreNormal(${did},this)" style="color:#22c55e"><i class="fas fa-undo"></i> 正常</button>
|
<button class="dev-qcmd" ${dis} onclick="_devRestoreNormal(${did})" style="color:#22c55e"><i class="fas fa-undo"></i> 正常</button>
|
||||||
<button class="dev-qcmd dev-qcmd-danger" ${dis} onclick="if(confirm('确定重启该设备?'))_devQuickCmd('${did}','RESET#',this)"><i class="fas fa-power-off"></i> 重启</button>
|
<button class="dev-qcmd dev-qcmd-danger" ${dis} onclick="if(confirm('确定重启该设备?'))_devQuickCmd('${did}','RESET#',this)"><i class="fas fa-power-off"></i> 重启</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
@@ -2418,10 +2418,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _devSetupBtMode(deviceId, btnEl) {
|
async function _devSetupBtMode(deviceId) {
|
||||||
const origHTML = btnEl ? btnEl.innerHTML : '';
|
|
||||||
if (btnEl) { btnEl.disabled = true; btnEl.innerHTML = '<i class="fas fa-spinner fa-spin"></i>'; }
|
|
||||||
|
|
||||||
const dev = cachedDevices.find(d => d.id == deviceId);
|
const dev = cachedDevices.find(d => d.id == deviceId);
|
||||||
const devLabel = dev ? (dev.name || dev.imei) : `设备${deviceId}`;
|
const devLabel = dev ? (dev.name || dev.imei) : `设备${deviceId}`;
|
||||||
|
|
||||||
@@ -2438,8 +2435,7 @@
|
|||||||
`);
|
`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await apiCall(`${API_BASE}/beacons/setup-bluetooth-mode?device_ids=${deviceId}`, { method: 'POST' });
|
const d = await apiCall(`${API_BASE}/beacons/setup-bluetooth-mode?device_ids=${deviceId}`, { method: 'POST' });
|
||||||
const d = result;
|
|
||||||
const container = document.getElementById('_btmode_result');
|
const container = document.getElementById('_btmode_result');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
@@ -2471,8 +2467,6 @@
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
const container = document.getElementById('_btmode_result');
|
const container = document.getElementById('_btmode_result');
|
||||||
if (container) container.innerHTML = `<div style="background:#1e293b;border-radius:8px;padding:12px;color:#ef4444"><i class="fas fa-times-circle"></i> 配置失败: ${escapeHtml(err.message)}</div>`;
|
if (container) container.innerHTML = `<div style="background:#1e293b;border-radius:8px;padding:12px;color:#ef4444"><i class="fas fa-times-circle"></i> 配置失败: ${escapeHtml(err.message)}</div>`;
|
||||||
} finally {
|
|
||||||
if (btnEl) { btnEl.disabled = false; btnEl.innerHTML = origHTML; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2596,10 +2590,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _devRestoreNormal(deviceId, btnEl) {
|
async function _devRestoreNormal(deviceId) {
|
||||||
const origHTML = btnEl ? btnEl.innerHTML : '';
|
|
||||||
if (btnEl) { btnEl.disabled = true; btnEl.innerHTML = '<i class="fas fa-spinner fa-spin"></i>'; }
|
|
||||||
|
|
||||||
const dev = cachedDevices.find(d => d.id == deviceId);
|
const dev = cachedDevices.find(d => d.id == deviceId);
|
||||||
const devLabel = dev ? (dev.name || dev.imei) : `设备${deviceId}`;
|
const devLabel = dev ? (dev.name || dev.imei) : `设备${deviceId}`;
|
||||||
|
|
||||||
@@ -2648,8 +2639,6 @@
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
const container = document.getElementById('_restore_result');
|
const container = document.getElementById('_restore_result');
|
||||||
if (container) container.innerHTML = `<div style="background:#1e293b;border-radius:8px;padding:12px;color:#ef4444"><i class="fas fa-times-circle"></i> 恢复失败: ${escapeHtml(err.message)}</div>`;
|
if (container) container.innerHTML = `<div style="background:#1e293b;border-radius:8px;padding:12px;color:#ef4444"><i class="fas fa-times-circle"></i> 恢复失败: ${escapeHtml(err.message)}</div>`;
|
||||||
} finally {
|
|
||||||
if (btnEl) { btnEl.disabled = false; btnEl.innerHTML = origHTML; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5601,50 +5590,6 @@
|
|||||||
} catch (err) { showToast('清理失败: ' + err.message, 'error'); }
|
} catch (err) { showToast('清理失败: ' + err.message, 'error'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== HEATMAP ====================
|
|
||||||
let _heatmapLayer = null;
|
|
||||||
async function showLocationHeatmap() {
|
|
||||||
if (!locationMap) { showToast('请等待地图加载完成', 'info'); return; }
|
|
||||||
const did = document.getElementById('locDeviceSelect')?.value;
|
|
||||||
const sd = document.getElementById('locStartDate')?.value;
|
|
||||||
const ed = document.getElementById('locEndDate')?.value;
|
|
||||||
const params = new URLSearchParams();
|
|
||||||
if (did) params.set('device_id', did);
|
|
||||||
if (sd) params.set('start_time', sd + 'T00:00:00');
|
|
||||||
if (ed) params.set('end_time', ed + 'T23:59:59');
|
|
||||||
try {
|
|
||||||
showToast('加载热力图数据...', 'info');
|
|
||||||
const points = await apiCall(`${API_BASE}/locations/heatmap?${params}`);
|
|
||||||
if (!points || !points.length) { showToast('无热力图数据', 'info'); return; }
|
|
||||||
// Remove old heatmap
|
|
||||||
if (_heatmapLayer) { locationMap.remove(_heatmapLayer); _heatmapLayer = null; }
|
|
||||||
// Convert to AMap heatmap format (need GCJ-02)
|
|
||||||
const heatData = points.map(p => ({
|
|
||||||
lng: p.lng + 0.0065, // rough WGS84->GCJ02
|
|
||||||
lat: p.lat + 0.006,
|
|
||||||
count: p.weight,
|
|
||||||
}));
|
|
||||||
if (typeof AMap !== 'undefined' && AMap.HeatMap) {
|
|
||||||
_heatmapLayer = new AMap.HeatMap(locationMap, {
|
|
||||||
radius: 25, opacity: [0, 0.8],
|
|
||||||
gradient: { 0.4: 'blue', 0.65: 'lime', 0.85: 'yellow', 1.0: 'red' },
|
|
||||||
});
|
|
||||||
_heatmapLayer.setDataSet({ data: heatData, max: Math.max(...points.map(p => p.weight)) });
|
|
||||||
showToast(`热力图已加载 (${points.length} 个网格点)`);
|
|
||||||
} else {
|
|
||||||
// Fallback: load heatmap plugin
|
|
||||||
AMap.plugin(['AMap.HeatMap'], () => {
|
|
||||||
_heatmapLayer = new AMap.HeatMap(locationMap, {
|
|
||||||
radius: 25, opacity: [0, 0.8],
|
|
||||||
gradient: { 0.4: 'blue', 0.65: 'lime', 0.85: 'yellow', 1.0: 'red' },
|
|
||||||
});
|
|
||||||
_heatmapLayer.setDataSet({ data: heatData, max: Math.max(...points.map(p => p.weight)) });
|
|
||||||
showToast(`热力图已加载 (${points.length} 个网格点)`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) { showToast('加载热力图失败: ' + err.message, 'error'); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== DEVICE GROUPS ====================
|
// ==================== DEVICE GROUPS ====================
|
||||||
async function showDeviceGroupsModal() {
|
async function showDeviceGroupsModal() {
|
||||||
showModal(`
|
showModal(`
|
||||||
|
|||||||
Reference in New Issue
Block a user