Files
freedakgmail 33b4c734aa feat: 完善前后端核心功能模块
后端:
- 新增认证(auth)、任务(tasks)、映射(mappings)、对账(reconciliation)、异常(exceptions)、导出(exports) API
- 新增核心模块: database, security, permissions, tenant, exceptions, error_handlers
- 新增数据模型: user, company, reconciliation_task, field_mapping, uploaded_file 等
- 新增服务层: ai_recognizer, file_parser, file_storage, mapping, reconciliation 等
- 添加数据库迁移脚本

前端:
- 新增登录页面和仪表盘页面
- 新增任务列表、任务详情、字段映射页面
- 新增异常处理页面和规则设置页面
- 新增 API 代理路由 /api/[...path]
- 新增 UI 组件库 (button, card, dialog, input, table 等)
- 新增 auth 组件 (ProtectedRoute, PermissionGate)
- 新增 layout 组件 (Header, Sidebar)
- 新增 mapping 组件 (FieldMappingTable, AISuggestionPanel)
- 新增 API 客户端和 hooks (useAsync, useToast, usePermission 等)
- 新增状态管理 (auth-store, company-store, ui-store)
- 集成 Tailwind CSS 和 shadcn/ui 组件库

其他:
- 添加 Alembic 数据库迁移配置
- 添加初始化示例数据脚本
- 更新项目文档
2026-07-07 09:04:47 +08:00

62 lines
2.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from enum import Enum
from sqlalchemy import Boolean, ForeignKey, Integer, JSON, String, DateTime
from sqlalchemy.orm import Mapped, mapped_column, relationship
from datetime import datetime
from app.models.base import BaseModel
class UserRole(str, Enum):
"""用户角色"""
ADMIN = "管理员"
FINANCE_MANAGER = "财务主管"
ACCOUNTANT = "会计"
CASHIER = "出纳"
HR = "人事"
class UserStatus(str, Enum):
"""用户状态"""
ACTIVE = "正常"
DISABLED = "禁用"
LOCKED = "锁定"
class User(BaseModel):
"""
用户模型
Attributes:
company_id: 企业ID
email: 邮箱(登录账号)
hashed_password: 加密后的密码
full_name: 姓名
role: 角色
permissions: 权限列表(JSONB
status: 状态
last_login_at: 最后登录时间
"""
__tablename__ = "users"
company_id: Mapped[int] = mapped_column(Integer, ForeignKey("companies.id"), nullable=False, index=True)
email: Mapped[str] = mapped_column(String(255), nullable=False, unique=True, index=True)
hashed_password: Mapped[str] = mapped_column(String(255), nullable=False)
full_name: Mapped[str] = mapped_column(String(100), nullable=False)
role: Mapped[str] = mapped_column(String(50), nullable=False, default=UserRole.ACCOUNTANT.value)
permissions: Mapped[dict | None] = mapped_column(JSON, nullable=True)
status: Mapped[str] = mapped_column(String(20), nullable=False, default=UserStatus.ACTIVE.value, index=True)
last_login_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
# 关系
company = relationship("Company", back_populates="users")
def __repr__(self) -> str:
return f"<User(id={self.id}, email='{self.email}', role='{self.role}')>"
def has_permission(self, permission: str) -> bool:
"""检查用户是否有指定权限"""
if not self.permissions:
return False
return permission in self.permissions.get("permissions", [])