特斯拉超级充电站分布数据可视化分析系统 - 技术文档
一、项目概述
1.1 项目简介
本系统是一个基于 Python 的特斯拉超级充电站(Tesla Supercharger)分布数据可视化分析平台。系统从公开数据源采集全球特斯拉充电站数据,存储于 SQLite 数据库,并通过 Web 界面提供丰富的数据可视化、统计分析和管理功能。
1.2 技术栈
| 层级 | 技术 | 版本 | 用途 |
|---|---|---|---|
| Web 框架 | FastAPI | 0.104.1 | 后端 API 服务 |
| ASGI 服务器 | Uvicorn | 0.24.0 | 应用运行服务器 |
| ORM | SQLAlchemy | 2.0.23 | 数据库操作 |
| 模板引擎 | Jinja2 | 3.1.2 | HTML 页面渲染 |
| 认证 | python-jose | 3.3.0 | JWT 令牌生成与验证 |
| 密码加密 | passlib[bcrypt] | 1.7.4 | 密码哈希处理 |
| 前端图表 | ECharts | 5.4.3 (CDN) | 数据可视化 |
| 数据库 | SQLite | 内置 | 数据持久化存储 |
| 前端样式 | 自定义 CSS | - | 响应式布局与主题 |
1.3 系统架构
┌─────────────────────────────────────────────────────────┐
│ 浏览器 (Browser) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ ECharts │ │ Jinja2 │ │ Fetch │ │ CSS │ │
│ │ 可视化 │ │ 模板渲染 │ │ API调用 │ │ 样式 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └─────────┘ │
└───────┼──────────────┼──────────────┼────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ FastAPI 应用服务器 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ auth_routes │ │analysis_rt │ │ admin_routes │ │
│ │ 认证路由 │ │ 分析路由 │ │ 管理路由 │ │
│ └──────┬──────┘ └──────┬──────┘ └───────┬─────────┘ │
│ │ │ │ │
│ ┌──────┴────────────────┴──────────────────┴─────────┐ │
│ │ SQLAlchemy ORM + JWT Auth │ │
│ └──────────────────────┬──────────────────────────────┘ │
└─────────────────────────┼─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ SQLite 数据库 │
│ ┌──────────┐ ┌───────────────────┐ ┌──────────────┐ │
│ │ users │ │ charging_stations │ │operation_logs│ │
│ └──────────┘ └───────────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
























二、项目结构
Charge/
├── main.py # 应用入口,FastAPI 实例化与路由注册
├── config.py # 全局配置常量
├── database.py # 数据库引擎、会话管理、迁移
├── models.py # SQLAlchemy ORM 数据模型
├── auth.py # 认证工具(密码哈希、JWT)
├── import_data.py # CSV 数据导入模块
├── update_data.py # 外部 API 数据更新脚本
├── requirements.txt # Python 依赖清单
├── Supercharge Locations.csv # 原始数据文件
├── tesla_supercharger.db # SQLite 数据库文件
│
├── routes/
│ ├── __init__.py
│ ├── auth_routes.py # 认证相关 API(7 个端点)
│ ├── analysis_routes.py # 数据分析 API(25 个端点)
│ └── admin_routes.py # 管理后台 API(10 个端点)
│
├── static/
│ ├── css/
│ │ └── style.css # 全局样式表(1573 行)
│ ├── js/
│ │ ├── app.js # 核心前端工具库
│ │ └── dashboard_screen.js # 可视化大屏脚本
│ ├── images/
│ │ └── tesla-bg.jpg # 登录页背景图
│ ├── uploads/ # 用户上传文件目录
│ ├── china.json # 中国地图 GeoJSON 数据
│ └── world.json # 世界地图 GeoJSON 数据
│
└── templates/
├── base.html # 基础布局模板(侧边栏 + 顶栏)
├── login.html # 登录页
├── register.html # 注册页
├── dashboard.html # 系统总览仪表盘
├── dashboard_screen.html # 可视化大屏
├── profile.html # 个人中心
├── map_global.html # 全球地图
├── map_china.html # 中国地图
│
├── analysis/ # 数据分析页面(13 个)
│ ├── trend.html # 年度趋势
│ ├── power.html # 功率分析
│ ├── stalls.html # 车位分布
│ ├── capacity.html # 容量分析
│ ├── elevation.html # 海拔分析
│ ├── multi.html # 多维分析
│ ├── scatter.html # 相关散点图
│ ├── performance.html # 性能对比
│ ├── search.html # 站点搜索
│ ├── forecast.html # 增长预测
│ ├── china.html # 中国分析
│ ├── us.html # 美国分析
│ └── station_list.html # 站点列表
│
└── admin/ # 管理后台页面(4 个)
├── users.html # 用户管理
├── stations.html # 站点管理
├── import.html # 数据导入
└── logs.html # 操作日志
三、数据库设计
3.1 数据库选型
系统使用 SQLite 作为数据库,具有零配置、单文件存储、免维护的优点,适合中小型数据分析项目。
- 数据库文件 :
tesla_supercharger.db - 连接配置 :
sqlite:///tesla_supercharger.db,check_same_thread=False
3.2 数据表结构
3.2.1 用户表 (users)
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | Integer | PRIMARY KEY, AUTO INCREMENT | 用户 ID |
| username | String(50) | UNIQUE, NOT NULL, INDEXED | 用户名 |
| password_hash | String(128) | NOT NULL | 密码哈希值(bcrypt) |
| String(100) | NULLABLE | 电子邮箱 | |
| role | String(20) | DEFAULT 'user' | 角色(user/admin) |
| avatar | String(500) | NULLABLE | 头像文件路径 |
| created_at | DateTime | DEFAULT utcnow | 创建时间 |
关系 : 一对多关联 operation_logs(通过 user_id)
3.2.2 充电站表 (charging_stations)
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | Integer | PRIMARY KEY, AUTO INCREMENT | 站点 ID |
| name | String(200) | NOT NULL | 站点名称 |
| street_address | String(300) | - | 街道地址 |
| city | String(100) | - | 城市 |
| state | String(50) | - | 州/省 |
| zip_code | String(20) | - | 邮编 |
| country | String(50) | - | 国家 |
| stalls | Integer | DEFAULT 0 | 充电桩数量 |
| kw | Integer | DEFAULT 150 | 充电功率 (kW) |
| latitude | Float | - | 纬度 |
| longitude | Float | - | 经度 |
| elevation | Integer | - | 海拔 (m) |
| open_date | String(20) | - | 开放日期(字符串格式) |
| created_at | DateTime | DEFAULT utcnow | 记录创建时间 |
说明 : open_date 存储为字符串而非日期类型,因为原始数据中存在多种日期格式(MM/DD/YYYY、YYYY-MM-DD、YYYY/MM/DD、MM/DD/YY),在查询层通过 _parse_open_date() 函数统一解析。
3.2.3 操作日志表 (operation_logs)
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | Integer | PRIMARY KEY, AUTO INCREMENT | 日志 ID |
| user_id | Integer | FOREIGN KEY → users.id | 操作用户 ID |
| action | String(200) | - | 操作类型 |
| detail | String(500) | - | 操作详情 |
| created_at | DateTime | DEFAULT utcnow | 操作时间 |
关系 : 多对一关联 users(通过 user_id)
3.3 数据库迁移
系统通过 database.py 中的 _migrate_db() 函数实现轻量级迁移。启动时检查表结构,若缺少 avatar 列则自动添加:
python
def _migrate_db():
db = SessionLocal()
try:
cols = [row[1] for row in db.execute(text("PRAGMA table_info(users)")).fetchall()]
if "avatar" not in cols:
db.execute(text("ALTER TABLE users ADD COLUMN avatar VARCHAR(500)"))
db.commit()
except Exception:
pass
finally:
db.close()
四、后端架构
4.1 应用入口 (main.py)
FastAPI 应用实例化后进行以下配置:
- CORS 中间件: 允许所有来源的跨域请求
- 静态文件 : 挂载
/static目录 - 模板引擎: 配置 Jinja2 模板目录
- 路由注册 : 引入
auth_routes、analysis_routes、admin_routes三个路由模块 - 启动事件: 初始化数据库并创建默认管理员账户(admin / admin123)
- 热重载 : 使用
uvicorn.run("main:app", ..., reload=True)启动,支持代码修改后自动重启
python
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="localhost", port=8002, reload=True)
4.2 认证系统 (auth.py)
4.2.1 密码加密
使用 passlib 库的 bcrypt 算法进行密码哈希:
python
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(plain: str, hashed: str) -> bool:
return pwd_context.verify(plain, hashed)
4.2.2 JWT 令牌
- 算法: HS256
- 有效期: 24 小时(1440 分钟)
- 载荷 :
{"sub": username, "exp": expire_time} - 提取方式 : 从请求头
Authorization: Bearer <token>中提取
python
def create_access_token(data: dict) -> str:
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
4.2.3 认证依赖注入
get_current_user 作为 FastAPI 依赖项,自动从请求头提取 JWT 令牌并验证用户身份:
python
def get_current_user(request: Request, db: Session = Depends(get_db)) -> User:
token = request.headers.get("Authorization", "").replace("Bearer ", "")
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username = payload.get("sub")
user = db.query(User).filter(User.username == username).first()
if not user:
raise HTTPException(status_code=401, detail="用户不存在")
return user
4.3 路由模块
4.3.1 认证路由 (auth_routes.py)
路由前缀: /api/auth
| 方法 | 路径 | 功能 | 认证要求 |
|---|---|---|---|
| POST | /register | 用户注册 | 无 |
| POST | /login | 用户登录 | 无 |
| GET | /me | 获取当前用户信息 | 需要 |
| PUT | /profile | 更新邮箱 | 需要 |
| PUT | /profile_info | 更新用户名和邮箱 | 需要 |
| POST | /change_password | 修改密码 | 需要 |
| POST | /avatar | 上传头像 | 需要 |
登录响应示例:
json
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"username": "admin",
"role": "admin"
}
4.3.2 分析路由 (analysis_routes.py)
路由前缀: /api/analysis
数据统计类:
| 方法 | 路径 | 功能 | 参数 |
|---|---|---|---|
| GET | /summary | 全局统计数据 | - |
| GET | /country_distribution | 国家分布 | top_n (默认20) |
| GET | /state_distribution | 州/省分布 | country, top_n |
| GET | /yearly_trend | 年度趋势 | - |
| GET | /monthly_distribution | 月度分布 | - |
| GET | /kw_distribution | 功率分布 | - |
| GET | /stalls_distribution | 车位分布 | - |
| GET | /elevation_distribution | 海拔分布 | - |
| GET | /scatter_data | 散点数据 | country |
| GET | /country_performance | 国家性能对比 | - |
区域分析类:
| 方法 | 路径 | 功能 | 参数 |
|---|---|---|---|
| GET | /china_stations | 中国站点 | - |
| GET | /china_state_distribution | 中国省份分布 | - |
| GET | /china_city_distribution | 中国城市分布 | top_n (默认30) |
| GET | /china_yearly_trend | 中国年度趋势 | - |
| GET | /country_stations | 指定国家站点 | country |
| GET | /global_stations | 全球站点坐标 | - |
高级功能类:
| 方法 | 路径 | 功能 | 参数 |
|---|---|---|---|
| GET | /search_stations | 高级搜索 | q, country, state, city, kw_min, kw_max, stalls_min, stalls_max, elevation_min, elevation_max, limit |
| GET | /export_stations | CSV 导出 | country, state, kw |
| GET | /growth_forecast | 增长预测 | - |
| GET | /station_list | 分页列表 | page, page_size, country, state, kw |
| GET | /countries | 国家列表 | - |
| GET | /states_by_country | 州/省列表 | country |
| GET | /cities_by_country | 城市列表 | country, state |
可视化大屏类:
| 方法 | 路径 | 功能 |
|---|---|---|
| GET | /screen_points | 大屏地图坐标点 |
| GET | /screen_overview | 大屏概览数据 |
| GET | /screen_data | 大屏完整数据 |
4.3.3 管理路由 (admin_routes.py)
路由前缀: /api/admin,所有端点均需 admin 角色。
| 方法 | 路径 | 功能 |
|---|---|---|
| GET | /users | 用户列表 |
| PUT | /users/{id} | 更新用户 |
| DELETE | /users/{id} | 删除用户 |
| GET | /stations | 站点列表(分页) |
| POST | /stations | 创建站点 |
| PUT | /stations/{id} | 更新站点 |
| DELETE | /stations/{id} | 删除站点 |
| GET | /logs | 操作日志(分页) |
| POST | /import_data | 触发 CSV 导入 |
| GET | /stats | 系统统计信息 |
4.4 数据分析算法
4.4.1 日期解析
系统支持多种日期格式的自动识别:
python
def _parse_open_date(date_str):
for fmt in ("%m/%d/%Y", "%Y-%m-%d", "%Y/%m/%d", "%m/%d/%y"):
try:
return datetime.strptime(raw, fmt)
except ValueError:
continue
return None
4.4.2 年度趋势构建
从 open_date 字段提取年份,统计每年新增站点数量:
python
def _build_yearly_trend(rows):
year_count = {}
for (date_str,) in rows:
parsed = _parse_open_date(date_str)
if parsed and 2010 <= parsed.year <= 2030:
year_count[parsed.year] = year_count.get(parsed.year, 0) + 1
return [{"year": year, "count": count} for year, count in sorted(year_count.items())]
4.4.3 线性回归增长预测
使用最小二乘法进行线性回归,预测未来 5 年的站点增长趋势:
python
# 线性回归: y = slope * x + intercept
n = len(years)
slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)
intercept = (sum_y - slope * sum_x) / n
# R² 决定系数
ss_tot = sum((y - y_mean) ** 2 for y in counts)
ss_res = sum((y - (slope * x + intercept)) ** 2 for x, y in zip(years, counts))
r_squared = 1 - ss_res / ss_tot
预测结果包含:
- 历史数据点
- 未来 5 年预测值(不低于 0)
- 模型参数(斜率、截距、R²)
- 置信区间(预测值 ±20%)
五、前端架构
5.1 页面路由体系
系统采用服务端渲染(SSR)模式,通过 FastAPI 的 Jinja2 模板引擎渲染 HTML 页面。
5.1.1 页面分类
| 分类 | 路径 | 模板 | 说明 |
|---|---|---|---|
| 首页 | / |
重定向至 /dashboard | |
| 仪表盘 | /dashboard |
dashboard.html | 系统总览 |
| 可视化大屏 | /dashboard/screen |
dashboard_screen.html | 全屏展示 |
| 全球地图 | /map/global |
map_global.html | 世界地图 |
| 中国地图 | /map/china |
map_china.html | 中国地图 |
| 分析页面 | /analysis/{name} |
analysis/{name}.html | 13 个分析页面 |
| 管理页面 | /admin/{name} |
admin/{name}.html | 4 个管理页面 |
| 登录 | /login |
login.html | |
| 注册 | /register |
register.html | |
| 个人中心 | /profile |
profile.html |
5.1.2 模板继承
所有页面(除登录/注册/大屏)继承 base.html 基础模板,该模板定义了:
- 侧边栏导航: 分为系统总览、地图视图、数据分析、区域分析、管理后台五个分组
- 顶部导航栏: 包含页面标题、用户信息、退出按钮
- 主内容区 : 通过
{% block content %}占位 - 脚本区 : 通过
{% block scripts %}占位 - 全局资源加载: CSS、ECharts CDN、app.js
5.2 核心前端模块
5.2.1 API 工具库 (app.js)
提供统一的 HTTP 请求封装,自动处理认证和错误:
javascript
// GET 请求,自动携带 JWT 令牌
async function apiGet(url, callback) {
const token = getToken();
const headers = {};
if (token) headers['Authorization'] = `Bearer ${token}`;
const res = await fetch(API_BASE + url, { headers });
if (res.status === 401) {
clearToken();
window.location.href = '/login';
return null;
}
if (!res.ok) throw new Error(`请求失败 (${res.status})`);
const data = await res.json();
if (typeof callback === 'function') callback(data);
return data;
}
提供的工具函数:
| 函数 | 功能 |
|---|---|
getToken() / setToken() / clearToken() |
JWT 令牌管理 |
apiGet(url, callback) |
GET 请求 |
apiPost(url, data) |
POST 请求 |
apiPut(url, data) |
PUT 请求 |
apiDelete(url) |
DELETE 请求 |
showToast(message, isError) |
消息提示 |
makeChart(domId, option) |
创建 ECharts 图表 |
loadChart(domId, apiUrl, buildOption) |
异步加载数据并渲染图表 |
checkAuth() |
检查登录状态 |
formatNumber(n) |
数字格式化 |
5.2.2 可视化大屏 (dashboard_screen.js)
全屏可视化大屏模块,包含以下功能:
场景系统: 5 个自动轮播场景(每 9 秒切换)
- 全球总览 - 展示全球分布
- 超高功率 - 聚焦 250kW+ 站点
- 中国密度 - 中国市场分析
- 美国覆盖 - 美国市场分析
- 枢纽容量 - 大型充电站分析
图表面板: 7 个独立图表
- 国家排名(水平柱状图)
- 世界地图(散点图叠加地图)
- 功率构成(环形图)
- 年度趋势(折线图)
- 国家份额(饼图)
- 城市排名(水平柱状图)
- 容量排名(水平柱状图)
交互功能:
- 场景卡片点击切换
- 筛选按钮(全部 / 250kW+ / 中国 / 美国 / 枢纽)
- 键盘导航(方向键切换场景,空格暂停)
- 面板聚焦/淡化效果
- 自动刷新(每 5 分钟)
- 全屏切换
5.3 地图渲染方案
系统使用本地 GeoJSON 文件注册 ECharts 地图,避免 CDN 404 问题:
javascript
// 注册世界地图
async function registerWorldMap() {
const res = await fetch('/static/world.json');
if (res.ok) {
const geoJson = await res.json();
echarts.registerMap('world', geoJson);
}
}
// 注册中国地图
async function registerChinaMap() {
const res = await fetch('/static/china.json');
if (res.ok) {
const geoJson = await res.json();
echarts.registerMap('china', geoJson);
}
}
GeoJSON 数据来源:
world.json: ECharts 4.x 官方世界地图数据(~987KB,217 个国家/地区)china.json: 阿里云 DataV 中国地图数据(~569KB,35 个省级行政区)
5.4 CSS 设计系统
5.4.1 颜色体系
css
:root {
--primary: #e82127; /* Tesla 红 */
--primary-light: #ff4d52;
--primary-dark: #c4191e;
--bg-dark: #0a1628; /* 深色背景 */
--bg-card: #111d33; /* 卡片背景 */
--text-primary: #e6f0ff; /* 主文字 */
--text-secondary: #8899aa; /* 次要文字 */
--border-color: rgba(255,255,255,0.08);
}
5.4.2 响应式断点
| 断点 | 适配 |
|---|---|
| > 1500px | 完整布局 |
| 960px - 1500px | 中等屏幕适配 |
| < 960px | 移动端适配 |
5.4.3 特殊组件
- 玻璃拟态登录页 :
backdrop-filter: blur(20px)实现毛玻璃效果 - 可视化大屏主题: 深色背景 + 霓虹边框 + 网格面板
- 数据表格: 斑马纹 + 悬停高亮
- Toast 通知: 右上角弹出,3 秒自动消失
六、数据采集与更新
6.1 初始数据导入 (import_data.py)
从 Supercharge Locations.csv 文件导入初始数据:
bash
python import_data.py
导入逻辑:
- 检测 CSV 列名,自动识别 GPS 坐标列、地址列等
- 启发式解析:自动拆分州/邮编,标准化城市名
- 仅在数据库为空时执行全量导入
repair_csv_data()函数可更新已有记录
6.2 在线数据更新 (update_data.py)
支持三种数据源:
6.2.1 美国能源部数据 (NREL API)
bash
python update_data.py --source us_doe
- API :
https://developer.nrel.gov/api/alt-fuel-stations/v1.json - 密钥 : 使用
DEMO_KEY(有速率限制) - 策略: 每 4 个请求等待 15 秒,遇到 429 错误等待 60 秒
- 数据范围: 美国特斯拉充电站
- 字段映射 :
date_last_confirmed作为open_date的备用字段
6.2.2 OpenChargeMap 全球数据
bash
python update_data.py --source ocm
- API :
https://api.openchargemap.io/v3/poi/ - 覆盖国家: US, CN, CA, DE, GB, FR, KR, NO, AU, NL, JP
- 注意: 需要 API 密钥,否则返回 403
6.2.3 CSV 文件导入
bash
python update_data.py --source file --file data.csv --mode upsert
- upsert 模式: 根据名称+城市匹配,更新已有记录或插入新记录
- insert 模式: 仅插入新记录
6.3 当前数据概况
| 指标 | 数值 |
|---|---|
| 总站点数 | 8,059 |
| 覆盖国家 | 30+ |
| 美国站点 | 4,420 |
| 中国站点 | 1,800+ |
| 数据年份范围 | 2012 - 2026 |
年度分布:
| 年份 | 新增站点 | 年份 | 新增站点 |
|---|---|---|---|
| 2012 | 8 | 2020 | 353 |
| 2013 | 178 | 2021 | 1,103 |
| 2014 | 449 | 2022 | 1,513 |
| 2015 | 862 | 2023 | 480 |
| 2016 | 566 | 2024 | 65 |
| 2017 | 605 | 2025 | 1 |
| 2018 | 784 | 2026 | 13 |
| 2019 | 329 | - | - |
七、功能模块详解
7.1 系统总览 (Dashboard)
URL : /dashboard
展示全局统计指标和四个核心图表:
- 统计卡片: 总站点数、覆盖国家数、州/省数、总充电桩数、平均车位数、平均功率
- 国家分布饼图: Top 20 国家的站点数量占比
- 年度增长趋势: 折线图展示历年新增站点数量
- 功率分布柱状图: 各功率等级的站点数量
- 车位分布柱状图: 各车位区间的站点数量
7.2 可视化大屏 (Screen)
URL : /dashboard/screen
全屏沉浸式数据展示,适用于大屏投影:
- 顶部信息栏: 系统名称、实时时钟、在线状态、用户信息
- 场景轮播: 5 个场景自动切换,每个场景有独立的筛选条件和叙述文本
- 核心指标: 6 个动态数字卡片
- 地图面板: 全球站点散点地图
- 分析面板: 7 个图表面板,支持场景联动的筛选和聚焦效果
- 操作方式: 鼠标点击场景卡片 / 键盘方向键 / 空格暂停
7.3 地图可视化
7.3.1 全球地图 (/map/global)
- ECharts 散点图叠加世界地图
- 按功率等级筛选(全部 / 250kW+ / 150kW+)
- 右侧:国家分布饼图 + Top 15 国家柱状图
- 点击散点查看站点详情
7.3.2 中国地图 (/map/china)
- ECharts 散点图叠加中国地图
- 按功率等级筛选
- 右侧:省份分布柱状图 + Top 15 城市柱状图
7.4 数据分析模块
7.4.1 年度趋势 (/analysis/trend)
- 年度新增站点折线图
- 月度分布柱状图
7.4.2 功率分析 (/analysis/power)
- 功率分布柱状图
- 功率占比饼图
7.4.3 车位分布 (/analysis/stalls)
- 车位区间分布柱状图(1-4, 5-8, 9-12, 13-16, 17-20, 21-30, 31+)
- 车位占比饼图
7.4.4 容量分析 (/analysis/capacity)
- 各国平均车位数对比
- 各国平均功率对比
7.4.5 海拔分析 (/analysis/elevation)
- 海拔区间分布柱状图(<100m, 100-500m, 500-1000m, 1000-2000m, 2000-3000m, >3000m)
- 海拔占比饼图
7.4.6 多维分析 (/analysis/multi)
- 综合统计卡片
- 四维图表:国家分布、功率分布、车位分布、海拔分布
7.4.7 相关散点 (/analysis/scatter)
- 车位数 vs 功率散点图
- 按国家筛选
- 悬停显示站点名称
7.4.8 性能对比 (/analysis/performance)
- 各国性能数据表格(站点数、平均车位、平均功率)
- Top 5 国家雷达图对比
7.4.9 站点搜索 (/analysis/search)
- 多条件高级搜索:关键词、国家、州/省(级联)、功率范围、车位范围
- 搜索结果地图展示
- 结果列表表格
- CSV 导出功能
- 实时统计(总数、国家数、城市数、平均功率、平均车位)
7.4.10 增长预测 (/analysis/forecast)
- 模型统计卡片(历史总量、最新年度、年均增长、R² 拟合度)
- 历史数据柱状图 + 预测趋势虚线 + 置信区间
- 预测详情表格(年份、新增站点、累计估算、类型)
- 累计增长面积图
- 年增长率柱状图(正增长绿色、负增长红色)
7.4.11 中国分析 (/analysis/china)
- 统计卡片(总站点、省份、城市、平均功率)
- 中国年度趋势
- 省份分布 Top 15
- 城市分布 Top 15
- 功率分布饼图
7.4.12 美国分析 (/analysis/us)
- 统计卡片(总站点、州数、城市、平均功率)
- 州分布 Top 15
- 车位 vs 功率散点
- 功率分布饼图
- 年度趋势
7.4.13 站点列表 (/analysis/station_list)
- 分页表格(每页 20 条)
- 国家/州/功率筛选
- 管理员可编辑/删除/新建站点
- CSV 导出
7.5 管理后台
7.5.1 用户管理 (/admin/users)
- 用户列表表格
- 编辑用户(用户名、邮箱、角色、密码)
- 删除用户(不能删除自己)
7.5.2 站点管理 (/admin/stations)
- 站点列表(分页、筛选)
- 创建/编辑/删除站点
- 编辑表单包含所有字段
7.5.3 数据导入 (/admin/import)
- 一键触发 CSV 数据导入
- 导入结果显示
- 系统统计信息
7.5.4 操作日志 (/admin/logs)
- 分页日志表格
- 显示操作用户、操作类型、详情、时间
八、部署与运行
8.1 环境要求
- Python: 3.8+
- 操作系统: Windows / macOS / Linux
- 浏览器: Chrome 80+ / Firefox 75+ / Edge 80+
8.2 安装步骤
bash
# 1. 进入项目目录
cd Charge
# 2. 创建虚拟环境(推荐)
python -m venv venv
venv\Scripts\activate # Windows
# source venv/bin/activate # macOS/Linux
# 3. 安装依赖
pip install -r requirements.txt
# 4. 导入初始数据
python import_data.py
# 5. 启动服务
python main.py
8.3 访问地址
- 系统地址: http://localhost:8002
- 默认管理员: admin / admin123
- 热重载模式: 修改代码后自动重启
8.4 数据更新
bash
# 从 NREL API 获取美国最新数据
python update_data.py --source us_doe
# 从 CSV 文件导入
python update_data.py --source file --file new_data.csv --mode upsert
8.5 依赖说明
| 包名 | 版本 | 用途 |
|---|---|---|
| fastapi | 0.104.1 | Web 框架 |
| uvicorn | 0.24.0 | ASGI 服务器 |
| sqlalchemy | 2.0.23 | ORM |
| python-jose[cryptography] | 3.3.0 | JWT |
| passlib[bcrypt] | 1.7.4 | 密码加密 |
| python-multipart | 0.0.6 | 文件上传 |
| jinja2 | 3.1.2 | 模板引擎 |
| aiofiles | 23.2.1 | 异步文件 |
| pandas | 2.1.3 | 数据处理 |
九、API 接口文档
9.1 认证接口
POST /api/auth/register
注册新用户。
请求体:
json
{
"username": "testuser",
"password": "password123",
"email": "test@example.com"
}
响应 (200):
json
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"username": "testuser",
"role": "user"
}
POST /api/auth/login
用户登录。
请求体:
json
{
"username": "admin",
"password": "admin123"
}
响应 (200):
json
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"username": "admin",
"role": "admin"
}
9.2 分析接口
GET /api/analysis/summary
获取全局统计摘要。
响应 (200):
json
{
"total_stations": 8059,
"total_countries": 30,
"total_states": 200,
"total_stalls": 64000,
"avg_stalls": 7.9,
"avg_kw": 195
}
GET /api/analysis/growth_forecast
获取增长预测数据。
响应 (200):
json
{
"historical": [
{"year": 2012, "count": 8},
{"year": 2013, "count": 178},
...
],
"forecast": [
{"year": 2024, "count": 450, "is_forecast": true},
{"year": 2025, "count": 480, "is_forecast": true},
...
],
"model": {
"slope": 45.32,
"intercept": -90123.45,
"r_squared": 0.7823
}
}
GET /api/analysis/search_stations
高级搜索站点。
查询参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| q | string | 关键词(模糊匹配名称、城市、地址) |
| country | string | 国家精确匹配 |
| state | string | 州/省精确匹配 |
| city | string | 城市模糊匹配 |
| kw_min | int | 最小功率 |
| kw_max | int | 最大功率 |
| stalls_min | int | 最小车位数 |
| stalls_max | int | 最大车位数 |
| elevation_min | int | 最小海拔 |
| elevation_max | int | 最大海拔 |
| limit | int | 返回数量上限(默认 200,最大 1000) |
响应 (200):
json
{
"total": 150,
"items": [
{
"id": 1,
"name": "Tesla Supercharger",
"street_address": "123 Main St",
"city": "Los Angeles",
"state": "CA",
"country": "USA",
"stalls": 20,
"kw": 250,
"latitude": 34.0522,
"longitude": -118.2437,
"elevation": 71,
"open_date": "03/15/2023"
},
...
]
}
GET /api/analysis/export_stations
导出站点数据为 CSV 文件。
查询参数 : country, state, kw(均可选)
响应 : CSV 文件下载(Content-Disposition: attachment; filename=tesla_stations.csv)
十、安全设计
10.1 认证与授权
- JWT 令牌: HS256 算法签名,24 小时有效期
- 密码存储: bcrypt 哈希,不可逆
- 角色控制: admin / user 两级角色
- API 保护: 分析接口需要登录,管理接口需要 admin 角色
10.2 前端安全
- 自动跳转: 401 响应自动跳转登录页
- Token 清除: 登出时清除 localStorage 中的所有用户信息
- 权限隐藏: 非管理员用户隐藏管理菜单项
10.3 输入校验
- FastAPI 参数验证 : 使用
Query()的ge、le参数限制数值范围 - SQL 注入防护: SQLAlchemy ORM 参数化查询
- 文件上传限制: 头像文件最大 5MB
十一、扩展建议
11.1 数据源扩展
- 申请 NREL API 密钥: 从 https://developer.nrel.gov/signup/ 获取免费密钥,突破 DEMO_KEY 的速率限制
- supercharge.info 数据 : 手动下载最新数据 CSV,通过
update_data.py --source file导入 - 定时更新 : 配置 cron/Task Scheduler 定期执行
update_data.py
11.2 功能扩展
- 数据缓存: 引入 Redis 缓存高频查询结果
- 实时更新: WebSocket 推送数据变更
- 更多图表: 热力图、时间轴动画、3D 地球
- 导出增强: 支持 PDF 报告导出
- 多语言: i18n 国际化支持
11.3 部署优化
- 生产服务器: 使用 Gunicorn + Uvicorn workers
- 反向代理: Nginx 配置静态文件服务
- 数据库迁移: 升级为 PostgreSQL 以支持并发
- 容器化: Docker + Docker Compose 部署
十二、常见问题
Q1: 启动后看不到数据?
确保已执行数据导入:
bash
python import_data.py
Q2: 地图页面报错?
检查 static/world.json 和 static/china.json 文件是否存在。这两个文件是本地 GeoJSON 数据,不依赖外部 CDN。
Q3: 更新数据时遇到 429 错误?
NREL API 的 DEMO_KEY 有速率限制。等待几分钟后重试,或申请正式 API 密钥。
Q4: 如何重置管理员密码?
直接在数据库中操作,或删除数据库文件后重启:
bash
rm tesla_supercharger.db
python main.py # 会自动重新创建
Q5: 如何修改端口?
编辑 main.py 最后一行:
python
uvicorn.run("main:app", host="localhost", port=8002, reload=True)
将 port=8002 修改为所需端口。