feat: switch to MySQL, add Chinese comments, health check, and technical docs

1. 数据源切换至 MySQL:
   - app.py 从 SQLite 切换到 PyMySQL,所有 API 读取 MySQL weread_dashboard 数据库
   - 新增 db_required 装饰器统一管理数据库连接和异常处理
   - 新增 /api/health 健康检查接口,检测 MySQL 连接状态
   - MySQL 连接失败时返回 HTTP 503 和告警信息
   - 修复 fetched_at 字段 Unix 时间戳到 MySQL TIMESTAMP 的兼容问题

2. 前端数据库连接告警:
   - 页面加载时优先调用 /api/health 检查 MySQL 连接
   - 连接失败时显示固定告警横幅,阻止后续数据加载
   - CSS 告警横幅样式(黄色背景、下滑动画)

3. 代码中文注释:
   - app.py:所有函数、API 接口、工具函数添加完整中文文档注释
   - fetch_data.py:所有 SQLite 建表语句添加列级中文注释
   - migrate_to_mysql.py:保留已有中文注释

4. 技术文档与元数据文档:
   - docs/TECHNICAL_DOC.md:项目概述、系统架构、API 设计、部署指南
   - docs/METADATA_DOC.md:18 张表完整字段说明、索引、表关系、数据类型规范
This commit is contained in:
admin committed 2026-07-17 10:26:07 +08:00
1 parent 72e9971a69
commit 507b9c5704
8 files changed
+1805 -436

No files matched your search

+44
View File
@@ -8,6 +8,9 @@
--text-light: #9b8e80;
--accent: #c17b4a;
--accent-light: #e8a87c;
--alert-bg: #fff3cd;
--alert-border: #ffc107;
--alert-text: #856404;
--accent-dark: #a05c2c;
--border: #e8e0d4;
--shadow: 0 2px 12px rgba(44, 36, 22, 0.08);
@@ -657,6 +660,47 @@ body {
opacity: 0.7;
}
/* ===== 数据库连接告警横幅 ===== */
.db-alert-banner {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 9999;
display: flex;
align-items: center;
gap: 10px;
padding: 12px 24px;
background: var(--alert-bg);
border-bottom: 2px solid var(--alert-border);
color: var(--alert-text);
font-size: 14px;
font-weight: 500;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
animation: slideDown 0.3s ease-out;
}
.db-alert-icon {
font-size: 20px;
}
.db-alert-text {
flex-shrink: 0;
}
.db-alert-detail {
font-size: 12px;
opacity: 0.8;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@keyframes slideDown {
from { transform: translateY(-100%); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
/* ===== 加载动画 ===== */
.loading {
display: flex;
+45 -1
View File
@@ -14,8 +14,52 @@ function formatHours(seconds) {
return (seconds / 3600).toFixed(1);
}
// ===== 数据库健康检查 =====
/**
* 页面加载时检查 MySQL 数据库连接状态。
* 如果连接失败,显示告警横幅并阻止后续数据加载。
*/
async function checkDBHealth() {
try {
const resp = await fetch(API_BASE + "/api/health");
const data = await resp.json();
if (resp.ok && data.database === "connected") {
// 数据库连接正常,隐藏告警横幅
document.getElementById("dbAlertBanner").style.display = "none";
return true;
} else {
// 数据库连接异常,显示告警横幅
showDBAlert(data.message || "数据库连接失败");
return false;
}
} catch (error) {
// 健康检查接口本身无法访问
showDBAlert("无法连接到服务器,请检查后端服务是否运行。");
return false;
}
}
/**
* 显示数据库连接告警横幅。
* @param {string} message - 告警详情信息
*/
function showDBAlert(message) {
const banner = document.getElementById("dbAlertBanner");
const detail = document.getElementById("dbAlertDetail");
if (banner) banner.style.display = "flex";
if (detail) detail.textContent = message;
}
// ===== 初始化 =====
document.addEventListener("DOMContentLoaded", () => {
document.addEventListener("DOMContentLoaded", async () => {
// 首先检查数据库连接状态
const isHealthy = await checkDBHealth();
if (!isHealthy) {
// 数据库连接失败,不加载后续数据
return;
}
// 数据库连接正常,加载所有数据模块
loadOverview();
loadYearlyTrend();
loadTimeDistribution();