stock-monitor/app/dao/config_dao.py
ycg 569c1c8813 重构股票监控系统:数据库架构升级与功能完善
- 重构数据访问层:引入DAO模式,支持MySQL/SQLite双数据库
- 新增数据库架构:完整的股票数据、AI分析、自选股管理表结构
- 升级AI分析服务:集成豆包大模型,支持多维度分析
- 优化API路由:分离市场数据API,提供更清晰的接口设计
- 完善项目文档:添加数据库迁移指南、新功能指南等
- 清理冗余文件:删除旧的缓存文件和无用配置
- 新增调度器:支持定时任务和数据自动更新
- 改进前端模板:简化的股票展示页面

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 15:44:25 +08:00

171 lines
6.2 KiB
Python

"""
系统配置数据访问对象
"""
from typing import Dict, List, Optional, Any
import json
from datetime import datetime, date
from .base_dao import BaseDAO
class ConfigDAO(BaseDAO):
"""系统配置数据访问对象"""
def get_config(self, key: str, default_value: Any = None) -> Any:
"""获取配置值"""
query = "SELECT config_value, config_type FROM system_config WHERE config_key = %s"
result = self._execute_single_query(query, (key,))
if not result:
return default_value
config_value = result['config_value']
config_type = result['config_type']
# 根据类型转换值
if config_type == 'integer':
try:
return int(config_value) if config_value else default_value
except (ValueError, TypeError):
return default_value
elif config_type == 'float':
try:
return float(config_value) if config_value else default_value
except (ValueError, TypeError):
return default_value
elif config_type == 'boolean':
return config_value.lower() in ('true', '1', 'yes', 'on') if config_value else default_value
elif config_type == 'json':
try:
return json.loads(config_value) if config_value else default_value
except json.JSONDecodeError:
return default_value
else: # string
return config_value if config_value else default_value
def set_config(self, key: str, value: Any, config_type: str = 'string') -> bool:
"""设置配置值"""
try:
# 转换值为字符串存储
if config_type == 'json':
str_value = json.dumps(value, ensure_ascii=False)
elif config_type == 'boolean':
str_value = str(value).lower()
else:
str_value = str(value)
# 检查配置是否存在
existing = self._execute_single_query(
"SELECT id FROM system_config WHERE config_key = %s", (key,)
)
if existing:
# 更新现有配置
query = """
UPDATE system_config
SET config_value = %s, config_type = %s, updated_at = CURRENT_TIMESTAMP
WHERE config_key = %s
"""
self._execute_update(query, (str_value, config_type, key))
else:
# 插入新配置
query = """
INSERT INTO system_config (config_key, config_value, config_type)
VALUES (%s, %s, %s)
"""
self._execute_insert(query, (key, str_value, config_type))
self.log_data_update('config', key, 'success', f'Config updated: {key}={value}')
return True
except Exception as e:
self.logger.error(f"设置配置失败: {key}={value}, 错误: {e}")
self.log_data_update('config', key, 'failed', str(e))
return False
def get_all_configs(self) -> Dict[str, Dict]:
"""获取所有配置"""
query = "SELECT * FROM system_config ORDER BY config_key"
results = self._execute_query(query)
configs = {}
for result in results:
key = result['config_key']
configs[key] = {
'value': self.get_config(key),
'type': result['config_type'],
'created_at': result['created_at'],
'updated_at': result['updated_at']
}
return configs
def delete_config(self, key: str) -> bool:
"""删除配置"""
try:
query = "DELETE FROM system_config WHERE config_key = %s"
affected_rows = self._execute_update(query, (key,))
success = affected_rows > 0
if success:
self.log_data_update('config', key, 'success', 'Config deleted')
else:
self.log_data_update('config', key, 'failed', 'Config not found')
return success
except Exception as e:
self.logger.error(f"删除配置失败: {key}, 错误: {e}")
self.log_data_update('config', key, 'failed', str(e))
return False
def increment_counter(self, key: str, increment: int = 1) -> int:
"""递增计数器配置"""
try:
current_value = self.get_config(key, 0)
new_value = current_value + increment
self.set_config(key, new_value, 'integer')
return new_value
except Exception as e:
self.logger.error(f"递增计数器失败: {key}, 错误: {e}")
return 0
def reset_daily_counters(self) -> None:
"""重置每日计数器"""
daily_counters = [
'tushare_api_calls_today',
]
for counter in daily_counters:
self.set_config(counter, 0, 'integer')
# 更新最后重置日期
self.set_config('last_counter_reset_date', self.get_today_date(), 'date')
def get_last_data_update_date(self) -> Optional[str]:
"""获取最后数据更新日期"""
return self.get_config('last_data_update_date')
def set_last_data_update_date(self, date_str: str) -> bool:
"""设置最后数据更新日期"""
return self.set_config('last_data_update_date', date_str, 'date')
def get_cache_expiration_hours(self) -> int:
"""获取缓存过期时间(小时)"""
return self.get_config('cache_expiration_hours', 24)
def get_max_watchlist_size(self) -> int:
"""获取最大监控列表大小"""
return self.get_config('max_watchlist_size', 50)
def is_cache_expired(self, data_date: str) -> bool:
"""检查缓存是否过期"""
try:
cache_hours = self.get_cache_expiration_hours()
current_date = date.today()
data_date_obj = datetime.strptime(data_date, '%Y-%m-%d').date()
days_diff = (current_date - data_date_obj).days
return days_diff > 0 # 如果不是今天的数据,就算过期
except Exception:
return True # 如果无法解析日期,认为过期