bf57aed17a
- git mv sanguo_web → _retired/sanguo_web/(git 历史保全+墓碑 README:
归档原因/拍板记录/现役=sanguo_api)
- 退出启动面三处: promote.sh ALL_MODS 白名单(15→14 模块)+docker/Dockerfile:63
COPY+docker/Dockerfile.nas:16 COPY——不可再被部署或启动为服务
- 背景(架构审计 P0-3): 硬编码 SECRET_KEY/admin123 默认口令/CORS 全开/可下
真实订单/零测试/与 sanguo_api 路由冲突; 生产从未部署为服务, 纯误启动风险
(README 旧「生产模式 uvicorn sanguo_web」指引已于 f6ca85e 勘误)
- three-env §3.1 模块清单+§12 矩阵行同步; session-guide §5 角色表前端行
勘误(旧表把 sanguo_web 当前端模块推——实为 legacy 后端, 前端=frontend/)
- 零外部 import(runuweb/tests/packages 全 grep 实证), pytest testpaths=tests
不受影响
Co-Authored-By: Claude Code <notify@anthropic.com>
174 lines
4.5 KiB
Python
174 lines
4.5 KiB
Python
"""
|
|
数据库模型定义
|
|
使用 SQLAlchemy ORM 定义数据表结构
|
|
"""
|
|
from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, Boolean, Text
|
|
from sqlalchemy.ext.declarative import declarative_base
|
|
from sqlalchemy.orm import sessionmaker, Session
|
|
from datetime import datetime
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# 声明基类
|
|
Base = declarative_base()
|
|
|
|
|
|
# ============================================
|
|
# 用户表
|
|
# ============================================
|
|
|
|
class User(Base):
|
|
"""用户表"""
|
|
__tablename__ = "users"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
username = Column(String(50), unique=True, index=True, nullable=False)
|
|
hashed_password = Column(String(200), nullable=False)
|
|
email = Column(String(100), unique=True, index=True)
|
|
full_name = Column(String(100))
|
|
is_active = Column(Boolean, default=True)
|
|
is_superuser = Column(Boolean, default=False)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
|
|
# ============================================
|
|
# API Token 表
|
|
# ============================================
|
|
|
|
class APIToken(Base):
|
|
"""API Token 表"""
|
|
__tablename__ = "api_tokens"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
user_id = Column(Integer, nullable=False)
|
|
token = Column(String(200), unique=True, index=True, nullable=False)
|
|
name = Column(String(100))
|
|
is_active = Column(Boolean, default=True)
|
|
expires_at = Column(DateTime)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
|
|
# ============================================
|
|
# 交易日志表
|
|
# ============================================
|
|
|
|
class TradeLog(Base):
|
|
"""交易日志表"""
|
|
__tablename__ = "trade_logs"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
order_id = Column(String(50), index=True)
|
|
symbol = Column(String(20), index=True)
|
|
exchange = Column(String(20))
|
|
direction = Column(String(10))
|
|
order_type = Column(String(20))
|
|
volume = Column(Float)
|
|
price = Column(Float)
|
|
traded_volume = Column(Float)
|
|
traded_price = Column(Float)
|
|
status = Column(String(20), index=True)
|
|
time = Column(DateTime, index=True)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
|
|
# ============================================
|
|
# 策略日志表
|
|
# ============================================
|
|
|
|
class StrategyLog(Base):
|
|
"""策略日志表"""
|
|
__tablename__ = "strategy_logs"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
strategy_name = Column(String(50), index=True)
|
|
level = Column(String(20)) # INFO, WARNING, ERROR
|
|
message = Column(Text)
|
|
created_at = Column(DateTime, default=datetime.utcnow, index=True)
|
|
|
|
|
|
# ============================================
|
|
# 系统配置表
|
|
# ============================================
|
|
|
|
class SystemConfig(Base):
|
|
"""系统配置表"""
|
|
__tablename__ = "system_configs"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
key = Column(String(100), unique=True, index=True, nullable=False)
|
|
value = Column(Text)
|
|
description = Column(String(200))
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
|
|
# ============================================
|
|
# 数据库初始化
|
|
# ============================================
|
|
|
|
# 全局数据库引擎和会话
|
|
_engine = None
|
|
_SessionLocal = None
|
|
|
|
|
|
def init_database(database_url: str = "sqlite:///sanguo_web.db") -> None:
|
|
"""
|
|
初始化数据库
|
|
|
|
- **database_url**: 数据库连接字符串
|
|
"""
|
|
global _engine, _SessionLocal
|
|
|
|
logger.info(f"Initializing database: {database_url}")
|
|
|
|
_engine = create_engine(
|
|
database_url,
|
|
connect_args={"check_same_thread": False} if database_url.startswith("sqlite") else {},
|
|
echo=False
|
|
)
|
|
|
|
_SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=_engine)
|
|
|
|
# 创建所有表
|
|
Base.metadata.create_all(bind=_engine)
|
|
|
|
logger.info("Database initialized successfully")
|
|
|
|
|
|
def get_db() -> Session:
|
|
"""
|
|
获取数据库会话
|
|
|
|
用于依赖注入
|
|
"""
|
|
global _SessionLocal
|
|
|
|
if _SessionLocal is None:
|
|
init_database()
|
|
|
|
db = _SessionLocal()
|
|
try:
|
|
yield db
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def get_engine():
|
|
"""获取数据库引擎"""
|
|
if _engine is None:
|
|
init_database()
|
|
return _engine
|
|
|
|
|
|
__all__ = [
|
|
"User",
|
|
"APIToken",
|
|
"TradeLog",
|
|
"StrategyLog",
|
|
"SystemConfig",
|
|
"init_database",
|
|
"get_db",
|
|
"get_engine",
|
|
]
|