feat: 天地图瓦片缓存(tile-cache)、拓扑标注助手与文档更新

- tile-cache: 瓦片缓存服务(vec/cva)、启动探针、详细日志、上游超时可配置(UPSTREAM_TIMEOUT_MS)
- central: docker-compose 集成 tile-cache,env.example 增加 TILE_CACHE_* / TIANDITU_TK
- topology-editor: 天地图/缓存加载、GPS 安全来源错误提示、TIANDITU 文档(403/白名单、localhost 测试说明)
- doc: README 部署步骤与 GPS 安全来源说明,TIANDITU_CONFIG 完善

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Super User
2026-02-25 11:11:38 -05:00
parent 84d2bcc2cf
commit 72a5bf30b4
32 changed files with 2496 additions and 1941 deletions

View File

@@ -31,13 +31,14 @@ ONVIF_TEMP=$(mktemp)
PING_TEMP=$(mktemp)
# 处理CSV文件跳过注释行和标题行
tail -n +2 "$CSV_FILE" | grep -v '^#' | while IFS=',' read -r type ip device group network device_type model location username password onvif_port lat lon; do
# 列顺序: type,ip,name,role,parent,uplink_type,network,device_type,model,location,username,password,onvif_port,lat,lon
tail -n +2 "$CSV_FILE" | grep -v '^#' | while IFS=',' read -r type ip name role parent uplink_type network device_type model location username password onvif_port lat lon; do
# 去除空格
type=$(echo "$type" | xargs)
ip=$(echo "$ip" | xargs)
# 跳过空行
if [ -z "$type" ] || [ -z "$ip" ]; then
if [ -z "$type" ]; then
continue
fi
@@ -84,22 +85,34 @@ tail -n +2 "$CSV_FILE" | grep -v '^#' | while IFS=',' read -r type ip device gro
elif [ "$type" = "ping" ]; then
# 处理 Ping 目标
device=$(echo "$device" | xargs)
group=$(echo "$group" | xargs)
device=$(echo "$name" | xargs) # name 作为 device 标签
role=$(echo "$role" | xargs)
parent=$(echo "$parent" | xargs)
uplink_type=$(echo "$uplink_type" | xargs)
network=$(echo "$network" | xargs)
labels="{
\"device\": \"$device\""
if [ -n "$group" ]; then
if [ -n "$uplink_type" ]; then
labels="$labels,
\"group\": \"$group\""
\"uplink_type\": \"$uplink_type\""
fi
if [ -n "$network" ]; then
labels="$labels,
\"network\": \"$network\""
fi
if [ -n "$role" ]; then
labels="$labels,
\"role\": \"$role\""
fi
if [ -n "$parent" ]; then
labels="$labels,
\"parent\": \"$parent\""
fi
labels="$labels
}"

View File

@@ -0,0 +1,100 @@
#!/bin/bash
# 从 targets.csv 生成拓扑 GeoJSON用于 Grafana Geomap
# - 支持 type: ping / onvif / topology
# - 使用列: name, role, parent, lat, lon
# - 输出: topology.geojsonFeatureCollection含 Point 和 LineString
set -e
CSV_FILE=${1:-"targets.csv"}
OUTPUT_FILE=${2:-"topology.geojson"}
if ! command -v jq &> /dev/null; then
echo "❌ jq 未安装,请先安装 jq"
exit 1
fi
if [ ! -f "$CSV_FILE" ]; then
echo "❌ CSV 文件 $CSV_FILE 不存在"
exit 1
fi
TMP_JSON=$(mktemp)
echo "🔄 正在从 $CSV_FILE 生成拓扑 GeoJSON 到 $OUTPUT_FILE ..."
# 列顺序: type,ip,name,role,parent,uplink_type,network,device_type,model,location,username,password,onvif_port,lat,lon
tail -n +2 "$CSV_FILE" | grep -v '^#' | while IFS=',' read -r type ip name role parent uplink_type network device_type model location username password onvif_port lat lon; do
type=$(echo "$type" | xargs)
name=$(echo "$name" | xargs)
# 空行跳过
if [ -z "$type" ] || [ -z "$name" ]; then
continue
fi
cat >> "$TMP_JSON" <<EOF
{"type":"$type","ip":"$ip","name":"$name","role":"$role","parent":"$parent","uplink_type":"$uplink_type","network":"$network","device_type":"$device_type","model":"$model","location":"$location","lat":"$lat","lon":"$lon"}
EOF
done
# 用 jq 生成 FeatureCollection
jq -s '
def toPoint:
select(.lat != "" and .lon != "") |
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [ (.lon|tonumber), (.lat|tonumber) ]
},
properties: {
kind: .type,
name: .name,
role: .role,
parent: .parent,
ip: .ip,
uplink_type: .uplink_type,
network: .network,
device_type: .device_type,
model: .model,
location: .location
}
};
def toLine(all):
select(.parent != "" and .lat != "" and .lon != "") as $child
| (all[] | select(.name == $child.parent and .lat != "" and .lon != "")) as $parent
| {
type: "Feature",
geometry: {
type: "LineString",
coordinates: [
[ ($parent.lon|tonumber), ($parent.lat|tonumber) ],
[ ($child.lon|tonumber), ($child.lat|tonumber) ]
]
},
properties: {
type: "link",
from: $parent.name,
to: $child.name,
from_role: $parent.role,
to_role: $child.role
}
};
. as $all
| {
type: "FeatureCollection",
features: (
[ $all[] | toPoint ] +
[ $all[] | toLine($all) ]
)
}
' "$TMP_JSON" > "$OUTPUT_FILE"
rm -f "$TMP_JSON"
echo "✅ 已生成 $OUTPUT_FILE"

View File

@@ -1,14 +1,25 @@
# 统一监控目标配置文件
# 格式: type,ip,device,group,network,device_type,model,location,username,password,onvif_port,lat,lon
# type: onvif 或 ping
# 对于 onvif 类型,需要填写: ip,device_type,model,location,username,password,onvif_port,lat,lon
# - lat / lon 为摄像头地理位置坐标(十进制度数),用于在 Geomap 上打点
# 对于 ping 类型,需要填写: ip,device,group,networklat / lon 可选)
type,ip,device,group,network,device_type,model,location,username,password,onvif_port,lat,lon
ping,192.168.2.1,main_router,network,internal,,,,,,,,
ping,8.8.8.8,google_dns,external,external,,,,,,,,
# 统一监控 + 拓扑目标配置文件
# 格式: type,ip,name,role,parent,uplink_type,network,device_type,model,location,username,password,onvif_port,lat,lon
# type: ping / onvif / topology
# - ping: 有 IP可做网络探测
# - onvif: 有 IP走 ONVIF Exporter
# - topology: 纯拓扑节点(无 IP 也可),只用于在 Geomap 上画点和连线
# role: core_switch / access_switch / camera / wireless_bridge / media_converter ...
# parent: 上联设备的 name用于生成拓扑连线
# uplink_type: 与上联 parent 之间的链路类型fiber / copper / wireless 等)
# lat / lon: 地理坐标(十进制度数),用于在 Geomap 上打点
type,ip,name,role,parent,uplink_type,network,device_type,model,location,username,password,onvif_port,lat,lon
# 核心交换机(有 IP可 ping暂无上联uplink_type 留空)
ping,192.168.2.1,core_sw_1,core_switch,, ,internal,,,,,,,22.5431,113.9876
# 互联网 DNS示例链路类型为 fiber / copper / wireless 之一)
ping,8.8.8.8,google_dns,dns,core_sw_1,fiber,external,,,,,,,22.5500,113.9900
# 哑设备示例:傻瓜交换机、光收发器(无 IP只画拓扑
# topology,,dumb_sw_1,access_switch,core_sw_1,copper,internal,switch,Unmanaged_8P,building_A_3F,,,,22.5438,113.9882
# topology,,optic_1,media_converter,dumb_sw_1,fiber,internal,media_conv,MC-1000,basement_1F,,,,22.5436,113.9880
# ONVIF 设备示例(取消注释并填写实际信息)
# onvif,192.168.1.100,,,front_door,camera,HIKVISION_DS-2CD2342WD-I,front_door,admin,password1,80,22.1234,113.5678
# onvif,192.168.1.101,,,back_yard,camera,DAHUA_IPC-HFW1230S,back_yard,admin,password2,80,22.2234,113.6678
# onvif,192.168.1.102,,,living_room,camera,UNIVIEW_IPC3120SR,living_room,admin,password3,8080,22.3234,113.7678
# onvif,192.168.1.50,,,server_rack,nvr,HIKVISION_DS-7608NI-I2,server_rack,admin,password4,80,22.4234,113.8678
# onvif,192.168.1.100,camera_front,camera,dumb_sw_1,copper,onvif_cameras,internal,camera,HIKVISION_DS-2CD2342WD-I,front_door,admin,password1,80,22.1234,113.5678
# onvif,192.168.1.101,camera_back,camera,bridge_1,wireless,onvif_cameras,internal,camera,DAHUA_IPC-HFW1230S,back_yard,admin,password2,80,22.2234,113.6678
1 # 统一监控目标配置文件 # 统一监控 + 拓扑目标配置文件
2 # 格式: type,ip,device,group,network,device_type,model,location,username,password,onvif_port,lat,lon # 格式: type,ip,name,role,parent,uplink_type,network,device_type,model,location,username,password,onvif_port,lat,lon
3 # type: onvif 或 ping # type: ping / onvif / topology
4 # 对于 onvif 类型,需要填写: ip,device_type,model,location,username,password,onvif_port,lat,lon # - ping: 有 IP,可做网络探测
5 # - lat / lon 为摄像头地理位置坐标(十进制度数),用于在 Geomap 上打点 # - onvif: 有 IP,走 ONVIF Exporter
6 # 对于 ping 类型,需要填写: ip,device,group,network(lat / lon 可选) # - topology: 纯拓扑节点(无 IP 也可),只用于在 Geomap 上画点和连线
7 type,ip,device,group,network,device_type,model,location,username,password,onvif_port,lat,lon # role: core_switch / access_switch / camera / wireless_bridge / media_converter ...
8 ping,192.168.2.1,main_router,network,internal,,,,,,,, # parent: 上联设备的 name,用于生成拓扑连线
9 ping,8.8.8.8,google_dns,external,external,,,,,,,, # uplink_type: 与上联 parent 之间的链路类型(fiber / copper / wireless 等)
10 # lat / lon: 地理坐标(十进制度数),用于在 Geomap 上打点
11 type,ip,name,role,parent,uplink_type,network,device_type,model,location,username,password,onvif_port,lat,lon
12 # 核心交换机(有 IP,可 ping,暂无上联,uplink_type 留空)
13 ping,192.168.2.1,core_sw_1,core_switch,, ,internal,,,,,,,22.5431,113.9876
14 # 互联网 DNS(示例,链路类型为 fiber / copper / wireless 之一)
15 ping,8.8.8.8,google_dns,dns,core_sw_1,fiber,external,,,,,,,22.5500,113.9900
16 # 哑设备示例:傻瓜交换机、光收发器(无 IP,只画拓扑)
17 # topology,,dumb_sw_1,access_switch,core_sw_1,copper,internal,switch,Unmanaged_8P,building_A_3F,,,,22.5438,113.9882
18 # topology,,optic_1,media_converter,dumb_sw_1,fiber,internal,media_conv,MC-1000,basement_1F,,,,22.5436,113.9880
19 # ONVIF 设备示例(取消注释并填写实际信息)
20 # onvif,192.168.1.100,camera_front,camera,dumb_sw_1,copper,onvif_cameras,internal,camera,HIKVISION_DS-2CD2342WD-I,front_door,admin,password1,80,22.1234,113.5678
21 # onvif,192.168.1.101,camera_back,camera,bridge_1,wireless,onvif_cameras,internal,camera,DAHUA_IPC-HFW1230S,back_yard,admin,password2,80,22.2234,113.6678
22
23 # ONVIF 设备示例(取消注释并填写实际信息)
24 # onvif,192.168.1.100,,,front_door,camera,HIKVISION_DS-2CD2342WD-I,front_door,admin,password1,80,22.1234,113.5678
25 # onvif,192.168.1.101,,,back_yard,camera,DAHUA_IPC-HFW1230S,back_yard,admin,password2,80,22.2234,113.6678
# onvif,192.168.1.102,,,living_room,camera,UNIVIEW_IPC3120SR,living_room,admin,password3,8080,22.3234,113.7678
# onvif,192.168.1.50,,,server_rack,nvr,HIKVISION_DS-7608NI-I2,server_rack,admin,password4,80,22.4234,113.8678