910 lines
32 KiB
Python
910 lines
32 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 TABLE IF NOT EXISTS users (
|
||
id TEXT PRIMARY KEY,
|
||
name TEXT NOT NULL,
|
||
username TEXT UNIQUE NOT NULL,
|
||
password TEXT NOT NULL,
|
||
register_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
is_active BOOLEAN DEFAULT 0,
|
||
user_type TEXT DEFAULT 'user',
|
||
phone TEXT DEFAULT '',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
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)')
|
||
cursor.execute('CREATE INDEX IF NOT EXISTS idx_users_username ON users (username)')
|
||
cursor.execute('CREATE INDEX IF NOT EXISTS idx_users_type ON users (user_type)')
|
||
cursor.execute('CREATE INDEX IF NOT EXISTS idx_users_phone ON users (phone)')
|
||
|
||
# 插入默认管理员账户(如果不存在)
|
||
cursor.execute('SELECT COUNT(*) FROM users WHERE username = ?', ('admin',))
|
||
admin_exists = cursor.fetchone()[0]
|
||
|
||
if admin_exists == 0:
|
||
import hashlib
|
||
admin_id = str(uuid.uuid4())
|
||
# 默认密码为 admin123,使用MD5加密
|
||
admin_password = hashlib.md5('admin123'.encode()).hexdigest()
|
||
|
||
cursor.execute('''
|
||
INSERT INTO users (id, name, username, password, is_active, user_type)
|
||
VALUES (?, ?, ?, ?, ?, ?)
|
||
''', (admin_id, '系统管理员', 'admin', admin_password, 1, 'admin'))
|
||
|
||
logger.info('创建默认管理员账户: admin/admin123')
|
||
|
||
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 register_user(self, user_data: Dict[str, Any]) -> Dict[str, Any]:
|
||
"""用户注册"""
|
||
conn = self.get_connection()
|
||
cursor = conn.cursor()
|
||
|
||
try:
|
||
import hashlib
|
||
|
||
# 检查手机号是否已存在(如果提供了手机号)
|
||
if user_data.get('phone'):
|
||
cursor.execute('SELECT COUNT(*) FROM users WHERE phone = ?', (user_data['phone'],))
|
||
if cursor.fetchone()[0] > 0:
|
||
return {
|
||
'success': False,
|
||
'message': '手机号已存在'
|
||
}
|
||
|
||
user_id = str(uuid.uuid4())
|
||
# 密码MD5加密
|
||
password_hash = hashlib.md5(user_data['password'].encode()).hexdigest()
|
||
|
||
cursor.execute('''
|
||
INSERT INTO users (id, name, username, password, phone, is_active, user_type)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||
''', (
|
||
user_id,
|
||
user_data['name'],
|
||
user_data['username'],
|
||
password_hash,
|
||
user_data.get('phone'), # 手机号可选
|
||
0, # 新注册用户默认未激活,需要管理员审核
|
||
'user'
|
||
))
|
||
|
||
conn.commit()
|
||
logger.info(f'用户注册成功: {user_data["username"]}')
|
||
return {
|
||
'success': True,
|
||
'user_id': user_id,
|
||
'message': '注册成功'
|
||
}
|
||
|
||
except sqlite3.IntegrityError:
|
||
conn.rollback()
|
||
logger.error(f'用户名已存在: {user_data["username"]}')
|
||
return {
|
||
'success': False,
|
||
'message': '用户名已存在'
|
||
}
|
||
except Exception as e:
|
||
conn.rollback()
|
||
logger.error(f'用户注册失败: {e}')
|
||
return {
|
||
'success': False,
|
||
'message': '注册失败'
|
||
}
|
||
|
||
def authenticate_user(self, username: str, password: str) -> Optional[Dict]:
|
||
"""用户登录验证"""
|
||
conn = self.get_connection()
|
||
cursor = conn.cursor()
|
||
|
||
try:
|
||
import hashlib
|
||
|
||
password_hash = hashlib.md5(password.encode()).hexdigest()
|
||
|
||
cursor.execute('''
|
||
SELECT * FROM users
|
||
WHERE username = ? AND password = ? AND is_active = 1
|
||
''', (username, password_hash))
|
||
|
||
row = cursor.fetchone()
|
||
if row:
|
||
user = dict(row)
|
||
# 不返回密码
|
||
del user['password']
|
||
logger.info(f'用户登录成功: {username}')
|
||
return user
|
||
else:
|
||
logger.warning(f'用户登录失败: {username}')
|
||
return None
|
||
|
||
except Exception as e:
|
||
logger.error(f'用户验证失败: {e}')
|
||
return None
|
||
|
||
def get_user_by_phone(self, phone: str) -> Optional[Dict]:
|
||
"""根据手机号查询用户"""
|
||
conn = self.get_connection()
|
||
cursor = conn.cursor()
|
||
|
||
try:
|
||
cursor.execute('SELECT * FROM users WHERE phone = ?', (phone,))
|
||
row = cursor.fetchone()
|
||
if row:
|
||
user = dict(row)
|
||
# 不返回密码
|
||
del user['password']
|
||
return user
|
||
return None
|
||
except Exception as e:
|
||
logger.error(f'根据手机号查询用户失败: {e}')
|
||
return None
|
||
|
||
def get_users(self, page: int = 1, size: int = 10, status: str = 'all') -> List[Dict]:
|
||
"""获取用户列表"""
|
||
conn = self.get_connection()
|
||
cursor = conn.cursor()
|
||
|
||
try:
|
||
offset = (page - 1) * size
|
||
|
||
if status == 'pending':
|
||
cursor.execute('''
|
||
SELECT id, name, username, phone, register_date, is_active, user_type, created_at
|
||
FROM users
|
||
WHERE is_active = 0 AND user_type = 'user'
|
||
ORDER BY created_at DESC
|
||
LIMIT ? OFFSET ?
|
||
''', (size, offset))
|
||
elif status == 'active':
|
||
cursor.execute('''
|
||
SELECT id, name, username, phone, register_date, is_active, user_type, created_at
|
||
FROM users
|
||
WHERE is_active = 1
|
||
ORDER BY created_at DESC
|
||
LIMIT ? OFFSET ?
|
||
''', (size, offset))
|
||
else:
|
||
cursor.execute('''
|
||
SELECT id, name, username, phone, register_date, is_active, user_type, created_at
|
||
FROM users
|
||
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}')
|
||
return []
|
||
|
||
def get_users_count(self, status: str = 'all') -> int:
|
||
"""获取用户总数"""
|
||
conn = self.get_connection()
|
||
cursor = conn.cursor()
|
||
|
||
try:
|
||
if status == 'pending':
|
||
cursor.execute('SELECT COUNT(*) FROM users WHERE is_active = 0 AND user_type = "user"')
|
||
elif status == 'active':
|
||
cursor.execute('SELECT COUNT(*) FROM users WHERE is_active = 1')
|
||
else:
|
||
cursor.execute('SELECT COUNT(*) FROM users')
|
||
|
||
return cursor.fetchone()[0]
|
||
|
||
except Exception as e:
|
||
logger.error(f'获取用户总数失败: {e}')
|
||
return 0
|
||
|
||
def approve_user(self, user_id: str, approved: bool = True):
|
||
"""审核用户"""
|
||
conn = self.get_connection()
|
||
cursor = conn.cursor()
|
||
|
||
try:
|
||
cursor.execute('''
|
||
UPDATE users SET
|
||
is_active = ?,
|
||
updated_at = CURRENT_TIMESTAMP
|
||
WHERE id = ?
|
||
''', (1 if approved else 0, user_id))
|
||
|
||
conn.commit()
|
||
status = '通过' if approved else '拒绝'
|
||
logger.info(f'用户审核{status}: {user_id}')
|
||
|
||
except Exception as e:
|
||
conn.rollback()
|
||
logger.error(f'用户审核失败: {e}')
|
||
raise
|
||
|
||
def get_user(self, user_id: str) -> Optional[Dict]:
|
||
"""获取单个用户信息"""
|
||
conn = self.get_connection()
|
||
cursor = conn.cursor()
|
||
|
||
try:
|
||
cursor.execute('''
|
||
SELECT id, name, username, phone, register_date, is_active, user_type, created_at, updated_at
|
||
FROM users WHERE id = ?
|
||
''', (user_id,))
|
||
|
||
row = cursor.fetchone()
|
||
return dict(row) if row else None
|
||
|
||
except Exception as e:
|
||
logger.error(f'获取用户信息失败: {e}')
|
||
return None
|
||
|
||
def update_user(self, user_id: str, user_data: Dict[str, Any]):
|
||
"""更新用户信息"""
|
||
conn = self.get_connection()
|
||
cursor = conn.cursor()
|
||
|
||
try:
|
||
# 如果包含密码,需要加密
|
||
if 'password' in user_data:
|
||
import hashlib
|
||
user_data['password'] = hashlib.md5(user_data['password'].encode()).hexdigest()
|
||
|
||
# 构建更新语句
|
||
fields = []
|
||
values = []
|
||
|
||
for key, value in user_data.items():
|
||
if key in ['name', 'username', 'password', 'is_active', 'user_type','phone']:
|
||
fields.append(f'{key} = ?')
|
||
values.append(value)
|
||
|
||
if fields:
|
||
fields.append('updated_at = CURRENT_TIMESTAMP')
|
||
values.append(user_id)
|
||
|
||
sql = f'UPDATE users SET {', '.join(fields)} WHERE id = ?'
|
||
cursor.execute(sql, values)
|
||
|
||
conn.commit()
|
||
logger.info(f'更新用户信息: {user_id}')
|
||
|
||
except Exception as e:
|
||
conn.rollback()
|
||
logger.error(f'更新用户信息失败: {e}')
|
||
raise
|
||
|
||
def delete_user(self, user_id: str):
|
||
"""删除用户"""
|
||
conn = self.get_connection()
|
||
cursor = conn.cursor()
|
||
|
||
try:
|
||
cursor.execute('DELETE FROM users WHERE id = ?', (user_id,))
|
||
conn.commit()
|
||
logger.info(f'删除用户: {user_id}')
|
||
|
||
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('数据库连接已关闭') |