BodyBalanceEvaluation/backend/database.py
2025-07-28 11:59:56 +08:00

618 lines
21 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据库管理模块
负责SQLite数据库的创建、连接和数据操作
"""
import sqlite3
import json
import uuid
from datetime import datetime
from typing import List, Dict, Optional, Any
import logging
logger = logging.getLogger(__name__)
class DatabaseManager:
"""数据库管理器"""
def __init__(self, db_path: str):
self.db_path = db_path
self.connection = None
def get_connection(self) -> sqlite3.Connection:
"""获取数据库连接"""
if not self.connection:
self.connection = sqlite3.connect(
self.db_path,
check_same_thread=False,
timeout=30.0
)
self.connection.row_factory = sqlite3.Row
return self.connection
def init_database(self):
"""初始化数据库表结构"""
conn = self.get_connection()
cursor = conn.cursor()
try:
# 创建患者表
cursor.execute('''
CREATE TABLE IF NOT EXISTS patients (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
gender TEXT,
age INTEGER,
height REAL,
weight REAL,
phone TEXT,
medical_history TEXT,
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
# 创建检测会话表
cursor.execute('''
CREATE TABLE IF NOT EXISTS detection_sessions (
id TEXT PRIMARY KEY,
patient_id TEXT NOT NULL,
start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
end_time TIMESTAMP,
duration INTEGER,
frequency INTEGER,
status TEXT DEFAULT 'created',
settings TEXT,
data_points INTEGER DEFAULT 0,
video_path TEXT,
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (patient_id) REFERENCES patients (id)
)
''')
# 创建检测数据表
cursor.execute('''
CREATE TABLE IF NOT EXISTS detection_data (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
data_type TEXT NOT NULL,
data_value TEXT NOT NULL,
FOREIGN KEY (session_id) REFERENCES detection_sessions (id)
)
''')
# 创建分析结果表
cursor.execute('''
CREATE TABLE IF NOT EXISTS analysis_results (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
analysis_type TEXT NOT NULL,
result_data TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (session_id) REFERENCES detection_sessions (id)
)
''')
# 创建系统设置表
cursor.execute('''
CREATE TABLE IF NOT EXISTS system_settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
description TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
# 创建索引
cursor.execute('CREATE INDEX IF NOT EXISTS idx_patients_name ON patients (name)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_sessions_patient ON detection_sessions (patient_id)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_sessions_time ON detection_sessions (start_time)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_data_session ON detection_data (session_id)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_data_timestamp ON detection_data (timestamp)')
conn.commit()
logger.info('数据库初始化完成')
except Exception as e:
conn.rollback()
logger.error(f'数据库初始化失败: {e}')
raise
# ==================== 患者管理 ====================
def create_patient(self, patient_data: Dict[str, Any]) -> str:
"""创建患者记录"""
conn = self.get_connection()
cursor = conn.cursor()
try:
patient_id = str(uuid.uuid4())
cursor.execute('''
INSERT INTO patients (
id, name, gender, age, height, weight,
phone, medical_history, notes
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
patient_id,
patient_data.get('name'),
patient_data.get('gender'),
patient_data.get('age'),
patient_data.get('height'),
patient_data.get('weight'),
patient_data.get('phone'),
patient_data.get('medical_history'),
patient_data.get('notes')
))
conn.commit()
logger.info(f'创建患者记录: {patient_id}')
return patient_id
except Exception as e:
conn.rollback()
logger.error(f'创建患者记录失败: {e}')
raise
def get_patients(self, page: int = 1, size: int = 10, keyword: str = '') -> List[Dict]:
"""获取患者列表"""
conn = self.get_connection()
cursor = conn.cursor()
try:
offset = (page - 1) * size
if keyword:
cursor.execute('''
SELECT * FROM patients
WHERE name LIKE ? OR phone LIKE ?
ORDER BY created_at DESC
LIMIT ? OFFSET ?
''', (f'%{keyword}%', f'%{keyword}%', size, offset))
else:
cursor.execute('''
SELECT * FROM patients
ORDER BY created_at DESC
LIMIT ? OFFSET ?
''', (size, offset))
rows = cursor.fetchall()
return [dict(row) for row in rows]
except Exception as e:
logger.error(f'获取患者列表失败: {e}')
raise
def get_patients_count(self, keyword: str = '') -> int:
"""获取患者总数"""
conn = self.get_connection()
cursor = conn.cursor()
try:
if keyword:
cursor.execute('''
SELECT COUNT(*) FROM patients
WHERE name LIKE ? OR phone LIKE ?
''', (f'%{keyword}%', f'%{keyword}%'))
else:
cursor.execute('SELECT COUNT(*) FROM patients')
return cursor.fetchone()[0]
except Exception as e:
logger.error(f'获取患者总数失败: {e}')
return 0
def get_patient(self, patient_id: str) -> Optional[Dict]:
"""获取单个患者信息"""
conn = self.get_connection()
cursor = conn.cursor()
try:
cursor.execute('SELECT * FROM patients WHERE id = ?', (patient_id,))
row = cursor.fetchone()
return dict(row) if row else None
except Exception as e:
logger.error(f'获取患者信息失败: {e}')
return None
def update_patient(self, patient_id: str, patient_data: Dict[str, Any]):
"""更新患者信息"""
conn = self.get_connection()
cursor = conn.cursor()
try:
cursor.execute('''
UPDATE patients SET
name = ?, gender = ?, age = ?, height = ?, weight = ?,
phone = ?, medical_history = ?, notes = ?,
updated_at = CURRENT_TIMESTAMP
WHERE id = ?
''', (
patient_data.get('name'),
patient_data.get('gender'),
patient_data.get('age'),
patient_data.get('height'),
patient_data.get('weight'),
patient_data.get('phone'),
patient_data.get('medical_history'),
patient_data.get('notes'),
patient_id
))
conn.commit()
logger.info(f'更新患者信息: {patient_id}')
except Exception as e:
conn.rollback()
logger.error(f'更新患者信息失败: {e}')
raise
def delete_patient(self, patient_id: str):
"""删除患者记录"""
conn = self.get_connection()
cursor = conn.cursor()
try:
# 删除相关的检测数据
cursor.execute('''
DELETE FROM detection_data
WHERE session_id IN (
SELECT id FROM detection_sessions WHERE patient_id = ?
)
''', (patient_id,))
# 删除相关的分析结果
cursor.execute('''
DELETE FROM analysis_results
WHERE session_id IN (
SELECT id FROM detection_sessions WHERE patient_id = ?
)
''', (patient_id,))
# 删除检测会话
cursor.execute('DELETE FROM detection_sessions WHERE patient_id = ?', (patient_id,))
# 删除患者记录
cursor.execute('DELETE FROM patients WHERE id = ?', (patient_id,))
conn.commit()
logger.info(f'删除患者记录: {patient_id}')
except Exception as e:
conn.rollback()
logger.error(f'删除患者记录失败: {e}')
raise
# ==================== 检测会话管理 ====================
def create_detection_session(self, patient_id: str, settings: Dict[str, Any]) -> str:
"""创建检测会话"""
conn = self.get_connection()
cursor = conn.cursor()
try:
session_id = str(uuid.uuid4())
cursor.execute('''
INSERT INTO detection_sessions (
id, patient_id, duration, frequency, settings, status
) VALUES (?, ?, ?, ?, ?, ?)
''', (
session_id,
patient_id,
settings.get('duration', 60),
settings.get('frequency', 60),
json.dumps(settings),
'created'
))
conn.commit()
logger.info(f'创建检测会话: {session_id}')
return session_id
except Exception as e:
conn.rollback()
logger.error(f'创建检测会话失败: {e}')
raise
def update_session_status(self, session_id: str, status: str, data_points: int = 0):
"""更新会话状态"""
conn = self.get_connection()
cursor = conn.cursor()
try:
if status in ['completed', 'stopped', 'error']:
cursor.execute('''
UPDATE detection_sessions SET
status = ?, data_points = ?, end_time = CURRENT_TIMESTAMP
WHERE id = ?
''', (status, data_points, session_id))
else:
cursor.execute('''
UPDATE detection_sessions SET
status = ?, data_points = ?
WHERE id = ?
''', (status, data_points, session_id))
conn.commit()
logger.info(f'更新会话状态: {session_id} -> {status}')
except Exception as e:
conn.rollback()
logger.error(f'更新会话状态失败: {e}')
raise
def get_detection_sessions(self, page: int = 1, size: int = 10, patient_id: str = None) -> List[Dict]:
"""获取检测会话列表"""
conn = self.get_connection()
cursor = conn.cursor()
try:
offset = (page - 1) * size
if patient_id:
cursor.execute('''
SELECT s.*, p.name as patient_name
FROM detection_sessions s
LEFT JOIN patients p ON s.patient_id = p.id
WHERE s.patient_id = ?
ORDER BY s.start_time DESC
LIMIT ? OFFSET ?
''', (patient_id, size, offset))
else:
cursor.execute('''
SELECT s.*, p.name as patient_name
FROM detection_sessions s
LEFT JOIN patients p ON s.patient_id = p.id
ORDER BY s.start_time DESC
LIMIT ? OFFSET ?
''', (size, offset))
rows = cursor.fetchall()
sessions = []
for row in rows:
session = dict(row)
# 解析设置JSON
if session['settings']:
try:
session['settings'] = json.loads(session['settings'])
except:
session['settings'] = {}
sessions.append(session)
return sessions
except Exception as e:
logger.error(f'获取检测会话列表失败: {e}')
raise
def get_sessions_count(self, patient_id: str = None) -> int:
"""获取会话总数"""
conn = self.get_connection()
cursor = conn.cursor()
try:
if patient_id:
cursor.execute('SELECT COUNT(*) FROM detection_sessions WHERE patient_id = ?', (patient_id,))
else:
cursor.execute('SELECT COUNT(*) FROM detection_sessions')
return cursor.fetchone()[0]
except Exception as e:
logger.error(f'获取会话总数失败: {e}')
return 0
def get_session_data(self, session_id: str) -> Optional[Dict]:
"""获取会话详细数据"""
conn = self.get_connection()
cursor = conn.cursor()
try:
# 获取会话基本信息
cursor.execute('''
SELECT s.*, p.name as patient_name
FROM detection_sessions s
LEFT JOIN patients p ON s.patient_id = p.id
WHERE s.id = ?
''', (session_id,))
session_row = cursor.fetchone()
if not session_row:
return None
session = dict(session_row)
# 解析设置JSON
if session['settings']:
try:
session['settings'] = json.loads(session['settings'])
except:
session['settings'] = {}
# 获取检测数据
cursor.execute('''
SELECT * FROM detection_data
WHERE session_id = ?
ORDER BY timestamp
''', (session_id,))
data_rows = cursor.fetchall()
session['data'] = []
for row in data_rows:
data_point = dict(row)
# 解析数据JSON
try:
data_point['data_value'] = json.loads(data_point['data_value'])
except:
pass
session['data'].append(data_point)
return session
except Exception as e:
logger.error(f'获取会话数据失败: {e}')
return None
# ==================== 检测数据管理 ====================
def save_detection_data(self, session_id: str, data: Dict[str, Any]):
"""保存检测数据"""
conn = self.get_connection()
cursor = conn.cursor()
try:
# 保存不同类型的数据
for data_type, data_value in data.items():
cursor.execute('''
INSERT INTO detection_data (session_id, data_type, data_value)
VALUES (?, ?, ?)
''', (session_id, data_type, json.dumps(data_value)))
conn.commit()
except Exception as e:
conn.rollback()
logger.error(f'保存检测数据失败: {e}')
raise
def get_latest_detection_data(self, session_id: str, limit: int = 10) -> List[Dict]:
"""获取最新的检测数据"""
conn = self.get_connection()
cursor = conn.cursor()
try:
cursor.execute('''
SELECT * FROM detection_data
WHERE session_id = ?
ORDER BY timestamp DESC
LIMIT ?
''', (session_id, limit))
rows = cursor.fetchall()
data_points = []
for row in rows:
data_point = dict(row)
try:
data_point['data_value'] = json.loads(data_point['data_value'])
except:
pass
data_points.append(data_point)
return data_points
except Exception as e:
logger.error(f'获取最新检测数据失败: {e}')
return []
# ==================== 分析结果管理 ====================
def save_analysis_result(self, session_id: str, analysis_result: Dict[str, Any]):
"""保存分析结果"""
conn = self.get_connection()
cursor = conn.cursor()
try:
for analysis_type, result_data in analysis_result.items():
cursor.execute('''
INSERT INTO analysis_results (session_id, analysis_type, result_data)
VALUES (?, ?, ?)
''', (session_id, analysis_type, json.dumps(result_data)))
conn.commit()
logger.info(f'保存分析结果: {session_id}')
except Exception as e:
conn.rollback()
logger.error(f'保存分析结果失败: {e}')
raise
def get_analysis_results(self, session_id: str) -> Dict[str, Any]:
"""获取分析结果"""
conn = self.get_connection()
cursor = conn.cursor()
try:
cursor.execute('''
SELECT * FROM analysis_results
WHERE session_id = ?
ORDER BY created_at DESC
''', (session_id,))
rows = cursor.fetchall()
results = {}
for row in rows:
analysis_type = row['analysis_type']
try:
result_data = json.loads(row['result_data'])
results[analysis_type] = result_data
except:
results[analysis_type] = row['result_data']
return results
except Exception as e:
logger.error(f'获取分析结果失败: {e}')
return {}
# ==================== 系统设置管理 ====================
def get_setting(self, key: str, default_value: Any = None) -> Any:
"""获取系统设置"""
conn = self.get_connection()
cursor = conn.cursor()
try:
cursor.execute('SELECT value FROM system_settings WHERE key = ?', (key,))
row = cursor.fetchone()
if row:
try:
return json.loads(row['value'])
except:
return row['value']
return default_value
except Exception as e:
logger.error(f'获取系统设置失败: {e}')
return default_value
def set_setting(self, key: str, value: Any, description: str = ''):
"""设置系统设置"""
conn = self.get_connection()
cursor = conn.cursor()
try:
value_str = json.dumps(value) if not isinstance(value, str) else value
cursor.execute('''
INSERT OR REPLACE INTO system_settings (key, value, description, updated_at)
VALUES (?, ?, ?, CURRENT_TIMESTAMP)
''', (key, value_str, description))
conn.commit()
logger.info(f'设置系统设置: {key}')
except Exception as e:
conn.rollback()
logger.error(f'设置系统设置失败: {e}')
raise
def close(self):
"""关闭数据库连接"""
if self.connection:
self.connection.close()
self.connection = None
logger.info('数据库连接已关闭')