初始化

This commit is contained in:
zg
2026-07-15 16:08:17 +08:00
parent f0d70aded4
commit 4e0057ece5
89 changed files with 13512 additions and 0 deletions

135
backend/models.py Normal file
View File

@@ -0,0 +1,135 @@
"""SQLAlchemy 数据模型"""
from datetime import datetime
from sqlalchemy import (
create_engine, Column, Integer, String, Text, DateTime, LargeBinary,
Enum as SAEnum, ForeignKey, Table
)
from sqlalchemy.orm import declarative_base, relationship, sessionmaker
from config import get_db_url
engine = create_engine(get_db_url(), echo=False, pool_pre_ping=True)
SessionLocal = sessionmaker(bind=engine, autocommit=False)
Base = declarative_base()
def get_db():
"""获取数据库会话FastAPI 依赖注入)"""
db = SessionLocal()
try:
yield db
finally:
db.close()
# ===== 文件夹 =====
class Folder(Base):
"""文件夹表 — 笔记和网站共用"""
__tablename__ = "folders"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100), nullable=False)
type = Column(SAEnum("note", "website", name="folder_type"), nullable=False, default="note")
parent_id = Column(Integer, ForeignKey("folders.id"), nullable=True)
sort_order = Column(Integer, default=0)
created_by = Column(String(100), nullable=False, default="admin")
created_at = Column(DateTime, default=datetime.utcnow)
children = relationship("Folder", backref="parent", remote_side=[id])
notes = relationship("Note", back_populates="folder", cascade="all, delete-orphan")
websites = relationship("Website", back_populates="folder", cascade="all, delete-orphan")
# ===== 笔记 =====
class Note(Base):
"""笔记表"""
__tablename__ = "notes"
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(500), nullable=False, default="无标题")
content = Column(Text, nullable=True) # Tiptap 输出的 HTML
folder_id = Column(Integer, ForeignKey("folders.id"), nullable=True)
created_by = Column(String(100), nullable=False, default="admin")
updated_by = Column(String(100), nullable=False, default="admin")
share_token = Column(String(64), nullable=True, unique=True)
share_expires_at = Column(DateTime, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
folder = relationship("Folder", back_populates="notes")
tags = relationship("Tag", secondary="note_tags", back_populates="notes")
# ===== 笔记-标签关联 =====
note_tags = Table(
"note_tags",
Base.metadata,
Column("note_id", Integer, ForeignKey("notes.id", ondelete="CASCADE"), primary_key=True),
Column("tag_id", Integer, ForeignKey("tags.id", ondelete="CASCADE"), primary_key=True),
)
# ===== 标签 =====
class Tag(Base):
"""标签表"""
__tablename__ = "tags"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False, unique=True)
color = Column(String(20), default="#666666")
notes = relationship("Note", secondary="note_tags", back_populates="tags")
# ===== 网站 =====
class Website(Base):
"""网站表"""
__tablename__ = "websites"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(200), nullable=False)
url = Column(String(500), nullable=False)
folder_id = Column(Integer, ForeignKey("folders.id"), nullable=True)
created_by = Column(String(100), nullable=False, default="admin")
updated_by = Column(String(100), nullable=False, default="admin")
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
folder = relationship("Folder", back_populates="websites")
accounts = relationship("Account", back_populates="website", cascade="all, delete-orphan",
order_by="Account.sort_order")
# ===== 账号 =====
class Account(Base):
"""账号表 — 存储网站登录凭据"""
__tablename__ = "accounts"
id = Column(Integer, primary_key=True, autoincrement=True)
website_id = Column(Integer, ForeignKey("websites.id", ondelete="CASCADE"), nullable=False)
username = Column(String(500), nullable=False)
password = Column(String(500), nullable=False) # 明文存储,后续加密
remark = Column(Text, nullable=True)
created_by = Column(String(100), nullable=False, default="admin")
updated_by = Column(String(100), nullable=False, default="admin")
sort_order = Column(Integer, default=0)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
website = relationship("Website", back_populates="accounts")
# ===== 上传文件 =====
class Upload(Base):
"""文件上传表 — 图片存储(新文件存文件服务,旧文件兼容 DB blob"""
__tablename__ = "uploads"
id = Column(Integer, primary_key=True, autoincrement=True)
filename = Column(String(255), nullable=False)
content_type = Column(String(100), nullable=False)
data = Column(LargeBinary(length=2**32-1), nullable=True) # 旧图片 LONGBLOB兼容新文件为 NULL
file_id = Column(String(64), nullable=True) # 文件服务返回的 fileId新文件
size = Column(Integer, default=0)
created_by = Column(String(100), nullable=False, default="admin")
created_at = Column(DateTime, default=datetime.utcnow)