Files
ljwx-health/ljwx-bigscreen-fastapi/app/api/v1/dashboard.py
T
BrunoGaoandClaude 18377b7b89 feat: 新增Ubuntu 22.04部署初始化脚本和FastAPI重构
## 新增功能

### Ubuntu 22.04初始化脚本
- 🚀 完整的系统环境初始化脚本 `ubuntu-22.04-init.sh`
- 🛠️ 支持Docker、Java 21、Node.js、Python3、MySQL、Redis等全套环境
- 🔧 自动配置防火墙、系统参数优化
- 📁 标准化项目目录结构 `/opt/ljwx`
- 📋 生成配置文件模板和维护脚本

### ljwx-bigscreen FastAPI重构
- 🏗️ 新的FastAPI架构设计,支持异步高性能
- 📊 完整的业务逻辑分层:API -> Service -> Repository
- 🎯 支持大屏主界面、个人界面、健康数据可视化
- 🔄 Redis缓存集成和数据库连接池
- 🎨 保留所有原有HTML模板和静态资源

### 文档完善
- 📖 新增FastAPI重构进度文档
- 🏗️ 详细的项目架构分析
- 📋 完整的部署组件清单和依赖关系

## 技术亮点

- **系统兼容性**: 专为Ubuntu 22.04优化的完整部署方案
- **架构现代化**: FastAPI异步框架替代传统Flask同步架构
- **企业级部署**: 13个服务组件的完整CI/CD + 业务系统
- **多架构支持**: linux/amd64 + linux/arm64双架构Docker支持

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-19 13:18:59 +08:00

859 lines
28 KiB
Python

"""
大屏仪表板数据 API
包含 main.html 和 personal.html 需要的所有 API 接口
"""
from datetime import datetime, timedelta
from typing import List, Optional, Dict, Any
from fastapi import APIRouter, Depends, HTTPException, status, Query
from pydantic import BaseModel
from app.api.deps import get_current_user
router = APIRouter()
# ============================================================================
# 响应模型定义
# ============================================================================
class StatisticsOverview(BaseModel):
"""统计概览响应模型"""
total_users: int
active_devices: int
today_alerts: int
health_score_avg: float
org_count: int
department_count: int
device_online_rate: float
data_upload_rate: float
class RealtimeStats(BaseModel):
"""实时统计响应模型"""
current_online: int
growth_rate: float
alert_trend: List[Dict]
device_status: Dict[str, int]
class HealthScore(BaseModel):
"""健康评分响应模型"""
user_id: str
overall_score: float
heart_rate_score: float
blood_oxygen_score: float
temperature_score: float
pressure_score: float
stress_score: float
exercise_score: float
sleep_score: float
trend: str
risk_level: str
device_breakdown: List[Dict]
class HealthBaseline(BaseModel):
"""健康基线响应模型"""
baseline_data: Dict[str, Any]
chart_data: List[Dict]
comparison: Dict[str, float]
generated_at: datetime
class PersonalInfo(BaseModel):
"""个人信息响应模型"""
user_id: str
device_sn: str
realname: str
avatar: str
org_name: str
latest_health_data: Dict[str, Any]
device_status: str
last_sync_time: datetime
class DeviceInfo(BaseModel):
"""设备信息响应模型"""
device_sn: str
device_name: str
device_type: str
battery_level: int
signal_strength: int
last_sync: datetime
status: str
firmware_version: str
class AlertData(BaseModel):
"""告警数据响应模型"""
alert_id: str
device_sn: str
user_id: str
alert_type: str
severity: str
message: str
created_time: datetime
status: str
acknowledged: bool
class HealthTrends(BaseModel):
"""健康趋势响应模型"""
device_sn: str
time_range: str
trends: Dict[str, List[Dict]]
analysis: Dict[str, Any]
predictions: List[Dict]
class HealthRecommendations(BaseModel):
"""健康建议响应模型"""
user_id: str
analysis_type: str
recommendations: List[Dict]
priority_alerts: List[Dict]
generated_at: datetime
# ============================================================================
# 统计概览相关 API
# ============================================================================
@router.get("/statistics/overview", response_model=StatisticsOverview, summary="获取统计概览")
async def get_statistics_overview(
customer_id: str = Query(..., description="客户ID"),
date: Optional[str] = Query(None, description="日期"),
current_user: dict = Depends(get_current_user)
):
"""获取系统统计概览数据"""
# 模拟数据
mock_data = StatisticsOverview(
total_users=1247,
active_devices=892,
today_alerts=23,
health_score_avg=78.5,
org_count=15,
department_count=48,
device_online_rate=89.7,
data_upload_rate=94.2
)
return mock_data
@router.get("/statistics/realtime", response_model=RealtimeStats, summary="获取实时统计")
async def get_realtime_stats(
date: Optional[str] = Query(None, description="日期"),
current_user: dict = Depends(get_current_user)
):
"""获取实时统计数据"""
mock_data = RealtimeStats(
current_online=756,
growth_rate=2.3,
alert_trend=[
{"time": "00:00", "count": 3},
{"time": "06:00", "count": 8},
{"time": "12:00", "count": 15},
{"time": "18:00", "count": 23}
],
device_status={
"online": 756,
"offline": 136,
"maintenance": 12
}
)
return mock_data
# ============================================================================
# 健康数据相关 API
# ============================================================================
@router.get("/health/score/comprehensive", response_model=HealthScore, summary="获取综合健康评分")
async def get_comprehensive_health_score(
customer_id: str = Query(..., description="客户ID"),
include_device_breakdown: bool = Query(False, description="包含设备详情"),
days: int = Query(7, description="天数"),
start_date: Optional[str] = Query(None, description="开始日期"),
end_date: Optional[str] = Query(None, description="结束日期"),
current_user: dict = Depends(get_current_user)
):
"""获取综合健康评分"""
mock_data = HealthScore(
user_id=current_user.get('id', 'mock_user'),
overall_score=78.5,
heart_rate_score=82.3,
blood_oxygen_score=95.7,
temperature_score=88.1,
pressure_score=75.2,
stress_score=68.9,
exercise_score=71.4,
sleep_score=79.8,
trend="improving",
risk_level="low",
device_breakdown=[
{"device_sn": "DEV001", "score": 78.5, "status": "normal"},
{"device_sn": "DEV002", "score": 76.2, "status": "warning"}
] if include_device_breakdown else []
)
return mock_data
@router.get("/health/charts/baseline", response_model=HealthBaseline, summary="获取健康基线图表")
async def get_health_baseline_chart(
org_id: str = Query(..., description="组织ID"),
start_date: str = Query(..., description="开始日期"),
end_date: str = Query(..., description="结束日期"),
current_user: dict = Depends(get_current_user)
):
"""获取健康基线图表数据"""
mock_data = HealthBaseline(
baseline_data={
"heart_rate": {"min": 60, "max": 100, "avg": 78},
"blood_oxygen": {"min": 95, "max": 100, "avg": 97.8},
"temperature": {"min": 36.0, "max": 37.5, "avg": 36.8}
},
chart_data=[
{"date": "2025-09-15", "heart_rate": 78, "blood_oxygen": 98, "temperature": 36.7},
{"date": "2025-09-16", "heart_rate": 82, "blood_oxygen": 97, "temperature": 36.9},
{"date": "2025-09-17", "heart_rate": 75, "blood_oxygen": 98, "temperature": 36.6}
],
comparison={
"heart_rate_change": 2.3,
"blood_oxygen_change": -0.5,
"temperature_change": 0.1
},
generated_at=datetime.now()
)
return mock_data
@router.get("/health/recommendations", response_model=HealthRecommendations, summary="获取健康建议")
async def get_health_recommendations(
analysis_type: str = Query("comprehensive", description="分析类型"),
device_sn: Optional[str] = Query(None, description="设备序列号"),
current_user: dict = Depends(get_current_user)
):
"""获取健康建议"""
mock_data = HealthRecommendations(
user_id=current_user.get('id', 'mock_user'),
analysis_type=analysis_type,
recommendations=[
{
"id": "rec_001",
"title": "改善睡眠质量",
"description": "建议每天保持7-8小时睡眠",
"priority": "high",
"category": "sleep"
},
{
"id": "rec_002",
"title": "增加有氧运动",
"description": "每周至少进行3次30分钟有氧运动",
"priority": "medium",
"category": "exercise"
}
],
priority_alerts=[
{
"id": "alert_001",
"type": "blood_pressure",
"message": "血压偏高,建议就医检查",
"severity": "high"
}
],
generated_at=datetime.now()
)
return mock_data
@router.get("/health/trends/analysis", response_model=HealthTrends, summary="获取健康趋势分析")
async def get_health_trends_analysis(
device_sn: str = Query(..., description="设备序列号"),
time_range: str = Query("24h", description="时间范围"),
current_user: dict = Depends(get_current_user)
):
"""获取健康趋势分析"""
mock_data = HealthTrends(
device_sn=device_sn,
time_range=time_range,
trends={
"heart_rate": [
{"time": "2025-09-19 00:00", "value": 72},
{"time": "2025-09-19 06:00", "value": 68},
{"time": "2025-09-19 12:00", "value": 85},
{"time": "2025-09-19 18:00", "value": 78}
],
"blood_oxygen": [
{"time": "2025-09-19 00:00", "value": 98},
{"time": "2025-09-19 06:00", "value": 97},
{"time": "2025-09-19 12:00", "value": 96},
{"time": "2025-09-19 18:00", "value": 98}
]
},
analysis={
"heart_rate_trend": "stable",
"blood_oxygen_trend": "normal",
"recommendations": ["保持当前运动量", "注意休息"]
},
predictions=[
{"metric": "heart_rate", "next_24h": 76, "confidence": 0.85},
{"metric": "blood_oxygen", "next_24h": 97, "confidence": 0.92}
]
)
return mock_data
@router.get("/health/analysis/comprehensive", summary="获取综合健康分析")
async def get_comprehensive_health_analysis(
device_sn: str = Query(..., description="设备序列号"),
days: int = Query(30, description="分析天数"),
current_user: dict = Depends(get_current_user)
):
"""获取综合健康分析"""
return {
"device_sn": device_sn,
"analysis_period": f"{days} days",
"overall_health_score": 78.5,
"health_categories": {
"cardiovascular": {"score": 82, "status": "good"},
"respiratory": {"score": 95, "status": "excellent"},
"sleep": {"score": 68, "status": "needs_improvement"},
"exercise": {"score": 71, "status": "fair"}
},
"risk_factors": [
{"factor": "irregular_sleep", "severity": "medium"},
{"factor": "low_activity", "severity": "low"}
],
"improvement_suggestions": [
"建立规律作息时间",
"增加日常活动量",
"定期监测血压"
]
}
# ============================================================================
# 个人信息相关 API
# ============================================================================
@router.get("/personal/realtime-health", summary="获取个人实时健康数据")
async def get_personal_realtime_health(
user_id: str = Query(..., description="用户ID"),
card_type: str = Query(..., description="卡片类型"),
device_sn: str = Query(..., description="设备序列号"),
current_user: dict = Depends(get_current_user)
):
"""获取个人实时健康数据"""
return {
"user_id": user_id,
"device_sn": device_sn,
"card_type": card_type,
"realtime_data": {
"heart_rate": 78,
"blood_oxygen": 98,
"temperature": 36.7,
"blood_pressure": "120/80",
"stress_level": 25,
"last_update": datetime.now().isoformat()
},
"status": "normal",
"device_online": True
}
@router.get("/personal/history-health", summary="获取个人历史健康数据")
async def get_personal_history_health(
user_id: str = Query(..., description="用户ID"),
card_type: str = Query(..., description="卡片类型"),
days: int = Query(7, description="天数"),
current_user: dict = Depends(get_current_user)
):
"""获取个人历史健康数据"""
return {
"user_id": user_id,
"card_type": card_type,
"days": days,
"history_data": [
{"date": "2025-09-18", "heart_rate": 75, "blood_oxygen": 97, "temperature": 36.6},
{"date": "2025-09-17", "heart_rate": 78, "blood_oxygen": 98, "temperature": 36.8},
{"date": "2025-09-16", "heart_rate": 82, "blood_oxygen": 96, "temperature": 36.9}
],
"trends": {
"heart_rate": "stable",
"blood_oxygen": "improving",
"temperature": "normal"
}
}
@router.get("/personal/ai-analysis", summary="获取个人AI分析")
async def get_personal_ai_analysis(
user_id: str = Query(..., description="用户ID"),
card_type: str = Query(..., description="卡片类型"),
analysis_type: str = Query("comprehensive", description="分析类型"),
current_user: dict = Depends(get_current_user)
):
"""获取个人AI分析"""
return {
"user_id": user_id,
"card_type": card_type,
"analysis_type": analysis_type,
"ai_insights": {
"health_score": 78.5,
"risk_assessment": "low",
"predictions": [
"未来7天心率将保持稳定",
"建议增加运动量以改善整体健康"
],
"personalized_advice": [
"根据您的睡眠模式,建议22:30前就寝",
"您的血氧水平优秀,继续保持"
]
},
"generated_at": datetime.now().isoformat()
}
@router.get("/personal/info", response_model=PersonalInfo, summary="获取个人信息")
async def get_personal_info(
device_sn: str = Query(..., description="设备序列号"),
current_user: dict = Depends(get_current_user)
):
"""获取个人信息"""
mock_data = PersonalInfo(
user_id=current_user.get('id', 'mock_user'),
device_sn=device_sn,
realname=current_user.get('realname', '模拟用户'),
avatar=current_user.get('avatar', '/static/images/default_avatar.png'),
org_name=current_user.get('org_name', '模拟组织'),
latest_health_data={
"heart_rate": 78,
"blood_oxygen": 98,
"temperature": 36.7,
"recorded_at": datetime.now().isoformat()
},
device_status="online",
last_sync_time=datetime.now()
)
return mock_data
@router.get("/personal/alerts", summary="获取个人告警")
async def get_personal_alerts(
device_sn: str = Query(..., description="设备序列号"),
current_user: dict = Depends(get_current_user)
):
"""获取个人告警信息"""
return {
"device_sn": device_sn,
"alerts": [
{
"id": "alert_001",
"type": "heart_rate_high",
"message": "心率异常偏高",
"severity": "warning",
"created_time": "2025-09-19T10:30:00",
"status": "active"
},
{
"id": "alert_002",
"type": "blood_oxygen_low",
"message": "血氧饱和度偏低",
"severity": "info",
"created_time": "2025-09-19T08:15:00",
"status": "acknowledged"
}
],
"total_count": 2,
"unread_count": 1
}
# ============================================================================
# 设备相关 API
# ============================================================================
@router.get("/device/info", response_model=DeviceInfo, summary="获取设备信息")
async def get_device_info(
device_sn: str = Query(..., description="设备序列号"),
current_user: dict = Depends(get_current_user)
):
"""获取设备信息"""
mock_data = DeviceInfo(
device_sn=device_sn,
device_name=f"智能手环 {device_sn}",
device_type="smart_bracelet",
battery_level=78,
signal_strength=89,
last_sync=datetime.now() - timedelta(minutes=5),
status="online",
firmware_version="v2.1.5"
)
return mock_data
@router.get("/device/user_org", summary="获取设备关联的用户和组织")
async def get_device_user_org(
device_sn: str = Query(..., description="设备序列号"),
current_user: dict = Depends(get_current_user)
):
"""获取设备关联的用户和组织信息"""
return {
"device_sn": device_sn,
"user_id": current_user.get('id', 'mock_user'),
"org_id": current_user.get('org_id', 'mock_org'),
"customer_id": current_user.get('customer_id', 'mock_customer'),
"user_info": {
"username": current_user.get('username', 'mock_user'),
"realname": current_user.get('realname', '模拟用户'),
"org_name": current_user.get('org_name', '模拟组织')
}
}
# ============================================================================
# 数据管理相关 API (兼容旧版)
# ============================================================================
@router.get("/get_personal_info", summary="获取个人信息 (兼容旧版)")
async def get_personal_info_legacy(
device_sn: str = Query(..., description="设备序列号"),
current_user: dict = Depends(get_current_user)
):
"""获取个人信息 (兼容旧版API)"""
return await get_personal_info(device_sn, current_user)
@router.get("/health_data/latest", summary="获取最新健康数据")
async def get_latest_health_data(
device_sn: str = Query(..., description="设备序列号"),
current_user: dict = Depends(get_current_user)
):
"""获取最新健康数据"""
return {
"device_sn": device_sn,
"latest_data": {
"heart_rate": 78,
"blood_oxygen": 98,
"temperature": 36.7,
"blood_pressure_high": 120,
"blood_pressure_low": 80,
"stress_level": 25,
"step_count": 8567,
"calories": 245.6,
"distance": 6.2,
"sleep_duration": 7.5,
"recorded_at": datetime.now().isoformat()
},
"quality_score": 95.2,
"device_status": "online"
}
# ============================================================================
# 用户和组织相关 API
# ============================================================================
@router.get("/users/list", summary="获取用户列表")
async def get_users_list(
org_id: str = Query(..., description="组织ID"),
current_user: dict = Depends(get_current_user)
):
"""获取用户列表"""
return {
"org_id": org_id,
"users": [
{
"id": "user_001",
"username": "zhangsan",
"realname": "张三",
"email": "zhangsan@example.com",
"phone": "13800138001",
"device_sn": "DEV001",
"status": "active",
"last_active": "2025-09-19T10:30:00"
},
{
"id": "user_002",
"username": "lisi",
"realname": "李四",
"email": "lisi@example.com",
"phone": "13800138002",
"device_sn": "DEV002",
"status": "active",
"last_active": "2025-09-19T09:45:00"
}
],
"total_count": 2
}
@router.get("/users/info", summary="获取用户信息")
async def get_user_info(
device_sn: str = Query(..., description="设备序列号"),
current_user: dict = Depends(get_current_user)
):
"""根据设备序列号获取用户信息"""
return {
"device_sn": device_sn,
"user_info": {
"id": current_user.get('id', 'mock_user'),
"username": current_user.get('username', 'mock_user'),
"realname": current_user.get('realname', '模拟用户'),
"email": current_user.get('email', 'mock@example.com'),
"phone": current_user.get('phone', '13800138000'),
"org_id": current_user.get('org_id', 'mock_org'),
"org_name": current_user.get('org_name', '模拟组织'),
"device_binding_time": "2025-09-01T08:00:00"
}
}
@router.get("/departments", summary="获取部门列表")
async def get_departments(
org_id: str = Query(..., description="组织ID"),
customer_id: str = Query(..., description="客户ID"),
current_user: dict = Depends(get_current_user)
):
"""获取部门列表"""
return {
"org_id": org_id,
"customer_id": customer_id,
"departments": [
{
"id": "dept_001",
"name": "技术部",
"parent_id": None,
"user_count": 25,
"device_count": 23,
"health_score_avg": 78.5
},
{
"id": "dept_002",
"name": "市场部",
"parent_id": None,
"user_count": 18,
"device_count": 16,
"health_score_avg": 82.1
},
{
"id": "dept_003",
"name": "人事部",
"parent_id": None,
"user_count": 12,
"device_count": 12,
"health_score_avg": 75.8
}
],
"total_count": 3
}
# ============================================================================
# 告警相关 API
# ============================================================================
@router.get("/alerts", summary="获取告警列表")
async def get_alerts(
org_id: Optional[str] = Query(None, description="组织ID"),
user_id: Optional[str] = Query(None, description="用户ID"),
customer_id: Optional[str] = Query(None, description="客户ID"),
severity_level: Optional[str] = Query(None, description="严重级别"),
current_user: dict = Depends(get_current_user)
):
"""获取告警列表"""
return {
"filters": {
"org_id": org_id,
"user_id": user_id,
"customer_id": customer_id,
"severity_level": severity_level
},
"alerts": [
{
"id": "alert_001",
"user_id": "user_001",
"device_sn": "DEV001",
"alert_type": "heart_rate_high",
"severity": "warning",
"message": "心率异常偏高 (105 bpm)",
"created_time": "2025-09-19T10:30:00",
"status": "active",
"acknowledged": False
},
{
"id": "alert_002",
"user_id": "user_002",
"device_sn": "DEV002",
"alert_type": "blood_oxygen_low",
"severity": "info",
"message": "血氧饱和度偏低 (92%)",
"created_time": "2025-09-19T08:15:00",
"status": "acknowledged",
"acknowledged": True
}
],
"total_count": 2,
"unread_count": 1
}
@router.get("/alerts/handle", summary="处理告警")
async def handle_alert(
alert_id: str = Query(..., description="告警ID"),
current_user: dict = Depends(get_current_user)
):
"""处理告警"""
return {
"alert_id": alert_id,
"action": "handled",
"handled_by": current_user.get('id', 'mock_user'),
"handled_at": datetime.now().isoformat(),
"status": "resolved"
}
@router.post("/alerts/acknowledge", summary="确认告警")
async def acknowledge_alert(
alert_data: Dict[str, Any],
current_user: dict = Depends(get_current_user)
):
"""确认告警"""
return {
"alert_id": alert_data.get('alert_id'),
"acknowledged": True,
"acknowledged_by": current_user.get('id', 'mock_user'),
"acknowledged_at": datetime.now().isoformat(),
"note": alert_data.get('note', '')
}
# ============================================================================
# 消息相关 API
# ============================================================================
@router.get("/messages", summary="获取消息列表")
async def get_messages(
org_id: Optional[str] = Query(None, description="组织ID"),
user_id: Optional[str] = Query(None, description="用户ID"),
customer_id: Optional[str] = Query(None, description="客户ID"),
message_type: Optional[str] = Query(None, description="消息类型"),
current_user: dict = Depends(get_current_user)
):
"""获取消息列表"""
return {
"filters": {
"org_id": org_id,
"user_id": user_id,
"customer_id": customer_id,
"message_type": message_type
},
"messages": [
{
"id": "msg_001",
"user_id": "user_001",
"type": "health_reminder",
"title": "健康提醒",
"content": "您今天的步数已达到目标,继续保持!",
"created_time": "2025-09-19T10:00:00",
"read": False
},
{
"id": "msg_002",
"user_id": "user_001",
"type": "system_notification",
"title": "系统通知",
"content": "您的设备固件已更新到最新版本",
"created_time": "2025-09-19T08:30:00",
"read": True
}
],
"total_count": 2,
"unread_count": 1
}
# ============================================================================
# 设备管理相关 API
# ============================================================================
@router.get("/devices", summary="获取设备列表")
async def get_devices(
org_id: Optional[str] = Query(None, description="组织ID"),
user_id: Optional[str] = Query(None, description="用户ID"),
customer_id: Optional[str] = Query(None, description="客户ID"),
current_user: dict = Depends(get_current_user)
):
"""获取设备列表"""
return {
"filters": {
"org_id": org_id,
"user_id": user_id,
"customer_id": customer_id
},
"devices": [
{
"device_sn": "DEV001",
"device_name": "智能手环 001",
"device_type": "smart_bracelet",
"user_id": "user_001",
"user_name": "张三",
"battery_level": 78,
"signal_strength": 89,
"status": "online",
"last_sync": "2025-09-19T10:25:00",
"firmware_version": "v2.1.5"
},
{
"device_sn": "DEV002",
"device_name": "智能手环 002",
"device_type": "smart_bracelet",
"user_id": "user_002",
"user_name": "李四",
"battery_level": 45,
"signal_strength": 76,
"status": "online",
"last_sync": "2025-09-19T10:20:00",
"firmware_version": "v2.1.4"
}
],
"total_count": 2,
"online_count": 2,
"offline_count": 0
}
# ============================================================================
# 健康基线相关 API
# ============================================================================
@router.post("/health/baseline/generate", summary="生成健康基线")
async def generate_health_baseline(
target_date: str,
current_user: dict = Depends(get_current_user)
):
"""生成健康基线"""
return {
"target_date": target_date,
"status": "success",
"message": "健康基线生成成功",
"baseline_id": f"baseline_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
"generated_at": datetime.now().isoformat(),
"records_processed": 1247
}
@router.get("/health/baseline/status", summary="获取健康基线状态")
async def get_health_baseline_status(
current_user: dict = Depends(get_current_user)
):
"""获取健康基线生成状态"""
return {
"status": "completed",
"last_generated": "2025-09-19T02:15:00",
"next_scheduled": "2025-09-20T02:15:00",
"records_count": 1247,
"coverage_rate": 94.2,
"quality_score": 98.7
}