feat: add system settings, audit log, device detail, dark mode, i18n, email notifications

System Management:
- System Settings page with 8 configurable parameters (admin only)
- Audit Log page with filterable table (user, action, resource, date range)
- Audit logging wired into auth, devices, users, alarms, reports API handlers
- SystemSetting model + migration (002)

Device Detail:
- Dedicated /devices/:id page with 4 tabs (realtime, historical trends, alarm history, device info)
- ECharts historical charts with granularity/time range selectors
- Device name clickable in Devices and Monitoring tables → navigates to detail

Email & Scheduling:
- Email service with SMTP support (STARTTLS/SSL/plain)
- Alarm email notification with professional HTML template
- Report scheduler using APScheduler for cron-based auto-generation
- Scheduled report task seeded (daily at 8am)

UI Enhancements:
- Dark mode toggle (persisted to localStorage, Ant Design darkAlgorithm)
- Data comparison view in Analysis page (dual date range, side-by-side metrics)
- i18n framework (i18next) with zh/en translations for menu and common UI
- Language switcher in header (中文/English)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Du Wenbo
2026-04-02 19:42:22 +08:00
parent 895af4caf9
commit ef9b5d055f
36 changed files with 2196 additions and 113 deletions

View File

@@ -14,7 +14,7 @@ from app.models.user import User, Role
from app.models.device import Device, DeviceType, DeviceGroup
from app.models.alarm import AlarmRule, AlarmEvent
from app.models.carbon import EmissionFactor
from app.models.report import ReportTemplate
from app.models.report import ReportTemplate, ReportTask
async def seed():
@@ -283,7 +283,8 @@ async def seed():
threshold=0.0,
duration=3600,
severity="critical",
notify_channels=["app", "sms", "wechat"],
notify_channels=["app", "sms", "wechat", "email"],
notify_targets={"emails": ["admin@tianpu.com", "energy@tianpu.com"]},
is_active=True,
),
AlarmRule(
@@ -294,7 +295,8 @@ async def seed():
threshold=38.0,
duration=300,
severity="critical",
notify_channels=["app", "sms"],
notify_channels=["app", "sms", "email"],
notify_targets={"emails": ["admin@tianpu.com"]},
is_active=True,
),
AlarmRule(
@@ -376,6 +378,24 @@ async def seed():
await session.flush()
# =====================================================================
# 8b. 定时报表任务 (daily report at 8am)
# =====================================================================
report_tasks = [
ReportTask(
template_id=1, # 日报模板
name="每日能源运行日报",
schedule="0 8 * * *",
recipients=["admin@tianpu.com"],
export_format="xlsx",
status="pending",
is_active=True,
created_by=1,
),
]
session.add_all(report_tasks)
await session.flush()
# =====================================================================
# 9. 历史告警事件 (15 events over last 7 days)
# =====================================================================
@@ -545,6 +565,7 @@ async def seed():
print(f" - {len(alarm_rules)} alarm rules")
print(f" - {len(factors)} emission factors")
print(f" - {len(templates)} report templates")
print(f" - {len(report_tasks)} report tasks (scheduled)")
print(f" - {len(alarm_events)} alarm events (historical)")
await engine.dispose()