new branch
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,6 +10,7 @@ from app.api.v1 import (
|
||||
alerts,
|
||||
settings,
|
||||
collected_data,
|
||||
visualization,
|
||||
)
|
||||
|
||||
api_router = APIRouter()
|
||||
@@ -25,3 +26,4 @@ api_router.include_router(tasks.router, prefix="/tasks", tags=["tasks"])
|
||||
api_router.include_router(dashboard.router, prefix="/dashboard", tags=["dashboard"])
|
||||
api_router.include_router(alerts.router, prefix="/alerts", tags=["alerts"])
|
||||
api_router.include_router(settings.router, prefix="/settings", tags=["settings"])
|
||||
api_router.include_router(visualization.router, prefix="/visualization", tags=["visualization"])
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
81
backend/app/api/v1/visualization.py
Normal file
81
backend/app/api/v1/visualization.py
Normal file
@@ -0,0 +1,81 @@
|
||||
"""Visualization API - GeoJSON endpoints for 3D Earth display"""
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
import httpx
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
CABLE_DATA_URL = "https://services.arcgis.com/6DIQcwlPy8knb6sg/arcgis/rest/services/SubmarineCables/FeatureServer/2/query?where=1%3D1&outFields=*&returnGeometry=true&f=geojson"
|
||||
LANDING_POINT_CSV_URL = "https://data.apps.fao.org/catalog/dataset/1b75ff21-92f2-4b96-9b7b-98e8aa65ad5d/resource/b6071077-d1d4-4e97-aa00-42e902847c87/download/landing-point-geo.csv"
|
||||
|
||||
|
||||
@router.get("/geo/cables")
|
||||
async def get_cables_geojson():
|
||||
"""获取海底电缆 GeoJSON 数据 (LineString)"""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=60.0) as client:
|
||||
response = await client.get(CABLE_DATA_URL)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPError as e:
|
||||
raise HTTPException(status_code=502, detail=f"Failed to fetch cable data: {str(e)}")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Internal error: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/geo/landing-points")
|
||||
async def get_landing_points_geojson():
|
||||
"""获取登陆点 GeoJSON 数据 (Point)"""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=60.0) as client:
|
||||
response = await client.get(LANDING_POINT_CSV_URL)
|
||||
response.raise_for_status()
|
||||
|
||||
lines = response.text.strip().split("\n")
|
||||
if not lines:
|
||||
raise HTTPException(status_code=500, detail="Empty CSV data")
|
||||
|
||||
features = []
|
||||
for line in lines[1:]:
|
||||
if not line.strip():
|
||||
continue
|
||||
parts = line.split(",")
|
||||
if len(parts) >= 4:
|
||||
try:
|
||||
lon = float(parts[0])
|
||||
lat = float(parts[1])
|
||||
feature_id = parts[2]
|
||||
name = parts[3].strip('"')
|
||||
is_tbd = parts[4].strip() == "true" if len(parts) > 4 else False
|
||||
|
||||
features.append(
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [lon, lat]},
|
||||
"properties": {"id": feature_id, "name": name, "is_tbd": is_tbd},
|
||||
}
|
||||
)
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
|
||||
return {"type": "FeatureCollection", "features": features}
|
||||
except httpx.HTTPError as e:
|
||||
raise HTTPException(status_code=502, detail=f"Failed to fetch landing point data: {str(e)}")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Internal error: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/geo/all")
|
||||
async def get_all_geojson():
|
||||
"""获取所有可视化数据 (电缆 + 登陆点)"""
|
||||
cables = await get_cables_geojson()
|
||||
points = await get_landing_points_geojson()
|
||||
|
||||
return {
|
||||
"cables": cables,
|
||||
"landing_points": points,
|
||||
"stats": {
|
||||
"cable_count": len(cables.get("features", [])) if cables else 0,
|
||||
"landing_point_count": len(points.get("features", [])) if points else 0,
|
||||
},
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -19,7 +19,7 @@ class Settings(BaseSettings):
|
||||
POSTGRES_USER: str = "postgres"
|
||||
POSTGRES_PASSWORD: str = "postgres"
|
||||
POSTGRES_DB: str = "planet_db"
|
||||
DATABASE_URL: str = f"postgresql+asyncpg://postgres:postgres@postgres:5432/planet_db"
|
||||
DATABASE_URL: str = f"postgresql+asyncpg://postgres:postgres@localhost:5432/planet_db"
|
||||
|
||||
REDIS_SERVER: str = "localhost"
|
||||
REDIS_PORT: int = 6379
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
39
backend/scripts/create_admin.py
Normal file
39
backend/scripts/create_admin.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, ".")
|
||||
|
||||
from app.db.session import async_session_factory
|
||||
from app.models.user import User
|
||||
from app.core.security import get_password_hash
|
||||
|
||||
|
||||
async def create_admin():
|
||||
async with async_session_factory() as session:
|
||||
# 检查用户是否已存在
|
||||
from sqlalchemy import select
|
||||
|
||||
result = await session.execute(select(User).where(User.username == "linkong"))
|
||||
existing_user = result.scalar_one_or_none()
|
||||
|
||||
if existing_user:
|
||||
print(f"用户 linkong 已存在,更新密码...")
|
||||
existing_user.set_password("LK12345678")
|
||||
existing_user.role = "super_admin"
|
||||
else:
|
||||
print("创建管理员用户...")
|
||||
user = User(
|
||||
username="linkong",
|
||||
email="linkong@example.com",
|
||||
password_hash=get_password_hash("LK12345678"),
|
||||
role="super_admin",
|
||||
is_active=True,
|
||||
)
|
||||
session.add(user)
|
||||
|
||||
await session.commit()
|
||||
print("完成!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(create_admin())
|
||||
Reference in New Issue
Block a user