36 lines
1.6 KiB
Python
36 lines
1.6 KiB
Python
"""登录账号表(需求第 5 节的"用户认证模块",这版直接做进来了)。"""
|
|||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from datetime import datetime
|
||
|
|
|
||
|
|
from sqlalchemy import Boolean, DateTime, ForeignKey, String
|
||
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||
|
|
|
||
|
|
from app.model.base import Base, SoftDeleteMixin, TimestampMixin
|
||
|
|
from app.model.constants import ROLE_TEXT, Role
|
||
|
|
|
||
|
|
|
||
|
|
class Account(Base, TimestampMixin, SoftDeleteMixin):
|
||
|
|
__tablename__ = "account"
|
||
|
|
__table_args__ = {"comment": "登录账号表"}
|
||
|
|
|
||
|
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||
|
|
username: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, comment="登录名")
|
||
|
|
hashed_password: Mapped[str] = mapped_column(String(120), nullable=False, comment="bcrypt 哈希后的密码")
|
||
|
|
real_name: Mapped[str] = mapped_column(String(30), nullable=False, comment="姓名")
|
||
|
|
role: Mapped[str] = mapped_column(String(20), default=Role.ADVISOR.value, nullable=False, comment="角色 admin/advisor/viewer")
|
||
|
|
advisor_id: Mapped[int | None] = mapped_column(ForeignKey("advisor.id"), comment="关联顾问(顾问账号专用)")
|
||
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False, comment="是否启用")
|
||
|
|
last_login_at: Mapped[datetime | None] = mapped_column(DateTime, comment="最近登录时间")
|
||
|
|
|
||
|
|
advisor: Mapped["Advisor"] = relationship(lazy="joined") # noqa: F821
|
||
|
|
|
||
|
|
@property
|
||
|
|
def role_text(self) -> str:
|
||
|
|
return ROLE_TEXT.get(self.role, self.role)
|
||
|
|
|
||
|
|
@property
|
||
|
|
def is_admin(self) -> bool:
|
||
|
|
return self.role == Role.ADMIN.value
|